eco2d/code/game/src/debug_replay.c

266 lines
7.1 KiB
C
Raw Normal View History

2021-08-10 15:21:25 +00:00
#include "debug_replay.h"
#include "camera.h"
#include "entity.h"
#include "cwpack/cwpack.h"
typedef enum {
RPKIND_KEY,
// NOTE(zaklaus): Special actions
RPKIND_SPAWN_CAR,
2021-08-11 10:22:46 +00:00
RPKIND_PLACE_ICE_RINK,
2021-08-30 09:59:36 +00:00
RPKIND_PLACE_ERASE_CHANGES,
2021-08-15 16:32:11 +00:00
RPKIND_SPAWN_CIRCLING_DRIVER,
2021-09-08 10:04:35 +00:00
RPKIND_SPAWN_ICEMAKER_ITEM,
} replay_kind;
2021-08-10 15:21:25 +00:00
typedef struct {
replay_kind kind;
2021-08-10 15:21:25 +00:00
pkt_send_keystate pkt;
uint64_t delay;
} replay_record;
2021-09-08 09:52:11 +00:00
#include "debug_replay_compat_v2.c"
2021-08-10 15:21:25 +00:00
static uint8_t is_recording = false;
static replay_record *records = NULL;
static uint64_t last_record_time = 0.0f;
static uint8_t is_playing = false;
static int record_pos = 0;
static uint64_t playback_time = 0;
static ecs_entity_t mime = 0;
static ecs_entity_t plr = 0;
2021-08-10 19:18:40 +00:00
static ecs_entity_t *temp_actors = NULL;
2021-08-10 15:21:25 +00:00
#define REPLAY_MAGIC 0x421DC97E
2021-09-08 09:52:11 +00:00
#define REPLAY_VERSION 3
static char replay_filename[1024] = {0};
2021-08-10 22:02:11 +00:00
static char replaybuf[sizeof(replay_record)*UINT16_MAX + 32];
void debug_replay_store(void) {
2021-08-11 13:49:44 +00:00
ZPL_ASSERT(replay_filename[0]);
2021-08-10 23:39:31 +00:00
if (!records) return;
cw_pack_context pc = {0};
cw_pack_context_init(&pc, replaybuf, sizeof(replaybuf), 0);
cw_pack_unsigned(&pc, REPLAY_MAGIC);
cw_pack_unsigned(&pc, REPLAY_VERSION);
cw_pack_array_size(&pc, zpl_array_count(records));
for (int i = 0; i < zpl_array_count(records); i++) {
cw_pack_bin(&pc, &records[i], sizeof(replay_record));
}
zpl_file f = {0};
zpl_file_create(&f, replay_filename);
zpl_file_write(&f, replaybuf, pc.current - pc.start);
zpl_file_close(&f);
}
void debug_replay_load(void) {
2021-08-11 13:49:44 +00:00
ZPL_ASSERT(replay_filename[0]);
zpl_file f = {0};
2021-08-11 13:49:44 +00:00
zpl_file_error err = zpl_file_open(&f, replay_filename);
ZPL_ASSERT(err == ZPL_FILE_ERROR_NONE);
size_t file_size = zpl_file_size(&f);
zpl_file_read(&f, replaybuf, file_size);
zpl_file_close(&f);
cw_unpack_context uc = {0};
cw_unpack_context_init(&uc, replaybuf, file_size, 0);
cw_unpack_next(&uc);
2021-08-11 13:49:44 +00:00
ZPL_ASSERT(uc.item.type == CWP_ITEM_POSITIVE_INTEGER && uc.item.as.u64 == REPLAY_MAGIC);
cw_unpack_next(&uc);
2021-09-08 09:52:11 +00:00
ZPL_ASSERT(uc.item.type == CWP_ITEM_POSITIVE_INTEGER);
uint64_t version = uc.item.as.u64;
ZPL_ASSERT(version >= 2);
cw_unpack_next(&uc);
2021-08-11 13:49:44 +00:00
ZPL_ASSERT(uc.item.type == CWP_ITEM_ARRAY);
size_t items = uc.item.as.array.size;
zpl_array_init_reserve(records, zpl_heap(), sizeof(replay_record)*items);
for (size_t i = 0; i < items; i++) {
cw_unpack_next(&uc);
2021-08-11 13:49:44 +00:00
ZPL_ASSERT(uc.item.type == CWP_ITEM_BIN);
replay_record rec = {0};
2021-09-08 09:52:11 +00:00
switch (version) {
case 2:{
debug_replay_load_record_v2(&rec, uc.item.as.bin.start);
}break;
default:{
zpl_memcopy(&rec, uc.item.as.bin.start, sizeof(replay_record));
}break;
}
zpl_array_append(records, rec);
}
}
2021-08-10 15:21:25 +00:00
void debug_replay_start(void) {
is_recording = true;
if (records) zpl_array_free(records);
2021-08-10 16:09:17 +00:00
zpl_array_init_reserve(records, zpl_heap(), UINT16_MAX);
2021-08-10 15:21:25 +00:00
last_record_time = zpl_time_rel_ms();
2021-10-27 00:42:54 +00:00
SetTargetFPS(60);
2021-08-10 15:21:25 +00:00
}
void debug_replay_clear(void) {
if (!records || is_playing || is_recording) return;
zpl_array_free(records);
records = NULL;
2021-08-10 16:09:17 +00:00
record_pos = 0;
2021-08-10 15:21:25 +00:00
}
2021-08-10 23:06:12 +00:00
void debug_replay_cleanup_ents(void) {
2021-10-27 00:42:54 +00:00
SetTargetFPS(0);
2021-08-10 23:06:12 +00:00
if (!mime) return;
entity_despawn(mime);
mime = 0;
is_playing = false;
camera_set_follow(plr);
for (int i = 0; i < zpl_array_count(temp_actors); i++) {
entity_despawn(temp_actors[i]);
}
zpl_array_free(temp_actors);
}
2021-08-10 15:21:25 +00:00
void debug_replay_stop(void) {
is_recording = false;
2021-08-10 23:06:12 +00:00
is_playing = false;
record_pos = 0;
debug_replay_cleanup_ents();
2021-08-10 15:21:25 +00:00
}
void debug_replay_run(void) {
if (mime) return;
is_playing = true;
record_pos = 0;
playback_time = zpl_time_rel_ms();
2021-08-10 19:18:40 +00:00
zpl_array_init(temp_actors, zpl_heap());
2021-08-10 15:21:25 +00:00
plr = camera_get().ent_id;
Position const *p1 = ecs_get(world_ecs(), plr, Position);
mime = entity_spawn(EKIND_MACRO_BOT);
2021-08-10 15:21:25 +00:00
Position *pos = ecs_get_mut(world_ecs(), mime, Position, NULL);
*pos = *p1;
ecs_set(world_ecs(), mime, Input, {0});
2021-08-30 15:50:05 +00:00
ecs_set(world_ecs(), mime, Inventory, {0});
2021-08-10 15:21:25 +00:00
camera_set_follow(mime);
2021-10-27 00:42:54 +00:00
SetTargetFPS(60);
2021-08-10 15:21:25 +00:00
}
2021-09-08 10:04:35 +00:00
void ActPlaceIceRink(void);
2021-08-15 16:32:11 +00:00
void ActSpawnCirclingDriver(void);
2021-08-30 09:59:36 +00:00
void ActEraseWorldChanges(void);
2021-09-08 10:04:35 +00:00
void ActSpawnIcemaker(void);
2021-08-11 10:22:46 +00:00
2021-08-10 15:21:25 +00:00
void debug_replay_update(void) {
if (!is_playing) return;
if (playback_time >= zpl_time_rel_ms()) return;
replay_record *r = &records[record_pos];
playback_time = zpl_time_rel() + r->delay;
switch (r->kind) {
case RPKIND_KEY: {
Input *i = ecs_get_mut(world_ecs(), mime, Input, NULL);
i->x = r->pkt.x;
i->y = r->pkt.y;
2021-08-30 15:50:05 +00:00
i->mx = r->pkt.mx;
i->my = r->pkt.my;
i->use = r->pkt.use;
i->sprint = r->pkt.sprint;
2021-08-30 15:50:05 +00:00
i->ctrl = r->pkt.ctrl;
i->selected_item = r->pkt.selected_item;
i->drop = r->pkt.drop;
i->swap = r->pkt.swap;
i->swap_from = r->pkt.swap_from;
i->swap_to = r->pkt.swap_to;
2021-11-01 17:35:33 +00:00
i->num_placements = r->pkt.placement_num;
for (uint8_t j = 0; j < i->num_placements; j++) {
i->placements_x[j] = r->pkt.placements[j].x;
i->placements_y[j] = r->pkt.placements[j].y;
}
}break;
case RPKIND_SPAWN_CAR: {
ecs_entity_t e = vehicle_spawn();
Position const *origin = ecs_get(world_ecs(), mime, Position);
Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL);
*dest = *origin;
2021-08-10 19:18:40 +00:00
zpl_array_append(temp_actors, e);
}break;
2021-08-11 10:22:46 +00:00
case RPKIND_PLACE_ICE_RINK: {
ActPlaceIceRink();
}break;
2021-08-15 16:32:11 +00:00
case RPKIND_SPAWN_CIRCLING_DRIVER: {
ActSpawnCirclingDriver();
}break;
2021-08-30 09:59:36 +00:00
case RPKIND_PLACE_ERASE_CHANGES:{
ActEraseWorldChanges();
}break;
2021-09-08 10:04:35 +00:00
case RPKIND_SPAWN_ICEMAKER_ITEM:{
ActSpawnIcemaker();
}break;
default: {
ZPL_PANIC("unreachable");
}break;
}
2021-08-10 15:21:25 +00:00
record_pos += 1;
// NOTE(zaklaus): remove our dummy art exhibist
if (mime && record_pos == zpl_array_count(records)) {
2021-08-10 23:06:12 +00:00
debug_replay_cleanup_ents();
2021-08-10 15:21:25 +00:00
}
}
void debug_replay_record_keystate(pkt_send_keystate state) {
if (!is_recording) return;
float record_time = zpl_time_rel_ms();
replay_record rec = {
.kind = RPKIND_KEY,
2021-08-10 15:21:25 +00:00
.pkt = state,
.delay = (record_time - last_record_time),
};
zpl_array_append(records, rec);
last_record_time = zpl_time_rel_ms();
}
void debug_replay_special_action(replay_kind kind) {
2021-08-11 13:49:44 +00:00
ZPL_ASSERT(kind != RPKIND_KEY);
if (!is_recording || is_playing) return;
float record_time = zpl_time_rel_ms();
replay_record rec = {
.kind = kind,
.delay = (record_time - last_record_time),
};
zpl_array_append(records, rec);
last_record_time = zpl_time_rel_ms();
}