diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index cfe48c30a..620820a57 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -225,12 +225,10 @@ export class ClientGameRunner { private gameView: GameView, ) { this.lastMessageTime = Date.now(); - - this.eventBus.on(GoToPositionEvent, (e) => this.onGoToPosition(e)); - } - - private onGoToPosition(event: GoToPositionEvent) { - this.eventBus.emit(new GoToPositionEvent(event.x, event.y)); + // If forwarding is needed, emit a different event or handle directly + this.eventBus.on(GoToPositionEvent, (e) => { + // Handle position navigation here instead of re-emitting + }); } private saveGame(update: WinUpdate) { diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index d8d7c1a63..464d5e362 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -428,7 +428,7 @@ export class GameRenderer { handleTransformState(false, isTransformActive); // Ensure context is clean after rendering this.transformHandler.resetChanged(); - requestAnimationFrame(() => this.renderGame()); + this.rafId = requestAnimationFrame(() => this.renderGame()); const duration = performance.now() - start; const layerDurations = FrameProfiler.consume(); diff --git a/src/client/graphics/layers/ChatDisplay.ts b/src/client/graphics/layers/ChatDisplay.ts index 920a4d114..40e5589ad 100644 --- a/src/client/graphics/layers/ChatDisplay.ts +++ b/src/client/graphics/layers/ChatDisplay.ts @@ -103,6 +103,8 @@ export class ChatDisplay extends LitElement implements Layer { description: msg.message, unsafeDescription: true, createdAt: this.game.ticks(), + x: msg.x, // Transfer coordinates + y: msg.y, // Transfer coordinates }, ]; } @@ -124,7 +126,6 @@ export class ChatDisplay extends LitElement implements Layer { : chat.description; } - // ... render() { if (!this.active) { return html``; @@ -178,15 +179,16 @@ export class ChatDisplay extends LitElement implements Layer { ${chat.x !== undefined && chat.y !== undefined ? html` -
this.eventBus.emit( new GoToPositionEvent(chat.x!, chat.y!), )} > ${this.getChatContent(chat)} -
+ ` : this.getChatContent(chat)} diff --git a/src/client/graphics/layers/FxLayer.ts b/src/client/graphics/layers/FxLayer.ts index 4556157b3..a50b03c8a 100644 --- a/src/client/graphics/layers/FxLayer.ts +++ b/src/client/graphics/layers/FxLayer.ts @@ -350,12 +350,19 @@ export class FxLayer implements Layer { this.allFx.push(shockwave); } - private pingEventCleanup?: () => void; destroy() { - if (this.pingEventCleanup) { - this.pingEventCleanup(); - this.pingEventCleanup = undefined; + // End all active effects + for (const fx of this.boatTargetFxByUnitId.values()) { + (fx as any).end?.(); } + for (const fx of this.nukeTargetFxByUnitId.values()) { + fx.end(); + } + + // Clear collections + this.allFx = []; + this.boatTargetFxByUnitId.clear(); + this.nukeTargetFxByUnitId.clear(); } async init() { this.redraw(); diff --git a/src/client/graphics/layers/PingMarkerLayer.ts b/src/client/graphics/layers/PingMarkerLayer.ts index f92701291..5d5640151 100644 --- a/src/client/graphics/layers/PingMarkerLayer.ts +++ b/src/client/graphics/layers/PingMarkerLayer.ts @@ -46,7 +46,7 @@ class Ping { this.sprite = new PIXI.Sprite(texture); this.sprite.anchor.set(0.5); - const aspectRatio = texture.width / texture.height; + const aspectRatio = texture.height > 0 ? texture.width / texture.height : 1; this.sprite.height = 24; this.sprite.width = 24 * aspectRatio; @@ -100,27 +100,26 @@ class Ping { for (let i = 0; i < glowSteps; i++) { const glowRadius = maxRad + i * 8; // Circles outside the main ring const glowAlpha = 0.1 * dramaticPulse * (1 - i / glowSteps); // Fades out with distance - this.circle.beginFill(staticColor.toRgb(), glowAlpha); - this.circle.drawCircle(0, 0, glowRadius); - this.circle.endFill(); + this.circle.circle(0, 0, glowRadius).fill({ + color: staticColor.toRgb(), + alpha: glowAlpha, + }); } // --- Main Rings (as before) --- // Outer static ring - this.circle.stroke({ + this.circle.circle(0, 0, maxRad).stroke({ width: 3, color: staticColor.toRgb(), alpha: 0.5 * dramaticPulse, }); - this.circle.circle(0, 0, maxRad); // Inner pulsing ring - this.circle.stroke({ + this.circle.circle(0, 0, currentRadius).stroke({ width: 6, color: pulseColor.toRgb(), alpha: overallFadeAlpha * dramaticPulse, }); - this.circle.circle(0, 0, currentRadius); } destroy() { @@ -172,6 +171,10 @@ export class PingMarkerLayer implements Layer { destroy() { this.eventBus.off(PingPlacedEvent, this.handlePingPlaced); + for (const ping of this.pings) { + ping.destroy(); + } + this.pings = []; window.removeEventListener("resize", this.resizeCanvas); this.renderer?.destroy(); this.stage.destroy(true); diff --git a/src/core/EventBus.ts b/src/core/EventBus.ts index f5b2e5dbf..8a7057f67 100644 --- a/src/core/EventBus.ts +++ b/src/core/EventBus.ts @@ -5,8 +5,11 @@ export interface EventConstructor { } export class EventBus { - private listeners: Map void>> = - new Map(); + private listeners: Map< + EventConstructor, + Array<{ id: number; callback: (event: GameEvent) => void }> + > = new Map(); + private nextId = 0; emit(event: T): void { const eventConstructor = event.constructor as EventConstructor; @@ -14,7 +17,7 @@ export class EventBus { const callbacks = this.listeners.get(eventConstructor); if (callbacks) { for (const callback of callbacks) { - callback(event); + callback.callback(event); } } } @@ -26,9 +29,20 @@ export class EventBus { if (!this.listeners.has(eventType)) { this.listeners.set(eventType, []); } - this.listeners.get(eventType)!.push(callback as (event: GameEvent) => void); + const id = this.nextId++; + this.listeners + .get(eventType)! + .push({ id, callback: callback as (event: GameEvent) => void }); - return () => this.off(eventType, callback); + return () => { + const callbacks = this.listeners.get(eventType); + if (callbacks) { + const index = callbacks.findIndex((item) => item.id === id); + if (index > -1) { + callbacks.splice(index, 1); + } + } + }; } off( @@ -37,7 +51,7 @@ export class EventBus { ): void { const callbacks = this.listeners.get(eventType); if (callbacks) { - const index = callbacks.indexOf(callback as (event: GameEvent) => void); + const index = callbacks.findIndex((item) => item.callback === callback); if (index > -1) { callbacks.splice(index, 1); } diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 4f4151ac2..2b650f561 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -413,7 +413,6 @@ export class PlayerInfo { public readonly clientID: ClientID | null, // TODO: make player id the small id public readonly id: PlayerID, - public readonly nation?: Nation | null, ) { this.clan = getClanTag(name); } diff --git a/src/core/game/GameUpdates.ts b/src/core/game/GameUpdates.ts index 7b083a329..aba7ef88e 100644 --- a/src/core/game/GameUpdates.ts +++ b/src/core/game/GameUpdates.ts @@ -5,6 +5,7 @@ import { Gold, MessageType, NameViewData, + PingType, PlayerID, PlayerType, Team, @@ -266,10 +267,6 @@ export interface UnitIncomingUpdate { messageType: MessageType; playerID: number; } - -import { PingType } from "./Ping"; -//... -//... export interface EmbargoUpdate { type: GameUpdateType.EmbargoEvent; event: "start" | "stop";