/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.collect.Lists * com.google.common.collect.Maps * com.google.common.collect.Sets * com.mojang.authlib.GameProfile * com.mojang.logging.LogUtils * org.jspecify.annotations.Nullable * org.slf4j.Logger */ package net.minecraft.server.players; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.mojang.authlib.GameProfile; import com.mojang.logging.LogUtils; import java.io.File; import java.io.IOException; import java.net.SocketAddress; import java.nio.file.CopyOption; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.SimpleDateFormat; import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Function; import java.util.function.Predicate; import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; import net.minecraft.core.BlockPos; import net.minecraft.core.LayeredRegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.Connection; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.ChatType; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.OutgoingChatMessage; import net.minecraft.network.chat.PlayerChatMessage; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.common.ClientboundUpdateTagsPacket; import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.network.protocol.game.ClientboundGameEventPacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.network.protocol.game.ClientboundLoginPacket; import net.minecraft.network.protocol.game.ClientboundPlayerAbilitiesPacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; import net.minecraft.network.protocol.game.ClientboundRespawnPacket; import net.minecraft.network.protocol.game.ClientboundSetBorderCenterPacket; import net.minecraft.network.protocol.game.ClientboundSetBorderLerpSizePacket; import net.minecraft.network.protocol.game.ClientboundSetBorderSizePacket; import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDelayPacket; import net.minecraft.network.protocol.game.ClientboundSetBorderWarningDistancePacket; import net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket; import net.minecraft.network.protocol.game.ClientboundSetDefaultSpawnPositionPacket; import net.minecraft.network.protocol.game.ClientboundSetExperiencePacket; import net.minecraft.network.protocol.game.ClientboundSetHeldSlotPacket; import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket; import net.minecraft.network.protocol.game.ClientboundSetSimulationDistancePacket; import net.minecraft.network.protocol.game.ClientboundSetTimePacket; import net.minecraft.network.protocol.game.ClientboundSoundPacket; import net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket; import net.minecraft.network.protocol.game.ClientboundUpdateRecipesPacket; import net.minecraft.network.protocol.game.GameProtocols; import net.minecraft.network.protocol.status.ServerStatus; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.PlayerAdvancements; import net.minecraft.server.RegistryLayer; import net.minecraft.server.ServerScoreboard; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.server.notifications.NotificationService; import net.minecraft.server.permissions.LevelBasedPermissionSet; import net.minecraft.server.permissions.PermissionLevel; import net.minecraft.server.players.IpBanList; import net.minecraft.server.players.IpBanListEntry; import net.minecraft.server.players.NameAndId; import net.minecraft.server.players.ServerOpList; import net.minecraft.server.players.ServerOpListEntry; import net.minecraft.server.players.UserBanList; import net.minecraft.server.players.UserBanListEntry; import net.minecraft.server.players.UserNameToIdResolver; import net.minecraft.server.players.UserWhiteList; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.stats.ServerStatsCounter; import net.minecraft.stats.Stats; import net.minecraft.tags.TagNetworkSerialization; import net.minecraft.util.FileUtil; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.ThrownEnderpearl; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.BorderChangeListener; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.gamerules.GameRules; import net.minecraft.world.level.portal.TeleportTransition; import net.minecraft.world.level.storage.LevelData; import net.minecraft.world.level.storage.LevelResource; import net.minecraft.world.level.storage.PlayerDataStorage; import net.minecraft.world.phys.Vec3; import net.minecraft.world.scores.DisplaySlot; import net.minecraft.world.scores.Objective; import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.Team; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; 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 players = Lists.newArrayList(); private final Map playersByUUID = Maps.newHashMap(); private final UserBanList bans; private final IpBanList ipBans; private final ServerOpList ops; private final UserWhiteList whitelist; private final Map stats = Maps.newHashMap(); private final Map advancements = Maps.newHashMap(); private final PlayerDataStorage playerIo; private final LayeredRegistryAccess registries; private int viewDistance; private int simulationDistance; private boolean allowCommandsForAllPlayers; private int sendAllPlayerInfoIn; public PlayerList(MinecraftServer server, LayeredRegistryAccess 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 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 ({}, {}, {})", new Object[]{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 = player.getGameProfile().name().equalsIgnoreCase(oldName) ? Component.translatable("multiplayer.player.joined", player.getDisplayName()) : 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) { HashSet 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)) continue; List> packets = scoreboard.getStartTrackingPackets(objective); for (Packet packet : packets) { player.connection.send(packet); } objectives.add(objective); } } public void addWorldborderListener(final ServerLevel level) { level.getWorldBorder().addListener(new BorderChangeListener(){ @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 loadPlayerData(NameAndId nameAndId) { CompoundTag singleplayerTag = this.server.getWorldData().getLoadedPlayerTag(); if (this.server.isSingleplayerOwner(nameAndId) && singleplayerTag != null) { LOGGER.debug("loading single player"); return Optional.of(singleplayerTag); } return this.playerIo.load(nameAndId); } protected void save(ServerPlayer player) { PlayerAdvancements advancements; this.playerIo.save(player); ServerStatsCounter stats = this.stats.get(player.getUUID()); if (stats != null) { stats.save(); } if ((advancements = this.advancements.get(player.getUUID())) != null) { advancements.save(); } } public void remove(ServerPlayer player) { Object vehicle; ServerLevel level = player.level(); player.awardStat(Stats.LEAVE_GAME); this.save(player); if (player.isPassenger() && ((Entity)(vehicle = player.getRootVehicle())).hasExactlyOnePlayerPassenger()) { LOGGER.debug("Removing player mount"); player.stopRiding(); ((Entity)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 = (UserBanListEntry)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; } if (!this.isWhiteListed(nameAndId)) { return Component.translatable("multiplayer.disconnect.not_whitelisted"); } 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; } if (this.players.size() >= this.getMaxPlayers() && !this.canBypassPlayerLimit(nameAndId)) { return Component.translatable("multiplayer.disconnect.server_full"); } return null; } public boolean disconnectAllPlayersWithProfile(UUID playerId) { Set dupes = Sets.newIdentityHashSet(); for (ServerPlayer player : this.players) { if (!player.getUUID().equals(playerId)) continue; dupes.add(player); } ServerPlayer serverPlayer = this.playersByUUID.get(playerId); if (serverPlayer != null) { dupes.add(serverPlayer); } for (ServerPlayer player : dupes) { player.connection.disconnect(DUPLICATE_LOGIN_DISCONNECT_MESSAGE); } return !dupes.isEmpty(); } public ServerPlayer respawn(ServerPlayer serverPlayer, boolean keepAllPlayerData, Entity.RemovalReason removalReason) { BlockPos respawnPosition; BlockState blockState; LevelData.RespawnData respawnData; ServerLevel respawnLevel; 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.getTags()) { 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 = keepAllPlayerData ? (byte)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 && (respawnLevel = this.server.getLevel((respawnData = respawnConfig.respawnData()).dimension())) != null && (blockState = respawnLevel.getBlockState(respawnPosition = respawnData.pos())).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 dimension) { for (ServerPlayer player : this.players) { if (player.level().dimension() != dimension) continue; player.connection.send(packet); } } public void broadcastSystemToTeam(Player player, Component message) { PlayerTeam team = player.getTeam(); if (team == null) { return; } Collection teamPlayers = ((Team)team).getPlayers(); for (String name : teamPlayers) { ServerPlayer teamPlayer = this.getPlayerByName(name); if (teamPlayer == null || teamPlayer == player) continue; teamPlayer.sendSystemMessage(message); } } public void broadcastSystemToAllExceptTeam(Player player, Component message) { PlayerTeam team = player.getTeam(); if (team == null) { this.broadcastSystemMessage(message, false); return; } for (int i = 0; i < this.players.size(); ++i) { ServerPlayer targetPlayer = this.players.get(i); if (targetPlayer.getTeam() == team) continue; 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 permissions, Optional 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) { ServerPlayer player; if (this.ops.remove(nameAndId) && (player = this.getPlayer(nameAndId.id())) != null) { this.sendPlayerPermissionLevel(player); } } private void sendPlayerPermissionLevel(ServerPlayer player, LevelBasedPermissionSet permissions) { if (player.connection != null) { byte eventId = switch (permissions.level()) { default -> throw new MatchException(null, null); case PermissionLevel.ALL -> 24; case PermissionLevel.MODERATORS -> 25; case PermissionLevel.GAMEMASTERS -> 26; case PermissionLevel.ADMINS -> 27; case PermissionLevel.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)) continue; return player; } return null; } public void broadcast(@Nullable Player except, double x, double y, double z, double range, ResourceKey dimension, Packet packet) { for (int i = 0; i < this.players.size(); ++i) { double zd; double yd; double xd; ServerPlayer player = this.players.get(i); if (player == except || player.level().dimension() != dimension || !((xd = x - player.getX()) * xd + (yd = y - player.getY()) * yd + (zd = z - player.getZ()) * zd < range * range)) continue; 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(new ClientboundSetTimePacket(level.getGameTime(), level.getDayTime(), level.getGameRules().get(GameRules.ADVANCE_TIME))); 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 getPlayersWithAddress(String ip) { ArrayList result = Lists.newArrayList(); for (ServerPlayer player : this.players) { if (!player.getIpAddress().equals(ip)) continue; result.add(player); } return result; } public int getViewDistance() { return this.viewDistance; } public int getSimulationDistance() { return this.simulationDistance; } public MinecraftServer getServer() { return this.server; } public @Nullable CompoundTag getSingleplayerData() { return null; } public void setAllowCommandsForAllPlayers(boolean allowCommands) { this.allowCommandsForAllPlayers = allowCommands; } public void removeAll() { for (int i = 0; i < this.players.size(); ++i) { this.players.get((int)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 playerMessages, boolean overlay) { this.server.sendSystemMessage(message); for (ServerPlayer player : this.players) { Component playerMessage = playerMessages.apply(player); if (playerMessage == null) continue; 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 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 playerNameStatsPath; Path statFolder = this.server.getWorldPath(LevelResource.PLAYER_STATS_DIR); Path uuidStatsFile = statFolder.resolve(String.valueOf(gameProfile.id()) + ".json"); if (Files.exists(uuidStatsFile, new LinkOption[0])) { return uuidStatsFile; } String playerNameStatsFile = gameProfile.name() + ".json"; if (FileUtil.isValidPathSegment(playerNameStatsFile) && Files.isRegularFile(playerNameStatsPath = statFolder.resolve(playerNameStatsFile), new LinkOption[0])) { try { return Files.move(playerNameStatsPath, uuidStatsFile, new CopyOption[0]); } catch (IOException e) { LOGGER.warn("Failed to copy file {} to {}", (Object)playerNameStatsFile, (Object)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(String.valueOf(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 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)) continue; 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; } }