57a08d4c7a
Currently the game comes with no demos; place your own replays into $userdir/resources/demos if you want to test this.
193 lines
4.4 KiB
C
193 lines
4.4 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 "demoplayer.h"
|
|
#include "replay.h"
|
|
#include "replay/struct.h"
|
|
#include "global.h"
|
|
#include "vfs/public.h"
|
|
#include "events.h"
|
|
|
|
#define DEMOPLAYER_DIR_PATH "res/demos"
|
|
#define DEMOPLAYER_WAIT_TIME (60 * FPS)
|
|
|
|
struct {
|
|
uint time;
|
|
uint wait_time;
|
|
uint next_demo_index;
|
|
char **demo_files;
|
|
size_t num_demo_files;
|
|
int suspend_level;
|
|
} dplr;
|
|
|
|
static bool demo_path_filter(const char *path) {
|
|
return strendswith(path, "." REPLAY_EXTENSION);
|
|
}
|
|
|
|
static bool demoplayer_check_demos(void) {
|
|
if(!dplr.demo_files || dplr.num_demo_files == 0) {
|
|
log_warn("No demos found");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void demoplayer_init(void) {
|
|
dplr.demo_files = vfs_dir_list_sorted(
|
|
DEMOPLAYER_DIR_PATH, &dplr.num_demo_files, vfs_dir_list_order_ascending, demo_path_filter
|
|
);
|
|
|
|
if(demoplayer_check_demos()) {
|
|
log_info("Found %zu demo files", dplr.num_demo_files);
|
|
}
|
|
|
|
dplr.wait_time = env_get("TAISEI_DEMO_TIME", DEMOPLAYER_WAIT_TIME);
|
|
|
|
if(!dplr.wait_time) {
|
|
dplr.wait_time = UINT32_MAX;
|
|
}
|
|
|
|
dplr.suspend_level = 1;
|
|
demoplayer_resume();
|
|
}
|
|
|
|
void demoplayer_shutdown(void) {
|
|
if(dplr.suspend_level == 0) {
|
|
demoplayer_suspend();
|
|
}
|
|
|
|
vfs_dir_list_free(dplr.demo_files, dplr.num_demo_files);
|
|
dplr.demo_files = NULL;
|
|
dplr.num_demo_files = 0;
|
|
}
|
|
|
|
typedef struct DemoPlayerContext {
|
|
Replay rpy;
|
|
} DemoPlayerContext;
|
|
|
|
static void demoplayer_start_demo_posttransition(CallChainResult ccr);
|
|
static void demoplayer_end_demo(CallChainResult ccr);
|
|
|
|
static void demoplayer_start_demo(void) {
|
|
auto ctx = ALLOC(DemoPlayerContext);
|
|
CallChain cc = CALLCHAIN(demoplayer_end_demo, ctx);
|
|
|
|
demoplayer_suspend();
|
|
|
|
if(!demoplayer_check_demos()) {
|
|
run_call_chain(&cc, NULL);
|
|
return;
|
|
}
|
|
|
|
uint demoidx = dplr.next_demo_index;
|
|
dplr.next_demo_index = (demoidx + 1) % dplr.num_demo_files;
|
|
|
|
char *demo_filename = dplr.demo_files[demoidx];
|
|
char demo_path[sizeof(DEMOPLAYER_DIR_PATH) + 1 + strlen(demo_filename)];
|
|
snprintf(demo_path, sizeof(demo_path), DEMOPLAYER_DIR_PATH "/%s", demo_filename);
|
|
|
|
log_debug("Staring demo %s", demo_path);
|
|
|
|
if(!replay_load_vfspath(&ctx->rpy, demo_path, REPLAY_READ_ALL)) {
|
|
log_error("Failed to load replay %s", demo_path);
|
|
run_call_chain(&cc, NULL);
|
|
return;
|
|
}
|
|
|
|
set_transition(TransFadeWhite, FADE_TIME * 3, FADE_TIME * 2,
|
|
CALLCHAIN(demoplayer_start_demo_posttransition, ctx));
|
|
}
|
|
|
|
static void demoplayer_start_demo_posttransition(CallChainResult ccr) {
|
|
DemoPlayerContext *ctx = ccr.ctx;
|
|
CallChain end = CALLCHAIN(demoplayer_end_demo, ctx);
|
|
|
|
if(TRANSITION_RESULT_CANCELED(ccr)) {
|
|
run_call_chain(&end, NULL);
|
|
} else {
|
|
replay_play(&ctx->rpy, 0, true, end);
|
|
}
|
|
}
|
|
|
|
static void demoplayer_end_demo(CallChainResult ccr) {
|
|
DemoPlayerContext *ctx = ccr.ctx;
|
|
replay_reset(&ctx->rpy);
|
|
mem_free(ctx);
|
|
demoplayer_resume();
|
|
}
|
|
|
|
static bool demoplayer_frame_event(SDL_Event *evt, void *arg) {
|
|
if(dplr.time == dplr.wait_time) {
|
|
demoplayer_start_demo();
|
|
dplr.time = 0;
|
|
return false;
|
|
}
|
|
|
|
assert(dplr.time < dplr.wait_time);
|
|
++dplr.time;
|
|
|
|
// log_debug("%u", dplr.time);
|
|
return false;
|
|
}
|
|
|
|
static bool demoplayer_activity_event(SDL_Event *evt, void *arg) {
|
|
switch(evt->type) {
|
|
case SDL_KEYDOWN:
|
|
goto reset;
|
|
|
|
default: switch(TAISEI_EVENT(evt->type)) {
|
|
case TE_GAMEPAD_BUTTON_DOWN:
|
|
case TE_GAMEPAD_AXIS:
|
|
goto reset;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
reset:
|
|
// log_debug("Reset timer (was %u)", dplr.time);
|
|
dplr.time = 0;
|
|
return false;
|
|
}
|
|
|
|
void demoplayer_suspend(void) {
|
|
dplr.suspend_level++;
|
|
assert(dplr.suspend_level > 0);
|
|
log_debug("Suspend level is now %i", dplr.suspend_level);
|
|
|
|
if(dplr.suspend_level > 1) {
|
|
return;
|
|
}
|
|
|
|
log_debug("Removing event handlers");
|
|
|
|
events_unregister_handler(demoplayer_frame_event);
|
|
events_unregister_handler(demoplayer_activity_event);
|
|
}
|
|
|
|
void demoplayer_resume(void) {
|
|
dplr.suspend_level--;
|
|
assert(dplr.suspend_level >= 0);
|
|
log_debug("Suspend level is now %i", dplr.suspend_level);
|
|
|
|
if(dplr.suspend_level > 0) {
|
|
return;
|
|
}
|
|
|
|
log_debug("Installing event handlers");
|
|
|
|
events_register_handler(&(EventHandler) {
|
|
demoplayer_frame_event, NULL, EPRIO_LAST, MAKE_TAISEI_EVENT(TE_FRAME),
|
|
});
|
|
events_register_handler(&(EventHandler) {
|
|
demoplayer_activity_event, NULL, EPRIO_SYSTEM,
|
|
});
|
|
}
|