add replay verification mode: taisei --verify-replay file.tsr

This commit is contained in:
Andrei Alexeyev 2018-04-18 02:17:28 +03:00
parent 73901b004a
commit 58252950d4
No known key found for this signature in database
GPG key ID: 363707CD4C7FE8A4
8 changed files with 75 additions and 21 deletions

View file

@ -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;
}
}

View file

@ -14,6 +14,7 @@
typedef enum {
CLI_RunNormally = 0,
CLI_PlayReplay,
CLI_VerifyReplay,
CLI_SelectStage,
CLI_DumpStages,
CLI_DumpVFSTree,

View file

@ -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, \

View file

@ -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);

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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