mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 15:10:43 +00:00
use GameView in renderers
This commit is contained in:
@@ -7,7 +7,6 @@ import { InputHandler, MouseUpEvent, ZoomEvent, DragEvent, MouseDownEvent } from
|
||||
import { ClientID, ClientIntentMessageSchema, ClientJoinMessageSchema, ClientMessageSchema, GameConfig, GameID, Intent, ServerMessage, ServerMessageSchema, ServerSyncMessage, Turn } from "../core/Schemas";
|
||||
import { loadTerrainFromFile, loadTerrainMap, TerrainMapImpl } from "../core/game/TerrainMapLoader";
|
||||
import { and, bfs, dist, generateID, manhattanDist } from "../core/Util";
|
||||
import { WinCheckExecution } from "../core/execution/WinCheckExecution";
|
||||
import { SendAttackIntentEvent, SendSpawnIntentEvent, Transport } from "./Transport";
|
||||
import { createCanvas } from "./Utils";
|
||||
import { MessageType } from '../core/game/Game';
|
||||
@@ -15,7 +14,7 @@ import { DisplayMessageEvent } from '../core/game/Game';
|
||||
import { WorkerClient } from "../core/worker/WorkerClient";
|
||||
import { consolex, initRemoteSender } from "../core/Consolex";
|
||||
import { getConfig, getServerConfig } from "../core/configuration/Config";
|
||||
import { GameUpdateViewData } from "../core/GameView";
|
||||
import { GameUpdateViewData, GameView } from "../core/GameView";
|
||||
|
||||
export interface LobbyConfig {
|
||||
playerName: () => string
|
||||
@@ -75,17 +74,15 @@ export async function createClientGame(lobbyConfig: LobbyConfig, gameConfig: Gam
|
||||
const config = getConfig(gameConfig)
|
||||
|
||||
const terrainMap = await loadTerrainMap(gameConfig.gameMap);
|
||||
const gameView = new GameView(terrainMap.map)
|
||||
|
||||
let game = createGame(terrainMap.map, terrainMap.miniMap, eventBus, config)
|
||||
const worker = new WorkerClient(lobbyConfig.gameID, gameConfig)
|
||||
await worker.initialize((gu: GameUpdateViewData) => {
|
||||
console.log('got update!')
|
||||
})
|
||||
await worker.initialize()
|
||||
|
||||
consolex.log('going to init path finder')
|
||||
consolex.log('inited path finder')
|
||||
const canvas = createCanvas()
|
||||
let gameRenderer = createRenderer(canvas, game, eventBus, lobbyConfig.clientID)
|
||||
let gameRenderer = createRenderer(canvas, gameView, eventBus, lobbyConfig.clientID)
|
||||
|
||||
|
||||
consolex.log(`creating private game got difficulty: ${gameConfig.difficulty}`)
|
||||
@@ -93,36 +90,29 @@ export async function createClientGame(lobbyConfig: LobbyConfig, gameConfig: Gam
|
||||
return new ClientGameRunner(
|
||||
lobbyConfig.clientID,
|
||||
eventBus,
|
||||
game,
|
||||
gameRenderer,
|
||||
new InputHandler(canvas, eventBus),
|
||||
new Executor(game, lobbyConfig.gameID),
|
||||
transport,
|
||||
worker,
|
||||
gameView
|
||||
)
|
||||
}
|
||||
|
||||
export class ClientGameRunner {
|
||||
private myPlayer: Player
|
||||
private turns: Turn[] = []
|
||||
private isActive = false
|
||||
|
||||
private currTurn = 0
|
||||
|
||||
private intervalID: NodeJS.Timeout
|
||||
|
||||
private isProcessingTurn = false
|
||||
private turnsSeen = 0
|
||||
private hasJoined = false
|
||||
|
||||
constructor(
|
||||
private clientID: ClientID,
|
||||
private eventBus: EventBus,
|
||||
private gs: Game,
|
||||
private renderer: GameRenderer,
|
||||
private input: InputHandler,
|
||||
private executor: Executor,
|
||||
private transport: Transport,
|
||||
private worker: WorkerClient
|
||||
private worker: WorkerClient,
|
||||
private gameView: GameView
|
||||
) { }
|
||||
|
||||
public start() {
|
||||
@@ -133,27 +123,25 @@ export class ClientGameRunner {
|
||||
|
||||
this.renderer.initialize()
|
||||
this.input.initialize()
|
||||
this.gs.addExecution(...this.executor.spawnBots(this.gs.config().numBots()))
|
||||
if (this.gs.config().spawnNPCs()) {
|
||||
this.gs.addExecution(...this.executor.fakeHumanExecutions())
|
||||
}
|
||||
this.gs.addExecution(new WinCheckExecution(this.eventBus))
|
||||
|
||||
this.intervalID = setInterval(() => this.tick(), 10);
|
||||
this.worker.start((gu: GameUpdateViewData) => {
|
||||
this.gameView.update(gu)
|
||||
this.renderer.tick()
|
||||
})
|
||||
|
||||
const onconnect = () => {
|
||||
consolex.log('Connected to game server!');
|
||||
this.transport.joinGame(this.turns.length)
|
||||
this.transport.joinGame(this.turnsSeen)
|
||||
};
|
||||
const onmessage = (message: ServerMessage) => {
|
||||
if (message.type == "start") {
|
||||
this.hasJoined = true
|
||||
consolex.log("starting game!")
|
||||
for (const turn of message.turns) {
|
||||
if (turn.turnNumber < this.turns.length) {
|
||||
if (turn.turnNumber < this.turnsSeen) {
|
||||
continue
|
||||
}
|
||||
this.turns.push(turn)
|
||||
this.worker.sendTurn(turn)
|
||||
this.turnsSeen++
|
||||
}
|
||||
}
|
||||
if (message.type == "turn") {
|
||||
@@ -161,48 +149,23 @@ export class ClientGameRunner {
|
||||
this.transport.joinGame(0)
|
||||
return
|
||||
}
|
||||
if (this.turns.length != message.turn.turnNumber) {
|
||||
consolex.error(`got wrong turn have turns ${this.turns.length}, received turn ${message.turn.turnNumber}`)
|
||||
if (this.turnsSeen != message.turn.turnNumber) {
|
||||
consolex.error(`got wrong turn have turns ${this.turnsSeen}, received turn ${message.turn.turnNumber}`)
|
||||
} else {
|
||||
this.turns.push(message.turn)
|
||||
this.worker.sendTurn(message.turn)
|
||||
this.turnsSeen++
|
||||
}
|
||||
}
|
||||
};
|
||||
this.transport.connect(onconnect, onmessage)
|
||||
|
||||
}
|
||||
|
||||
public stop() {
|
||||
clearInterval(this.intervalID)
|
||||
this.worker.cleanup()
|
||||
this.isActive = false
|
||||
this.transport.leaveGame()
|
||||
}
|
||||
|
||||
public tick() {
|
||||
if (this.currTurn >= this.turns.length || this.isProcessingTurn) {
|
||||
return
|
||||
}
|
||||
this.isProcessingTurn = true
|
||||
this.worker.sendTurn(this.turns[this.currTurn])
|
||||
this.gs.addExecution(...this.executor.createExecs(this.turns[this.currTurn]))
|
||||
try {
|
||||
const start = performance.now()
|
||||
this.gs.executeNextTick()
|
||||
const duration = performance.now() - start
|
||||
if (duration > 200) {
|
||||
console.warn(`tick ${this.gs.ticks() - 1} took ${duration}ms to execute`)
|
||||
}
|
||||
} catch (error) {
|
||||
showErrorModal(error, this.clientID)
|
||||
this.stop()
|
||||
const errorText = `Error: ${error.message}\nStack: ${error.stack}`;
|
||||
consolex.error(errorText)
|
||||
}
|
||||
this.renderer.tick()
|
||||
this.currTurn++
|
||||
this.isProcessingTurn = false
|
||||
}
|
||||
|
||||
private playerEvent(event: PlayerEvent) {
|
||||
if (event.player.clientID() == this.clientID) {
|
||||
consolex.log('setting name')
|
||||
@@ -215,16 +178,16 @@ export class ClientGameRunner {
|
||||
return
|
||||
}
|
||||
const cell = this.renderer.transformHandler.screenToWorldCoordinates(event.x, event.y)
|
||||
if (!this.gs.isOnMap(cell)) {
|
||||
if (!this.gameView.isOnMap(cell)) {
|
||||
return
|
||||
}
|
||||
consolex.log(`clicked cell ${cell}`)
|
||||
const tile = this.gs.tile(cell)
|
||||
if (tile.terrain().isLand() && !tile.hasOwner() && this.gs.inSpawnPhase()) {
|
||||
const tile = this.gameView.tile(cell)
|
||||
if (tile.terrain().isLand() && !tile.hasOwner() && this.gameView.inSpawnPhase()) {
|
||||
this.eventBus.emit(new SendSpawnIntentEvent(cell))
|
||||
return
|
||||
}
|
||||
if (this.gs.inSpawnPhase()) {
|
||||
if (this.gameView.inSpawnPhase()) {
|
||||
return
|
||||
}
|
||||
if (this.myPlayer == null) {
|
||||
|
||||
@@ -19,9 +19,10 @@ import { StructureLayer } from "./layers/StructureLayer";
|
||||
import { PlayerInfoOverlay } from "./layers/PlayerInfoOverlay";
|
||||
import { consolex } from "../../core/Consolex";
|
||||
import { RefreshGraphicsEvent as RedrawGraphicsEvent } from "../InputHandler";
|
||||
import { GameView } from "../../core/GameView";
|
||||
|
||||
|
||||
export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus: EventBus, clientID: ClientID): GameRenderer {
|
||||
export function createRenderer(canvas: HTMLCanvasElement, game: GameView, eventBus: EventBus, clientID: ClientID): GameRenderer {
|
||||
const transformHandler = new TransformHandler(game, eventBus, canvas)
|
||||
|
||||
const uiState = { attackRatio: 20 }
|
||||
@@ -44,6 +45,7 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus:
|
||||
}
|
||||
leaderboard.clientID = clientID
|
||||
leaderboard.eventBus = eventBus
|
||||
leaderboard.game = game
|
||||
|
||||
|
||||
const controlPanel = document.querySelector('control-panel') as ControlPanel;
|
||||
@@ -53,6 +55,7 @@ export function createRenderer(canvas: HTMLCanvasElement, game: Game, eventBus:
|
||||
controlPanel.clientID = clientID
|
||||
controlPanel.eventBus = eventBus
|
||||
controlPanel.uiState = uiState
|
||||
controlPanel.game = game
|
||||
|
||||
const eventsDisplay = document.querySelector('events-display') as EventsDisplay;
|
||||
if (!(eventsDisplay instanceof EventsDisplay)) {
|
||||
@@ -94,7 +97,7 @@ export class GameRenderer {
|
||||
|
||||
private context: CanvasRenderingContext2D
|
||||
|
||||
constructor(private game: Game, private eventBus: EventBus, private canvas: HTMLCanvasElement, public transformHandler: TransformHandler, public uiState: UIState, private layers: Layer[]) {
|
||||
constructor(private game: GameView, private eventBus: EventBus, private canvas: HTMLCanvasElement, public transformHandler: TransformHandler, public uiState: UIState, private layers: Layer[]) {
|
||||
this.context = canvas.getContext("2d")
|
||||
}
|
||||
|
||||
@@ -107,7 +110,7 @@ export class GameRenderer {
|
||||
})
|
||||
})
|
||||
|
||||
this.layers.forEach(l => l.init(this.game))
|
||||
this.layers.forEach(l => l.init())
|
||||
|
||||
document.body.appendChild(this.canvas);
|
||||
window.addEventListener('resize', () => this.resizeCanvas());
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Game, Player, Tile, Cell } from '../../core/game/Game';
|
||||
import { GameView } from '../../core/GameView';
|
||||
import { calculateBoundingBox, within } from '../../core/Util';
|
||||
|
||||
export interface Point {
|
||||
@@ -14,7 +15,7 @@ export interface Rectangle {
|
||||
}
|
||||
|
||||
|
||||
export function placeName(game: Game, player: Player): [position: Cell, fontSize: number] {
|
||||
export function placeName(game: GameView, player: Player): [position: Cell, fontSize: number] {
|
||||
const boundingBox = calculateBoundingBox(player.borderTiles());
|
||||
|
||||
const rawScalingFactor = (boundingBox.max.x - boundingBox.min.x) / 50
|
||||
@@ -38,7 +39,7 @@ export function placeName(game: Game, player: Player): [position: Cell, fontSize
|
||||
return [center, fontSize]
|
||||
}
|
||||
|
||||
export function createGrid(game: Game, player: Player, boundingBox: { min: Point; max: Point }, scalingFactor: number): boolean[][] {
|
||||
export function createGrid(game: GameView, player: Player, boundingBox: { min: Point; max: Point }, scalingFactor: number): boolean[][] {
|
||||
const scaledBoundingBox: { min: Point; max: Point } = {
|
||||
min: {
|
||||
x: Math.floor(boundingBox.min.x / scalingFactor),
|
||||
|
||||
@@ -5,6 +5,7 @@ import { calculateBoundingBox, calculateBoundingBoxCenter, manhattanDist } from
|
||||
import { ZoomEvent, DragEvent } from "../InputHandler";
|
||||
import { GoToPlayerEvent } from "./layers/Leaderboard";
|
||||
import { placeName } from "./NameBoxCalculator";
|
||||
import { GameView } from "../../core/GameView";
|
||||
|
||||
export class TransformHandler {
|
||||
public scale: number = 1.8
|
||||
@@ -14,7 +15,7 @@ export class TransformHandler {
|
||||
private target: Cell
|
||||
private intervalID = null
|
||||
|
||||
constructor(private game: Game, private eventBus: EventBus, private canvas: HTMLCanvasElement) {
|
||||
constructor(private game: GameView, private eventBus: EventBus, private canvas: HTMLCanvasElement) {
|
||||
this.eventBus.on(ZoomEvent, (e) => this.onZoom(e))
|
||||
this.eventBus.on(DragEvent, (e) => this.onMove(e))
|
||||
this.eventBus.on(GoToPlayerEvent, (e) => this.onGoToPlayer(e))
|
||||
|
||||
@@ -7,10 +7,11 @@ import { renderNumber, renderTroops } from '../../Utils';
|
||||
import { EventBus } from '../../../core/EventBus';
|
||||
import { UIState } from '../UIState';
|
||||
import { SendSetTargetTroopRatioEvent } from '../../Transport';
|
||||
import { GameView } from '../../../core/GameView';
|
||||
|
||||
@customElement('control-panel')
|
||||
export class ControlPanel extends LitElement implements Layer {
|
||||
private game: Game;
|
||||
public game: GameView;
|
||||
public clientID: ClientID;
|
||||
public eventBus: EventBus;
|
||||
public uiState: UIState;
|
||||
@@ -51,8 +52,7 @@ export class ControlPanel extends LitElement implements Layer {
|
||||
@state()
|
||||
private _goldPerSecond: number;
|
||||
|
||||
init(game: Game) {
|
||||
this.game = game;
|
||||
init() {
|
||||
this.attackRatio = .20;
|
||||
this.uiState.attackRatio = this.attackRatio;
|
||||
this.currentTroopRatio = this.targetTroopRatio;
|
||||
|
||||
@@ -17,6 +17,7 @@ import { Layer } from "./Layer";
|
||||
import { SendAllianceReplyIntentEvent } from "../../Transport";
|
||||
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
||||
import { onlyImages, sanitize } from '../../../core/Util';
|
||||
import { GameView } from '../../../core/GameView';
|
||||
|
||||
interface Event {
|
||||
description: string;
|
||||
@@ -35,7 +36,7 @@ interface Event {
|
||||
@customElement('events-display')
|
||||
export class EventsDisplay extends LitElement implements Layer {
|
||||
public eventBus: EventBus;
|
||||
public game: Game;
|
||||
public game: GameView;
|
||||
public clientID: ClientID;
|
||||
|
||||
private events: Event[] = [];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Game } from "../../../core/game/Game"
|
||||
|
||||
export interface Layer {
|
||||
init(game: Game)
|
||||
init()
|
||||
tick()
|
||||
renderLayer(context: CanvasRenderingContext2D)
|
||||
shouldTransform(): boolean
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ClientID } from '../../../core/Schemas';
|
||||
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
||||
import { EventBus, GameEvent } from '../../../core/EventBus';
|
||||
import { renderNumber } from '../../Utils';
|
||||
import { GameView } from '../../../core/GameView';
|
||||
|
||||
interface Entry {
|
||||
name: string
|
||||
@@ -23,12 +24,11 @@ export class GoToPlayerEvent implements GameEvent {
|
||||
@customElement('leader-board')
|
||||
export class Leaderboard extends LitElement implements Layer {
|
||||
|
||||
private game: Game
|
||||
public game: GameView
|
||||
public clientID: ClientID
|
||||
public eventBus: EventBus
|
||||
|
||||
init(game: Game) {
|
||||
this.game = game
|
||||
init() {
|
||||
}
|
||||
|
||||
tick() {
|
||||
|
||||
@@ -13,6 +13,7 @@ import targetIcon from '../../../../resources/images/TargetIcon.png';
|
||||
import { ClientID } from "../../../core/Schemas"
|
||||
import { EventBus } from "../../../core/EventBus"
|
||||
import { AlternateViewEvent } from "../../InputHandler"
|
||||
import { GameView } from "../../../core/GameView"
|
||||
|
||||
|
||||
class RenderInfo {
|
||||
@@ -47,7 +48,7 @@ export class NameLayer implements Layer {
|
||||
private alternateView = false
|
||||
|
||||
constructor(
|
||||
private game: Game,
|
||||
private game: GameView,
|
||||
private eventBus: EventBus,
|
||||
private theme: Theme,
|
||||
private transformHandler: TransformHandler,
|
||||
@@ -72,7 +73,7 @@ export class NameLayer implements Layer {
|
||||
return true
|
||||
}
|
||||
|
||||
public init(game: Game) {
|
||||
public init() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@ import { MouseMoveEvent } from '../../InputHandler';
|
||||
import { euclideanDist, distSortUnit } from '../../../core/Util';
|
||||
import { renderNumber, renderTroops } from '../../Utils';
|
||||
import { PauseGameEvent } from '../../Transport';
|
||||
import { GameView } from '../../../core/GameView';
|
||||
|
||||
@customElement('player-info-overlay')
|
||||
export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
@property({ type: Object })
|
||||
public game!: Game;
|
||||
public game!: GameView;
|
||||
|
||||
@property({ type: String })
|
||||
public clientID!: ClientID;
|
||||
@@ -41,8 +42,7 @@ export class PlayerInfoOverlay extends LitElement implements Layer {
|
||||
|
||||
private _isActive = false
|
||||
|
||||
init(game: Game) {
|
||||
this.game = game;
|
||||
init() {
|
||||
this.eventBus.on(MouseMoveEvent, (e: MouseMoveEvent) => this.onMouseEvent(e));
|
||||
this._isActive = true
|
||||
this.showPauseButton = this.game.config().gameConfig().gameType == GameType.Singleplayer
|
||||
|
||||
@@ -9,6 +9,7 @@ import anchorIcon from '../../../../resources/images/AnchorIcon.png';
|
||||
import missileSiloIcon from '../../../../resources/images/MissileSiloUnit.png';
|
||||
import shieldIcon from '../../../../resources/images/ShieldIcon.png';
|
||||
import cityIcon from '../../../../resources/images/CityIcon.png';
|
||||
import { GameView } from "../../../core/GameView";
|
||||
|
||||
interface UnitRenderConfig {
|
||||
icon: string;
|
||||
@@ -47,7 +48,7 @@ export class StructureLayer implements Layer {
|
||||
}
|
||||
};
|
||||
|
||||
constructor(private game: Game, private eventBus: EventBus) {
|
||||
constructor(private game: GameView, private eventBus: EventBus) {
|
||||
this.theme = game.config().theme();
|
||||
this.loadUnitImages();
|
||||
}
|
||||
@@ -69,7 +70,7 @@ export class StructureLayer implements Layer {
|
||||
tick() {
|
||||
}
|
||||
|
||||
init(game: Game) {
|
||||
init() {
|
||||
this.eventBus.on(UnitEvent, e => this.onUnitEvent(e));
|
||||
this.redraw()
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Game } from "../../../core/game/Game";
|
||||
import { throws } from "assert";
|
||||
import { Layer } from "./Layer";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { GameView } from "../../../core/GameView";
|
||||
|
||||
export class TerrainLayer implements Layer {
|
||||
private canvas: HTMLCanvasElement
|
||||
@@ -10,14 +11,14 @@ export class TerrainLayer implements Layer {
|
||||
private imageData: ImageData
|
||||
|
||||
|
||||
constructor(private game: Game) { }
|
||||
constructor(private game: GameView) { }
|
||||
shouldTransform(): boolean {
|
||||
return true
|
||||
}
|
||||
tick() {
|
||||
}
|
||||
|
||||
init(game: Game) {
|
||||
init() {
|
||||
console.log('redrew terrain layer')
|
||||
this.redraw()
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { TransformHandler } from "../TransformHandler";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { initRemoteSender } from "../../../core/Consolex";
|
||||
import { AlternateViewEvent } from "../../InputHandler";
|
||||
import { GameView } from "../../../core/GameView";
|
||||
|
||||
export class TerritoryLayer implements Layer {
|
||||
private canvas: HTMLCanvasElement
|
||||
@@ -26,7 +27,7 @@ export class TerritoryLayer implements Layer {
|
||||
private alternativeView = false
|
||||
|
||||
|
||||
constructor(private game: Game, private eventBus: EventBus) {
|
||||
constructor(private game: GameView, private eventBus: EventBus) {
|
||||
this.theme = game.config().theme()
|
||||
}
|
||||
|
||||
@@ -59,7 +60,7 @@ export class TerritoryLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
init(game: Game) {
|
||||
init() {
|
||||
this.eventBus.on(TileEvent, e => this.tileUpdate(e))
|
||||
this.eventBus.on(AlternateViewEvent, e => { this.alternativeView = e.alternateView })
|
||||
this.redraw()
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ClientID } from "../../../core/Schemas";
|
||||
import { Layer } from "./Layer";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { consolex } from "../../../core/Consolex";
|
||||
import { GameView } from "../../../core/GameView";
|
||||
|
||||
interface MenuOption {
|
||||
label: string;
|
||||
@@ -20,7 +21,7 @@ export class UILayer implements Layer {
|
||||
|
||||
constructor(
|
||||
private eventBus: EventBus,
|
||||
private game: Game,
|
||||
private game: GameView,
|
||||
private clientID: ClientID,
|
||||
private transformHandler: TransformHandler
|
||||
) {
|
||||
@@ -52,7 +53,7 @@ export class UILayer implements Layer {
|
||||
tick() {
|
||||
}
|
||||
|
||||
init(game: Game) {
|
||||
init() {
|
||||
this.createWinModal()
|
||||
this.initRightClickMenu()
|
||||
this.eventBus.on(WinEvent, (e) => this.onWinEvent(e))
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Layer } from "./Layer";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { AlternateViewEvent } from "../../InputHandler";
|
||||
import { ClientID } from "../../../core/Schemas";
|
||||
import { GameView } from "../../../core/GameView";
|
||||
|
||||
enum Relationship {
|
||||
Self,
|
||||
@@ -28,7 +29,7 @@ export class UnitLayer implements Layer {
|
||||
private oldShellTile = new Map<Unit, Tile>()
|
||||
|
||||
|
||||
constructor(private game: Game, private eventBus: EventBus, private clientID: ClientID) {
|
||||
constructor(private game: GameView, private eventBus: EventBus, private clientID: ClientID) {
|
||||
this.theme = game.config().theme();
|
||||
}
|
||||
|
||||
@@ -43,7 +44,7 @@ export class UnitLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
init(game: Game) {
|
||||
init() {
|
||||
this.eventBus.on(UnitEvent, e => this.onUnitEvent(e));
|
||||
this.eventBus.on(AlternateViewEvent, e => this.onAlternativeViewEvent(e))
|
||||
this.redraw()
|
||||
|
||||
@@ -14,6 +14,7 @@ import shieldIcon from '../../../../../resources/images/ShieldIconWhite.svg';
|
||||
import cityIcon from '../../../../../resources/images/CityIconWhite.svg';
|
||||
import { renderNumber } from '../../../Utils';
|
||||
import { ContextMenuEvent } from '../../../InputHandler';
|
||||
import { GameView } from '../../../../core/GameView';
|
||||
|
||||
interface BuildItemDisplay {
|
||||
unitType: UnitType
|
||||
@@ -35,7 +36,7 @@ const buildTable: BuildItemDisplay[][] = [
|
||||
|
||||
@customElement('build-menu')
|
||||
export class BuildMenu extends LitElement {
|
||||
public game: Game;
|
||||
public game: GameView;
|
||||
public eventBus: EventBus;
|
||||
private myPlayer: Player;
|
||||
private clickedCell: Cell;
|
||||
|
||||
@@ -20,6 +20,7 @@ import { EmojiTable } from "./EmojiTable";
|
||||
import { UIState } from "../../UIState";
|
||||
import { BuildMenu } from "./BuildMenu";
|
||||
import { consolex } from "../../../../core/Consolex";
|
||||
import { GameView } from "../../../../core/GameView";
|
||||
|
||||
|
||||
enum Slot {
|
||||
@@ -53,7 +54,7 @@ export class RadialMenu implements Layer {
|
||||
|
||||
constructor(
|
||||
private eventBus: EventBus,
|
||||
private game: Game,
|
||||
private game: GameView,
|
||||
private transformHandler: TransformHandler,
|
||||
private clientID: ClientID,
|
||||
private emojiTable: EmojiTable,
|
||||
@@ -363,7 +364,7 @@ export class RadialMenu implements Layer {
|
||||
}
|
||||
|
||||
if (myPlayerBordersOcean && otherPlayerBordersOcean) {
|
||||
const dst = targetTransportTile(this.game, tile)
|
||||
const dst = targetTransportTile(this.game.width(), tile)
|
||||
if (dst != null) {
|
||||
if (myPlayer.canBuild(UnitType.TransportShip, dst)) {
|
||||
this.activateMenuElement(Slot.Boat, "#3f6ab1", boatIcon, () => {
|
||||
|
||||
+11
-17
@@ -1,6 +1,6 @@
|
||||
import { MessageType } from './game/Game';
|
||||
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, Player, PlayerID, PlayerInfo, PlayerType, Relation, TerrainMap, TerrainTile, TerrainType, TerraNullius, Tick, Tile, Unit, UnitInfo, UnitType } from "./game/Game";
|
||||
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";
|
||||
|
||||
export interface ViewSerializable<T> {
|
||||
@@ -20,8 +20,8 @@ export interface TileViewData extends ViewData<TileViewData> {
|
||||
isBorder: boolean
|
||||
}
|
||||
|
||||
export class TileView implements Tile {
|
||||
constructor(private game: Game, private data: TileViewData, private _terrain: TerrainTile) { }
|
||||
export class TileView {
|
||||
constructor(private game: GameView, private data: TileViewData, private _terrain: TerrainTile) { }
|
||||
type(): TerrainType {
|
||||
return this._terrain.type()
|
||||
}
|
||||
@@ -44,7 +44,7 @@ export class TileView implements Tile {
|
||||
return this._terrain
|
||||
}
|
||||
|
||||
neighbors(): Tile[] {
|
||||
neighbors(): TileView[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export interface UnitViewData extends ViewData<UnitView> {
|
||||
health?: number
|
||||
}
|
||||
|
||||
export class UnitView implements Unit {
|
||||
export class UnitView {
|
||||
constructor(private data: UnitViewData) { }
|
||||
|
||||
type(): UnitType {
|
||||
@@ -76,10 +76,10 @@ export class UnitView implements Unit {
|
||||
troops(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
tile(): Tile {
|
||||
tile(): TileView {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
owner(): Player {
|
||||
owner(): PlayerView {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
isActive(): boolean {
|
||||
@@ -109,7 +109,7 @@ export interface PlayerViewData extends ViewData<PlayerViewData> {
|
||||
targetTroopRatio: number
|
||||
}
|
||||
|
||||
export class PlayerView implements Player {
|
||||
export class PlayerView {
|
||||
constructor(private game: Game, private data: PlayerViewData) { }
|
||||
name(): string {
|
||||
return this.data.name
|
||||
@@ -129,7 +129,7 @@ export class PlayerView implements Player {
|
||||
isAlive(): boolean {
|
||||
return this.data.isAlive
|
||||
}
|
||||
isPlayer(): this is Player {
|
||||
isPlayer(): this is PlayerView {
|
||||
return true
|
||||
}
|
||||
numTilesOwned(): number {
|
||||
@@ -211,9 +211,6 @@ export class PlayerView implements Player {
|
||||
canBuild(type: UnitType, targetTile: Tile): Tile | false {
|
||||
return false
|
||||
}
|
||||
lastTileChange(): Tick {
|
||||
return 0
|
||||
}
|
||||
info(): PlayerInfo {
|
||||
return null
|
||||
}
|
||||
@@ -225,7 +222,7 @@ export interface GameUpdateViewData extends ViewData<GameUpdateViewData> {
|
||||
tileUpdates: TileViewData[]
|
||||
}
|
||||
|
||||
export class GameView implements Game {
|
||||
export class GameView {
|
||||
private lastGameUpdate: GameUpdateViewData
|
||||
private tiles: TileViewData[][] = []
|
||||
|
||||
@@ -266,9 +263,6 @@ export class GameView implements Game {
|
||||
isOnMap(cell: Cell): boolean {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
neighbors(cell: Cell | Tile): Tile[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
width(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
+4
-3
@@ -7,6 +7,7 @@ import { Cell, Game, Player, TerraNullius, Tile, Unit } from "./game/Game";
|
||||
import { number } from 'zod';
|
||||
import { GameConfig, GameID, GameRecord, PlayerRecord, Turn } from './Schemas';
|
||||
import { customAlphabet, nanoid } from 'nanoid';
|
||||
import { GameView } from './GameView';
|
||||
|
||||
|
||||
|
||||
@@ -62,7 +63,7 @@ export function and(x: (tile: Tile) => boolean, y: (tile: Tile) => boolean): (ti
|
||||
}
|
||||
|
||||
// TODO: refactor to new file
|
||||
export function sourceDstOceanShore(game: Game, src: Player, tile: Tile): [Tile | null, Tile | null] {
|
||||
export function sourceDstOceanShore(game: GameView, src: Player, tile: Tile): [Tile | null, Tile | null] {
|
||||
const dst = tile.owner()
|
||||
let srcTile = closestOceanShoreFromPlayer(src, tile, game.width())
|
||||
let dstTile: Tile | null = null
|
||||
@@ -74,11 +75,11 @@ export function sourceDstOceanShore(game: Game, src: Player, tile: Tile): [Tile
|
||||
return [srcTile, dstTile]
|
||||
}
|
||||
|
||||
export function targetTransportTile(game: Game, tile: Tile): Tile | null {
|
||||
export function targetTransportTile(gameWidth: number, tile: Tile): Tile | null {
|
||||
const dst = tile.owner()
|
||||
let dstTile: Tile | null = null
|
||||
if (dst.isPlayer()) {
|
||||
dstTile = closestOceanShoreFromPlayer(dst as Player, tile, game.width())
|
||||
dstTile = closestOceanShoreFromPlayer(dst as Player, tile, gameWidth)
|
||||
} else {
|
||||
dstTile = closestOceanShoreTN(tile, 300)
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ export class TransportShipExecution implements Execution {
|
||||
|
||||
this.troops = Math.min(this.troops, this.attacker.troops())
|
||||
|
||||
this.dst = targetTransportTile(this.mg, this.mg.tile(this.cell))
|
||||
this.dst = targetTransportTile(this.mg.width(), this.mg.tile(this.cell))
|
||||
if (this.dst == null) {
|
||||
consolex.warn(`${this.attacker} cannot send ship to ${this.target}, cannot find attack tile`)
|
||||
this.active = false
|
||||
|
||||
@@ -17,7 +17,7 @@ export class WorkerClient {
|
||||
this.worker = new Worker(new URL('./Worker.worker.ts', import.meta.url));
|
||||
}
|
||||
|
||||
initialize(gameUpdate: (gu: GameUpdateViewData) => void): Promise<void> {
|
||||
initialize(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.worker.postMessage({
|
||||
type: 'init',
|
||||
@@ -28,21 +28,28 @@ export class WorkerClient {
|
||||
const handler = (e: MessageEvent) => {
|
||||
if (e.data.type === 'initialized') {
|
||||
this.isInitialized = true;
|
||||
this.worker.removeEventListener('message', handler)
|
||||
resolve();
|
||||
return
|
||||
}
|
||||
if (!this.isInitialized) {
|
||||
reject('Failed to initialize pathfinder');
|
||||
}
|
||||
if (e.data.type == "game_update") {
|
||||
gameUpdate(e.data.gameUpdate)
|
||||
}
|
||||
};
|
||||
|
||||
this.worker.addEventListener('message', handler);
|
||||
});
|
||||
}
|
||||
|
||||
start(gameUpdate: (gu: GameUpdateViewData) => void) {
|
||||
if (!this.isInitialized) {
|
||||
throw new Error('Failed to initialize pathfinder');
|
||||
}
|
||||
const handler = (e: MessageEvent) => {
|
||||
if (e.data.type == "game_update") {
|
||||
gameUpdate(e.data.gameUpdate)
|
||||
}
|
||||
}
|
||||
this.worker.addEventListener('message', handler);
|
||||
}
|
||||
|
||||
sendTurn(turn: Turn) {
|
||||
this.worker.postMessage({
|
||||
type: "turn",
|
||||
|
||||
Reference in New Issue
Block a user