Update Healer Man server

This commit is contained in:
phenom committed 2026-09-26 17:51:56 -04:00
1 parent 9c5fb4c614
commit bd073fb00f
113 files changed
+4902 -273

No files matched your search

+134
View File
@@ -12,6 +12,8 @@ import {
cloneDefaultCompanionCooldownPolicy,
normalizeCompanionCooldownPolicy,
} from "./companion-cooldown-policy.mjs";
import { DEFAULT_PARTY_BUFF_POLICY, normalizePartyBuffPolicy } from "./party-buff-policy.mjs";
import { DEFAULT_DUNGEON_QUEUE_POLICY, normalizeDungeonQueuePolicy } from "./dungeon-queue-policy.mjs";
import {
cloneDefaultCompanionSpecReadinessPolicy,
normalizeCompanionSpecReadinessPolicy,
@@ -20,6 +22,7 @@ import { arenaRatingBand, calculateArenaRating, clampArenaRating } from "./arena
import { arenaRoleForSpecialization } from "./arena-specializations.mjs";
import { createDungeonReportRepository } from "./dungeon-reports.mjs";
import { createDungeonLeaderboardRepository } from "./dungeon-leaderboards.mjs";
import { createDungeonRaceRepository } from "./dungeon-races.mjs";
import { createDungeonSimulationRepository } from "./dungeon-simulation.mjs";
import dungeonLeaderboardCatalog from "../src/game/generated/dungeonLeaderboardCatalog.generated.json" with { type: "json" };
@@ -110,6 +113,24 @@ export function openGameDatabase(options = {}) {
updated_by_username TEXT,
updated_at INTEGER
) STRICT;
CREATE TABLE IF NOT EXISTS party_buff_policy (
id INTEGER PRIMARY KEY CHECK (id = 1),
schema_version INTEGER NOT NULL,
revision INTEGER NOT NULL,
config_json TEXT NOT NULL,
updated_by_account_id TEXT REFERENCES accounts(id) ON DELETE SET NULL,
updated_by_username TEXT,
updated_at INTEGER
) STRICT;
CREATE TABLE IF NOT EXISTS dungeon_queue_policy (
id INTEGER PRIMARY KEY CHECK (id = 1),
schema_version INTEGER NOT NULL,
revision INTEGER NOT NULL,
config_json TEXT NOT NULL,
updated_by_account_id TEXT REFERENCES accounts(id) ON DELETE SET NULL,
updated_by_username TEXT,
updated_at INTEGER
) STRICT;
CREATE TABLE IF NOT EXISTS companion_spec_readiness (
id INTEGER PRIMARY KEY CHECK (id = 1),
schema_version INTEGER NOT NULL,
@@ -215,6 +236,16 @@ export function openGameDatabase(options = {}) {
id, schema_version, revision, config_json, updated_by_account_id, updated_by_username, updated_at
) VALUES (1, 1, 0, ?, NULL, NULL, NULL)
`).run(JSON.stringify(cloneDefaultCompanionCooldownPolicy()));
database.prepare(`
INSERT OR IGNORE INTO party_buff_policy (
id, schema_version, revision, config_json, updated_by_account_id, updated_by_username, updated_at
) VALUES (1, 1, 0, ?, NULL, NULL, NULL)
`).run(JSON.stringify(DEFAULT_PARTY_BUFF_POLICY));
database.prepare(`
INSERT OR IGNORE INTO dungeon_queue_policy (
id, schema_version, revision, config_json, updated_by_account_id, updated_by_username, updated_at
) VALUES (1, 1, 0, ?, NULL, NULL, NULL)
`).run(JSON.stringify(DEFAULT_DUNGEON_QUEUE_POLICY));
database.prepare(`
INSERT OR IGNORE INTO companion_spec_readiness (
id, schema_version, revision, config_json, updated_by_account_id, updated_by_username, updated_at
@@ -252,6 +283,22 @@ export function openGameDatabase(options = {}) {
RETURNING revision, updated_at
`),
companionCooldownPolicy: database.prepare("SELECT * FROM companion_cooldown_policy WHERE id = 1"),
partyBuffPolicy: database.prepare("SELECT * FROM party_buff_policy WHERE id = 1"),
dungeonQueuePolicy: database.prepare("SELECT * FROM dungeon_queue_policy WHERE id = 1"),
updateDungeonQueuePolicy: database.prepare(`
UPDATE dungeon_queue_policy
SET schema_version = 1, revision = revision + 1, config_json = ?,
updated_by_account_id = ?, updated_by_username = ?, updated_at = ?
WHERE id = 1 AND revision = ?
RETURNING revision, updated_at
`),
updatePartyBuffPolicy: database.prepare(`
UPDATE party_buff_policy
SET schema_version = 1, revision = revision + 1, config_json = ?,
updated_by_account_id = ?, updated_by_username = ?, updated_at = ?
WHERE id = 1 AND revision = ?
RETURNING revision, updated_at
`),
updateCompanionCooldownPolicy: database.prepare(`
UPDATE companion_cooldown_policy
SET schema_version = 1, revision = revision + 1, config_json = ?,
@@ -450,6 +497,74 @@ export function openGameDatabase(options = {}) {
return { revision: Number(row.revision), updatedAt: Number(row.updated_at), updatedBy: account.username, config: normalized };
}
function getPartyBuffPolicy() {
const row = statements.partyBuffPolicy.get();
try {
return {
revision: Number(row?.revision ?? 0),
updatedAt: row?.updated_at == null ? null : Number(row.updated_at),
updatedBy: row?.updated_by_username ?? null,
config: normalizePartyBuffPolicy(JSON.parse(row?.config_json ?? "null")),
};
} catch (error) {
console.error("Healer Man party buff policy is corrupt; using safe defaults", error);
return { revision: 0, updatedAt: null, updatedBy: null, config: DEFAULT_PARTY_BUFF_POLICY };
}
}
function getDungeonQueuePolicy() {
const row = statements.dungeonQueuePolicy.get();
try {
return {
revision: Number(row?.revision ?? 0),
updatedAt: row?.updated_at == null ? null : Number(row.updated_at),
updatedBy: row?.updated_by_username ?? null,
config: normalizeDungeonQueuePolicy(JSON.parse(row?.config_json ?? "null")),
};
} catch (error) {
console.error("Healer Man dungeon queue policy is corrupt; using defaults", error);
return { revision: 0, updatedAt: null, updatedBy: null, config: DEFAULT_DUNGEON_QUEUE_POLICY };
}
}
function putDungeonQueuePolicy(account, expectedRevision, config) {
if (!isGameMaster(account)) throw new GameDatabaseError("Game Master access is required.", 403, "gm_required");
if (!Number.isInteger(expectedRevision) || expectedRevision < 0) {
throw new GameDatabaseError("A valid expected revision is required.", 400, "invalid_revision");
}
let normalized;
try {
normalized = normalizeDungeonQueuePolicy(config);
} catch (error) {
throw new GameDatabaseError(error instanceof Error ? error.message : "Invalid dungeon queue policy.", 400, "invalid_dungeon_queue_policy");
}
const now = Date.now();
const row = statements.updateDungeonQueuePolicy.get(
JSON.stringify(normalized), account.id, account.username, now, expectedRevision,
);
if (!row) throw new GameDatabaseError("The dungeon queue policy changed. Reload and try again.", 409, "revision_conflict");
return { revision: Number(row.revision), updatedAt: Number(row.updated_at), updatedBy: account.username, config: normalized };
}
function putPartyBuffPolicy(account, expectedRevision, config) {
if (!isGameMaster(account)) throw new GameDatabaseError("Game Master access is required.", 403, "gm_required");
if (!Number.isInteger(expectedRevision) || expectedRevision < 0) {
throw new GameDatabaseError("A valid expected revision is required.", 400, "invalid_revision");
}
let normalized;
try {
normalized = normalizePartyBuffPolicy(config);
} catch (error) {
throw new GameDatabaseError(error instanceof Error ? error.message : "Invalid party buff policy.", 400, "invalid_party_buff_policy");
}
const now = Date.now();
const row = statements.updatePartyBuffPolicy.get(
JSON.stringify(normalized), account.id, account.username, now, expectedRevision,
);
if (!row) throw new GameDatabaseError("The party buff policy changed. Reload and try again.", 409, "revision_conflict");
return { revision: Number(row.revision), updatedAt: Number(row.updated_at), updatedBy: account.username, config: normalized };
}
function getCompanionSpecReadiness() {
const row = statements.companionSpecReadiness.get();
try {
@@ -1066,6 +1181,21 @@ export function openGameDatabase(options = {}) {
databasePath,
...createDungeonReportRepository(database, { isGameMaster, ErrorType: GameDatabaseError }),
...createDungeonLeaderboardRepository(database, { ErrorType: GameDatabaseError }),
...(() => {
const races = createDungeonRaceRepository(database, { ErrorType: GameDatabaseError });
return {
getDungeonRaceMatch: races.getMatch,
createDungeonRaceMatch: races.createMatch,
readyDungeonRace: races.ready,
startDungeonRace: races.start,
settleDungeonRace: races.settleMatch,
completeDungeonRaceRun: races.completeRaceRun,
replaceDungeonRaceWithBot: races.replaceWithBot,
voidDungeonRace: races.void,
dungeonRaceRecordForAccount: races.recordForAccount,
listDungeonRaceLeaderboard: races.leaderboard,
};
})(),
...createDungeonSimulationRepository(database, { isGameMaster, ErrorType: GameDatabaseError }),
register,
login,
@@ -1078,6 +1208,10 @@ export function openGameDatabase(options = {}) {
putManastormConfig,
getCompanionCooldownPolicy,
putCompanionCooldownPolicy,
getPartyBuffPolicy,
putPartyBuffPolicy,
getDungeonQueuePolicy,
putDungeonQueuePolicy,
getCompanionSpecReadiness,
putCompanionSpecReadiness,
onlineGroupState,