From 13e2a02b2db472a417ba788b2764263b3c921d78 Mon Sep 17 00:00:00 2001 From: evan Date: Wed, 23 Apr 2025 12:30:33 -0700 Subject: [PATCH 1/2] fix private games not archiving because they haven't prestarted --- src/server/GameServer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/GameServer.ts b/src/server/GameServer.ts index 9cbd712c2..a267c4f3a 100644 --- a/src/server/GameServer.ts +++ b/src/server/GameServer.ts @@ -356,7 +356,7 @@ export class GameServer { client.ws.close(1000, "game has ended"); } }); - if (!this._hasPrestarted || !this._hasStarted) { + if (!this._hasPrestarted && !this._hasStarted) { this.log.info(`game not started, not archiving game`); return; } From b13029591de890a755ae7f5f52438f3ae71728fc Mon Sep 17 00:00:00 2001 From: evan Date: Wed, 23 Apr 2025 13:04:33 -0700 Subject: [PATCH 2/2] bugfix: Path.Mini was modified to only pathfinding on water, which broke nukes. Created AirPathfinder class to handle pathfinding for nukes --- src/core/execution/MIRVExecution.ts | 30 +++++----------- src/core/execution/NukeExecution.ts | 40 ++++----------------- src/core/execution/SAMMissileExecution.ts | 43 +++++++++-------------- src/core/pathfinding/PathFinding.ts | 39 +++++++++++++++++++- 4 files changed, 69 insertions(+), 83 deletions(-) diff --git a/src/core/execution/MIRVExecution.ts b/src/core/execution/MIRVExecution.ts index 55b928c17..a752adfef 100644 --- a/src/core/execution/MIRVExecution.ts +++ b/src/core/execution/MIRVExecution.ts @@ -10,8 +10,7 @@ import { UnitType, } from "../game/Game"; import { TileRef } from "../game/GameMap"; -import { PathFindResultType } from "../pathfinding/AStar"; -import { PathFinder } from "../pathfinding/PathFinding"; +import { AirPathFinder } from "../pathfinding/PathFinding"; import { PseudoRandom } from "../PseudoRandom"; import { simpleHash } from "../Util"; import { NukeExecution } from "./NukeExecution"; @@ -30,7 +29,7 @@ export class MirvExecution implements Execution { private random: PseudoRandom; - private pathFinder: PathFinder; + private pathFinder: AirPathFinder; private targetPlayer: Player | TerraNullius; @@ -50,7 +49,7 @@ export class MirvExecution implements Execution { this.random = new PseudoRandom(mg.ticks() + simpleHash(this.senderID)); this.mg = mg; - this.pathFinder = PathFinder.Mini(mg, 10_000); + this.pathFinder = new AirPathFinder(mg, this.random); this.player = mg.player(this.senderID); this.targetPlayer = this.mg.owner(this.dst); @@ -90,23 +89,12 @@ export class MirvExecution implements Execution { this.nuke.tile(), this.separateDst, ); - switch (result.type) { - case PathFindResultType.Completed: - this.nuke.move(result.tile); - this.separate(); - this.active = false; - return; - case PathFindResultType.NextTile: - this.nuke.move(result.tile); - break; - case PathFindResultType.Pending: - break; - case PathFindResultType.PathNotFound: - consolex.warn( - `nuke cannot find path from ${this.nuke.tile()} to ${this.dst}`, - ); - this.active = false; - return; + if (result === true) { + this.separate(); + this.active = false; + return; + } else { + this.nuke.move(result); } } } diff --git a/src/core/execution/NukeExecution.ts b/src/core/execution/NukeExecution.ts index d75a556da..8795e349f 100644 --- a/src/core/execution/NukeExecution.ts +++ b/src/core/execution/NukeExecution.ts @@ -11,6 +11,7 @@ import { UnitType, } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { AirPathFinder } from "../pathfinding/PathFinding"; import { PseudoRandom } from "../PseudoRandom"; export class NukeExecution implements Execution { @@ -20,6 +21,7 @@ export class NukeExecution implements Execution { private nuke: Unit; private random: PseudoRandom; + private pathFinder: AirPathFinder; constructor( private type: NukeType, @@ -43,6 +45,7 @@ export class NukeExecution implements Execution { if (this.speed == -1) { this.speed = this.mg.config().defaultNukeSpeed(); } + this.pathFinder = new AirPathFinder(mg, this.random); } public target(): Player | TerraNullius { @@ -143,45 +146,14 @@ export class NukeExecution implements Execution { return; } - const r = (this.mg.y(this.dst) * this.mg.x(this.dst)) % 10; - const s = this.speed + (this.mg.ticks() % r); - for (let i = 0; i < this.speed; i++) { - const x = this.mg.x(this.nuke.tile()); - const y = this.mg.y(this.nuke.tile()); - const dstX = this.mg.x(this.dst); - const dstY = this.mg.y(this.dst); - - // If we've reached the destination, detonate - if (x === dstX && y === dstY) { + // Move to next tile + const nextTile = this.pathFinder.nextTile(this.nuke.tile(), this.dst); + if (nextTile === true) { this.detonate(); return; - } - - // Calculate next position - let nextX = x; - let nextY = y; - - const ratio = Math.floor( - 1 + Math.abs(dstY - y) / (Math.abs(dstX - x) + 1), - ); - - if (this.random.chance(ratio) && x != dstX) { - if (x < dstX) nextX++; - else if (x > dstX) nextX--; } else { - if (y < dstY) nextY++; - else if (y > dstY) nextY--; - } - - // Move to next tile - const nextTile = this.mg.ref(nextX, nextY); - if (nextTile !== undefined) { this.nuke.move(nextTile); - } else { - consolex.warn(`invalid tile position ${nextX},${nextY}`); - this.active = false; - return; } } } diff --git a/src/core/execution/SAMMissileExecution.ts b/src/core/execution/SAMMissileExecution.ts index 33d769fd9..959c53330 100644 --- a/src/core/execution/SAMMissileExecution.ts +++ b/src/core/execution/SAMMissileExecution.ts @@ -1,4 +1,3 @@ -import { consolex } from "../Consolex"; import { Execution, Game, @@ -8,12 +7,12 @@ import { UnitType, } from "../game/Game"; import { TileRef } from "../game/GameMap"; -import { PathFindResultType } from "../pathfinding/AStar"; -import { PathFinder } from "../pathfinding/PathFinding"; +import { AirPathFinder } from "../pathfinding/PathFinding"; +import { PseudoRandom } from "../PseudoRandom"; export class SAMMissileExecution implements Execution { private active = true; - private pathFinder: PathFinder; + private pathFinder: AirPathFinder; private SAMMissile: Unit; private mg: Game; @@ -26,7 +25,7 @@ export class SAMMissileExecution implements Execution { ) {} init(mg: Game, ticks: number): void { - this.pathFinder = PathFinder.Mini(mg, 2000, 10); + this.pathFinder = new AirPathFinder(mg, new PseudoRandom(mg.ticks())); this.mg = mg; } @@ -58,29 +57,19 @@ export class SAMMissileExecution implements Execution { const result = this.pathFinder.nextTile( this.SAMMissile.tile(), this.target.tile(), - 3, ); - switch (result.type) { - case PathFindResultType.Completed: - this.mg.displayMessage( - `Missile intercepted ${this.target.type()}`, - MessageType.SUCCESS, - this._owner.id(), - ); - this.active = false; - this.target.delete(); - this.SAMMissile.delete(false); - return; - case PathFindResultType.NextTile: - this.SAMMissile.move(result.tile); - break; - case PathFindResultType.Pending: - return; - case PathFindResultType.PathNotFound: - consolex.log(`Missile ${this.SAMMissile} could not find target`); - this.active = false; - this.SAMMissile.delete(false); - return; + if (result === true) { + this.mg.displayMessage( + `Missile intercepted ${this.target.type()}`, + MessageType.SUCCESS, + this._owner.id(), + ); + this.active = false; + this.target.delete(); + this.SAMMissile.delete(false); + return; + } else { + this.SAMMissile.move(result); } } } diff --git a/src/core/pathfinding/PathFinding.ts b/src/core/pathfinding/PathFinding.ts index 4760587e4..1a255c8dd 100644 --- a/src/core/pathfinding/PathFinding.ts +++ b/src/core/pathfinding/PathFinding.ts @@ -1,9 +1,46 @@ import { consolex } from "../Consolex"; import { Game } from "../game/Game"; -import { TileRef } from "../game/GameMap"; +import { GameMap, TileRef } from "../game/GameMap"; +import { PseudoRandom } from "../PseudoRandom"; import { AStar, PathFindResultType, TileResult } from "./AStar"; import { MiniAStar } from "./MiniAStar"; +export class AirPathFinder { + constructor( + private mg: GameMap, + private random: PseudoRandom, + ) {} + + nextTile(tile: TileRef, dst: TileRef): TileRef | true { + const x = this.mg.x(tile); + const y = this.mg.y(tile); + const dstX = this.mg.x(dst); + const dstY = this.mg.y(dst); + + if (x === dstX && y === dstY) { + return true; + } + + // Calculate next position + let nextX = x; + let nextY = y; + + const ratio = Math.floor(1 + Math.abs(dstY - y) / (Math.abs(dstX - x) + 1)); + + if (this.random.chance(ratio) && x != dstX) { + if (x < dstX) nextX++; + else if (x > dstX) nextX--; + } else { + if (y < dstY) nextY++; + else if (y > dstY) nextY--; + } + if (nextX == x && nextY == y) { + return true; + } + return this.mg.ref(nextX, nextY); + } +} + export class PathFinder { private curr: TileRef = null; private dst: TileRef = null;