game kind of working with GameView

This commit is contained in:
Evan
2025-01-03 11:15:11 -08:00
parent 3e8517363f
commit 2441abd7c8
11 changed files with 76 additions and 65 deletions
+1 -1
View File
@@ -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()
+1 -1
View File
@@ -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)';
+6 -3
View File
@@ -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<GameRunner> {
@@ -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<PlayerID, PlayerViewData>
})
this.isExecuting = false
+52 -48
View File
@@ -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<T> {
toViewData(): T;
@@ -21,24 +22,29 @@ export interface TileViewData extends ViewData<TileViewData> {
}
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<PlayerViewData> {
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<GameUpdateViewData> {
tick: number
units: UnitViewData[]
players: PlayerViewData[]
players: Record<PlayerID, PlayerViewData>
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
}
}
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
}
+1
View File
@@ -159,6 +159,7 @@ export interface TerrainMap {
neighbors(terrainTile: TerrainTile): TerrainTile[]
width(): number
height(): number
isOnMap(cell: Cell): boolean
}
export interface TerrainTile extends SearchNode {
+2 -2
View File
@@ -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 {
+5 -5
View File
@@ -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<Cell, Tile> = new Map<Cell, Tile>();
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; }
}
+3
View File
@@ -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();