新增:模拟一致性检查页(/dev/sim-check.html),任意设备的浏览器重放黄金结果的整套战斗,逐帧与 Node 比较
This commit is contained in:
1 parent
bc50cac01f
commit
ce52512559
11 files changed
+826
No files matched your search
@@ -0,0 +1,62 @@
|
||||
// Stronghold Protocol's battles for simcheck (core.js): the golden battle corpus — tools/golden.mjs's families roster,
|
||||
// bonds, fields, standins and diy (its matches are not single battles) — as BattleSpecs (written by
|
||||
// tools/sim-check.mjs), each built with /sim/spec.js createBattleFromSpec as the browser runner does
|
||||
// (public/js/battle/runner.js) and stepped tick by tick; a field battle stops at its golden cap like the corpus.
|
||||
// state after every tick: the battle time, the RNG state and per unit FIELDS (exact bits)
|
||||
// view b.snapshot(): what viewers are sent
|
||||
// deep every value reachable from the units, the definitions and the process-wide sequence numbers left out
|
||||
// result resultDigest(b.result()).hash: what the server's SP_VERIFY compares
|
||||
// The page (sim-check.js) and the tool (tools/sim-check.mjs) both use it, with the sim and its data loaded their way.
|
||||
import { deepHash } from './core.js';
|
||||
|
||||
/** The data files the sim reads: public/js/battle/runner.js SIM_DATA_FILES (test/sim/simcheck.test.js keeps them equal). */
|
||||
export const SIM_DATA_FILES = Object.freeze(['chess', 'enemies', 'tokens', 'stages', 'waves', 'bonds', 'items', 'garrisons', 'bands', 'effects', 'backups']);
|
||||
/** Per unit in the state vector. */
|
||||
export const FIELDS = Object.freeze(['alive', 'removed', 'deployed', 'x', 'y', 'hp', 'atkCd', 'sp', 'burn', 'neural', 'necrosis', 'apoptosis', 'erosion',
|
||||
'dmg', 'taken', 'heal', 'blocking']);
|
||||
// left out of the deep state: references back to definitions and the battle, and buffs.js's process-wide `seq` (it
|
||||
// depends on what ran before in the same page or process)
|
||||
const DEEP_SKIP = Object.freeze(['def', 'profile', 'kit', 'battle', 'b', 'seq']);
|
||||
const QUIET = Object.freeze({ error() {}, warn() {}, info() {}, debug() {} });
|
||||
|
||||
/** The scenario list of a specs document: id, golden family, in the fast subset. */
|
||||
export const scenariosOf = (doc) => doc.specs.map((s) => ({ id: s.id, family: s.fam, fast: s.fast }));
|
||||
|
||||
/**
|
||||
* @param {{ spec: { createBattleFromSpec: Function, resultDigest: Function }, ds: object, doc: { specs: object[] }, logger?: object }} o
|
||||
* spec: the /sim/spec.js module; ds: a simdata DataSource over SIM_DATA_FILES; doc: the specs document
|
||||
*/
|
||||
export function strongholdAdapter({ spec, ds, doc, logger = QUIET }) {
|
||||
const byId = new Map(doc.specs.map((s) => [s.id, s]));
|
||||
return {
|
||||
maxTicks: 200000,
|
||||
start(sc) {
|
||||
const s = byId.get(sc.id);
|
||||
return { b: spec.createBattleFromSpec(s.spec, ds, { logger }), cap: s.cap ?? null };
|
||||
},
|
||||
step(r) {
|
||||
const b = r.b;
|
||||
if (b.finished) return false;
|
||||
if (r.cap != null && b.time >= r.cap - 1e-9) { b.forceEnd('forced'); return false; }
|
||||
b.step();
|
||||
return true;
|
||||
},
|
||||
state(r) {
|
||||
const b = r.b, v = [b.time, b.rng.state() >>> 0];
|
||||
for (const u of b.units) {
|
||||
const e = u.elem || {}, s = u.stats || {};
|
||||
v.push(u.alive ? 1 : 0, u.removed ? 1 : 0, u.deployed ? 1 : 0, u.x, u.y, u.hp, u.atkCd, u.skill && u.skill.sp != null ? u.skill.sp : -1,
|
||||
e.burn ?? 0, e.neural ?? 0, e.necrosis ?? 0, e.apoptosis ?? 0, e.erosion ?? 0, s.dmg ?? 0, s.taken ?? 0, s.heal ?? 0, (u.blocking || []).length);
|
||||
}
|
||||
return v;
|
||||
},
|
||||
labels(r) {
|
||||
const out = ['time', 'rng'];
|
||||
for (const u of r.b.units) { const name = `${u.side === 'enemy' ? 'enemy' : 'ally'} ${u.defId}#${u.id}`; for (const f of FIELDS) out.push(`${name}.${f}`); }
|
||||
return out;
|
||||
},
|
||||
view(r) { return r.b.snapshot(); },
|
||||
deep(r) { return deepHash(r.b.units, { skip: DEEP_SKIP }); },
|
||||
result(r) { return spec.resultDigest(r.b.result()).hash; },
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user