mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 13:40:46 +00:00
schedule game duration based on time of day
This commit is contained in:
@@ -63,8 +63,8 @@ export function getServerConfig(): ServerConfig {
|
||||
|
||||
export interface ServerConfig {
|
||||
turnIntervalMs(): number;
|
||||
gameCreationRate(): number;
|
||||
lobbyLifetime(): number;
|
||||
gameCreationRate(highTraffic: boolean): number;
|
||||
lobbyLifetime(highTraffic): number;
|
||||
discordRedirectURI(): string;
|
||||
numWorkers(): number;
|
||||
workerIndex(gameID: GameID): number;
|
||||
|
||||
@@ -30,11 +30,15 @@ export abstract class DefaultServerConfig implements ServerConfig {
|
||||
turnIntervalMs(): number {
|
||||
return 100;
|
||||
}
|
||||
gameCreationRate(): number {
|
||||
return 30 * 1000;
|
||||
gameCreationRate(highTraffic: boolean): number {
|
||||
if (highTraffic) {
|
||||
return 30 * 1000;
|
||||
} else {
|
||||
return 60 * 1000;
|
||||
}
|
||||
}
|
||||
lobbyLifetime(): number {
|
||||
return 1 * 60 * 1000;
|
||||
lobbyLifetime(highTraffic: boolean): number {
|
||||
return this.gameCreationRate(highTraffic) * 2;
|
||||
}
|
||||
workerIndex(gameID: GameID): number {
|
||||
return simpleHash(gameID) % this.numWorkers();
|
||||
|
||||
@@ -8,12 +8,8 @@ export class DevServerConfig extends DefaultServerConfig {
|
||||
env(): GameEnv {
|
||||
return GameEnv.Dev;
|
||||
}
|
||||
gameCreationRate(): number {
|
||||
return 10 * 1000;
|
||||
}
|
||||
|
||||
lobbyLifetime(): number {
|
||||
return 10 * 1000;
|
||||
gameCreationRate(highTraffic: boolean): number {
|
||||
return 5 * 1000;
|
||||
}
|
||||
|
||||
discordRedirectURI(): string {
|
||||
|
||||
+18
-11
@@ -3,6 +3,7 @@ import { GameConfig, GameID } from "../core/Schemas";
|
||||
import { Client } from "./Client";
|
||||
import { GamePhase, GameServer } from "./GameServer";
|
||||
import { Difficulty, GameMapType, GameType } from "../core/game/Game";
|
||||
import { isHighTrafficTime } from "./Util";
|
||||
|
||||
export class GameManager {
|
||||
private games: Map<GameID, GameServer> = new Map();
|
||||
@@ -25,17 +26,23 @@ export class GameManager {
|
||||
}
|
||||
|
||||
createGame(id: GameID, gameConfig: GameConfig | undefined) {
|
||||
const game = new GameServer(id, Date.now(), this.config, {
|
||||
gameMap: GameMapType.World,
|
||||
gameType: GameType.Private,
|
||||
difficulty: Difficulty.Medium,
|
||||
disableNPCs: false,
|
||||
infiniteGold: false,
|
||||
infiniteTroops: false,
|
||||
instantBuild: false,
|
||||
bots: 400,
|
||||
...gameConfig,
|
||||
});
|
||||
const game = new GameServer(
|
||||
id,
|
||||
Date.now(),
|
||||
isHighTrafficTime(),
|
||||
this.config,
|
||||
{
|
||||
gameMap: GameMapType.World,
|
||||
gameType: GameType.Private,
|
||||
difficulty: Difficulty.Medium,
|
||||
disableNPCs: false,
|
||||
infiniteGold: false,
|
||||
infiniteTroops: false,
|
||||
instantBuild: false,
|
||||
bots: 400,
|
||||
...gameConfig,
|
||||
},
|
||||
);
|
||||
this.games.set(id, game);
|
||||
return game;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ export class GameServer {
|
||||
constructor(
|
||||
public readonly id: string,
|
||||
public readonly createdAt: number,
|
||||
public readonly highTraffic: boolean,
|
||||
private config: ServerConfig,
|
||||
public gameConfig: GameConfig,
|
||||
) {}
|
||||
@@ -203,7 +204,7 @@ export class GameServer {
|
||||
return this._startTime;
|
||||
} else {
|
||||
//game hasn't started yet, only works for public games
|
||||
return this.createdAt + this.config.lobbyLifetime();
|
||||
return this.createdAt + this.config.lobbyLifetime(this.highTraffic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,11 +372,12 @@ export class GameServer {
|
||||
}
|
||||
}
|
||||
|
||||
if (now - this.createdAt < this.config.lobbyLifetime()) {
|
||||
if (now - this.createdAt < this.config.lobbyLifetime(this.highTraffic)) {
|
||||
return GamePhase.Lobby;
|
||||
}
|
||||
const warmupOver =
|
||||
now > this.createdAt + this.config.lobbyLifetime() + 30 * 1000;
|
||||
now >
|
||||
this.createdAt + this.config.lobbyLifetime(this.highTraffic) + 30 * 1000;
|
||||
if (noActive && warmupOver && noRecentPings) {
|
||||
return GamePhase.Finished;
|
||||
}
|
||||
@@ -396,7 +398,7 @@ export class GameServer {
|
||||
})),
|
||||
gameConfig: this.gameConfig,
|
||||
msUntilStart: this.isPublic()
|
||||
? this.createdAt + this.config.lobbyLifetime()
|
||||
? this.createdAt + this.config.lobbyLifetime(this.highTraffic)
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
+17
-6
@@ -9,6 +9,7 @@ import { GameInfo } from "../core/Schemas";
|
||||
import path from "path";
|
||||
import rateLimit from "express-rate-limit";
|
||||
import { fileURLToPath } from "url";
|
||||
import { isHighTrafficTime } from "./Util";
|
||||
|
||||
const config = getServerConfig();
|
||||
const readyWorkers = new Set();
|
||||
@@ -62,19 +63,29 @@ export async function startMaster() {
|
||||
console.log(
|
||||
`Worker ${workerId} is ready. (${readyWorkers.size}/${config.numWorkers()} ready)`,
|
||||
);
|
||||
|
||||
// Start scheduling when all workers are ready
|
||||
if (readyWorkers.size === config.numWorkers()) {
|
||||
console.log("All workers ready, starting game scheduling");
|
||||
// let the workers start up
|
||||
|
||||
// Safe implementation of dynamic interval
|
||||
let timeoutId = null;
|
||||
|
||||
const scheduleLobbies = () => {
|
||||
schedulePublicGame().catch((error) => {
|
||||
console.error("Error scheduling public game:", error);
|
||||
});
|
||||
schedulePublicGame()
|
||||
.catch((error) => {
|
||||
console.error("Error scheduling public game:", error);
|
||||
})
|
||||
.finally(() => {
|
||||
// Schedule next run with the current config value
|
||||
const currentLifetime = config.lobbyLifetime(isHighTrafficTime());
|
||||
timeoutId = setTimeout(scheduleLobbies, currentLifetime);
|
||||
});
|
||||
};
|
||||
|
||||
// Run first execution immediately
|
||||
scheduleLobbies();
|
||||
setInterval(scheduleLobbies, config.gameCreationRate());
|
||||
|
||||
// Regular interval for fetching lobbies
|
||||
setInterval(() => fetchLobbies(), 250);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
export function isHighTrafficTime(): boolean {
|
||||
// More traffic from 4am to 4pm
|
||||
const now = new Date();
|
||||
|
||||
// Convert current time to PST (America/Los_Angeles timezone)
|
||||
// Using a more compatible approach
|
||||
const formatter = new Intl.DateTimeFormat("en-US", {
|
||||
timeZone: "America/Los_Angeles",
|
||||
hour: "numeric",
|
||||
hour12: false,
|
||||
});
|
||||
|
||||
const formattedTime = formatter.format(now);
|
||||
const hourPST = parseInt(formattedTime.split(":")[0], 10);
|
||||
|
||||
return hourPST >= 4 && hourPST < 16;
|
||||
}
|
||||
Reference in New Issue
Block a user