The behavioural compare found 8 of 45 StrategyServer::MoveFleet calls diverging by one ULP on a position component. Read off the instruction stream, the cause is that the engine's vector normalise narrows to float32 four separate times and we kept everything in double: delta.c = f32(dest.c - pos.c) stored back to a float32 slot before normalising sumsq = f32(x*x + y*y + z*z) products/adds in 53-bit regs, only the SUM stored len = f32(sqrt(sumsq)) inv = f32(1.0 / len) a reciprocal, MULTIPLIED through, not three divides dir.c = f32(delta.c * inv) and the same call returns the leg distance, so it is never recomputed in a wider precision either. The position tail was already right, which is why the error was a constant absolute ~1.2e-7 (half an ULP of the inputs) rather than a formula error. Adds NormalizeVec3 / StraightLeg / StraightLegDistance / AdvanceAlongUnitDirection and rebuilds AdvanceAlongDirection on them; the movement hook now takes both the direction and the distance from one StraightLeg call, as the original does. The arrival test is an exact float compare, so the distance has to be that same float32. Tests pin float32 BIT PATTERNS, not tolerances: one case per narrowing plus four independent legs component by component. A CHECK_NEAR would pass against the old arithmetic. sim::Distance is left in double on purpose and flagged at its declaration: it now serves only the node-line/stutter geometry, which very likely needs the same treatment but has zero behavioural coverage to correct it against. Live, same VM/save/workload, run twice by this lane: control recap-7584bad-20260908T0615Z 45 calls, 45 compared, 8 diverged, exit 1 fixed mf-45bdf7d-dirty-20260908T0721Z 45 calls, 45 compared, 0 diverged, exit 0 with identical arguments, identical pos.before and identical ORIGINAL pos.after on all 45 calls. The control reproduced the eight divergent call_ids exactly. Coverage unchanged and still thin: all 15 moving calls are the same straight-run waypoint type; types 2-5 were attempted and could not be reached (the only player that would travel a node line has no ships on this save). See docs/M-movefleet.md. ctest 32/32; tools/clean_room_check.sh OK. |
||
|---|---|---|
| cmake | ||
| docs | ||
| include/generated | ||
| src | ||
| tests | ||
| third_party | ||
| tools | ||
| .gitignore | ||
| CMakeLists.txt | ||
| CMakePresets.json | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| README.md | ||
sots-engine
A from-scratch, functional reimplementation of the engine behind Sword of the Stars (2006). Not a byte-for-byte decompilation: behavior-equivalent code, built up one verified piece at a time (OpenRCT2-style) until the tree can build the whole application on its own.
Bring your own game. This repository contains engine code only. Game data, assets, saves, and
the original binaries are never included; tests and tools read an owner-supplied copy via
$SOTS_DATA_DIR. See CONTRIBUTING.md for the clean-room rules.
Status
Phase 2. M0 done — the shim frontend (src/shim/, a proxy binkw32.dll the original game
loads) builds, deploys, hooks, and logs from a real game launch. Engine code accrues under
src/mars/ and src/game/; each module is oracle-verified against the owner's game data before merge:
mars/parse— brace-block +.effectreaders (1,531/1,531 files agree with the reference)mars/text— flat key/value tables, id manifests, CSV (64/64 files agree)game/sim— strategic formulas (economy, research, colonies, movement) as pure functions; 356 hand-computed checksmars/vfs—.gob(ZIP) archive reader + loose-file override; entry counts and bytes verified againstunzipmars/stream— the game's self-describing save/serialization format (reader, writer, typed shapes) + gzip; three real saves round-trip byte-identicalmars/rng— MT19937 with save-state load/store; layout confirmed against real saves, draw mappings read off the binary (docs/mars-rng.md)game/data— typed catalogs (weapons, ship sections, turrets, id registries, tech tree, strings) with cross-reference checks; 229k values agree with the referencegame/design— ship-design assembly/fit/tech-gating rules and derived stats; validates all 127 stock designs from real saves
Build: cmake --preset host && cmake --build --preset host && ctest --preset host (Linux);
tools/sync-build.sh cross-builds the shim on the lab box and stages it for deployment.
Layout (grows with the work)
src/shim/— binkw32 proxy + hooks + old-vs-new compare harness (frontend #1)src/mars/,src/game/— the engine and game reimplementation (accruing)include/generated/sots_addresses.h— binary facts (RVAs/prototypes), generated from the RE repotests/— host tests; real-data tests skip unless$SOTS_DATA_DIRis settools/— build (MinGW i686 cross) and deploy scripts
Planning, findings, and verification evidence are tracked in the private RE repo (sots-re).