From 7d04d25e6f6c3315226ac12e15211277ef0f781f Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 7 Jan 2025 20:59:27 -0800 Subject: [PATCH] thread_split: get units working --- src/client/graphics/layers/StructureLayer.ts | 32 ++++++++--------- src/client/graphics/layers/UnitLayer.ts | 3 ++ .../graphics/layers/radial/RadialMenu.ts | 2 +- src/core/GameRunner.ts | 2 -- src/core/GameView.ts | 35 ++++++++++++++----- src/core/configuration/DevConfig.ts | 12 +++---- src/core/game/GameImpl.ts | 13 +++++-- src/core/game/PlayerImpl.ts | 2 +- src/core/game/UnitImpl.ts | 3 +- 9 files changed, 63 insertions(+), 41 deletions(-) diff --git a/src/client/graphics/layers/StructureLayer.ts b/src/client/graphics/layers/StructureLayer.ts index d0c5f5337..34f4fd319 100644 --- a/src/client/graphics/layers/StructureLayer.ts +++ b/src/client/graphics/layers/StructureLayer.ts @@ -24,6 +24,8 @@ export class StructureLayer implements Layer { private unitImages: Map = new Map(); private theme: Theme = null; + private seenUnits = new Set() + // Configuration for supported unit types only private readonly unitConfigs: Partial> = { [UnitType.Port]: { @@ -68,10 +70,10 @@ export class StructureLayer implements Layer { } tick() { + this.game.units().forEach(u => this.handleUnitRendering(new UnitEvent(u, u.tile()))) } init() { - this.eventBus.on(UnitEvent, e => this.onUnitEvent(e)); this.redraw() } @@ -102,6 +104,15 @@ export class StructureLayer implements Layer { const unitType = event.unit.type(); if (!this.isUnitTypeSupported(unitType)) return; + if (event.unit.isActive() && this.seenUnits.has(event.unit)) { + // Already rendered, so don't do anything. + return + } + if (!event.unit.isActive() && !this.seenUnits.has(event.unit)) { + // Has been deleted and render is cleared so don't do anything. + return + } + const config = this.unitConfigs[unitType]; const unitImage = this.unitImages.get(unitType); @@ -112,8 +123,10 @@ export class StructureLayer implements Layer { .forEach(t => this.clearCell(t.cell())); if (!event.unit.isActive()) { + this.seenUnits.delete(event.unit) return; } + this.seenUnits.add(event.unit) // Create temporary canvas for icon processing const tempCanvas = document.createElement('canvas'); @@ -170,23 +183,6 @@ export class StructureLayer implements Layer { } } - onUnitEvent(event: UnitEvent) { - this.handleUnitRendering(event); - if (event.unit.type() == UnitType.DefensePost) { - if (!event.unit.isActive()) { - return - } - // Array.from( - // bfs( - // event.unit.tile(), - // dist(event.unit.tile(), this.game.config().defensePostRange()) - // ) - // ).filter(t => t.isBorder() && t.owner() == event.unit.owner()).forEach(t => { - // this.paintCell(t.cell(), colord({ r: 255, g: 255, b: 255 }), 255) - // }) - } - } - paintCell(cell: Cell, color: Colord, alpha: number) { this.clearCell(cell) this.context.fillStyle = color.alpha(alpha / 255).toRgbString(); diff --git a/src/client/graphics/layers/UnitLayer.ts b/src/client/graphics/layers/UnitLayer.ts index 3d42d0e91..e6588b40b 100644 --- a/src/client/graphics/layers/UnitLayer.ts +++ b/src/client/graphics/layers/UnitLayer.ts @@ -42,6 +42,9 @@ export class UnitLayer implements Layer { if (this.myPlayer == null) { this.myPlayer = this.game.playerByClientID(this.clientID) } + for (const unit of this.game.units()) { + this.onUnitEvent(new UnitEvent(unit, unit.tile())) + } } init() { diff --git a/src/client/graphics/layers/radial/RadialMenu.ts b/src/client/graphics/layers/radial/RadialMenu.ts index acfc9e4a7..0e571eae3 100644 --- a/src/client/graphics/layers/radial/RadialMenu.ts +++ b/src/client/graphics/layers/radial/RadialMenu.ts @@ -274,7 +274,7 @@ export class RadialMenu implements Layer { this.activateMenuElement(Slot.Boat, "#3f6ab1", boatIcon, () => { this.eventBus.emit( new SendBoatAttackIntentEvent( - myPlayer.id(), + tile.owner().id(), this.clickedCell, this.uiState.attackRatio * myPlayer.troops() ) diff --git a/src/core/GameRunner.ts b/src/core/GameRunner.ts index d9de3f8a7..274fd9d86 100644 --- a/src/core/GameRunner.ts +++ b/src/core/GameRunner.ts @@ -86,8 +86,6 @@ export class GameRunner { packedTileUpdates: Array.from(this.updatedTiles).map(t => packTileData(t.toViewData())), players: playerViewData }) - - this.isExecuting = false } diff --git a/src/core/GameView.ts b/src/core/GameView.ts index 41accf38a..abdb8b3a8 100644 --- a/src/core/GameView.ts +++ b/src/core/GameView.ts @@ -64,6 +64,7 @@ export class TileView { } export interface UnitViewData extends ViewData { + id: number, type: UnitType, troops: number, x: number, @@ -73,23 +74,31 @@ export interface UnitViewData extends ViewData { health?: number } -export class UnitView { - constructor(private data: UnitViewData) { } +export class UnitView implements Unit { + constructor(private gameView: GameView, private data: UnitViewData) { } + + update(data: UnitViewData) { + this.data = data + } + + id(): number { + return this.data.id + } type(): UnitType { - throw new Error("Method not implemented."); + return this.data.type } troops(): number { - throw new Error("Method not implemented."); + return this.data.troops } - tile(): TileView { - throw new Error("Method not implemented."); + tile(): Tile { + return this.gameView.tile(new Cell(this.data.x, this.data.y)) } owner(): PlayerView { - throw new Error("Method not implemented."); + return this.gameView.player(this.data.owner) } isActive(): boolean { - throw new Error("Method not implemented."); + return this.data.isActive } hasHealth(): boolean { return this.data.health != undefined @@ -276,6 +285,7 @@ export class GameView { private tiles: TileView[][] = [] private smallIDToID = new Map() private _players = new Map() + private _units = new Map() constructor(public worker: WorkerClient, private _config: Config, private _terrainMap: TerrainMap) { // Initialize the 2D array @@ -310,6 +320,13 @@ export class GameView { this._players.set(key, new PlayerView(this, value)) } }); + gu.units.forEach(unit => { + if (this._units.has(unit.id)) { + this._units.get(unit.id).update(unit) + } else { + this._units.set(unit.id, new UnitView(this, unit)) + } + }) } recentlyUpdatedTiles(): TileView[] { @@ -377,7 +394,7 @@ export class GameView { return this._config } units(...types: UnitType[]): Unit[] { - return [] + return Array.from(this._units.values()) } unitInfo(type: UnitType): UnitInfo { return this._config.unitInfo(type) diff --git a/src/core/configuration/DevConfig.ts b/src/core/configuration/DevConfig.ts index 59d83dc33..7e4999d6f 100644 --- a/src/core/configuration/DevConfig.ts +++ b/src/core/configuration/DevConfig.ts @@ -23,12 +23,12 @@ export class DevConfig extends DefaultConfig { // return 100 } - // unitInfo(type: UnitType): UnitInfo { - // const info = super.unitInfo(type) - // const oldCost = info.cost - // info.cost = (p: Player) => oldCost(p) / 10000 - // return info - // } + unitInfo(type: UnitType): UnitInfo { + const info = super.unitInfo(type) + const oldCost = info.cost + info.cost = (p: Player) => oldCost(p) / 10000 + return info + } // tradeShipSpawnRate(): number { // return 10 diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index 327072fc0..c7cc9e8c7 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -40,7 +40,8 @@ export class GameImpl implements MutableGame { allianceRequests: AllianceRequestImpl[] = [] alliances_: AllianceImpl[] = [] - private nextID = 1 + private nextPlayerID = 1 + private _nextUnitID = 1 constructor( @@ -68,6 +69,12 @@ export class GameImpl implements MutableGame { )) } + nextUnitID(): number { + const old = this._nextUnitID + this._nextUnitID++ + return old + } + addFallout(tile: Tile) { const ti = tile as TileImpl if (tile.hasOwner()) { @@ -247,8 +254,8 @@ export class GameImpl implements MutableGame { } addPlayer(playerInfo: PlayerInfo, manpower: number): MutablePlayer { - let player = new PlayerImpl(this, this.nextID, playerInfo, manpower) - this.nextID++ + let player = new PlayerImpl(this, this.nextPlayerID, playerInfo, manpower) + this.nextPlayerID++ this._players.set(playerInfo.id, player) return player } diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 11edd1445..8644d50e6 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -424,7 +424,7 @@ export class PlayerImpl implements MutablePlayer { buildUnit(type: UnitType, troops: number, spawnTile: Tile): UnitImpl { const cost = this.gs.unitInfo(type).cost(this) - const b = new UnitImpl(type, this.gs, spawnTile, troops, this); + const b = new UnitImpl(type, this.gs, spawnTile, troops, this.gs.nextUnitID(), this); this._units.push(b); this.removeGold(cost) this.removeTroops(troops) diff --git a/src/core/game/UnitImpl.ts b/src/core/game/UnitImpl.ts index faacaca18..a21e69d8c 100644 --- a/src/core/game/UnitImpl.ts +++ b/src/core/game/UnitImpl.ts @@ -4,7 +4,6 @@ import { simpleHash, within } from "../Util"; import { MutableUnit, Tile, TerraNullius, UnitType, Player, UnitInfo } from "./Game"; import { GameImpl } from "./GameImpl"; import { PlayerImpl } from "./PlayerImpl"; -import { TerraNulliusImpl } from "./TerraNulliusImpl"; export class UnitImpl implements MutableUnit { @@ -16,6 +15,7 @@ export class UnitImpl implements MutableUnit { private g: GameImpl, private _tile: Tile, private _troops: number, + private _id: number, public _owner: PlayerImpl, ) { // default to half health (or 1 is no health specified) @@ -24,6 +24,7 @@ export class UnitImpl implements MutableUnit { toViewData(): UnitViewData { return { + id: this._id, type: this._type, troops: this._troops, x: this.tile().cell().x,