game start delay 5 seconds

This commit is contained in:
evanpelle
2024-08-16 20:42:10 -07:00
parent 1cf112c0fb
commit bc8463fa79
12 changed files with 54 additions and 39 deletions
+3 -1
View File
@@ -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
+4 -6
View File
@@ -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
}
+3 -2
View File
@@ -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 {
+6
View File
@@ -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}`)
+1
View File
@@ -9,6 +9,7 @@ export interface Config {
gameCreationRate(): number
lobbyLifetime(): number
numBots(): number
turnsUntilGameStart(): number
}
export interface PlayerConfig {
+4 -1
View File
@@ -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
+7 -4
View File
@@ -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()) {
+3 -3
View File
@@ -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
}
+4 -6
View File
@@ -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
))
}
+8 -8
View File
@@ -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))
}
}
+6 -3
View File
@@ -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 {
+5 -5
View File
@@ -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
}