SeededChallengeService class
FEAT-97: ties together this kit's existing deterministic-replay primitives — SeededRandomService (RNG snapshot/resume), ReplayRecorder/ReplayCapsule (recorded event replay + divergence detection), and LocalScoreboardService (on-device ranking) — into one "same challenge, reproducible run, fully offline" building block, so a consuming game doesn't have to wire all 3 together itself and risk a seed/clock/replay mismatch doing it.
Deliberately a thin glue layer, not a reimplementation: every
correctness property (RNG determinism, replay divergence detection,
leaderboard ranking, clock-rewind resistance) is inherited unchanged
from the primitive that already owns it — this class only derives the
shared seed and scopes a LocalScoreboardService instance per
(challengeId, periodKey) pair.
No backend/network: every piece of state here is either derived (the seed) or local-only (LocalScoreboardService's on-device table) — nothing in this class makes a network call or depends on one.
Constructors
- SeededChallengeService({required String challengeId, required ChallengePeriod period, int scoreboardCapacity = 50})
Properties
- challengeId → String
-
final
- currentSeed → int
-
Deterministically derived from
(periodKey, challengeId)— the SAME pair always yields the SAME seed, on any instance/process/restart (FNV-1a is a pure function of its input string, seeutils/fnv1a.dart— no process-local state). Changes only when periodKey rolls over to a new period, or when a different challengeId is used.no setter - hashCode → int
-
The hash code for this object.
no setterinherited
- period → ChallengePeriod
-
final
- periodKey → String
-
Clock-derived — see ChallengePeriod's doc. Always goes through
todayEpochDayClamped, so winding the device clock BACK can never
reopen a period that has already advanced past (same anti-cheat
clamp every other time-gated system in this package relies on); it
only ever "loses" real future time, never replays a past one.
no setter
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
endRun(
ReplayRecorder recorder, {String appVersion = '1'}) → ReplayCapsule -
Stops
recorderand packages everything it captured since startRun into a ReplayCapsule — hand this to replay (locally, or after exporting it elsewhere) to verify the run reproduces deterministically. -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
replay(
ReplayCapsule capsule, Object? handler(ReplayEvent event, SeededRandomService rng)) → SeededChallengeReplayResult -
Replays
capsulethroughhandler(same contract as the free function replayCapsule) and reports whether the replay reproduced the original run's outcomes exactly — see ReplayDivergence for what counts as a mismatch and whyhandlermust read randomness only through the SeededRandomService it's given. -
startRun(
{ReplayRecorder? recorder}) → SeededRandomService -
Starts a fresh run for the current period: a SeededRandomService
seeded from currentSeed for the caller's own gameplay namespaces
(e.g.
rng.stream('gameplay')), optionally paired withrecorder(if given, ReplayRecorder.started with the same seed) so the run can later be packaged into a ReplayCapsule via endRun. -
submitScore(
String playerLabel, int score) → void -
Submits
scoreforplayerLabelinto this challenge's current-period local scoreboard. See LocalScoreboardService.submitScore. -
topScores(
int n) → List< LeaderboardEntry> -
This challenge's current-period top
nscores. See LocalScoreboardService.topN. -
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited