Delayed lobby start (#4184)

Resolves #4169

## Description:

Adds a delayed lobby start option.
Utilizes the same system as for public lobbies.
The default for the option is for lobbies to take 3 seconds to start,
however this can easily be changed.

The current setting is controlled through an enable-disable slider,
however there are multiple other options for how to control this.
For example we could do a slider, an input field, a dropdown etc. And i
dont necessarily know if the currently implemented option is the best.

Furhtermore im not sure if i have used the language file completely
correctly. There is now a duplicate field for both private and public
lobby. However there is not category shared between the two. So i
decided to reuse the field from public for private games, as this
simplified the code a bit.

**Host video**

https://github.com/user-attachments/assets/6f3db6e4-7323-4fad-8544-efb8cef4d969

**Non-host video**

https://github.com/user-attachments/assets/ee02a072-1f42-4dde-a5d9-120fda862eb7

## 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


## Please put your Discord username so you can be contacted if a bug or
regression is found:
FrederikJA
This commit is contained in:
FrederikJA
2026-06-12 12:22:03 -07:00
committed by GitHub
parent d96c055df1
commit 19db66f424
10 changed files with 212 additions and 105 deletions
+11 -21
View File
@@ -149,6 +149,9 @@ export class GameServer {
if (gameConfig.maxTimerValue !== undefined) {
this.gameConfig.maxTimerValue = gameConfig.maxTimerValue ?? undefined;
}
if (gameConfig.startDelay !== undefined) {
this.gameConfig.startDelay = gameConfig.startDelay ?? undefined;
}
if (gameConfig.instantBuild !== undefined) {
this.gameConfig.instantBuild = gameConfig.instantBuild;
}
@@ -488,7 +491,7 @@ export class GameServer {
this.updateGameConfig(stampedIntent.config);
return;
}
case "start_game": {
case "toggle_game_start_timer": {
if (client.clientID !== this.lobbyCreatorID) {
this.log.warn(`Only lobby creator can start game`, {
clientID: client.clientID,
@@ -514,7 +517,13 @@ export class GameServer {
creatorID: client.clientID,
gameID: this.id,
});
this.start();
if (this.startsAt) {
this.startsAt = undefined;
} else {
this.setStartsAt(
Date.now() + (this.gameConfig.startDelay ?? 0) * 1000,
);
}
return;
}
case "toggle_pause": {
@@ -931,25 +940,6 @@ export class GameServer {
const noRecentPings = now > this.lastPingUpdate + 20 * 1000;
const noActive = this.activeClients.length === 0;
if (this.gameConfig.gameType !== GameType.Public) {
if (this._hasStarted) {
if (noActive && noRecentPings) {
this.log.info("private game complete", {
gameID: this.id,
});
return GamePhase.Finished;
} else {
return GamePhase.Active;
}
} else if (this._hasEnded) {
return GamePhase.Finished;
} else {
return GamePhase.Lobby;
}
}
// Public Games
const lessThanLifetime = this.startsAt ? Date.now() < this.startsAt : true;
if (
lessThanLifetime &&