replayFrameAt function

  1. @riverpod
GameFrame? replayFrameAt(
  1. Ref ref, {
  2. required String gameId,
  3. required int index,
})

The GameFrame for a single replay frame index.

Memoized per (gameId, index): GameRules.parseObservation runs once per frame no matter how often the user steps back and forth across it. Timing is always empty, since a replay has no live clocks. Returns null until the frames and the version unit have both loaded, or for an out-of-range index.

Implementation

@riverpod
GameFrame? replayFrameAt(
  Ref ref, {
  required String gameId,
  required int index,
}) {
  final rules = ref.watch(gameRulesProvider(gameId: gameId)).value;
  final frames = ref.watch(replayFramesProvider(gameId: gameId)).value;
  if (rules == null || frames == null || index < 0 || index >= frames.length) {
    return null;
  }
  final frame = frames[index];
  return GameFrame(
    observation: rules.parseObservation(frame.data as Map<String, dynamic>),
    pendingPlayers: frame.pendingPlayers,
    version: frame.version,
    // A replay has no live clocks: the deadlines these frames carried have
    // long passed, and re-rendering them as countdowns would be nonsense.
    timing: TimingContext(clock: ref.watch(serverClockProvider)),
  );
}