Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186package sim
// A run history is not a movie of positions. It is the command stream needed to// ask the same simulation to produce the same behavior again.Run_History :: struct { run_id: u32, sim_version: u32, seed: u64, initial_state: Initial_State_Descriptor, commands: [dynamic]Input_Command,}
// Completed histories live behind an archive instead of actor-owned pointers.// Echo actors store source run ids and cursors; each tick resolves commands here.Run_Archive :: struct { histories: [dynamic]Run_History,}
Run_Session :: struct { sim: Sim_State, archive: Run_Archive, current_history: Run_History, current_run_id: u32, next_run_id: u32,}
run_history_init :: proc( history: ^Run_History, run_id := u32(0), seed := DEFAULT_WORLD_SEED, initial := DEFAULT_INITIAL_STATE,) { history^ = Run_History{ run_id = run_id, sim_version = SIM_VERSION, seed = seed, initial_state = initial, commands = make([dynamic]Input_Command), }}
run_history_destroy :: proc(history: ^Run_History) { delete(history.commands) history^ = {}}
run_history_copy :: proc(dst: ^Run_History, src: ^Run_History) { run_history_init(dst, src.run_id, src.seed, src.initial_state) dst.sim_version = src.sim_version for command in src.commands { append(&dst.commands, command) }}
run_history_clear_commands :: proc(history: ^Run_History) { clear(&history.commands)}
run_history_record_tick :: proc(history: ^Run_History, state: ^Sim_State, command: Input_Command) -> bool { if u64(len(history.commands)) != state.tick { return false } append(&history.commands, command) return true}
run_history_command_count :: proc(history: ^Run_History) -> u64 { return u64(len(history.commands))}
replay_history :: proc(history: ^Run_History, state: ^Sim_State) -> u64 { sim_init(state, history.seed, history.initial_state) for command in history.commands { sim_tick(state, command) } return sim_digest(state)}
run_archive_init :: proc(archive: ^Run_Archive) { archive^ = Run_Archive{histories = make([dynamic]Run_History)}}
run_archive_destroy :: proc(archive: ^Run_Archive) { for &history in archive.histories { run_history_destroy(&history) } delete(archive.histories) archive^ = {}}
run_archive_add_completed :: proc(archive: ^Run_Archive, history: ^Run_History) -> bool { if run_archive_find(archive, history.run_id) != nil { return false }
archived: Run_History run_history_copy(&archived, history) append(&archive.histories, archived) return true}
run_archive_find :: proc(archive: ^Run_Archive, run_id: u32) -> ^Run_History { if archive == nil { return nil }
for &history in archive.histories { if history.run_id == run_id { return &history } } return nil}
run_archive_command_count_for_run :: proc(archive: ^Run_Archive, run_id: u32) -> u64 { history := run_archive_find(archive, run_id) if history == nil { return 0 } return run_history_command_count(history)}
run_archive_command_at :: proc( archive: ^Run_Archive, run_id: u32, tick: u64,) -> (Input_Command, bool) { history := run_archive_find(archive, run_id) if history == nil || tick >= u64(len(history.commands)) { return {}, false } return history.commands[tick], true}
run_session_init :: proc( session: ^Run_Session, seed := DEFAULT_WORLD_SEED, initial := DEFAULT_INITIAL_STATE,) { session^ = Run_Session{ current_run_id = 1, next_run_id = 2, } run_archive_init(&session.archive) run_history_init(&session.current_history, session.current_run_id, seed, initial) sim_init(&session.sim, seed, initial)}
run_session_destroy :: proc(session: ^Run_Session) { run_history_destroy(&session.current_history) run_archive_destroy(&session.archive) session^ = {}}
run_session_tick :: proc(session: ^Run_Session, live_command: Input_Command) -> bool { if !run_history_record_tick(&session.current_history, &session.sim, live_command) { return false } sim_tick_with_archive(&session.sim, live_command, &session.archive) return true}
run_session_complete_and_restart :: proc(session: ^Run_Session) -> bool { seed := session.current_history.seed initial := session.current_history.initial_state
if !run_archive_add_completed(&session.archive, &session.current_history) { return false }
run_history_destroy(&session.current_history) session.current_run_id = session.next_run_id session.next_run_id += 1 run_history_init(&session.current_history, session.current_run_id, seed, initial) sim_init(&session.sim, seed, initial)
for history in session.archive.histories { _, spawned := world_spawn_echo(&session.sim.world, history.run_id, history.initial_state.player_position) if !spawned { return false } }
return true}