From bc8463fa795de246a391bfe27e4ce349b4ff59c3 Mon Sep 17 00:00:00 2001 From: evanpelle Date: Fri, 16 Aug 2024 20:42:10 -0700 Subject: [PATCH] game start delay 5 seconds --- TODO.txt | 4 +++- src/client/ClientGame.ts | 10 ++++------ src/core/Game.ts | 5 +++-- src/core/GameImpl.ts | 6 ++++++ src/core/configuration/Config.ts | 1 + src/core/configuration/DefaultConfig.ts | 5 ++++- src/core/execution/AttackExecution.ts | 11 +++++++---- src/core/execution/BoatAttackExecution.ts | 6 +++--- src/core/execution/BotExecution.ts | 10 ++++------ src/core/execution/Executor.ts | 16 ++++++++-------- src/core/execution/PlayerExecution.ts | 9 ++++++--- src/core/execution/SpawnExecution.ts | 10 +++++----- 12 files changed, 54 insertions(+), 39 deletions(-) diff --git a/TODO.txt b/TODO.txt index 9a8839e15..71b3403e8 100644 --- a/TODO.txt +++ b/TODO.txt @@ -18,8 +18,9 @@ * fix multiplayer DONE 8/14/2024 * fix server resource leak DONE 8/14/2024 * fix bug where game stops after 10s (websocket disconnection) DONE 8/16/2024 +* balance attacks/expansions better DONE 8/16/2024 +* fix desync * fix server memory leak -* balance attacks/expansions better * BUG: boats not going to destination, coast not being recognized * BUG: boats freeze game on path calculation * double attack add troops @@ -34,3 +35,4 @@ * remove player.info() * fix enemy islands when attacking * BUG: ocean is considered TerraNullius +* on websocket connect server only send missing turns not all turns diff --git a/src/client/ClientGame.ts b/src/client/ClientGame.ts index af97e383b..e5ee2bab8 100644 --- a/src/client/ClientGame.ts +++ b/src/client/ClientGame.ts @@ -1,7 +1,6 @@ import {Executor} from "../core/execution/Executor"; -import {Cell, MutableGame, PlayerEvent, PlayerID, PlayerInfo, MutablePlayer, TerrainMap, TileEvent, Player, Game, BoatEvent, TerrainTypes} from "../core/Game"; +import {Cell, MutableGame, PlayerEvent, PlayerID, MutablePlayer, TerrainMap, TileEvent, Player, Game, BoatEvent, TerrainTypes} from "../core/Game"; import {createGame} from "../core/GameImpl"; -import {Ticker, TickEvent} from "../core/Ticker"; import {EventBus} from "../core/EventBus"; import {Config} from "../core/configuration/Config"; import {GameRenderer} from "./graphics/GameRenderer"; @@ -23,7 +22,7 @@ export function createClientGame(name: string, clientID: ClientID, gameID: GameI gs, gameRenderer, new InputHandler(eventBus), - new Executor(gs, config.player()), + new Executor(gs, config), config ) } @@ -110,8 +109,7 @@ export class ClientGame { this.renderer.initialize() this.input.initialize() - this.executor.spawnBots(this.config.numBots()) - + this.gs.addExecution(...this.executor.spawnBots(this.config.numBots())) this.intervalID = setInterval(() => this.tick(), 10); } @@ -142,7 +140,7 @@ export class ClientGame { private playerEvent(event: PlayerEvent) { console.log('received new player event!') - if (event.player.info().gameID == this.id) { + if (event.player.info().clientID == this.id) { console.log('setting name') this.myPlayer = event.player } diff --git a/src/core/Game.ts b/src/core/Game.ts index 3347c45b2..b2a33df6e 100644 --- a/src/core/Game.ts +++ b/src/core/Game.ts @@ -1,5 +1,5 @@ import {GameEvent} from "./EventBus" -import {GameID} from "./Schemas" +import {ClientID, GameID} from "./Schemas" export type PlayerID = number // TODO: make string? @@ -33,7 +33,7 @@ export class PlayerInfo { public readonly name: string, public readonly isBot: boolean, // null if bot. - public readonly gameID: GameID | null + public readonly clientID: ClientID | null ) { } } @@ -103,6 +103,7 @@ export interface Player { neighbors(): (Player | TerraNullius)[] numTilesOwned(): number sharesBorderWith(other: Player | TerraNullius): boolean + toString(): string } export interface MutablePlayer extends Player { diff --git a/src/core/GameImpl.ts b/src/core/GameImpl.ts index 38df7cb92..4178b5156 100644 --- a/src/core/GameImpl.ts +++ b/src/core/GameImpl.ts @@ -145,6 +145,9 @@ export class PlayerImpl implements MutablePlayer { hash(): number { return this.id() * (this.troops() + this.numTilesOwned()) } + toString(): string { + return `Player:{name:${this.info().name},clientID:${this.info().clientID},isAlive:${this.isAlive()},troops:${this._troops},numTileOwned:${this.numTilesOwned()}}]` + } } class TerraNulliusImpl implements TerraNullius { @@ -220,6 +223,9 @@ export class GameImpl implements MutableGame { if (this.ticks % 100 == 0) { let hash = 1; this._players.forEach(p => { + if (!p.info().isBot) { + console.log(`${p.toString()}`) + } hash += p.hash() }) console.log(`tick ${this.ticks}: hash ${hash}`) diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index 31d164f6f..cdc53bebc 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -9,6 +9,7 @@ export interface Config { gameCreationRate(): number lobbyLifetime(): number numBots(): number + turnsUntilGameStart(): number } export interface PlayerConfig { diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index 3b2486d63..9e3872b97 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -4,8 +4,11 @@ import {Config, PlayerConfig, Theme} from "./Config"; import {pastelTheme} from "./PastelTheme"; export const defaultConfig = new class implements Config { + turnsUntilGameStart(): number { + return 50 + } numBots(): number { - return 1000 + return 20 } player(): PlayerConfig { return defaultPlayerConfig diff --git a/src/core/execution/AttackExecution.ts b/src/core/execution/AttackExecution.ts index c387ac6de..32cfcf7ce 100644 --- a/src/core/execution/AttackExecution.ts +++ b/src/core/execution/AttackExecution.ts @@ -2,7 +2,7 @@ import PriorityQueue from "priority-queue-typescript"; import {Cell, Execution, MutableGame, MutablePlayer, PlayerID, Player, TerrainTypes, TerraNullius, Tile} from "../Game"; import {PseudoRandom} from "../PseudoRandom"; import {manhattanDist} from "../Util"; -import {PlayerConfig} from "../configuration/Config"; +import {Config, PlayerConfig} from "../configuration/Config"; export class AttackExecution implements Execution { private active: boolean = true; @@ -22,7 +22,7 @@ export class AttackExecution implements Execution { private _ownerID: PlayerID, private targetID: PlayerID | null, private targetCell: Cell | null, - private playerConfig: PlayerConfig + private config: Config ) { } init(mg: MutableGame, ticks: number) { @@ -68,8 +68,11 @@ export class AttackExecution implements Execution { if (!this.active) { return } + if (ticks < this.config.turnsUntilGameStart()) { + return + } - let numTilesPerTick = this.playerConfig.attackTilesPerTick(this._owner, this.target, this.numTilesWithEnemy) + let numTilesPerTick = this.config.player().attackTilesPerTick(this._owner, this.target, this.numTilesWithEnemy) if (this.targetCell != null) { numTilesPerTick /= 2 } @@ -104,7 +107,7 @@ export class AttackExecution implements Execution { badTiles++ continue } - const {attackerTroopLoss, defenderTroopLoss, tilesPerTickUsed} = this.playerConfig.attackLogic(this._owner, this.target, tileToConquer) + const {attackerTroopLoss, defenderTroopLoss, tilesPerTickUsed} = this.config.player().attackLogic(this._owner, this.target, tileToConquer) numTilesPerTick -= tilesPerTickUsed this.troops -= attackerTroopLoss if (this.target.isPlayer()) { diff --git a/src/core/execution/BoatAttackExecution.ts b/src/core/execution/BoatAttackExecution.ts index f844c80e4..a855deb16 100644 --- a/src/core/execution/BoatAttackExecution.ts +++ b/src/core/execution/BoatAttackExecution.ts @@ -2,7 +2,7 @@ import PriorityQueue from "priority-queue-typescript"; import {Boat, Cell, Execution, MutableBoat, MutableGame, MutablePlayer, Player, PlayerID, Tile} from "../Game"; import {manhattanDist} from "../Util"; import {AttackExecution} from "./AttackExecution"; -import {PlayerConfig} from "../configuration/Config"; +import {Config, PlayerConfig} from "../configuration/Config"; export class BoatAttackExecution implements Execution { @@ -31,7 +31,7 @@ export class BoatAttackExecution implements Execution { private targetID: PlayerID | null, private cell: Cell, private troops: number, - private playerConfig: PlayerConfig + private config: Config ) { } init(mg: MutableGame, ticks: number) { @@ -82,7 +82,7 @@ export class BoatAttackExecution implements Execution { return } this.attacker.conquer(this.dst) - this.mg.addExecution(new AttackExecution(this.troops, this.attacker.id(), this.targetID, null, this.playerConfig)) + this.mg.addExecution(new AttackExecution(this.troops, this.attacker.id(), this.targetID, null, this.config)) this.active = false return } diff --git a/src/core/execution/BotExecution.ts b/src/core/execution/BotExecution.ts index ce05c8d8b..060a7626e 100644 --- a/src/core/execution/BotExecution.ts +++ b/src/core/execution/BotExecution.ts @@ -1,4 +1,4 @@ -import {PlayerConfig} from "../configuration/Config"; +import {Config, PlayerConfig} from "../configuration/Config"; import {Cell, Execution, MutableGame, MutablePlayer, Player, PlayerID, PlayerInfo, TerrainTypes, TerraNullius} from "../Game" import {PseudoRandom} from "../PseudoRandom" import {AttackExecution} from "./AttackExecution"; @@ -11,9 +11,8 @@ export class BotExecution implements Execution { private gs: MutableGame private neighborsTerra = true - private ticksUntilStart = 50 - constructor(private bot: MutablePlayer, private playerConfig: PlayerConfig) { + constructor(private bot: MutablePlayer, private config: Config) { this.random = new PseudoRandom(bot.id()) this.attackRate = this.random.nextInt(10, 50) @@ -26,10 +25,9 @@ export class BotExecution implements Execution { tick(ticks: number) { - if (ticks < this.ticksUntilStart) { + if (ticks < this.config.turnsUntilGameStart()) { return } - return if (!this.bot.isAlive()) { this.active = false @@ -64,7 +62,7 @@ export class BotExecution implements Execution { this.bot.id(), toAttack.isPlayer() ? toAttack.id() : null, null, - this.playerConfig + this.config )) } diff --git a/src/core/execution/Executor.ts b/src/core/execution/Executor.ts index ff55b5eb2..dcae2545c 100644 --- a/src/core/execution/Executor.ts +++ b/src/core/execution/Executor.ts @@ -5,12 +5,12 @@ import {AttackExecution} from "./AttackExecution"; import {SpawnExecution} from "./SpawnExecution"; import {BotSpawner} from "./BotSpawner"; import {BoatAttackExecution} from "./BoatAttackExecution"; -import {PlayerConfig} from "../configuration/Config"; +import {Config, PlayerConfig} from "../configuration/Config"; export class Executor { - constructor(private gs: Game, private playerConfig: PlayerConfig) { + constructor(private gs: Game, private config: Config) { } @@ -18,20 +18,20 @@ export class Executor { return turn.intents.map(i => this.createExec(i)) } - createExec(intent: Intent) { + createExec(intent: Intent): Execution { if (intent.type == "attack") { return new AttackExecution( intent.troops, intent.attackerID, intent.targetID, new Cell(intent.targetX, intent.targetY), - this.playerConfig + this.config ) } else if (intent.type == "spawn") { return new SpawnExecution( new PlayerInfo(intent.name, intent.isBot, intent.clientID), new Cell(intent.x, intent.y), - this.playerConfig + this.config ) } else if (intent.type == "boat") { return new BoatAttackExecution( @@ -39,7 +39,7 @@ export class Executor { intent.targetID, new Cell(intent.x, intent.y), intent.troops, - this.playerConfig + this.config ) } else { throw new Error(`intent type ${intent} not found`) @@ -47,7 +47,7 @@ export class Executor { } - spawnBots(numBots: number): void { - new BotSpawner(this.gs).spawnBots(numBots).forEach(i => this.createExec(i)) + spawnBots(numBots: number): Execution[] { + return new BotSpawner(this.gs).spawnBots(numBots).map(i => this.createExec(i)) } } \ No newline at end of file diff --git a/src/core/execution/PlayerExecution.ts b/src/core/execution/PlayerExecution.ts index cd1c19ed0..20fbc622b 100644 --- a/src/core/execution/PlayerExecution.ts +++ b/src/core/execution/PlayerExecution.ts @@ -1,11 +1,11 @@ -import {PlayerConfig} from "../configuration/Config" +import {Config, PlayerConfig} from "../configuration/Config" import {Execution, MutableGame, MutablePlayer, PlayerID} from "../Game" export class PlayerExecution implements Execution { private player: MutablePlayer - constructor(private playerID: PlayerID, private playerConfig: PlayerConfig) { + constructor(private playerID: PlayerID, private config: Config) { } init(gs: MutableGame, ticks: number) { @@ -13,7 +13,10 @@ export class PlayerExecution implements Execution { } tick(ticks: number) { - this.player.setTroops(this.playerConfig.troopAdditionRate(this.player)) + if (ticks < this.config.turnsUntilGameStart()) { + return + } + this.player.setTroops(this.config.player().troopAdditionRate(this.player)) } owner(): MutablePlayer { diff --git a/src/core/execution/SpawnExecution.ts b/src/core/execution/SpawnExecution.ts index aa58ce0d9..d4ea07e77 100644 --- a/src/core/execution/SpawnExecution.ts +++ b/src/core/execution/SpawnExecution.ts @@ -1,4 +1,4 @@ -import {PlayerConfig} from "../configuration/Config" +import {Config, PlayerConfig} from "../configuration/Config" import {Cell, Execution, MutableGame, MutablePlayer, PlayerInfo} from "../Game" import {BotExecution} from "./BotExecution" import {PlayerExecution} from "./PlayerExecution" @@ -12,7 +12,7 @@ export class SpawnExecution implements Execution { constructor( private playerInfo: PlayerInfo, private cell: Cell, - private playerConfig: PlayerConfig + private config: Config ) { } @@ -24,13 +24,13 @@ export class SpawnExecution implements Execution { if (!this.isActive()) { return } - const player = this.gs.addPlayer(this.playerInfo, this.playerConfig.startTroops(this.playerInfo)) + const player = this.gs.addPlayer(this.playerInfo, this.config.player().startTroops(this.playerInfo)) getSpawnCells(this.gs, this.cell).forEach(c => { player.conquer(this.gs.tile(c)) }) - this.gs.addExecution(new PlayerExecution(player.id(), this.playerConfig)) + this.gs.addExecution(new PlayerExecution(player.id(), this.config)) if (player.info().isBot) { - this.gs.addExecution(new BotExecution(player, this.playerConfig)) + this.gs.addExecution(new BotExecution(player, this.config)) } this.active = false }