summaryrefslogtreecommitdiffhomepage
path: root/game/study_player/systems/seek_system.rb
blob: a11858aa9d0d41bf90febb8112138a19e11d9174 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Study Player — Seek system (PRE_UPDATE).
#
# Applies a pending seek intent:
#   1. Calls Rl.seek_music_stream to the target position.
#   2. Sets current_time = seek_target (instant visual update).
#   3. Sets skip_auto_update = N to implement non-blocking seek cooldown.
#   4. Clears seek_pending.
#
# Running in PRE_UPDATE means the subsequent UpdateSystem (ON_UPDATE)
# sees the already-applied seek and honours the cooldown counter.
#
# See: notes/study-player-rewrite-plan.md §7 (non-blocking seek design)

module StudyPlayer
  class SeekSystem
    # Number of frames to skip current_time auto-update after a seek.
    # 3 frames at 60 fps = ~50 ms — enough for raylib's miniaudio stream
    # to flush and report a stable time.
    SKIP_FRAMES = 3

    def self.build(world, player_entity, runtime, playback_state)
      world.system("ApplySeek", with: [], phase: Flecs::PRE_UPDATE) do
        pb = player_entity.get(playback_state)
        next unless pb && pb[:loaded] && pb[:seek_pending]

        audio = runtime.audio
        next unless audio.loaded?

        target = pb[:seek_target]

        # Apply the seek
        audio.seek(target)

        # Update component state
        pb[:current_time]     = target
        pb[:skip_auto_update] = SKIP_FRAMES
        pb[:seek_pending]     = false

        player_entity.set(playback_state, pb)
      end
    end
  end
end