Ensure integrated server is ticked at least once before player connects

Fixes #639
This commit is contained in:
embeddedt 2026-04-12 16:02:54 -04:00
parent d749205427
commit 85955ebf75
No known key found for this signature in database
GPG Key ID: A69433EC199B5613

View File

@ -17,6 +17,8 @@ import org.embeddedt.modernfix.duck.suspend_integrated_server_during_load.IDefer
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.net.Proxy; import java.net.Proxy;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -28,6 +30,7 @@ public abstract class IntegratedServerMixin extends MinecraftServer implements I
@Shadow @Shadow
private boolean paused; private boolean paused;
private int mfix$numTickServerCalls = 0;
private final AtomicBoolean mfix$hasPrimaryClientJoined = new AtomicBoolean(false); private final AtomicBoolean mfix$hasPrimaryClientJoined = new AtomicBoolean(false);
public IntegratedServerMixin(Thread serverThread, LevelStorageSource.LevelStorageAccess storageSource, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer fixerUpper, Services services, ChunkProgressListenerFactory progressListenerFactory) { public IntegratedServerMixin(Thread serverThread, LevelStorageSource.LevelStorageAccess storageSource, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer fixerUpper, Services services, ChunkProgressListenerFactory progressListenerFactory) {
@ -44,14 +47,26 @@ public abstract class IntegratedServerMixin extends MinecraftServer implements I
return !mfix$hasPrimaryClientJoined.get() || original.call(instance); return !mfix$hasPrimaryClientJoined.get() || original.call(instance);
} }
/**
* @author embeddedt
* @reason Keep our own tick count for the integrated server specifically, rather than relying on super
* to increment.
*/
@Inject(method = "tickServer", at = @At("HEAD"))
private void mfix$countTicks(CallbackInfo ci) {
this.mfix$numTickServerCalls++;
}
/** /**
* @author embeddedt * @author embeddedt
* @reason If waiting for a client connection to exist, we only need to tick the server connection, * @reason If waiting for a client connection to exist, we only need to tick the server connection,
* not the whole server as vanilla does. * not the whole server as vanilla does. However, we must tick the whole server once to accommodate mods
* that rely on the first tick to initialize state as a side effect. Not doing this causes issues like
* <a href="https://github.com/embeddedt/ModernFix/issues/639">#639</a>.
*/ */
@WrapWithCondition(method = "tickServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;tickServer(Ljava/util/function/BooleanSupplier;)V", ordinal = 0)) @WrapWithCondition(method = "tickServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;tickServer(Ljava/util/function/BooleanSupplier;)V", ordinal = 0))
private boolean preventRunningFullServerTick(MinecraftServer server, BooleanSupplier hasTimeLeft) { private boolean preventRunningFullServerTick(MinecraftServer server, BooleanSupplier hasTimeLeft) {
if (this.paused && !mfix$hasPrimaryClientJoined.get()) { if (this.mfix$numTickServerCalls >= 2 && this.paused && !mfix$hasPrimaryClientJoined.get()) {
var conn = this.getConnection(); var conn = this.getConnection();
if (conn != null) { if (conn != null) {
conn.tick(); conn.tick();