From 2441abd7c8102e3486498bcb7e5aa2b66f37cecc Mon Sep 17 00:00:00 2001 From: Evan Date: Fri, 3 Jan 2025 11:15:11 -0800 Subject: [PATCH] game kind of working with GameView --- src/client/ClientGameRunner.ts | 2 +- src/client/graphics/layers/UILayer.ts | 2 +- src/core/GameRunner.ts | 9 ++- src/core/GameView.ts | 100 ++++++++++++------------ src/core/configuration/Config.ts | 2 +- src/core/configuration/DefaultConfig.ts | 4 +- src/core/configuration/DevConfig.ts | 4 +- src/core/game/Game.ts | 1 + src/core/game/GameImpl.ts | 4 +- src/core/game/TerraNulliusImpl.ts | 10 +-- src/core/game/TerrainMapLoader.ts | 3 + 11 files changed, 76 insertions(+), 65 deletions(-) diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index 6074970db..416cdcadd 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -74,7 +74,7 @@ export async function createClientGame(lobbyConfig: LobbyConfig, gameConfig: Gam const config = getConfig(gameConfig) const terrainMap = await loadTerrainMap(gameConfig.gameMap); - const gameView = new GameView(terrainMap.map) + const gameView = new GameView(config, terrainMap.map) const worker = new WorkerClient(lobbyConfig.gameID, gameConfig) await worker.initialize() diff --git a/src/client/graphics/layers/UILayer.ts b/src/client/graphics/layers/UILayer.ts index 853ad7a95..9bf976eb2 100644 --- a/src/client/graphics/layers/UILayer.ts +++ b/src/client/graphics/layers/UILayer.ts @@ -36,7 +36,7 @@ export class UILayer implements Layer { const barHeight = 15; const barBackgroundWidth = this.transformHandler.width(); - const ratio = this.game.ticks() / this.game.config().numSpawnPhaseTurns(this.game.config().gameConfig().gameType) + const ratio = this.game.ticks() / this.game.config().numSpawnPhaseTurns() // Draw bar background context.fillStyle = 'rgba(0, 0, 0, 0.5)'; diff --git a/src/core/GameRunner.ts b/src/core/GameRunner.ts index 8a114c487..6b8b99a78 100644 --- a/src/core/GameRunner.ts +++ b/src/core/GameRunner.ts @@ -2,10 +2,10 @@ import { getConfig } from "./configuration/Config"; import { EventBus } from "./EventBus"; import { Executor } from "./execution/ExecutionManager"; import { WinCheckExecution } from "./execution/WinCheckExecution"; -import { Game, MutableGame, MutableTile, Tile, TileEvent } from "./game/Game"; +import { Game, MutableGame, MutableTile, PlayerID, Tile, TileEvent } from "./game/Game"; import { createGame } from "./game/GameImpl"; import { loadTerrainMap } from "./game/TerrainMapLoader"; -import { GameUpdateViewData } from "./GameView"; +import { GameUpdateViewData, PlayerViewData } from "./GameView"; import { GameConfig, Turn } from "./Schemas"; export async function createGameRunner(gameID: string, gameConfig: GameConfig, callBack: (gu: GameUpdateViewData) => void): Promise { @@ -63,9 +63,12 @@ export class GameRunner { this.game.executeNextTick() this.callBack({ + tick: this.game.ticks(), units: this.game.units().map(u => u.toViewData()), tileUpdates: this.updatedTiles.map(t => t.toViewData()), - players: this.game.players().map(p => p.toViewData()) + players: Object.fromEntries( + this.game.players().map(p => [p.id(), p.toViewData()]) + ) as Record }) this.isExecuting = false diff --git a/src/core/GameView.ts b/src/core/GameView.ts index e149564e8..9d8357b19 100644 --- a/src/core/GameView.ts +++ b/src/core/GameView.ts @@ -2,6 +2,7 @@ import { MessageType, Player, Tile, Unit } from './game/Game'; import { Config } from "./configuration/Config"; import { Alliance, AllianceRequest, AllPlayers, Cell, DefenseBonus, EmojiMessage, Execution, ExecutionView, Game, Gold, MutableTile, Nation, PlayerID, PlayerInfo, PlayerType, Relation, TerrainMap, TerrainTile, TerrainType, TerraNullius, Tick, UnitInfo, UnitType } from "./game/Game"; import { ClientID } from "./Schemas"; +import { TerraNulliusImpl } from './game/TerraNulliusImpl'; export interface ViewSerializable { toViewData(): T; @@ -21,24 +22,29 @@ export interface TileViewData extends ViewData { } export class TileView { + constructor(private game: GameView, private data: TileViewData, private _terrain: TerrainTile) { } + type(): TerrainType { return this._terrain.type() } owner(): Player | TerraNullius { - return this.game.player(this.data.owner) + if (!this.hasOwner()) { + return new TerraNulliusImpl() + } + return this.game.player(this.data?.owner) } hasOwner(): boolean { - return this.data.owner != null + return this.data?.owner != undefined } isBorder(): boolean { - return this.data.isBorder + return this.data?.isBorder } cell(): Cell { - return new Cell(this.data.x, this.data.y) + return this._terrain.cell() } hasFallout(): boolean { - return this.data.hasFallout + return this.data?.hasFallout } terrain(): TerrainTile { return this._terrain @@ -109,8 +115,11 @@ export interface PlayerViewData extends ViewData { targetTroopRatio: number } -export class PlayerView { - constructor(private game: Game, private data: PlayerViewData) { } +export class PlayerView implements Player { + constructor(private game: GameView, private data: PlayerViewData) { } + lastTileChange(): Tick { + return 0 + } name(): string { return this.data.name } @@ -129,7 +138,7 @@ export class PlayerView { isAlive(): boolean { return this.data.isAlive } - isPlayer(): this is PlayerView { + isPlayer(): this is Player { return true } numTilesOwned(): number { @@ -217,95 +226,90 @@ export class PlayerView { } export interface GameUpdateViewData extends ViewData { + tick: number units: UnitViewData[] - players: PlayerViewData[] + players: Record tileUpdates: TileViewData[] } export class GameView { - private lastGameUpdate: GameUpdateViewData + private data: GameUpdateViewData private tiles: TileViewData[][] = [] - constructor(private _terrainMap: TerrainMap) { } - executions(): ExecutionView[] { - throw new Error("Method not implemented."); - } - executeNextTick(): void { - throw new Error("Method not implemented."); + constructor(private _config: Config, private _terrainMap: TerrainMap) { + this.tiles = Array(_terrainMap.width()).fill(null).map(() => Array(_terrainMap.height()).fill(null)); + this.data = { + tick: 0, + units: [], + tileUpdates: [], + players: {} + } } public update(gu: GameUpdateViewData) { - this.lastGameUpdate = gu + this.data = gu gu.tileUpdates.forEach(tu => { this.tiles[tu.x][tu.y] = tu }) } recentlyUpdatedTiles(): TileView[] { - return this.lastGameUpdate.tileUpdates.map(tu => new TileView(this, tu, this._terrainMap.terrain(new Cell(tu.x, tu.y)))) + return this.data.tileUpdates.map(tu => new TileView(this, tu, this._terrainMap.terrain(new Cell(tu.x, tu.y)))) } player(id: PlayerID): Player { - throw new Error("Method not implemented."); + if (id in this.data.players) { + return new PlayerView(this, this.data.players[id]) + } + throw Error(`player id ${id} not found`) } playerByClientID(id: ClientID): Player | null { - throw new Error("Method not implemented."); + return null } hasPlayer(id: PlayerID): boolean { - throw new Error("Method not implemented."); + return false } players(): Player[] { - throw new Error("Method not implemented."); + return [] } tile(cell: Cell): Tile { - throw new Error("Method not implemented."); + return new TileView(this, this.tiles[cell.x][cell.y], this._terrainMap.terrain(cell)) } isOnMap(cell: Cell): boolean { - throw new Error("Method not implemented."); + return this._terrainMap.isOnMap(cell) } width(): number { - throw new Error("Method not implemented."); + return this._terrainMap.width() } height(): number { - throw new Error("Method not implemented."); + return this._terrainMap.height() } numLandTiles(): number { throw new Error("Method not implemented."); } forEachTile(fn: (tile: Tile) => void): void { - throw new Error("Method not implemented."); - } - terraNullius(): TerraNullius { - throw new Error("Method not implemented."); + for (let x = 0; x < this._terrainMap.width(); x++) { + for (let y = 0; y < this._terrainMap.height(); y++) { + fn(this.tile(new Cell(x, y))) + } + } } ticks(): Tick { - throw new Error("Method not implemented."); + return this.data.tick } inSpawnPhase(): boolean { - throw new Error("Method not implemented."); - } - addExecution(...exec: Execution[]): void { - throw new Error("Method not implemented."); - } - nations(): Nation[] { - throw new Error("Method not implemented."); + return this.data.tick <= this._config.numSpawnPhaseTurns() } config(): Config { - throw new Error("Method not implemented."); - } - displayMessage(message: string, type: MessageType, playerID: PlayerID | null): void { - throw new Error("Method not implemented."); + return this._config } units(...types: UnitType[]): Unit[] { - throw new Error("Method not implemented."); + return [] } unitInfo(type: UnitType): UnitInfo { - throw new Error("Method not implemented."); + return this._config.unitInfo(type) } terrainMap(): TerrainMap { - throw new Error("Method not implemented."); - } - terrainMiniMap(): TerrainMap { - throw new Error("Method not implemented."); + return this._terrainMap } } \ No newline at end of file diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index f2991967d..7378e8a56 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -54,7 +54,7 @@ export interface Config { percentageTilesOwnedToWin(): number numBots(): number spawnNPCs(): boolean - numSpawnPhaseTurns(gameType: GameType): number + numSpawnPhaseTurns(): number startManpower(playerInfo: PlayerInfo): number populationIncreaseRate(player: Player): number diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index ccac63ba8..8aeeb76ff 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -178,8 +178,8 @@ export class DefaultConfig implements Config { boatMaxDistance(): number { return 500 } - numSpawnPhaseTurns(gameType: GameType): number { - return gameType == GameType.Singleplayer ? 100 : 300 + numSpawnPhaseTurns(): number { + return this._gameConfig.gameType == GameType.Singleplayer ? 100 : 300 } numBots(): number { return 400 diff --git a/src/core/configuration/DevConfig.ts b/src/core/configuration/DevConfig.ts index 0b71918a7..59d83dc33 100644 --- a/src/core/configuration/DevConfig.ts +++ b/src/core/configuration/DevConfig.ts @@ -18,8 +18,8 @@ export class DevConfig extends DefaultConfig { super(sc, gc); } - numSpawnPhaseTurns(gameType: GameType): number { - return gameType == GameType.Singleplayer ? 40 : 200 + numSpawnPhaseTurns(): number { + return this.gameConfig().gameType == GameType.Singleplayer ? 40 : 200 // return 100 } diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 4632f6350..c3806e19f 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -159,6 +159,7 @@ export interface TerrainMap { neighbors(terrainTile: TerrainTile): TerrainTile[] width(): number height(): number + isOnMap(cell: Cell): boolean } export interface TerrainTile extends SearchNode { diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index a155f774b..7ecaaa2ee 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -47,7 +47,7 @@ export class GameImpl implements MutableGame { public eventBus: EventBus, private _config: Config, ) { - this._terraNullius = new TerraNulliusImpl(this) + this._terraNullius = new TerraNulliusImpl() this._width = _terrainMap.width(); this._height = _terrainMap.height(); this._numLandTiles = _terrainMap.numLandTiles @@ -145,7 +145,7 @@ export class GameImpl implements MutableGame { } inSpawnPhase(): boolean { - return this._ticks <= this.config().numSpawnPhaseTurns(this.config().gameConfig().gameType) + return this._ticks <= this.config().numSpawnPhaseTurns() } ticks(): number { diff --git a/src/core/game/TerraNulliusImpl.ts b/src/core/game/TerraNulliusImpl.ts index fd5afdac4..a37bbf3b7 100644 --- a/src/core/game/TerraNulliusImpl.ts +++ b/src/core/game/TerraNulliusImpl.ts @@ -1,13 +1,13 @@ -import {ClientID} from "../Schemas"; -import {TerraNullius, Cell, Tile, PlayerID} from "./Game"; -import {GameImpl} from "./GameImpl"; +import { ClientID } from "../Schemas"; +import { TerraNullius, Cell, Tile, PlayerID } from "./Game"; +import { GameImpl } from "./GameImpl"; export class TerraNulliusImpl implements TerraNullius { public tiles: Map = new Map(); - constructor(private gs: GameImpl) { + constructor() { } clientID(): ClientID { return "TERRA_NULLIUS_CLIENT_ID" @@ -20,5 +20,5 @@ export class TerraNulliusImpl implements TerraNullius { ownsTile(cell: Cell): boolean { return this.tiles.has(cell); } - isPlayer(): false {return false as const;} + isPlayer(): false { return false as const; } } diff --git a/src/core/game/TerrainMapLoader.ts b/src/core/game/TerrainMapLoader.ts index 2ed34664c..1b65815c3 100644 --- a/src/core/game/TerrainMapLoader.ts +++ b/src/core/game/TerrainMapLoader.ts @@ -85,6 +85,9 @@ export class TerrainMapImpl implements TerrainMap { public nationMap: NationMap constructor( ) { } + isOnMap(cell: Cell): boolean { + return cell.x >= 0 && cell.x < this.tiles.length && cell.y >= 0 && cell.y < this.tiles[0].length + } neighbors(terrainTile: TerrainTile): TerrainTile[] { return (terrainTile as TerrainTileImpl).neighbors();