taisei/src/replay/state.c
Andrei Alexeyev 173c8c3cc6
replay: general refactor
* 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.
2021-06-16 01:43:10 +03:00

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