Fix the stale disconnected (Zzz) icon persisting when a client reconnects (#1631)

Fix the stale disconnected (Zzz) icon persisting when a client
reconnects

## Description:

Refer to issue #1630 

This change modifies the GameServer.addClient function to send the
mark_disconnected = false intent when a client that was previously
disconnected gets replaced by a newly joined client with the same
clientID. Under the old logic, this mark_disconnected = false intent is
not sent if the client was disconnected for longer than 60 seconds
before reconnecting.



https://github.com/user-attachments/assets/5e0ce1c3-9519-4f39-aa80-e46f1275649c

Left side browser (player with red tiles) is the disconnected client
that was disconnected at 00:14 game clock time. It reconnected around
03:56 game clock time.
Right side browser (player with green tiles) is the other client. Use
the game clock time from the right side for the live game clock time.

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I have read and accepted the CLA agreement (only required once).

## Please put your Discord username so you can be contacted if a bug or
regression is found:

slyty

---------

Co-authored-by: Drills Kibo <59177241+drillskibo@users.noreply.github.com>
This commit is contained in:
Tyler Hanavan
2025-08-01 00:24:15 -04:00
committed by GitHub
parent 38eb48cd2e
commit 488188ff86
2 changed files with 15 additions and 12 deletions
-1
View File
@@ -5,7 +5,6 @@ import { ClientID } from "../core/Schemas";
export class Client {
public lastPing: number = Date.now();
public isDisconnected: boolean = false;
public hashes: Map<Tick, number> = new Map();
+15 -11
View File
@@ -43,6 +43,7 @@ export class GameServer {
public activeClients: Client[] = [];
// Used for record record keeping
private allClients: Map<ClientID, Client> = new Map();
private clientsDisconnectedStatus: Map<ClientID, boolean> = new Map();
private _hasStarted = false;
private _startTime: number | null = null;
@@ -174,7 +175,6 @@ export class GameServer {
return;
}
client.isDisconnected = existing.isDisconnected;
client.lastPing = existing.lastPing;
this.activeClients = this.activeClients.filter((c) => c !== existing);
@@ -184,6 +184,8 @@ export class GameServer {
this.activeClients.push(client);
client.lastPing = Date.now();
this.markClientDisconnected(client.clientID, false);
this.allClients.set(client.clientID, client);
client.ws.removeAllListeners("message");
@@ -571,25 +573,27 @@ export class GameServer {
const now = Date.now();
for (const [clientID, client] of this.allClients) {
if (
client.isDisconnected === false &&
now - client.lastPing > this.disconnectedTimeout
) {
this.markClientDisconnected(client, true);
const isDisconnected = this.isClientDisconnected(clientID);
if (!isDisconnected && now - client.lastPing > this.disconnectedTimeout) {
this.markClientDisconnected(clientID, true);
} else if (
client.isDisconnected &&
isDisconnected &&
now - client.lastPing < this.disconnectedTimeout
) {
this.markClientDisconnected(client, false);
this.markClientDisconnected(clientID, false);
}
}
}
private markClientDisconnected(client: Client, isDisconnected: boolean) {
client.isDisconnected = isDisconnected;
public isClientDisconnected(clientID: string): boolean {
return this.clientsDisconnectedStatus.get(clientID) ?? true;
}
private markClientDisconnected(clientID: string, isDisconnected: boolean) {
this.clientsDisconnectedStatus.set(clientID, isDisconnected);
this.addIntent({
type: "mark_disconnected",
clientID: client.clientID,
clientID: clientID,
isDisconnected: isDisconnected,
});
}