HarbourMasters / HarbourMasters/Lighthouse

[ANCHOR] Automatic seed alignment and save identity

Open
#531 2 comments 0 reactions 0 assignees View on GitHub
anchor rando
Dominant language
C
Stars
431
Forks
38
Avg merge
1d 22h
Merged PRs (30d)
26

Description

Here's the scenario: a host starts a rando game. Joiners can only play vanilla or roll their own seed, with the sole workaround being manual distribution of a spoiler log. That doesn't scale to, say, a streamer's 100+ viewers.
- You can't just send the seed, because the pool is filtered by local CVars. Same seed, different settings, different game.
- `std::shuffle`'s permutation is implementation-defined even with a standardized `mt19937`. Cross-platforms disagree.
- `GlitchlessLogic.cpp` uses `srand()` and `rand()`, which is also implementation-defined. Cross-platforms disagree.
- The code already treats `seedId` as a label, it's never re-simulated.

It's not user friendly and not intuitive. With Lighthouse especially, it's more likely that players in private rooms will hotswap rando vs vanilla and romhacks.

This may be a smaller resolution than we think though. Both halves exist: rando files currently write a spoiler log, and `GenerateFromSpoiler` reconstructs from that. Size will fit one packet, ~79KB compacted, which is still over the server's limit, and 38.9KB if check-name keys are dropped (names are re-derived from `StaticData::Checks` on import). Check-name keys must be dropped if spoiler files are to be sent as a packet, given the server's 64KB `bufio.Scanner` limit.

My sketch:
- Joiner enters a room with `roomState.isRando`, requests the spoiler from `roomState.ownerClientId`; owner replies.
- Prefetch and cache on join: file creation in `onFileLoad` is synchronous, so the blob must already be in hand.
- The existing `UseExistingLog` branch prefers the cached anchor spoiler, falls back if nothing arrives.
- Must land on a newly created file, never adopting an existing one.
- Must complete before the team-state exchange, or `gameSig` (see #530 where it's added) will refuse the host's state on the way in.

### Session identity:
`gameSig` can't tell "solo vanilla file" from "the team's vanilla file". Same game, different session. A joiner with an existing vanilla file in a vanilla room still gets overwritten. An `anchorSessionId` on `shipSaveData` would let a fresh file adopt the session, let a returning file match it, and a file carrying unrelated progress would prompt first.

### TL;DR
A host starts a randomizer game. Anyone who joins them cannot play that same randomized game unless the host manually sends each of them a file. For a couple of friends that's annoying; for a streamer with an audience it doesn't work at all.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with GlitchlessLogic.cpp, GenerateFromSpoiler, the UseExistingLog branch, and onFileLoad; then trace the team-state exchange and gameSig, including shipSaveData. Define the owner-to-joiner spoiler transfer and session identity behavior, including the file-creation and completion-order constraints. Done means joiners can obtain the host's randomized game and safely distinguish matching, new, and unrelated save files.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
distributed-systems, game-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.