/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.collect.Lists * com.mojang.logging.LogUtils * io.netty.bootstrap.Bootstrap * io.netty.channel.Channel * io.netty.channel.ChannelException * io.netty.channel.ChannelHandler * io.netty.channel.ChannelInitializer * io.netty.channel.ChannelOption * org.slf4j.Logger */ package net.minecraft.client.multiplayer; import com.google.common.collect.Lists; import com.mojang.logging.LogUtils; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelException; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Optional; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.screens.ConnectScreen; import net.minecraft.client.multiplayer.LegacyServerPinger; import net.minecraft.client.multiplayer.ServerData; import net.minecraft.client.multiplayer.resolver.ResolvedServerAddress; import net.minecraft.client.multiplayer.resolver.ServerAddress; import net.minecraft.client.multiplayer.resolver.ServerNameResolver; import net.minecraft.network.Connection; import net.minecraft.network.DisconnectionDetails; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.ping.ClientboundPongResponsePacket; import net.minecraft.network.protocol.ping.ServerboundPingRequestPacket; import net.minecraft.network.protocol.status.ClientStatusPacketListener; import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket; import net.minecraft.network.protocol.status.ServerStatus; import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.EventLoopGroupHolder; import net.minecraft.server.players.NameAndId; import net.minecraft.util.Util; import org.slf4j.Logger; 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 final List connections = Collections.synchronizedList(Lists.newArrayList()); public void pingServer(final ServerData data, final Runnable onPersistentDataChange, final Runnable onPongResponse, final EventLoopGroupHolder eventLoopGroupHolder) throws UnknownHostException { final ServerAddress rawAddress = ServerAddress.parseString(data.ip); Optional resolvedAddress = ServerNameResolver.DEFAULT.resolveAddress(rawAddress).map(ResolvedServerAddress::asInetSocketAddress); if (resolvedAddress.isEmpty()) { this.onPingFailed(ConnectScreen.UNKNOWN_HOST_MESSAGE, data); return; } 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; @Override public void handleStatusResponse(ClientboundStatusResponsePacket packet) { if (this.receivedPing) { connection.disconnect(Component.translatable("multiplayer.status.unrequested")); return; } this.receivedPing = true; ServerStatus status = packet.status(); data.motd = status.description(); status.version().ifPresentOrElse(version -> { data2.version = Component.literal(version.name()); data2.protocol = version.protocol(); }, () -> { data2.version = Component.translatable("multiplayer.status.old"); data2.protocol = 0; }); status.players().ifPresentOrElse(players -> { data2.status = ServerStatusPinger.formatPlayerCount(players.online(), players.max()); data2.players = players; if (!players.sample().isEmpty()) { ArrayList playerNames = new ArrayList(players.sample().size()); for (NameAndId profile : players.sample()) { MutableComponent playerName = profile.equals(MinecraftServer.ANONYMOUS_PLAYER_PROFILE) ? Component.translatable("multiplayer.status.anonymous_player") : 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())); } data2.playerList = playerNames; } else { data2.playerList = List.of(); } }, () -> { data2.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; } @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 t) { LOGGER.error("Failed to ping server {}", (Object)rawAddress, (Object)t); } } private void onPingFailed(Component reason, ServerData data) { LOGGER.error("Can't ping {}: {}", (Object)data.ip, (Object)reason.getString()); data.motd = CANT_CONNECT_MESSAGE; data.status = CommonComponents.EMPTY; } private void pingLegacyServer(InetSocketAddress resolvedAddress, final ServerAddress rawAddress, final ServerData data, EventLoopGroupHolder eventLoopGroupHolder) { ((Bootstrap)((Bootstrap)((Bootstrap)new Bootstrap().group(eventLoopGroupHolder.eventLoopGroup())).handler((ChannelHandler)new ChannelInitializer(this){ protected void initChannel(Channel channel) { try { channel.config().setOption(ChannelOption.TCP_NODELAY, (Object)true); } catch (ChannelException channelException) { // empty catch block } channel.pipeline().addLast(new ChannelHandler[]{new LegacyServerPinger(rawAddress, (protocolVersion, gameVersion, motd, players, maxPlayers) -> { data.setState(ServerData.State.INCOMPATIBLE); data2.version = Component.literal(gameVersion); data2.motd = Component.literal(motd); data2.status = ServerStatusPinger.formatPlayerCount(players, maxPlayers); data2.players = new ServerStatus.Players(maxPlayers, players, List.of()); })}); } })).channel(eventLoopGroupHolder.channelCls())).connect(resolvedAddress.getAddress(), resolvedAddress.getPort()); } public static Component formatPlayerCount(int curPlayers, int maxPlayers) { MutableComponent current = Component.literal(Integer.toString(curPlayers)).withStyle(ChatFormatting.GRAY); MutableComponent max = Component.literal(Integer.toString(maxPlayers)).withStyle(ChatFormatting.GRAY); return Component.translatable("multiplayer.status.player_count", current, max).withStyle(ChatFormatting.DARK_GRAY); } /* * WARNING - Removed try catching itself - possible behaviour change. */ public void tick() { List list = this.connections; synchronized (list) { Iterator iterator = this.connections.iterator(); while (iterator.hasNext()) { Connection connection = iterator.next(); if (connection.isConnected()) { connection.tick(); continue; } iterator.remove(); connection.handleDisconnection(); } } } /* * WARNING - Removed try catching itself - possible behaviour change. */ public void removeAll() { List list = this.connections; synchronized (list) { Iterator iterator = this.connections.iterator(); while (iterator.hasNext()) { Connection connection = iterator.next(); if (!connection.isConnected()) continue; iterator.remove(); connection.disconnect(Component.translatable("multiplayer.status.cancelled")); } } } }