Improve server ping list response

Change the read timeout and connection timeout both to 5s. This
is to decrease the time to label servers as offline.

Additionally, increase the worker count for pinging servers to 128
from 5. This allows many more server pings to occur at the same time,
which allows users to scroll their serverlist.
This commit is contained in:
Spottedleaf
2023-10-30 14:31:39 -07:00
parent a5038c0856
commit 701a7c7fc1
4 changed files with 144 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
package ca.spottedleaf.moonrise.mixin.serverlist;
import ca.spottedleaf.moonrise.patches.serverlist.ServerListConnection;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import net.minecraft.client.multiplayer.ServerStatusPinger;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.Packet;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.net.InetSocketAddress;
@Mixin(Connection.class)
public abstract class ConnectionMixin extends SimpleChannelInboundHandler<Packet<?>> implements ServerListConnection {
@Shadow
private Channel channel;
@Unique
private static final String TIMEOUT_PIPELINE_NAME = "timeout";
@Unique
private static final int DEFAULT_TIMEOUT = 30;
@Unique
private volatile int timeout;
/**
* @reason Initialise fields during construction
* @author Spottedleaf
*/
@Inject(
method = "<init>",
at = @At(
value = "RETURN"
)
)
private void init(final CallbackInfo ci) {
this.timeout = DEFAULT_TIMEOUT;
}
@Override
public final int moonrise$getReadTimeout() {
return this.timeout;
}
@Override
public final void moonrise$setReadTimeout(final int seconds) {
if (this.channel != null) {
this.channel.eventLoop().execute(() -> {
this.timeout = seconds;
if (this.channel != null) {
this.channel.pipeline().replace(TIMEOUT_PIPELINE_NAME, TIMEOUT_PIPELINE_NAME, new ReadTimeoutHandler(seconds));
this.channel.pipeline().channel().config().setOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, seconds * 1000);
}
});
} else {
this.timeout = seconds;
}
}
/**
* @reason Used to set the timeout handler for connectToServer
* @author Spottedleaf
*/
@Inject(
method = "configurePacketHandler",
at = @At(
value = "RETURN"
)
)
private void delayedTimeout(final ChannelPipeline pipeline, final CallbackInfo ci) {
final int timeout = this.timeout;
if (timeout != DEFAULT_TIMEOUT) {
pipeline.replace(TIMEOUT_PIPELINE_NAME, TIMEOUT_PIPELINE_NAME, new ReadTimeoutHandler(timeout));
pipeline.channel().config().setOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout * 1000);
}
}
/**
* @reason Dirty hack to set the timeout before connecting for server ping list
* @author Spottedleaf
*/
@Redirect(
method = "connectToServer",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/network/Connection;connect(Ljava/net/InetSocketAddress;ZLnet/minecraft/network/Connection;)Lio/netty/channel/ChannelFuture;"
)
)
private static ChannelFuture setReadTimeoutHook(final InetSocketAddress address, final boolean epoll,
final Connection connection) {
if (StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).walk((s -> s.filter(f -> f.getDeclaringClass() == ServerStatusPinger.class).findAny())).isPresent()) {
final int timeout = 5;
// reduce timeout to 5s so that non-responding servers release the thread allocation fast
((ServerListConnection)connection).moonrise$setReadTimeout(timeout);
}
return Connection.connect(address, epoll, connection);
}
}

View File

@@ -0,0 +1,23 @@
package ca.spottedleaf.moonrise.mixin.serverlist;
import net.minecraft.client.gui.screens.multiplayer.ServerSelectionList;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(ServerSelectionList.class)
public class ServerSelectionListMixin {
/**
* @reason Massively increase the threadpool count so that slow servers do not stall the pinging of other servers
* on the status list
* @author Spottedleaf
*/
@ModifyConstant(
method = "<clinit>",
constant = @Constant(intValue = 5, ordinal = 0)
)
private static int noPingLimitExecutor(final int constant) {
return 128;
}
}

View File

@@ -0,0 +1,8 @@
package ca.spottedleaf.moonrise.patches.serverlist;
public interface ServerListConnection {
public int moonrise$getReadTimeout();
public void moonrise$setReadTimeout(final int seconds);
}

View File

@@ -47,6 +47,7 @@
"poi_lookup.AcquirePoiMixin",
"poi_lookup.PoiManagerMixin",
"poi_lookup.PortalForcerMixin",
"serverlist.ConnectionMixin",
"starlight.blockstate.BlockStateBaseMixin",
"starlight.chunk.ChunkAccessMixin",
"starlight.chunk.EmptyLevelChunkMixin",
@@ -67,6 +68,7 @@
"collisions.LiquidBlockRendererMixin",
"collisions.ParticleMixin",
"profiler.MinecraftMixin",
"serverlist.ServerSelectionListMixin",
"starlight.multiplayer.ClientPacketListenerMixin",
"starlight.world.ClientLevelMixin"
],