ServerStatusPinger.java
net.minecraft.client.multiplayer.ServerStatusPinger
信息
- 全限定名:net.minecraft.client.multiplayer.ServerStatusPinger
- 类型:public class
- 包:net.minecraft.client.multiplayer
- 源码路径:src/main/java/net/minecraft/client/multiplayer/ServerStatusPinger.java
- 起始行号:L47
- 职责:
TODO
字段/常量
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L48 - 说明:
TODO
- 类型:
-
CANT_CONNECT_MESSAGE- 类型:
Component - 修饰符:
private static final - 源码定位:
L49 - 说明:
TODO
- 类型:
-
DESCRIPTION_SANITIZE_CONTEXT- 类型:
ResolutionContext - 修饰符:
private static final - 源码定位:
L50 - 说明:
TODO
- 类型:
-
connections- 类型:
List<Connection> - 修饰符:
private final - 源码定位:
L55 - 说明:
TODO
- 类型:
内部类/嵌套类型
- 无
构造器
- 无
方法
下面的方法块按源码顺序生成。
public void pingServer(ServerData data, Runnable onPersistentDataChange, Runnable onPongResponse, EventLoopGroupHolder eventLoopGroupHolder) @ L57
- 方法名:pingServer
- 源码定位:L57
- 返回类型:void
- 修饰符:public
参数:
- data: ServerData
- onPersistentDataChange: Runnable
- onPongResponse: Runnable
- eventLoopGroupHolder: EventLoopGroupHolder
说明:
TODO
private void onPingFailed(Component reason, ServerData data) @ L171
- 方法名:onPingFailed
- 源码定位:L171
- 返回类型:void
- 修饰符:private
参数:
- reason: Component
- data: ServerData
说明:
TODO
private void pingLegacyServer(InetSocketAddress resolvedAddress, ServerAddress rawAddress, ServerData data, EventLoopGroupHolder eventLoopGroupHolder) @ L177
- 方法名:pingLegacyServer
- 源码定位:L177
- 返回类型:void
- 修饰符:private
参数:
- resolvedAddress: InetSocketAddress
- rawAddress: ServerAddress
- data: ServerData
- eventLoopGroupHolder: EventLoopGroupHolder
说明:
TODO
public static Component formatPlayerCount(int curPlayers, int maxPlayers) @ L201
- 方法名:formatPlayerCount
- 源码定位:L201
- 返回类型:Component
- 修饰符:public static
参数:
- curPlayers: int
- maxPlayers: int
说明:
TODO
public void tick() @ L207
- 方法名:tick
- 源码定位:L207
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
public void removeAll() @ L223
- 方法名:removeAll
- 源码定位:L223
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class ServerStatusPinger {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Component CANT_CONNECT_MESSAGE = Component.translatable("multiplayer.status.cannot_connect").withColor(-65536);
private static final ResolutionContext DESCRIPTION_SANITIZE_CONTEXT = ResolutionContext.builder()
.withObjectInfoValidator(description -> !(description instanceof PlayerSprite))
.setDepthLimit(16)
.setDepthLimitBehavior(ResolutionContext.LimitBehavior.DISCARD_REMAINING)
.build();
private final List<Connection> connections = Collections.synchronizedList(Lists.newArrayList());
public void pingServer(ServerData data, Runnable onPersistentDataChange, Runnable onPongResponse, EventLoopGroupHolder eventLoopGroupHolder) throws UnknownHostException {
final ServerAddress rawAddress = ServerAddress.parseString(data.ip);
Optional<InetSocketAddress> resolvedAddress = ServerNameResolver.DEFAULT.resolveAddress(rawAddress).map(ResolvedServerAddress::asInetSocketAddress);
if (resolvedAddress.isEmpty()) {
this.onPingFailed(ConnectScreen.UNKNOWN_HOST_MESSAGE, data);
} else {
final InetSocketAddress address = resolvedAddress.get();
final Connection connection = Connection.connectToServer(address, eventLoopGroupHolder, null);
this.connections.add(connection);
data.motd = Component.translatable("multiplayer.status.pinging");
data.playerList = Collections.emptyList();
ClientStatusPacketListener listener = new ClientStatusPacketListener() {
private boolean success;
private boolean receivedPing;
private long pingStart;
{
Objects.requireNonNull(ServerStatusPinger.this);
}
@Override
public void handleStatusResponse(ClientboundStatusResponsePacket packet) {
if (this.receivedPing) {
connection.disconnect(Component.translatable("multiplayer.status.unrequested"));
} else {
this.receivedPing = true;
ServerStatus status = packet.status();
data.motd = sanitizeDescription(status.description());
status.version().ifPresentOrElse(version -> {
data.version = Component.literal(version.name());
data.protocol = version.protocol();
}, () -> {
data.version = Component.translatable("multiplayer.status.old");
data.protocol = 0;
});
status.players().ifPresentOrElse(players -> {
data.status = ServerStatusPinger.formatPlayerCount(players.online(), players.max());
data.players = players;
if (!players.sample().isEmpty()) {
List<Component> playerNames = new ArrayList<>(players.sample().size());
for (NameAndId profile : players.sample()) {
Component playerName;
if (profile.equals(MinecraftServer.ANONYMOUS_PLAYER_PROFILE)) {
playerName = Component.translatable("multiplayer.status.anonymous_player");
} else {
playerName = Component.literal(profile.name());
}
playerNames.add(playerName);
}
if (players.sample().size() < players.online()) {
playerNames.add(Component.translatable("multiplayer.status.and_more", players.online() - players.sample().size()));
}
data.playerList = playerNames;
} else {
data.playerList = List.of();
}
}, () -> data.status = Component.translatable("multiplayer.status.unknown").withStyle(ChatFormatting.DARK_GRAY));
status.favicon().ifPresent(newIcon -> {
if (!Arrays.equals(newIcon.iconBytes(), data.getIconBytes())) {
data.setIconBytes(ServerData.validateIcon(newIcon.iconBytes()));
onPersistentDataChange.run();
}
});
this.pingStart = Util.getMillis();
connection.send(new ServerboundPingRequestPacket(this.pingStart));
this.success = true;
}
}
private static Component sanitizeDescription(Component original) {
try {
return ComponentUtils.resolve(ServerStatusPinger.DESCRIPTION_SANITIZE_CONTEXT, original);
} catch (CommandSyntaxException var2) {
ServerStatusPinger.LOGGER.warn("Failed to sanitize status {}", original, var2);
return Component.empty();
}
}
@Override
public void handlePongResponse(ClientboundPongResponsePacket packet) {
long then = this.pingStart;
long now = Util.getMillis();
data.ping = now - then;
connection.disconnect(Component.translatable("multiplayer.status.finished"));
onPongResponse.run();
}
@Override
public void onDisconnect(DisconnectionDetails details) {
if (!this.success) {
ServerStatusPinger.this.onPingFailed(details.reason(), data);
ServerStatusPinger.this.pingLegacyServer(address, rawAddress, data, eventLoopGroupHolder);
}
}
@Override
public boolean isAcceptingMessages() {
return connection.isConnected();
}
};
try {
connection.initiateServerboundStatusConnection(rawAddress.getHost(), rawAddress.getPort(), listener);
connection.send(ServerboundStatusRequestPacket.INSTANCE);
} catch (Throwable var11) {
LOGGER.error("Failed to ping server {}", rawAddress, var11);
}
}
}
private void onPingFailed(Component reason, ServerData data) {
LOGGER.error("Can't ping {}: {}", data.ip, reason.getString());
data.motd = CANT_CONNECT_MESSAGE;
data.status = CommonComponents.EMPTY;
}
private void pingLegacyServer(InetSocketAddress resolvedAddress, ServerAddress rawAddress, ServerData data, EventLoopGroupHolder eventLoopGroupHolder) {
new Bootstrap().group(eventLoopGroupHolder.eventLoopGroup()).handler(new ChannelInitializer<Channel>() {
{
Objects.requireNonNull(ServerStatusPinger.this);
}
@Override
protected void initChannel(Channel channel) {
try {
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
} catch (ChannelException var3) {
}
channel.pipeline().addLast(new LegacyServerPinger(rawAddress, (protocolVersion, gameVersion, motd, players, maxPlayers) -> {
data.setState(ServerData.State.INCOMPATIBLE);
data.version = Component.literal(gameVersion);
data.motd = Component.literal(motd);
data.status = ServerStatusPinger.formatPlayerCount(players, maxPlayers);
data.players = new ServerStatus.Players(maxPlayers, players, List.of());
}));
}
}).channel(eventLoopGroupHolder.channelCls()).connect(resolvedAddress.getAddress(), resolvedAddress.getPort());
}
public static Component formatPlayerCount(int curPlayers, int maxPlayers) {
Component current = Component.literal(Integer.toString(curPlayers)).withStyle(ChatFormatting.GRAY);
Component max = Component.literal(Integer.toString(maxPlayers)).withStyle(ChatFormatting.GRAY);
return Component.translatable("multiplayer.status.player_count", current, max).withStyle(ChatFormatting.DARK_GRAY);
}
public void tick() {
synchronized (this.connections) {
Iterator<Connection> iterator = this.connections.iterator();
while (iterator.hasNext()) {
Connection connection = iterator.next();
if (connection.isConnected()) {
connection.tick();
} else {
iterator.remove();
connection.handleDisconnection();
}
}
}
}
public void removeAll() {
synchronized (this.connections) {
Iterator<Connection> iterator = this.connections.iterator();
while (iterator.hasNext()) {
Connection connection = iterator.next();
if (connection.isConnected()) {
iterator.remove();
connection.disconnect(Component.translatable("multiplayer.status.cancelled"));
}
}
}
}
}引用的其他类
-
- 引用位置:
构造调用 - 关联成员:
LegacyServerPinger()
- 引用位置:
-
- 引用位置:
参数/方法调用 - 关联成员:
ServerData.validateIcon()
- 引用位置:
-
- 引用位置:
参数/方法调用 - 关联成员:
ServerAddress.parseString()
- 引用位置:
-
- 引用位置:
字段/方法调用 - 关联成员:
Connection.connectToServer()
- 引用位置:
-
- 引用位置:
参数/字段/方法调用/返回值 - 关联成员:
Component.empty(), Component.literal(), Component.translatable()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
ComponentUtils.resolve()
- 引用位置:
-
- 引用位置:
字段/方法调用 - 关联成员:
ResolutionContext.builder()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ServerboundPingRequestPacket()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
ClientStatusPacketListener()
- 引用位置:
-
- 引用位置:
方法调用/构造调用 - 关联成员:
Players(), ServerStatus.Players()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Util.getMillis()
- 引用位置: