add replay verification mode: taisei --verify-replay file.tsr
This commit is contained in:
parent
73901b004a
commit
58252950d4
8 changed files with 75 additions and 21 deletions
25
src/cli.c
25
src/cli.c
|
@ -41,8 +41,9 @@ static void print_help(struct TsOption* opts) {
|
|||
}
|
||||
|
||||
int cli_args(int argc, char **argv, CLIAction *a) {
|
||||
struct TsOption taisei_opts[] =
|
||||
{{{"replay", required_argument, 0, 'r'}, "Play a replay from %s", "FILE"},
|
||||
struct TsOption taisei_opts[] = {
|
||||
{{"replay", required_argument, 0, 'r'}, "Play a replay from %s", "FILE"},
|
||||
{{"verify-replay", required_argument, 0, 'R'}, "Play a replay from %s in headless mode, crash as soon as it desyncs", "FILE"},
|
||||
#ifdef DEBUG
|
||||
{{"play", no_argument, 0, 'p'}, "Play a specific stage", 0},
|
||||
{{"sid", required_argument, 0, 'i'}, "Select stage by %s", "ID"},
|
||||
|
@ -105,6 +106,10 @@ int cli_args(int argc, char **argv, CLIAction *a) {
|
|||
a->type = CLI_PlayReplay;
|
||||
a->filename = strdup(optarg);
|
||||
break;
|
||||
case 'R':
|
||||
a->type = CLI_VerifyReplay;
|
||||
a->filename = strdup(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
a->type = CLI_SelectStage;
|
||||
break;
|
||||
|
@ -162,10 +167,18 @@ int cli_args(int argc, char **argv, CLIAction *a) {
|
|||
}
|
||||
|
||||
if(stageid) {
|
||||
if(a->type != CLI_PlayReplay && a->type != CLI_SelectStage) {
|
||||
log_warn("--sid was ignored");
|
||||
} else if(!stage_get(stageid)) {
|
||||
log_fatal("Invalid stage id: %X", stageid);
|
||||
switch(a->type) {
|
||||
case CLI_PlayReplay:
|
||||
case CLI_VerifyReplay:
|
||||
case CLI_SelectStage:
|
||||
if(stage_get(stageid) == NULL) {
|
||||
log_fatal("Invalid stage id: %X", stageid);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warn("--sid was ignored");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
typedef enum {
|
||||
CLI_RunNormally = 0,
|
||||
CLI_PlayReplay,
|
||||
CLI_VerifyReplay,
|
||||
CLI_SelectStage,
|
||||
CLI_DumpStages,
|
||||
CLI_DumpVFSTree,
|
||||
|
|
|
@ -31,6 +31,7 @@ void env_set_double(const char *var, double val, bool override)
|
|||
const char* : env_get_string, \
|
||||
char* : env_get_string, \
|
||||
void* : env_get_string, \
|
||||
bool : env_get_int, \
|
||||
int8_t : env_get_int, \
|
||||
uint8_t : env_get_int, \
|
||||
int16_t : env_get_int, \
|
||||
|
@ -47,6 +48,7 @@ void env_set_double(const char *var, double val, bool override)
|
|||
const char* : env_set_string, \
|
||||
char* : env_set_string, \
|
||||
void* : env_set_string, \
|
||||
bool : env_set_int, \
|
||||
int8_t : env_set_int, \
|
||||
uint8_t : env_set_int, \
|
||||
int16_t : env_set_int, \
|
||||
|
|
|
@ -71,6 +71,11 @@ void loop_at_fps(LogicFrameFunc logic_frame, RenderFrameFunc render_frame, void
|
|||
bool uncapped_rendering_env = env_get("TAISEI_FRAMELIMITER_LOGIC_ONLY", 0);
|
||||
bool late_swap = config_get_int(CONFIG_VID_LATE_SWAP);
|
||||
|
||||
if(global.is_replay_verification) {
|
||||
uncapped_rendering_env = false;
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
uint32_t frame_num = 0;
|
||||
|
||||
// don't care about thread safety, we can render only on the main thread anyway
|
||||
|
@ -153,7 +158,7 @@ begin_frame:
|
|||
fpscounter_update(&global.fps.logic);
|
||||
}
|
||||
|
||||
if(!uncapped_rendering && frame_num % get_effective_frameskip()) {
|
||||
if((!uncapped_rendering && frame_num % get_effective_frameskip()) || global.is_replay_verification) {
|
||||
rframe_action = RFRAME_DROP;
|
||||
} else {
|
||||
rframe_action = render_frame(arg);
|
||||
|
|
|
@ -25,7 +25,11 @@ void init_global(CLIAction *cli) {
|
|||
global.replaymode = REPLAY_RECORD;
|
||||
global.frameskip = cli->frameskip;
|
||||
|
||||
if(global.frameskip) {
|
||||
if(cli->type == CLI_VerifyReplay) {
|
||||
global.is_headless = true;
|
||||
global.is_replay_verification = true;
|
||||
global.frameskip = 1;
|
||||
} else if(global.frameskip) {
|
||||
log_warn("FPS limiter disabled. Gotta go fast! (frameskip = %i)", global.frameskip);
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,9 @@ typedef struct {
|
|||
|
||||
StageInfo *stage;
|
||||
|
||||
bool is_practice_mode;
|
||||
uint is_practice_mode : 1;
|
||||
uint is_headless : 1;
|
||||
uint is_replay_verification : 1;
|
||||
} Global;
|
||||
|
||||
extern Global global;
|
||||
|
|
38
src/main.c
38
src/main.c
|
@ -31,8 +31,11 @@
|
|||
static void taisei_shutdown(void) {
|
||||
log_info("Shutting down");
|
||||
|
||||
config_save();
|
||||
progress_save();
|
||||
if(!global.is_replay_verification) {
|
||||
config_save();
|
||||
progress_save();
|
||||
}
|
||||
|
||||
progress_unload();
|
||||
|
||||
free_all_refs();
|
||||
|
@ -208,6 +211,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
Replay replay = {0};
|
||||
int replay_idx = 0;
|
||||
bool headless = false;
|
||||
|
||||
init_log();
|
||||
|
||||
|
@ -233,7 +237,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
free_cli_action(&a);
|
||||
return 0;
|
||||
} else if(a.type == CLI_PlayReplay) {
|
||||
} else if(a.type == CLI_PlayReplay || a.type == CLI_VerifyReplay) {
|
||||
if(!replay_load_syspath(&replay, a.filename, REPLAY_READ_ALL)) {
|
||||
free_cli_action(&a);
|
||||
return 1;
|
||||
|
@ -245,6 +249,10 @@ int main(int argc, char **argv) {
|
|||
free_cli_action(&a);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(a.type == CLI_VerifyReplay) {
|
||||
headless = true;
|
||||
}
|
||||
} else if(a.type == CLI_DumpVFSTree) {
|
||||
vfs_setup(true);
|
||||
|
||||
|
@ -269,14 +277,23 @@ int main(int argc, char **argv) {
|
|||
|
||||
free_cli_action(&a);
|
||||
vfs_setup(false);
|
||||
init_log_file();
|
||||
|
||||
if(headless) {
|
||||
env_set("SDL_AUDIODRIVER", "dummy", true);
|
||||
env_set("SDL_VIDEODRIVER", "dummy", true);
|
||||
env_set("TAISEI_RENDERER", "null", true);
|
||||
env_set("TAISEI_NOPRELOAD", true, false);
|
||||
env_set("TAISEI_PRELOAD_REQUIRED", false, false);
|
||||
} else {
|
||||
init_log_file();
|
||||
}
|
||||
|
||||
log_info("%s %s", TAISEI_VERSION_FULL, TAISEI_VERSION_BUILD_TYPE);
|
||||
log_system_specs();
|
||||
log_lib_versions();
|
||||
|
||||
config_load();
|
||||
|
||||
log_lib_versions();
|
||||
|
||||
init_sdl();
|
||||
time_init();
|
||||
init_global(&a);
|
||||
|
@ -286,11 +303,14 @@ int main(int argc, char **argv) {
|
|||
init_resources();
|
||||
r_post_init();
|
||||
draw_loading_screen();
|
||||
audio_init();
|
||||
|
||||
if(!headless) {
|
||||
audio_init();
|
||||
}
|
||||
|
||||
load_resources();
|
||||
gamepad_init();
|
||||
progress_load();
|
||||
r_shader_standard();
|
||||
|
||||
set_transition(TransLoader, 0, FADE_TIME*2);
|
||||
|
||||
|
@ -298,7 +318,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
atexit(taisei_shutdown);
|
||||
|
||||
if(a.type == CLI_PlayReplay) {
|
||||
if(a.type == CLI_PlayReplay || a.type == CLI_VerifyReplay) {
|
||||
replay_play(&replay, replay_idx);
|
||||
replay_destroy(&replay);
|
||||
return 0;
|
||||
|
|
13
src/replay.c
13
src/replay.c
|
@ -716,15 +716,22 @@ void replay_stage_check_desync(ReplayStage *stg, int time, uint16_t check, Repla
|
|||
|
||||
if(mode == REPLAY_PLAY) {
|
||||
if(stg->desync_check && stg->desync_check != check) {
|
||||
log_warn("Replay desync detected! %u != %u", stg->desync_check, check);
|
||||
log_warn("Frame %d: replay desync detected! 0x%04x != 0x%04x", time, stg->desync_check, check);
|
||||
stg->desynced = true;
|
||||
|
||||
if(global.is_replay_verification) {
|
||||
// log_fatal("Replay verification failed");
|
||||
exit(1);
|
||||
}
|
||||
} else if(global.is_replay_verification) {
|
||||
log_info("Frame %d: 0x%04x OK", time, check);
|
||||
} else {
|
||||
log_debug("%u OK", check);
|
||||
log_debug("Frame %d: 0x%04x OK", time, check);
|
||||
}
|
||||
}
|
||||
#ifdef REPLAY_WRITE_DESYNC_CHECKS
|
||||
else {
|
||||
// log_debug("%u", check);
|
||||
// log_debug("0x%04x", check);
|
||||
replay_stage_event(stg, time, EV_CHECK_DESYNC, (int16_t)check);
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue