Skip to content

Durable mod metadata cache + ghost mods (allowGhostMods)#87

Open
tomjn wants to merge 4 commits into
Yaribz:masterfrom
tomjn:feature/archiveless-metadata-cache
Open

Durable mod metadata cache + ghost mods (allowGhostMods)#87
tomjn wants to merge 4 commits into
Yaribz:masterfrom
tomjn:feature/archiveless-metadata-cache

Conversation

@tomjn

@tomjn tomjn commented Jun 21, 2026

Copy link
Copy Markdown

Summary

SPADS persists full map metadata durably (mapInfoCache.dat for start
positions/dimensions/options, mapHashes.dat for version-keyed hashes), but
mod metadata (hash, options, sides) only ever lived in the in-memory
%cachedMods and was lost on restart. As a result there was no "ghost mod"
equivalent to ghost maps: a dedicated relay host always required the game
archive locally, even though it never simulates.

This PR mirrors the existing map machinery for mods and adds a allowGhostMods
setting so a dedicated host can host a configured game whose archive is absent,
using previously-cached metadata.

Changes

  • Durable mod cache (SpadsConf.pm): modHashes.dat (version-keyed
    checksums, dumped in dumpDynamicData alongside mapHashes.dat) and
    modInfoCache.dat (Storable: options + sides). New accessors
    getCachedModInfo / cacheModInfo / getModHash / saveModHash.
  • Persist on load (loadArchivesPostActions): a mod's hash and info are
    written to the durable cache the first time its archive is loaded.
  • Cache-aware accessors: getModHash / getModOptions / getModSides
    now fall back to the durable cache, mirroring getMapHash / getMapOptions.
  • allowGhostMods setting (preset setting, mirrors allowGhostMaps) plus
    canUseGhostMod() and ghost-mod resolution in updateTargetMod() and on
    initial load.

Design notes

The data splits cleanly by version-sensitivity: the checksum is
engine-version-sensitive (kept keyed by springMajorVersion, like map hashes),
while options and sides are intrinsic to the archive (version-independent).

canUseGhostMod() requires both a version-matching cached hash and
cached info (options + sides) before a ghost mod is used, so a battle is never
opened with incomplete mod metadata.

Existing configs need allowGhostMods added to spads.conf (handled by the
normal config update flow, as with any new setting). Generated setting docs
(doc/*.html) are not updated in this PR.

Testing status (please read)

This is compile-checked only, not runtime-tested. The repo has no automated
tests, and I was not able to run SPADS in my environment (no Spring/unitsync
install), so I verified each change with perl -c only. The open-battle path in
particular should be exercised on a real dedicated host before this is relied
on. Feedback on correctness and on anything I've missed is very welcome.

Scope is the "complete the cache" half of the work; an optional external
metadata import/export/fetch layer is intentionally left out of this PR.

tomjn added 3 commits June 21, 2026 23:41
Mods previously kept their hash, options and sides only in the in-memory
%cachedMods hash, lost on restart - unlike maps which persist full info via
mapInfoCache.dat and mapHashes.dat.

Mirror the map machinery for mods:
- modHashes.dat: version-keyed mod checksums (fast table), dumped in
  dumpDynamicData alongside mapHashes
- modInfoCache.dat: mod options and sides (Storable), version-independent
- accessors getCachedModInfo/cacheModInfo/getModHash/saveModHash
- persist mod hash and info on first archive load in loadArchivesPostActions

Foundation for ghost mods (hosting a game whose archive is absent).
getModHash/getModOptions/getModSides only consulted the in-memory %cachedMods,
so a mod whose archive is absent returned no hash/options/sides. Mirror the map
accessors (getMapHash/getMapOptions): prefer live in-memory data, then fall back
to the durable mod cache (getModHash/getCachedModInfo) keyed by spring version.

No behavior change on existing installs until the cache is populated (empty
modHashes.dat/modInfoCache.dat still yield 0/{}/[]).
A dedicated host can now host a configured game whose archive is absent, using
the durable mod cache, mirroring allowGhostMaps for maps.

- new allowGhostMods preset setting (etc/spads.conf template + spadsSectionParameters)
- canUseGhostMod(): gated on allowGhostMods + dedicated server, and requires BOTH
  a version-matching cached hash AND cached info (options+sides) so a battle is
  never opened with incomplete mod metadata (fail-loud)
- updateTargetMod() falls back to the ghost mod when the configured mod is not
  found among locally available mods
- loadArchivesPostActions() resolves to the ghost mod on initial load when the
  configured mod archive is absent

Existing configs must add allowGhostMods (handled by the normal config update
flow, as with any new setting). Setting docs (doc/*.html) are generated and not
updated here.
Adds the settings-help entry for the new allowGhostMods preset setting, mirroring
allowGhostMaps. The generated doc/*.html is produced by 'spads.pl --doc' at
release time and is not regenerated here.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant