HandmadeHero/project/engine/state_and_replay.cpp

236 lines
7.4 KiB
C++

/* TODO(Ed) : Do this properly later
I shoved this in here to depollute the mess Casey is making in engine.cpp.
I'll set this up more properly later when I see a good time to clean things up.
Doing my best to follow his advice to leave cleaning to when things are more "cemented".
*/
#if INTELLISENSE_DIRECTIVES
#include "engine.hpp"
#include "input.hpp"
#endif
NS_ENGINE_BEGIN
using SnapshotFn = void ( Memory* memory, platform::ModuleAPI* platform_api );
internal
void load_engine_snapshot( Memory* memory, platform::ModuleAPI* platform_api )
{
platform_api->memory_copy( memory->persistent, memory->total_size()
, memory->snapshots[ memory->active_snapshot_slot ].memory );
}
internal
void load_game_snapshot( Memory* memory, platform::ModuleAPI* platform_api )
{
s32 slot = memory->active_snapshot_slot;
EngineState* state = rcast( EngineState*, memory->persistent );
void* persistent_slot = memory->snapshots[ slot ].memory;
void* transient_slot = rcast( Byte*, memory->snapshots[ slot ].memory ) + state->game_memory.persistent_size;
platform_api->memory_copy( state->game_memory.persistent, state->game_memory.persistent_size, persistent_slot );
platform_api->memory_copy( state->game_memory.transient, state->game_memory.transient_size, transient_slot );
}
internal
void take_engine_snapshot( Memory* memory, platform::ModuleAPI* platform_api )
{
platform_api->memory_copy( memory->snapshots[ memory->active_snapshot_slot ].memory, memory->total_size(), memory->persistent );
memory->snapshots[ memory->active_snapshot_slot ].age = platform_api->get_wall_clock();
}
internal
void take_game_snapshot( Memory* memory, platform::ModuleAPI* platform_api )
{
s32 slot = memory->active_snapshot_slot;
EngineState* state = rcast( EngineState*, memory->persistent );
void* persistent_slot = memory->snapshots[ slot ].memory;
void* transient_slot = rcast( Byte*, memory->snapshots[ slot ].memory ) + state->game_memory.persistent_size;
platform_api->memory_copy( persistent_slot, state->game_memory.persistent_size, state->game_memory.persistent );
platform_api->memory_copy( transient_slot, state->game_memory.transient_size, state->game_memory.transient );
memory->snapshots[ memory->active_snapshot_slot ].age = platform_api->get_wall_clock();
}
internal
void begin_recording_input( Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{
Str file_name = str_ascii("test_input_");
StrPath file_path = {};
file_path.concat( platform_api->path_scratch, file_name );
snprintf( file_path.ptr, file_path.len, "%s%d.hm_replay", file_name.ptr, memory->active_snapshot_slot );
memory->active_input_replay_file.path = file_path;
platform_api->file_delete( memory->active_input_replay_file.path );
memory->replay_mode = ReplayMode_Record;
}
internal
void end_recording_input( Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{
memory->replay_mode = ReplayMode_Off;
platform_api->file_close( & memory->active_input_replay_file );
}
internal
void begin_playback_input( Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{
Str file_name = str_ascii("test_input_");
StrPath file_path = {};
file_path.concat( platform_api->path_scratch, file_name );
snprintf( file_path.ptr, file_path.len, "%s%d.hm_replay", file_name.ptr, memory->active_snapshot_slot );
// TODO(Ed - From Casey): Recording system still seems to take too long
// on record start - find out what Windows is doing and if
// we can speed up / defer some of that processing.
if ( platform_api->file_check_exists( file_path ) )
{
memory->active_input_replay_file.path = file_path;
memory->replay_mode = ReplayMode_Playback;
}
else
{
// TODO(Ed) : Logging
}
}
internal
void end_playback_input( Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{
memory->replay_mode = ReplayMode_Off;
platform_api->file_close( & memory->active_input_replay_file );
}
InputStateSnapshot input_state_snapshot( InputState* input )
{
#if NEW_INPUT_DESIGN
InputStateSnapshot snapshot = {};
if ( input->keyboard )
snapshot.keyboard = * input->keyboard;
if ( input->mouse )
snapshot.mouse = * input->mouse;
for ( s32 idx = 0; idx < Max_Controllers; ++ idx )
{
XInputPadState* xpad = input->xpads[ idx ];
if ( xpad )
snapshot.xpads[ idx ] = * xpad;
DualsensePadState* ds_pad = input->ds_pads[ idx ];
if ( ds_pad )
snapshot.ds_pads[ idx ] = * ds_pad;
}
return snapshot;
#else
InputStateSnapshot snapshot = {};
for ( s32 idx = 0; idx < array_count( snapshot.controllers ); ++ idx )
{
ControllerState* controller = & input->controllers[idx];
if ( controller == nullptr )
continue;
if ( controller->ds_pad )
snapshot.controllers[idx].ds_pad = *controller->ds_pad;
if ( controller->xpad )
snapshot.controllers[idx].xpad = *controller->xpad;
if ( controller->keyboard )
snapshot.controllers[idx].keyboard = *controller->keyboard;
if ( controller->mouse )
snapshot.controllers[idx].mouse = *controller->mouse;
}
return snapshot;
#endif
}
internal
void record_input( Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{
InputStateSnapshot snapshot = input_state_snapshot( input );
if ( platform_api->file_write_stream( & memory->active_input_replay_file, sizeof(snapshot), &snapshot ) == 0 )
{
// TODO(Ed) : Logging
}
}
internal
void play_input( SnapshotFn* load_snapshot, Memory* memory, InputState* input, platform::ModuleAPI* platform_api )
{
InputStateSnapshot new_input;
if ( platform_api->file_read_stream( & memory->active_input_replay_file, sizeof(InputStateSnapshot), & new_input ) == 0 )
{
load_snapshot( memory, platform_api );
platform_api->file_rewind( & memory->active_input_replay_file );
return;
}
#if NEW_INPUT_DESIGN
if ( input->keyboard )
* input->keyboard = new_input.keyboard;
if ( input->mouse )
* input->mouse = new_input.mouse;
for ( s32 idx = 0; idx < Max_Controllers; ++ idx )
{
XInputPadState* xpad = input->xpads[ idx ];
if ( xpad )
* xpad = new_input.xpads[ idx ];
DualsensePadState* ds_pad = input->ds_pads[ idx ];
if ( ds_pad )
* ds_pad = new_input.ds_pads[ idx ];
}
#else
for ( s32 idx = 0; idx < array_count( new_input.controllers ); ++ idx )
{
ControllerState* controller = & input->controllers[idx];
if ( controller == nullptr )
continue;
if ( controller->ds_pad )
*controller->ds_pad = new_input.controllers[idx].ds_pad;
if ( controller->xpad )
*controller->xpad = new_input.controllers[idx].xpad;
if ( controller->keyboard )
{
*controller->keyboard = new_input.controllers[idx].keyboard;
}
if ( controller->mouse )
*controller->mouse = new_input.controllers[idx].mouse;
}
#endif
}
void process_loop_mode( SnapshotFn* take_snapshot, SnapshotFn* load_snapshot
, Memory* memory, EngineState* state, InputState* input, platform::ModuleAPI* platform_api )
{
if ( memory->replay_mode == ReplayMode_Off )
{
take_snapshot( memory, platform_api );
begin_recording_input( memory, input, platform_api );
}
else if ( memory->replay_mode == ReplayMode_Playback )
{
end_playback_input( memory, input, platform_api );
load_snapshot( memory, platform_api );
}
else if ( memory->replay_mode == ReplayMode_Record )
{
end_recording_input( memory, input, platform_api );
load_snapshot( memory, platform_api );
begin_playback_input( memory, input, platform_api );
}
}
NS_ENGINE_END