Merge pull request #101 from Zhyren-git/fix/keepalive-timeout

Fixes player getting "Timed out" while standing still due to Keep-Alive not being sent correctly.
This commit is contained in:
LOOHP 2025-12-18 17:00:58 +00:00 committed by GitHub
commit 835caf7d71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 30 additions and 23 deletions

View File

@ -43,7 +43,6 @@ import com.loohp.limbo.inventory.ItemStack;
import com.loohp.limbo.location.GlobalPos;
import com.loohp.limbo.location.Location;
import com.loohp.limbo.network.protocol.packets.ClientboundFinishConfigurationPacket;
import com.loohp.limbo.network.protocol.packets.ClientboundLevelChunkWithLightPacket;
import com.loohp.limbo.network.protocol.packets.ClientboundRegistryDataPacket;
import com.loohp.limbo.network.protocol.packets.PacketHandshakingIn;
import com.loohp.limbo.network.protocol.packets.PacketIn;
@ -112,7 +111,6 @@ import com.loohp.limbo.utils.GameMode;
import com.loohp.limbo.utils.InventoryClickUtils;
import com.loohp.limbo.utils.MojangAPIUtils;
import com.loohp.limbo.utils.MojangAPIUtils.SkinResponse;
import com.loohp.limbo.world.BlockPosition;
import com.loohp.limbo.world.BlockState;
import com.loohp.limbo.world.World;
import net.kyori.adventure.key.Key;
@ -164,10 +162,12 @@ public class ClientConnection extends Thread {
private boolean running;
private volatile ClientState state;
private final AtomicLong lastPacketTimestamp;
private final AtomicLong lastKeepAlivePayLoad;
private final AtomicLong lastKeepAliveResponse;
private Player player;
private TimerTask keepAliveTask;
private AtomicLong lastPacketTimestamp;
private AtomicLong lastKeepAlivePayLoad;
private InetAddress inetAddress;
private boolean ready;
@ -176,6 +176,7 @@ public class ClientConnection extends Thread {
this.inetAddress = clientSocket.getInetAddress();
this.lastPacketTimestamp = new AtomicLong(-1);
this.lastKeepAlivePayLoad = new AtomicLong(-1);
this.lastKeepAliveResponse = new AtomicLong(-1);
this.channel = null;
this.running = false;
this.ready = false;
@ -193,6 +194,10 @@ public class ClientConnection extends Thread {
this.lastKeepAlivePayLoad.set(payLoad);
}
public long getLastKeepAliveResponse() {
return lastKeepAliveResponse.get();
}
public long getLastPacketTimestamp() {
return lastPacketTimestamp.get();
}
@ -251,6 +256,9 @@ public class ClientConnection extends Thread {
} catch (IOException ignored) {
}
try {
ServerProperties properties = Limbo.getInstance().getServerProperties();
String str = (properties.isLogPlayerIPAddresses() ? inetAddress.getHostName() : "<ip address withheld>") + ":" + clientSocket.getPort();
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player disconnected with the reason " + PlainTextComponentSerializer.plainText().serialize(reason));
clientSocket.close();
} catch (IOException ignored) {
}
@ -650,22 +658,21 @@ public class ClientConnection extends Thread {
keepAliveTask = new TimerTask() {
@Override
public void run() {
if (state.equals(ClientState.DISCONNECTED)) {
if (state != ClientState.PLAY || !ready) {
this.cancel();
} else if (ready && state.equals(ClientState.PLAY)) {
long now = System.currentTimeMillis();
if (now - getLastPacketTimestamp() > 15000) {
PacketPlayOutKeepAlive keepAlivePacket = new PacketPlayOutKeepAlive(now);
try {
sendPacket(keepAlivePacket);
setLastKeepAlivePayLoad(now);
} catch (Exception e) {
}
}
}
long now = System.currentTimeMillis();
PacketPlayOutKeepAlive keepAlive = new PacketPlayOutKeepAlive(now);
try {
sendPacket(keepAlive);
setLastKeepAlivePayLoad(now);
} catch (IOException e) {
cancel();
}
}
};
new Timer().schedule(keepAliveTask, 5000, 10000);
new Timer().schedule(keepAliveTask, 0, 10000);
while (clientSocket.isConnected()) {
try {
@ -717,12 +724,12 @@ public class ClientConnection extends Thread {
processMoveEvent.consume(event, to);
}
} else if (packetIn instanceof PacketPlayInKeepAlive) {
long lastPayload = getLastKeepAlivePayLoad();
PacketPlayInKeepAlive alive = (PacketPlayInKeepAlive) packetIn;
if (lastPayload == -1) {
Limbo.getInstance().getConsole().sendMessage("Unsolicited KeepAlive packet for player " + player.getName());
} else if (alive.getPayload() != lastPayload) {
Limbo.getInstance().getConsole().sendMessage("Incorrect Payload received in KeepAlive packet for player " + player.getName());
if (alive.getPayload() == getLastKeepAlivePayLoad()) {
lastKeepAliveResponse.set(System.currentTimeMillis());
} else {
disconnect(Component.text("Bad Keepalive Payload"));
break;
}
} else if (packetIn instanceof PacketPlayInTabComplete) {