173c8c3cc6
* Split replay.c into multiple files under replay/; improve logical separation of replay-related code. * Separate replay playback state from data. * Get rid of global static replay struct and avoid unnecessary replay copying. * Replay playback and recording are now independent and may occur simultaneously, although this functionality is not yet exposed. This enables replay "re-recording" while synthesizing new desync check events, possibly at a different rate from the original replay. * Rate of recorded desync check events can now be controlled with the TAISEI_REPLAY_DESYNC_CHECK_FREQUENCY environment variable. The default value is 300 as before. * Probably other stuff I forgot about.
93 lines
2 KiB
C
93 lines
2 KiB
C
/*
|
|
* This software is licensed under the terms of the MIT License.
|
|
* See COPYING for further information.
|
|
* ---
|
|
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
|
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
|
*/
|
|
|
|
#include "taisei.h"
|
|
|
|
#include "state.h"
|
|
#include "struct.h"
|
|
#include "eventcodes.h"
|
|
|
|
#include "util.h"
|
|
|
|
void replay_state_init_play(ReplayState *rst, Replay *rpy, ReplayStage *rstage) {
|
|
memset(rst, 0, sizeof(*rst));
|
|
rst->replay = rpy;
|
|
rst->stage = rstage;
|
|
rst->mode = REPLAY_PLAY;
|
|
rst->play.desync_frame = -1;
|
|
rst->play.desync_check_frame = -1;
|
|
}
|
|
|
|
void replay_state_init_record(ReplayState *rst, Replay *rpy) {
|
|
memset(rst, 0, sizeof(*rst));
|
|
rst->replay = rpy;
|
|
rst->mode = REPLAY_RECORD;
|
|
}
|
|
|
|
void replay_state_deinit(ReplayState *rst) {
|
|
memset(rst, 0, sizeof(*rst));
|
|
}
|
|
|
|
ReplaySyncStatus replay_state_check_desync(ReplayState *rst, int time, uint16_t check) {
|
|
if(!rst->stage) {
|
|
return REPLAY_SYNC_NODATA;
|
|
}
|
|
|
|
assert(rst->replay != NULL);
|
|
assert(rst->mode == REPLAY_PLAY);
|
|
|
|
if(rst->play.desync_check_frame != time) {
|
|
return REPLAY_SYNC_NODATA;
|
|
}
|
|
|
|
if(rst->play.desync_check != check) {
|
|
log_warn("Frame %d: replay desync detected! 0x%04x != 0x%04x", time, rst->play.desync_check, check);
|
|
|
|
if(rst->play.desync_frame < 0) {
|
|
rst->play.desync_frame = time;
|
|
}
|
|
|
|
return REPLAY_SYNC_FAIL;
|
|
}
|
|
|
|
log_debug("Frame %d: 0x%04x OK", time, check);
|
|
return REPLAY_SYNC_OK;
|
|
}
|
|
|
|
void replay_state_play_advance(ReplayState *rst, int frame, ReplayEventFunc event_callback, void *arg) {
|
|
assert(rst->mode == REPLAY_PLAY);
|
|
|
|
ReplayStage *s = NOT_NULL(rst->stage);
|
|
int nevents = s->events.num_elements;
|
|
|
|
int i;
|
|
for(i = rst->play.pos; i < nevents; ++i) {
|
|
ReplayEvent *e = dynarray_get_ptr(&s->events, i);
|
|
|
|
if(e->frame != frame) {
|
|
break;
|
|
}
|
|
|
|
switch(e->type) {
|
|
case EV_CHECK_DESYNC:
|
|
rst->play.desync_check = e->value;
|
|
rst->play.desync_check_frame = frame;
|
|
break;
|
|
|
|
case EV_FPS:
|
|
rst->play.fps = e->value;
|
|
break;
|
|
|
|
default:
|
|
event_callback(e, arg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
rst->play.pos = i;
|
|
}
|