crappy delta encoding test
This commit is contained in:
parent
fd550a7119
commit
ff0fbf0878
@ -91,7 +91,7 @@ void bw_seek_to(struct byte_writer *bw, u64 pos)
|
||||
bw->at = bw->buff.text + pos;
|
||||
}
|
||||
|
||||
void br_write_bytes(struct byte_writer *bw, struct string bytes)
|
||||
void bw_write_bytes(struct byte_writer *bw, struct string bytes)
|
||||
{
|
||||
write(bw, bytes.text, bytes.len);
|
||||
}
|
||||
@ -167,7 +167,7 @@ void bw_write_v2(struct byte_writer *bw, struct v2 v)
|
||||
void bw_write_string(struct byte_writer *bw, struct string str)
|
||||
{
|
||||
bw_write_var_uint(bw, str.len);
|
||||
br_write_bytes(bw, str);
|
||||
bw_write_bytes(bw, str);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
|
||||
@ -25,7 +25,7 @@ struct byte_writer bw_branch(struct byte_writer *bw, u64 size);
|
||||
void bw_seek(struct byte_writer *bw, u64 amount);
|
||||
void bw_seek_to(struct byte_writer *bw, u64 pos);
|
||||
|
||||
void br_write_bytes(struct byte_writer *bw, struct string bytes);
|
||||
void bw_write_bytes(struct byte_writer *bw, struct string bytes);
|
||||
void bw_write_u8(struct byte_writer *bw, u8 v);
|
||||
void bw_write_u16(struct byte_writer *bw, u16 v);
|
||||
void bw_write_u32(struct byte_writer *bw, u32 v);
|
||||
|
||||
@ -724,7 +724,7 @@ void host_update(struct host *host)
|
||||
u64 chunk_count = br_read_var_uint(&br);
|
||||
|
||||
b32 is_last_chunk = (chunk_id + 1) == chunk_count;
|
||||
u64 data_len = is_last_chunk ? (br_read_var_uint(&br) + 1) : PACKET_MSG_CHUNK_MAX_LEN;
|
||||
u64 data_len = is_last_chunk ? br_read_var_uint(&br) : PACKET_MSG_CHUNK_MAX_LEN;
|
||||
|
||||
struct host_msg_assembler *ma = host_get_msg_assembler(host, channel->id, msg_id);
|
||||
if (!ma) {
|
||||
@ -916,9 +916,9 @@ void host_update(struct host *host)
|
||||
bw_write_var_uint(&bw, chunk_count);
|
||||
if (is_last_chunk) {
|
||||
/* FIXME: Ensure data_len can never be 0 */
|
||||
bw_write_var_uint(&bw, data_len - 1);
|
||||
bw_write_var_uint(&bw, data_len);
|
||||
}
|
||||
br_write_bytes(&bw, STRING(data_len, data));
|
||||
bw_write_bytes(&bw, STRING(data_len, data));
|
||||
host_packet->data_len = bw_pos(&bw);
|
||||
}
|
||||
} break;
|
||||
|
||||
286
src/sim.c
286
src/sim.c
@ -1,7 +1,6 @@
|
||||
#include "sim.h"
|
||||
#include "sim_ent.h"
|
||||
#include "sim_client.h"
|
||||
#include "sim_encode.h"
|
||||
#include "sim_snapshot.h"
|
||||
#include "sys.h"
|
||||
#include "util.h"
|
||||
@ -22,7 +21,6 @@
|
||||
* Ctx
|
||||
* ========================== */
|
||||
|
||||
|
||||
struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
||||
struct phys_startup_receipt *phys_sr,
|
||||
struct host_startup_receipt *host_sr,
|
||||
@ -79,7 +77,7 @@ void sim_ctx_release(struct sim_ctx *ctx)
|
||||
|
||||
/* TODO: Remove this */
|
||||
|
||||
INTERNAL void spawn_test_entities(struct sim_ctx *ctx)
|
||||
INTERNAL void spawn_test_entities(struct sim_ctx *ctx, struct v2 offset)
|
||||
{
|
||||
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
|
||||
root->mass_unscaled = F32_INFINITY;
|
||||
@ -90,6 +88,7 @@ INTERNAL void spawn_test_entities(struct sim_ctx *ctx)
|
||||
struct sim_ent *e = sim_ent_alloc(root);
|
||||
|
||||
struct v2 pos = V2(1, -2);
|
||||
pos = v2_add(pos, offset);
|
||||
f32 r = 0;
|
||||
struct v2 size = V2(1, 1);
|
||||
struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size);
|
||||
@ -112,6 +111,7 @@ INTERNAL void spawn_test_entities(struct sim_ctx *ctx)
|
||||
struct sim_ent *e = sim_ent_alloc(root);
|
||||
|
||||
struct v2 pos = V2(1, -0.5);
|
||||
pos = v2_add(pos, offset);
|
||||
f32 r = 0;
|
||||
struct v2 size = V2(0.5, 0.25);
|
||||
struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size);
|
||||
@ -135,6 +135,7 @@ INTERNAL void spawn_test_entities(struct sim_ctx *ctx)
|
||||
struct sim_ent *e = sim_ent_alloc(root);
|
||||
|
||||
struct v2 pos = V2(1, -0.5);
|
||||
pos = v2_add(pos, offset);
|
||||
f32 r = PI / 4;
|
||||
struct v2 size = V2(0.5, 0.25);
|
||||
struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size);
|
||||
@ -408,10 +409,10 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
/* Release old snapshots */
|
||||
{
|
||||
/* TODO: Something better */
|
||||
i64 release_tick = (i64)ctx->world->tick - 5; /* Arbitrary tick offset */
|
||||
i64 release_tick = (i64)ctx->world->tick - 100; /* Arbitrary tick offset */
|
||||
if (release_tick > 0) {
|
||||
struct sim_snapshot *old = sim_snapshot_from_tick(ctx->snapshot_store, release_tick);
|
||||
if (old) {
|
||||
if (old->valid) {
|
||||
sim_snapshot_release(old);
|
||||
}
|
||||
}
|
||||
@ -452,7 +453,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
static b32 run = 0;
|
||||
if (!run) {
|
||||
run = 1;
|
||||
spawn_test_entities(ctx);
|
||||
spawn_test_entities(ctx, V2(0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -552,6 +553,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
* ========================== */
|
||||
|
||||
/* Process client cmds */
|
||||
ctx->oldest_client_ack_tick = ctx->world->tick;
|
||||
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &ctx->world->clients[i];
|
||||
if (client->valid) {
|
||||
@ -560,9 +562,13 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
struct sim_control *control = &client->control;
|
||||
|
||||
client->dbg_drag_start = false;
|
||||
|
||||
client->dbg_drag_stop = false;
|
||||
|
||||
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
||||
if (cmd->ack_tick > client->ack_tick) {
|
||||
client->ack_tick = cmd->ack_tick;
|
||||
}
|
||||
|
||||
enum sim_cmd_kind kind = cmd->kind;
|
||||
b32 start = cmd->state == SIM_CMD_STATE_START;
|
||||
b32 stop = cmd->state == SIM_CMD_STATE_STOP;
|
||||
@ -620,7 +626,10 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
case SIM_CMD_KIND_SPAWN_TEST:
|
||||
{
|
||||
logf_info("Spawning (test)");
|
||||
spawn_test_entities(ctx);
|
||||
u32 count = 1000;
|
||||
for (u32 j = 0; j < count; ++j) {
|
||||
spawn_test_entities(ctx, V2(0, (((f32)j / (f32)count) - 0.5) * 2000));
|
||||
}
|
||||
} break;
|
||||
|
||||
/* Disconnect client */
|
||||
@ -633,6 +642,10 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
default: break;
|
||||
};
|
||||
}
|
||||
|
||||
if (client->ack_tick < ctx->oldest_client_ack_tick || ctx->oldest_client_ack_tick == 0) {
|
||||
ctx->oldest_client_ack_tick = client->ack_tick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -667,9 +680,9 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||
if (sprite_tag_is_nil(ent->sprite)) continue;
|
||||
|
||||
/* Update animation */
|
||||
|
||||
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite);
|
||||
|
||||
/* Update animation */
|
||||
{
|
||||
struct sprite_sheet_span span = sprite_sheet_get_span(sheet, ent->sprite_span_name);
|
||||
|
||||
@ -1340,6 +1353,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
* Publish tick
|
||||
* ========================== */
|
||||
|
||||
#if 0
|
||||
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &ctx->world->clients[i];
|
||||
if (client->valid) {
|
||||
@ -1349,7 +1363,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
struct sim_event snapshot_event = ZI;
|
||||
snapshot_event.tick = ctx->world->tick;
|
||||
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT;
|
||||
snapshot_event.snapshot_data = sim_encode_snapshot(temp.arena, client, ctx->world);
|
||||
snapshot_event.encoded_snapshot = sim_snapshot_encode(temp.arena, client, ctx->world);
|
||||
|
||||
struct sim_event_list l = ZI;
|
||||
l.first = &snapshot_event;
|
||||
@ -1362,6 +1376,45 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
arena_temp_end(temp);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
|
||||
struct sim_client *client = &ctx->world->clients[i];
|
||||
if (client->valid) {
|
||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
u64 ss0_tick = client->ack_tick;
|
||||
u64 ss1_tick = ctx->world->tick;
|
||||
struct sim_snapshot *ss0 = sim_snapshot_from_tick(ctx->snapshot_store, ss0_tick);
|
||||
struct sim_snapshot *ss1 = ctx->world;
|
||||
ss0_tick = ss0->tick; /* In case ack tick is no longer in store we need to do a full resend */
|
||||
|
||||
struct sim_event snapshot_event = ZI;
|
||||
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT;
|
||||
snapshot_event.tick = ctx->world->tick;
|
||||
|
||||
snapshot_event.snapshot_tick_start = ss0_tick;
|
||||
snapshot_event.snapshot_tick_end = ss1_tick;
|
||||
|
||||
struct sim_encoder encoder = ZI;
|
||||
encoder.client = client;
|
||||
/* FIXME: Don't store external arena in bw. Could end up with hidden scratch conflicts. */
|
||||
encoder.bw = bw_from_arena(temp.arena);
|
||||
|
||||
sim_snapshot_encode(&encoder, ss0, ss1);
|
||||
snapshot_event.snapshot_encoded = bw_get_written(&encoder.bw);
|
||||
|
||||
struct sim_event_list l = ZI;
|
||||
l.first = &snapshot_event;
|
||||
l.last = &snapshot_event;
|
||||
struct string msg = sim_string_from_events(temp.arena, l);
|
||||
|
||||
host_queue_write(ctx->host, client->channel_id, msg, 0);
|
||||
//host_queue_write(ctx->host, HOST_CHANNEL_ID_ALL, msg, 0);
|
||||
|
||||
arena_temp_end(temp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
host_update(ctx->host);
|
||||
__profframe("Sim");
|
||||
@ -1374,3 +1427,214 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Sim cmd
|
||||
* ========================== */
|
||||
|
||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds, u64 ack_tick)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
|
||||
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||
u64 start = bw_pos(&bw);
|
||||
|
||||
bw_write_i8(&bw, cmd->kind);
|
||||
bw_write_i8(&bw, cmd->state);
|
||||
bw_write_var_uint(&bw, ack_tick);
|
||||
|
||||
#if COLLIDER_DEBUG
|
||||
bw_write_u32(&bw, cmd->collider_gjk_steps);
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
{
|
||||
bw_write_v2(&bw, cmd->move_dir);
|
||||
bw_write_v2(&bw, cmd->aim_dir);
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
bw_write_v2(&bw, cmd->cursor_pos);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
u64 size = bw_pos(&bw) - start;
|
||||
bw_write_u64(&bw_size, size);
|
||||
}
|
||||
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
|
||||
{
|
||||
__prof;
|
||||
for (u64 i = 0; i < host_events.count; ++i) {
|
||||
struct host_event host_event = host_events.events[i];
|
||||
enum host_event_kind host_event_kind = host_event.kind;
|
||||
switch (host_event_kind) {
|
||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||
{
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_CONNECT;
|
||||
cmd->channel_id = host_event.channel_id;
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||
{
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_DISCONNECT;
|
||||
cmd->disconnect_reason = LIT("Connection lost");
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_MSG:
|
||||
{
|
||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
||||
while (br_bytes_left(&br) > 0) {
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
u64 cmd_size = br_read_u64(&br);
|
||||
u64 cmd_pos_end = br_pos(&br) + cmd_size;
|
||||
cmd->kind = br_read_i8(&br);
|
||||
cmd->channel_id = host_event.channel_id;
|
||||
cmd->state = br_read_i8(&br);
|
||||
cmd->ack_tick = br_read_var_uint(&br);
|
||||
#if COLLIDER_DEBUG
|
||||
cmd->collider_gjk_steps = br_read_u32(&br);
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
{
|
||||
cmd->move_dir = br_read_v2(&br);
|
||||
cmd->aim_dir = br_read_v2(&br);
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
cmd->cursor_pos = br_read_v2(&br);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
ASSERT(br_pos(&br) == cmd_pos_end);
|
||||
br_seek_to(&br, cmd_pos_end);
|
||||
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Sim event
|
||||
* ========================== */
|
||||
|
||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
for (struct sim_event *event = events.first; event; event = event->next) {
|
||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||
u64 start = bw_pos(&bw);
|
||||
bw_write_var_uint(&bw, event->tick);
|
||||
bw_write_i8(&bw, event->kind);
|
||||
|
||||
switch (event->kind) {
|
||||
case SIM_EVENT_KIND_SNAPSHOT:
|
||||
{
|
||||
bw_write_var_uint(&bw, event->snapshot_tick_start);
|
||||
bw_write_var_uint(&bw, event->snapshot_tick_end);
|
||||
bw_write_string(&bw, event->snapshot_encoded);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
u64 size = bw_pos(&bw) - start;
|
||||
bw_write_u64(&bw_size, size);
|
||||
}
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out)
|
||||
{
|
||||
__prof;
|
||||
for (u64 i = 0; i < host_events.count; ++i) {
|
||||
struct sim_event *sim_event = arena_push_zero(arena, struct sim_event);
|
||||
struct host_event host_event = host_events.events[i];
|
||||
enum host_event_kind host_event_kind = host_event.kind;
|
||||
sim_event->channel_id = host_event.channel_id;
|
||||
switch (host_event_kind) {
|
||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||
{
|
||||
sim_event->kind = SIM_EVENT_KIND_CONNECT;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||
{
|
||||
sim_event->kind = SIM_EVENT_KIND_DISCONNECT;
|
||||
sim_event->disconnect_reason = LIT("Connection lost");
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_MSG:
|
||||
{
|
||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
||||
while (br_bytes_left(&br) > 0) {
|
||||
u64 event_size = br_read_u64(&br);
|
||||
u64 event_pos_end = br_pos(&br) + event_size;
|
||||
|
||||
sim_event->tick = br_read_var_uint(&br);
|
||||
sim_event->kind = br_read_i8(&br);
|
||||
switch (sim_event->kind) {
|
||||
case SIM_EVENT_KIND_SNAPSHOT:
|
||||
{
|
||||
sim_event->snapshot_tick_start = br_read_var_uint(&br);
|
||||
sim_event->snapshot_tick_end = br_read_var_uint(&br);
|
||||
sim_event->snapshot_encoded = br_read_string(arena, &br);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
ASSERT(br_pos(&br) == event_pos_end);
|
||||
br_seek_to(&br, event_pos_end);
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (events_out->last) {
|
||||
events_out->last->next = sim_event;
|
||||
} else {
|
||||
events_out->first = sim_event;
|
||||
}
|
||||
events_out->last = sim_event;
|
||||
}
|
||||
}
|
||||
|
||||
32
src/sim.h
32
src/sim.h
@ -43,6 +43,7 @@ struct sim_cmd {
|
||||
enum sim_cmd_kind kind;
|
||||
enum sim_cmd_state state;
|
||||
struct host_channel_id channel_id;
|
||||
u64 ack_tick;
|
||||
|
||||
/* SIM_CMD_KIND_PLAYER_CONTROL */
|
||||
struct v2 move_dir;
|
||||
@ -90,7 +91,9 @@ struct sim_event {
|
||||
struct string disconnect_reason;
|
||||
|
||||
/* SIM_EVENT_KIND_SNAPSHOT */
|
||||
struct string snapshot_data;
|
||||
u64 snapshot_tick_start;
|
||||
u64 snapshot_tick_end;
|
||||
struct string snapshot_encoded; /* Delta encoded snapshot containing changes between start & end ticks */
|
||||
|
||||
struct sim_event *next;
|
||||
};
|
||||
@ -130,6 +133,8 @@ struct sim_ctx {
|
||||
/* TODO: Store in snapshot for determinism */
|
||||
u64 last_phys_iteration;
|
||||
|
||||
/* This is the oldest tick stored in ctx that we need to hold a reference to for delta encoding */
|
||||
u64 oldest_client_ack_tick;
|
||||
|
||||
/* Bookkeeping structures */
|
||||
/* TODO: Store in snapshot for determinism */
|
||||
@ -155,5 +160,30 @@ void sim_ctx_release(struct sim_ctx *ctx);
|
||||
|
||||
void sim_update(struct sim_ctx *ctx, i64 target_dt_ns);
|
||||
|
||||
/* ========================== *
|
||||
* Event & cmd encode/decode
|
||||
* ========================== */
|
||||
|
||||
/* TODO: Move this */
|
||||
|
||||
#include "byteio.h"
|
||||
#include "host.h"
|
||||
|
||||
struct sim_encoder {
|
||||
struct byte_writer bw;
|
||||
struct sim_client *client;
|
||||
};
|
||||
|
||||
struct sim_decoder {
|
||||
struct byte_reader br;
|
||||
};
|
||||
|
||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds, u64 ack_tick);
|
||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
|
||||
|
||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events);
|
||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#include "sim_client.h"
|
||||
#include "sim.h"
|
||||
#include "sim_snapshot.h"
|
||||
#include "host.h"
|
||||
#include "arena.h"
|
||||
@ -118,3 +119,40 @@ void sim_client_lerp(struct sim_client *c, struct sim_client *c0, struct sim_cli
|
||||
c->control.focus = v2_lerp(c0->control.focus, c1->control.focus, blend);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Encode
|
||||
* ========================== */
|
||||
|
||||
void sim_client_encode(struct sim_encoder *enc, struct sim_client *c0, struct sim_client *c1)
|
||||
{
|
||||
struct byte_writer *bw = &enc->bw;
|
||||
struct sim_snapshot *ss = c1->ss;
|
||||
|
||||
c1->ss = c0->ss;
|
||||
if (MEMEQ_STRUCT(c0, c1)) {
|
||||
bw_write_u8(bw, 0);
|
||||
} else {
|
||||
bw_write_u8(bw, 1);
|
||||
struct string bytes = STRING_FROM_STRUCT(c1);
|
||||
bw_write_var_uint(bw, bytes.len);
|
||||
bw_write_bytes(bw, bytes);
|
||||
}
|
||||
c1->ss = ss;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Decode
|
||||
* ========================== */
|
||||
|
||||
void sim_client_decode(struct sim_decoder *dec, struct sim_client *c)
|
||||
{
|
||||
struct byte_reader *br = &dec->br;
|
||||
struct sim_snapshot *ss = c->ss;
|
||||
|
||||
if (br_read_u8(br)) {
|
||||
u64 size = br_read_var_uint(br);
|
||||
*c = *(struct sim_client *)br_seek(br, size);
|
||||
c->ss = ss;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,9 @@ struct sim_client {
|
||||
struct sim_client_handle next_in_bucket;
|
||||
struct sim_client_handle prev_in_bucket;
|
||||
|
||||
/* This is the last tick we know that this client has received */
|
||||
u64 ack_tick;
|
||||
|
||||
struct v2 cursor_pos;
|
||||
struct sim_ent_handle camera_ent;
|
||||
struct sim_ent_handle control_ent;
|
||||
@ -49,4 +52,7 @@ void sim_client_release(struct sim_client *client);
|
||||
|
||||
void sim_client_lerp(struct sim_client *c, struct sim_client *c0, struct sim_client *c1, f64 blend);
|
||||
|
||||
void sim_client_encode(struct sim_encoder *enc, struct sim_client *c0, struct sim_client *c1);
|
||||
void sim_client_decode(struct sim_decoder *dec, struct sim_client *c);
|
||||
|
||||
#endif
|
||||
|
||||
636
src/sim_encode.c
636
src/sim_encode.c
@ -1,636 +0,0 @@
|
||||
#include "sim_encode.h"
|
||||
#include "sim_snapshot.h"
|
||||
#include "arena.h"
|
||||
#include "byteio.h"
|
||||
|
||||
/* ========================== *
|
||||
* Sim cmd
|
||||
* ========================== */
|
||||
|
||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
|
||||
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||
u64 start = bw_pos(&bw);
|
||||
|
||||
bw_write_i8(&bw, cmd->kind);
|
||||
bw_write_i8(&bw, cmd->state);
|
||||
|
||||
#if COLLIDER_DEBUG
|
||||
bw_write_u32(&bw, cmd->collider_gjk_steps);
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
{
|
||||
bw_write_v2(&bw, cmd->move_dir);
|
||||
bw_write_v2(&bw, cmd->aim_dir);
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
bw_write_v2(&bw, cmd->cursor_pos);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
u64 size = bw_pos(&bw) - start;
|
||||
bw_write_u64(&bw_size, size);
|
||||
}
|
||||
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
|
||||
{
|
||||
__prof;
|
||||
for (u64 i = 0; i < host_events.count; ++i) {
|
||||
struct host_event host_event = host_events.events[i];
|
||||
enum host_event_kind host_event_kind = host_event.kind;
|
||||
switch (host_event_kind) {
|
||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||
{
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_CONNECT;
|
||||
cmd->channel_id = host_event.channel_id;
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||
{
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_DISCONNECT;
|
||||
cmd->disconnect_reason = LIT("Connection lost");
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_MSG:
|
||||
{
|
||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
||||
while (br_bytes_left(&br) > 0) {
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
u64 cmd_size = br_read_u64(&br);
|
||||
u64 cmd_pos_end = br_pos(&br) + cmd_size;
|
||||
cmd->kind = br_read_i8(&br);
|
||||
cmd->channel_id = host_event.channel_id;
|
||||
cmd->state = br_read_i8(&br);
|
||||
#if COLLIDER_DEBUG
|
||||
cmd->collider_gjk_steps = br_read_u32(&br);
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
{
|
||||
cmd->move_dir = br_read_v2(&br);
|
||||
cmd->aim_dir = br_read_v2(&br);
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
cmd->cursor_pos = br_read_v2(&br);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
ASSERT(br_pos(&br) == cmd_pos_end);
|
||||
br_seek_to(&br, cmd_pos_end);
|
||||
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Sim event
|
||||
* ========================== */
|
||||
|
||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
for (struct sim_event *event = events.first; event; event = event->next) {
|
||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||
u64 start = bw_pos(&bw);
|
||||
bw_write_var_uint(&bw, event->tick);
|
||||
bw_write_i8(&bw, event->kind);
|
||||
|
||||
switch (event->kind) {
|
||||
case SIM_EVENT_KIND_SNAPSHOT:
|
||||
{
|
||||
bw_write_string(&bw, event->snapshot_data);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
u64 size = bw_pos(&bw) - start;
|
||||
bw_write_u64(&bw_size, size);
|
||||
}
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out)
|
||||
{
|
||||
__prof;
|
||||
for (u64 i = 0; i < host_events.count; ++i) {
|
||||
struct sim_event *sim_event = arena_push_zero(arena, struct sim_event);
|
||||
struct host_event host_event = host_events.events[i];
|
||||
enum host_event_kind host_event_kind = host_event.kind;
|
||||
sim_event->channel_id = host_event.channel_id;
|
||||
switch (host_event_kind) {
|
||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||
{
|
||||
sim_event->kind = SIM_EVENT_KIND_CONNECT;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||
{
|
||||
sim_event->kind = SIM_EVENT_KIND_DISCONNECT;
|
||||
sim_event->disconnect_reason = LIT("Connection lost");
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_MSG:
|
||||
{
|
||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
||||
while (br_bytes_left(&br) > 0) {
|
||||
u64 event_size = br_read_u64(&br);
|
||||
u64 event_pos_end = br_pos(&br) + event_size;
|
||||
|
||||
sim_event->tick = br_read_var_uint(&br);
|
||||
sim_event->kind = br_read_i8(&br);
|
||||
switch (sim_event->kind) {
|
||||
case SIM_EVENT_KIND_SNAPSHOT:
|
||||
{
|
||||
sim_event->snapshot_data = br_read_string(arena, &br);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
ASSERT(br_pos(&br) == event_pos_end);
|
||||
br_seek_to(&br, event_pos_end);
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (events_out->last) {
|
||||
events_out->last->next = sim_event;
|
||||
} else {
|
||||
events_out->first = sim_event;
|
||||
}
|
||||
events_out->last = sim_event;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Snapshot
|
||||
* ========================== */
|
||||
|
||||
struct string sim_encode_snapshot(struct arena *arena, struct sim_client *client, struct sim_snapshot *snapshot)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
|
||||
bw_write_var_uint(&bw, snapshot->continuity_gen);
|
||||
|
||||
bw_write_var_sint(&bw, snapshot->real_dt_ns);
|
||||
bw_write_var_sint(&bw, snapshot->real_time_ns);
|
||||
|
||||
bw_write_f64(&bw, snapshot->world_timescale);
|
||||
bw_write_var_sint(&bw, snapshot->world_dt_ns);
|
||||
bw_write_var_sint(&bw, snapshot->world_time_ns);
|
||||
|
||||
bw_write_var_uint(&bw, client->handle.gen);
|
||||
bw_write_var_uint(&bw, client->handle.idx);
|
||||
|
||||
/* Client s*/
|
||||
u64 num_clients = snapshot->num_clients_reserved;
|
||||
bw_write_var_uint(&bw, num_clients);
|
||||
|
||||
struct string clients_src = ZI;
|
||||
clients_src.text = (u8 *)snapshot->clients;
|
||||
clients_src.len = sizeof(struct sim_client) * num_clients;
|
||||
br_write_bytes(&bw, clients_src);
|
||||
|
||||
/* Entity store */
|
||||
u64 num_entities = snapshot->num_ents_reserved;
|
||||
bw_write_var_uint(&bw, num_entities);
|
||||
|
||||
struct string entities_src = ZI;
|
||||
entities_src.text = (u8 *)snapshot->ents;
|
||||
entities_src.len = sizeof(struct sim_ent) * num_entities;
|
||||
br_write_bytes(&bw, entities_src);
|
||||
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void sim_decode_snapshot(struct string str, struct sim_snapshot *snapshot)
|
||||
{
|
||||
__prof;
|
||||
struct byte_reader br = br_from_buffer(str);
|
||||
|
||||
snapshot->continuity_gen = br_read_var_uint(&br);
|
||||
|
||||
snapshot->real_dt_ns = br_read_var_sint(&br);
|
||||
snapshot->real_time_ns = br_read_var_sint(&br);
|
||||
|
||||
snapshot->world_timescale = br_read_f64(&br);
|
||||
snapshot->world_dt_ns = br_read_var_sint(&br);
|
||||
snapshot->world_time_ns = br_read_var_sint(&br);
|
||||
|
||||
snapshot->local_client.gen = br_read_var_uint(&br);
|
||||
snapshot->local_client.idx = br_read_var_uint(&br);
|
||||
|
||||
/* Client store */
|
||||
u64 num_clients = br_read_var_uint(&br);
|
||||
arena_push_array(&snapshot->clients_arena, struct sim_client, num_clients - snapshot->num_clients_reserved);
|
||||
snapshot->num_clients_reserved = num_clients;
|
||||
|
||||
snapshot->num_clients_allocated = 0;
|
||||
struct sim_client *clients_src = br_seek(&br, num_clients * sizeof(struct sim_client));
|
||||
if (clients_src) {
|
||||
for (u64 i = 0; i < num_clients; ++i) {
|
||||
struct sim_client *src = &clients_src[i];
|
||||
struct sim_client *dst = &snapshot->clients[i];
|
||||
if (dst->valid) {
|
||||
++snapshot->num_clients_allocated;
|
||||
}
|
||||
*dst = *src;
|
||||
}
|
||||
}
|
||||
|
||||
/* Entity store */
|
||||
u64 num_entities = br_read_var_uint(&br);
|
||||
arena_push_array(&snapshot->ents_arena, struct sim_ent, num_entities - snapshot->num_ents_reserved);
|
||||
snapshot->num_ents_reserved = num_entities;
|
||||
|
||||
snapshot->num_ents_allocated = 0;
|
||||
struct sim_ent *entities_src = br_seek(&br, num_entities * sizeof(struct sim_ent));
|
||||
if (entities_src) {
|
||||
for (u64 i = 0; i < num_entities; ++i) {
|
||||
struct sim_ent *src = &entities_src[i];
|
||||
struct sim_ent *dst = &snapshot->ents[i];
|
||||
if (dst->valid) {
|
||||
++snapshot->num_ents_allocated;
|
||||
}
|
||||
*dst = *src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
#include "sim_encode.h"
|
||||
#include "sim_snapshot.h"
|
||||
#include "arena.h"
|
||||
#include "byteio.h"
|
||||
|
||||
/* ========================== *
|
||||
* Sim cmd
|
||||
* ========================== */
|
||||
|
||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
|
||||
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
|
||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||
u64 start = bw_pos(&bw);
|
||||
|
||||
bw_write_i8(&bw, cmd->kind);
|
||||
bw_write_i8(&bw, cmd->state);
|
||||
|
||||
#if COLLIDER_DEBUG
|
||||
bw_write_u32(&bw, cmd->collider_gjk_steps);
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
{
|
||||
bw_write_v2(&bw, cmd->move_dir);
|
||||
bw_write_v2(&bw, cmd->aim_dir);
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
bw_write_v2(&bw, cmd->cursor_pos);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
u64 size = bw_pos(&bw) - start;
|
||||
bw_write_u64(&bw_size, size);
|
||||
}
|
||||
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
|
||||
{
|
||||
__prof;
|
||||
for (u64 i = 0; i < host_events.count; ++i) {
|
||||
struct host_event host_event = host_events.events[i];
|
||||
enum host_event_kind host_event_kind = host_event.kind;
|
||||
switch (host_event_kind) {
|
||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||
{
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_CONNECT;
|
||||
cmd->channel_id = host_event.channel_id;
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||
{
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_DISCONNECT;
|
||||
cmd->disconnect_reason = LIT("Connection lost");
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_MSG:
|
||||
{
|
||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
||||
while (br_bytes_left(&br) > 0) {
|
||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||
u64 cmd_size = br_read_u64(&br);
|
||||
u64 cmd_pos_end = br_pos(&br) + cmd_size;
|
||||
cmd->kind = br_read_i8(&br);
|
||||
cmd->channel_id = host_event.channel_id;
|
||||
cmd->state = br_read_i8(&br);
|
||||
#if COLLIDER_DEBUG
|
||||
cmd->collider_gjk_steps = br_read_u32(&br);
|
||||
#endif
|
||||
|
||||
switch (cmd->kind) {
|
||||
case SIM_CMD_KIND_PLAYER_CONTROL:
|
||||
{
|
||||
cmd->move_dir = br_read_v2(&br);
|
||||
cmd->aim_dir = br_read_v2(&br);
|
||||
} break;
|
||||
|
||||
case SIM_CMD_KIND_CURSOR_MOVE:
|
||||
{
|
||||
cmd->cursor_pos = br_read_v2(&br);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
ASSERT(br_pos(&br) == cmd_pos_end);
|
||||
br_seek_to(&br, cmd_pos_end);
|
||||
|
||||
if (cmds_out->last) {
|
||||
cmds_out->last->next = cmd;
|
||||
} else {
|
||||
cmds_out->first = cmd;
|
||||
}
|
||||
cmds_out->last = cmd;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Sim event
|
||||
* ========================== */
|
||||
|
||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
for (struct sim_event *event = events.first; event; event = event->next) {
|
||||
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
|
||||
u64 start = bw_pos(&bw);
|
||||
bw_write_var_uint(&bw, event->tick);
|
||||
bw_write_i8(&bw, event->kind);
|
||||
|
||||
switch (event->kind) {
|
||||
case SIM_EVENT_KIND_SNAPSHOT:
|
||||
{
|
||||
bw_write_string(&bw, event->snapshot_data);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
u64 size = bw_pos(&bw) - start;
|
||||
bw_write_u64(&bw_size, size);
|
||||
}
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out)
|
||||
{
|
||||
__prof;
|
||||
for (u64 i = 0; i < host_events.count; ++i) {
|
||||
struct sim_event *sim_event = arena_push_zero(arena, struct sim_event);
|
||||
struct host_event host_event = host_events.events[i];
|
||||
enum host_event_kind host_event_kind = host_event.kind;
|
||||
sim_event->channel_id = host_event.channel_id;
|
||||
switch (host_event_kind) {
|
||||
case HOST_EVENT_KIND_CHANNEL_OPENED:
|
||||
{
|
||||
sim_event->kind = SIM_EVENT_KIND_CONNECT;
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_CHANNEL_CLOSED:
|
||||
{
|
||||
sim_event->kind = SIM_EVENT_KIND_DISCONNECT;
|
||||
sim_event->disconnect_reason = LIT("Connection lost");
|
||||
} break;
|
||||
|
||||
case HOST_EVENT_KIND_MSG:
|
||||
{
|
||||
struct byte_reader br = br_from_buffer(host_event.msg);
|
||||
while (br_bytes_left(&br) > 0) {
|
||||
u64 event_size = br_read_u64(&br);
|
||||
u64 event_pos_end = br_pos(&br) + event_size;
|
||||
|
||||
sim_event->tick = br_read_var_uint(&br);
|
||||
sim_event->kind = br_read_i8(&br);
|
||||
switch (sim_event->kind) {
|
||||
case SIM_EVENT_KIND_SNAPSHOT:
|
||||
{
|
||||
sim_event->snapshot_data = br_read_string(arena, &br);
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
ASSERT(br_pos(&br) == event_pos_end);
|
||||
br_seek_to(&br, event_pos_end);
|
||||
}
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (events_out->last) {
|
||||
events_out->last->next = sim_event;
|
||||
} else {
|
||||
events_out->first = sim_event;
|
||||
}
|
||||
events_out->last = sim_event;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Ent
|
||||
* ========================== */
|
||||
|
||||
void sim_encode_ent(struct sim_encoder *enc, struct sim_ent *ent)
|
||||
{
|
||||
(UNUSED)arena;
|
||||
(UNUSED)client;
|
||||
(UNUSED)ent;
|
||||
|
||||
struct byte_writer bw = bw_from_arena(arena);
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
struct sim_ent *sim_decode_ent(struct sim_decoder *dec, struct sim_ent_store *store)
|
||||
{
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Snapshot
|
||||
* ========================== */
|
||||
|
||||
struct string sim_encode_snapshot(struct sim_encoder *enc, struct sim_snapshot *snapshot)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer *bw = &enc->bw;
|
||||
|
||||
bw_write_var_uint(&bw, snapshot->continuity_gen);
|
||||
|
||||
bw_write_var_sint(&bw, snapshot->real_dt_ns);
|
||||
bw_write_var_sint(&bw, snapshot->real_time_ns);
|
||||
|
||||
bw_write_f64(&bw, snapshot->world_timescale);
|
||||
bw_write_var_sint(&bw, snapshot->world_dt_ns);
|
||||
bw_write_var_sint(&bw, snapshot->world_time_ns);
|
||||
|
||||
bw_write_var_uint(&bw, client->handle.gen);
|
||||
bw_write_var_uint(&bw, client->handle.idx);
|
||||
|
||||
/* Client store */
|
||||
u64 num_clients = snapshot->client_store->num_reserved;
|
||||
bw_write_var_uint(&bw, num_clients);
|
||||
|
||||
struct string clients_src = ZI;
|
||||
clients_src.text = (u8 *)snapshot->client_store->clients;
|
||||
clients_src.len = sizeof(struct sim_client) * num_clients;
|
||||
br_write_bytes(&bw, clients_src);
|
||||
|
||||
/* Ents */
|
||||
for (u64 i = 0; i < snapshot->num_ents_reserved; ++i) {
|
||||
bw_write_u8(bw, 1);
|
||||
struct sim_ent *ent = &snapshot->ents[i];
|
||||
sim_encode_ent(enc, ent);
|
||||
}
|
||||
bw_write_u8(bw, 0);
|
||||
|
||||
return bw_get_written(&bw);
|
||||
}
|
||||
|
||||
struct sim_snapshot *sim_decode_snapshot(struct sim_decoder *dec, struct sim_snapshot_store *store)
|
||||
{
|
||||
__prof;
|
||||
struct byte_reader *br = &dec->bw;
|
||||
|
||||
snapshot->continuity_gen = br_read_var_uint(&br);
|
||||
|
||||
snapshot->real_dt_ns = br_read_var_sint(&br);
|
||||
snapshot->real_time_ns = br_read_var_sint(&br);
|
||||
|
||||
snapshot->world_timescale = br_read_f64(&br);
|
||||
snapshot->world_dt_ns = br_read_var_sint(&br);
|
||||
snapshot->world_time_ns = br_read_var_sint(&br);
|
||||
|
||||
snapshot->local_client.gen = br_read_var_uint(&br);
|
||||
snapshot->local_client.idx = br_read_var_uint(&br);
|
||||
|
||||
/* Client store */
|
||||
u64 num_clients = br_read_var_uint(&br);
|
||||
arena_push_array(&snapshot->client_store->arena, struct sim_client, num_clients - snapshot->client_store->num_reserved);
|
||||
snapshot->client_store->num_reserved = num_clients;
|
||||
|
||||
snapshot->client_store->num_allocated = 0;
|
||||
struct sim_client *clients_src = br_seek(&br, num_clients * sizeof(struct sim_client));
|
||||
if (clients_src) {
|
||||
for (u64 i = 0; i < num_clients; ++i) {
|
||||
struct sim_client *src = &clients_src[i];
|
||||
struct sim_client *dst = &snapshot->client_store->clients[i];
|
||||
if (dst->valid) {
|
||||
++snapshot->client_store->num_allocated;
|
||||
}
|
||||
*dst = *src;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ents */
|
||||
b32 read_entity = br_read_u8(br);
|
||||
while (read_entity) {
|
||||
sim_decode_ent(dec, snapshot);
|
||||
read_entity = br_read_u8(br);
|
||||
}f
|
||||
}
|
||||
#endif
|
||||
@ -1,64 +0,0 @@
|
||||
#ifndef SIM_ENCODE_H
|
||||
#define SIM_ENCODE_H
|
||||
|
||||
#include "host.h"
|
||||
#include "sim.h"
|
||||
|
||||
struct sim_snapshot;
|
||||
struct sim_client;
|
||||
|
||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds);
|
||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
|
||||
|
||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events);
|
||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
|
||||
|
||||
/* ========================== *
|
||||
* Snapshot
|
||||
* ========================== */
|
||||
|
||||
struct string sim_encode_snapshot(struct arena *arena, struct sim_client *client, struct sim_snapshot *snapshot);
|
||||
void sim_decode_snapshot(struct string str, struct sim_snapshot *snapshot);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
#ifndef SIM_ENCODE_H
|
||||
#define SIM_ENCODE_H
|
||||
|
||||
#include "sim.h"
|
||||
#include "host.h"
|
||||
|
||||
struct sim_encoder {
|
||||
struct byte_writer bw;
|
||||
struct sim_client *client;
|
||||
};
|
||||
|
||||
struct sim_decoder {
|
||||
struct byte_reader bw;
|
||||
};
|
||||
|
||||
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds);
|
||||
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
|
||||
|
||||
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events);
|
||||
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
|
||||
|
||||
struct string sim_encode_snapshot(struct arena *arena, struct sim_client *client, struct sim_snapshot *snapshot);
|
||||
void sim_decode_snapshot(struct string str, struct sim_snapshot *snapshot);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@ -1,4 +1,5 @@
|
||||
#include "sim_ent.h"
|
||||
#include "sim.h"
|
||||
#include "sim_snapshot.h"
|
||||
#include "math.h"
|
||||
|
||||
@ -473,3 +474,41 @@ void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64
|
||||
e->tracer_gradient_end = v2_lerp(e0->tracer_gradient_end, e1->tracer_gradient_end, blend);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Encode
|
||||
* ========================== */
|
||||
|
||||
void sim_ent_encode(struct sim_encoder *enc, struct sim_ent *e0, struct sim_ent *e1)
|
||||
{
|
||||
struct byte_writer *bw = &enc->bw;
|
||||
struct sim_snapshot *ss = e1->ss;
|
||||
|
||||
e1->ss = e0->ss;
|
||||
if (MEMEQ_STRUCT(e0, e1)) {
|
||||
bw_write_u8(bw, 0);
|
||||
} else {
|
||||
bw_write_u8(bw, 1);
|
||||
struct string bytes = STRING_FROM_STRUCT(e1);
|
||||
bw_write_var_uint(bw, bytes.len);
|
||||
bw_write_bytes(bw, bytes);
|
||||
}
|
||||
e1->ss = ss;
|
||||
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Decode
|
||||
* ========================== */
|
||||
|
||||
void sim_ent_decode(struct sim_decoder *dec, struct sim_ent *e)
|
||||
{
|
||||
struct byte_reader *br = &dec->br;
|
||||
struct sim_snapshot *ss = e->ss;
|
||||
|
||||
if (br_read_u8(br)) {
|
||||
u64 size = br_read_var_uint(br);
|
||||
*e = *(struct sim_ent *)br_seek(br, size);
|
||||
e->ss = ss;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,9 @@
|
||||
#define SIM_ENT_NIL_HANDLE ((struct sim_ent_handle){ .gen = 0, .idx = 0 })
|
||||
#define SIM_ENT_ROOT_HANDLE ((struct sim_ent_handle){ .gen = 1, .idx = 0 })
|
||||
|
||||
struct sim_encoder;
|
||||
struct sim_decoder;
|
||||
|
||||
enum sim_ent_prop {
|
||||
SIM_ENT_PROP_NONE,
|
||||
|
||||
@ -402,4 +405,8 @@ void sim_ent_activate(struct sim_ent *ent, u64 current_tick);
|
||||
/* Lerp */
|
||||
void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64 blend);
|
||||
|
||||
/* Encode / decode */
|
||||
void sim_ent_encode(struct sim_encoder *enc, struct sim_ent *e0, struct sim_ent *e1);
|
||||
void sim_ent_decode(struct sim_decoder *dec, struct sim_ent *e);
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
#include "sim_snapshot.h"
|
||||
#include "sim.h"
|
||||
#include "sim_ent.h"
|
||||
#include "sim_client.h"
|
||||
#include "arena.h"
|
||||
#include "scratch.h"
|
||||
|
||||
#define TICK_LOOKUP_BUCKETS 31
|
||||
#define TICK_LOOKUP_BUCKETS 127
|
||||
#define CLIENT_LOOKUP_BUCKETS 127
|
||||
|
||||
struct sim_snapshot_lookup_bucket {
|
||||
@ -94,15 +95,19 @@ struct sim_snapshot_store *sim_snapshot_store_alloc(void)
|
||||
void sim_snapshot_store_release(struct sim_snapshot_store *store)
|
||||
{
|
||||
/* Release snapshot internal memory */
|
||||
struct sim_snapshot *ss = sim_snapshot_from_tick(store, store->first_tick);
|
||||
while (ss->valid) {
|
||||
struct sim_snapshot *next = sim_snapshot_from_tick(store, ss->next_tick);
|
||||
for (u64 i = 0; i < store->num_lookup_buckets; ++i) {
|
||||
struct sim_snapshot_lookup_bucket *bucket = &store->lookup_buckets[i];
|
||||
struct sim_snapshot *ss = bucket->first;
|
||||
while (ss) {
|
||||
struct sim_snapshot *next = ss->next_in_bucket;
|
||||
arena_release(&ss->clients_arena);
|
||||
arena_release(&ss->ents_arena);
|
||||
arena_release(&ss->arena);
|
||||
ss = next;
|
||||
}
|
||||
ss = store->first_free_snapshot;
|
||||
}
|
||||
{
|
||||
struct sim_snapshot *ss = store->first_free_snapshot;
|
||||
while (ss) {
|
||||
struct sim_snapshot *next = ss->next_free;
|
||||
arena_release(&ss->clients_arena);
|
||||
@ -110,6 +115,7 @@ void sim_snapshot_store_release(struct sim_snapshot_store *store)
|
||||
arena_release(&ss->arena);
|
||||
ss = next;
|
||||
}
|
||||
}
|
||||
/* Release store */
|
||||
arena_release(&store->arena);
|
||||
}
|
||||
@ -140,9 +146,9 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct
|
||||
arena = ss->arena;
|
||||
} else {
|
||||
/* Arenas allocated here will be released along with the entire snasphot store */
|
||||
arena = arena_alloc(GIGABYTE(64));
|
||||
clients_arena = arena_alloc(GIGABYTE(64));
|
||||
ents_arena = arena_alloc(GIGABYTE(64));
|
||||
arena = arena_alloc(GIGABYTE(8));
|
||||
clients_arena = arena_alloc(GIGABYTE(8));
|
||||
ents_arena = arena_alloc(GIGABYTE(8));
|
||||
}
|
||||
}
|
||||
arena_reset(&arena);
|
||||
@ -401,3 +407,136 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *sto
|
||||
|
||||
return ss;
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Encode
|
||||
* ========================== */
|
||||
|
||||
void sim_snapshot_encode(struct sim_encoder *enc, struct sim_snapshot *ss0, struct sim_snapshot *ss1)
|
||||
{
|
||||
__prof;
|
||||
struct byte_writer *bw = &enc->bw;
|
||||
struct sim_client *client = enc->client;
|
||||
|
||||
bw_write_var_uint(bw, ss1->continuity_gen);
|
||||
|
||||
bw_write_var_sint(bw, ss1->real_dt_ns);
|
||||
bw_write_var_sint(bw, ss1->real_time_ns);
|
||||
|
||||
bw_write_f64(bw, ss1->world_timescale);
|
||||
bw_write_var_sint(bw, ss1->world_dt_ns);
|
||||
bw_write_var_sint(bw, ss1->world_time_ns);
|
||||
|
||||
bw_write_var_uint(bw, client->handle.gen);
|
||||
bw_write_var_uint(bw, client->handle.idx);
|
||||
|
||||
/* Clients */
|
||||
if (ss1->num_clients_allocated == ss0->num_clients_allocated) {
|
||||
bw_write_u8(bw, 0);
|
||||
} else {
|
||||
bw_write_u8(bw, 1);
|
||||
bw_write_var_uint(bw, ss1->num_clients_allocated);
|
||||
}
|
||||
if (ss1->num_clients_reserved == ss0->num_clients_reserved) {
|
||||
bw_write_u8(bw, 0);
|
||||
} else {
|
||||
bw_write_u8(bw, 1);
|
||||
bw_write_var_uint(bw, ss1->num_clients_reserved);
|
||||
}
|
||||
for (u64 i = 0; i < ss1->num_clients_reserved; ++i) {
|
||||
struct sim_client *c0 = sim_client_nil();
|
||||
if (i < ss0->num_clients_reserved) {
|
||||
c0 = &ss0->clients[i];
|
||||
}
|
||||
struct sim_client *c1 = &ss1->clients[i];
|
||||
sim_client_encode(enc, c0, c1);
|
||||
}
|
||||
|
||||
/* Ents */
|
||||
if (ss1->num_ents_allocated == ss0->num_ents_allocated) {
|
||||
bw_write_u8(bw, 0);
|
||||
} else {
|
||||
bw_write_u8(bw, 1);
|
||||
bw_write_var_uint(bw, ss1->num_ents_allocated);
|
||||
}
|
||||
if (ss1->num_ents_reserved == ss0->num_ents_reserved) {
|
||||
bw_write_u8(bw, 0);
|
||||
} else {
|
||||
bw_write_u8(bw, 1);
|
||||
bw_write_var_uint(bw, ss1->num_ents_reserved);
|
||||
}
|
||||
for (u64 i = 0; i < ss1->num_ents_reserved; ++i) {
|
||||
struct sim_ent *e0 = sim_ent_nil();
|
||||
if (i < ss0->num_ents_reserved) {
|
||||
e0 = &ss0->ents[i];
|
||||
}
|
||||
struct sim_ent *e1 = &ss1->ents[i];
|
||||
sim_ent_encode(enc, e0, e1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================== *
|
||||
* Decode
|
||||
* ========================== */
|
||||
|
||||
void sim_snapshot_decode(struct sim_decoder *dec, struct sim_snapshot *ss)
|
||||
{
|
||||
__prof;
|
||||
struct byte_reader *br = &dec->br;
|
||||
|
||||
ss->continuity_gen = br_read_var_uint(br);
|
||||
|
||||
ss->real_dt_ns = br_read_var_sint(br);
|
||||
ss->real_time_ns = br_read_var_sint(br);
|
||||
|
||||
ss->world_timescale = br_read_f64(br);
|
||||
ss->world_dt_ns = br_read_var_sint(br);
|
||||
ss->world_time_ns = br_read_var_sint(br);
|
||||
|
||||
ss->local_client.gen = br_read_var_uint(br);
|
||||
ss->local_client.idx = br_read_var_uint(br);
|
||||
|
||||
/* Clients */
|
||||
if (br_read_u8(br)) {
|
||||
ss->num_clients_allocated = br_read_var_uint(br);
|
||||
}
|
||||
if (br_read_u8(br)) {
|
||||
u64 old_num_clients_reserved = ss->num_clients_reserved;
|
||||
ss->num_clients_reserved = br_read_var_uint(br);
|
||||
i64 reserve_diff = (i64)ss->num_clients_reserved - (i64)old_num_clients_reserved;
|
||||
if (reserve_diff > 0) {
|
||||
arena_push_array(&ss->clients_arena, struct sim_client, reserve_diff);
|
||||
for (u64 i = old_num_clients_reserved; i < ss->num_clients_reserved; ++i) {
|
||||
struct sim_client *c = &ss->clients[i];
|
||||
*c = *sim_client_nil();
|
||||
c->ss = ss;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (u64 i = 0; i < ss->num_clients_reserved; ++i) {
|
||||
struct sim_client *c = &ss->clients[i];
|
||||
sim_client_decode(dec, c);
|
||||
}
|
||||
|
||||
/* Ents */
|
||||
if (br_read_u8(br)) {
|
||||
ss->num_ents_allocated = br_read_var_uint(br);
|
||||
}
|
||||
if (br_read_u8(br)) {
|
||||
u64 old_num_ents_reserved = ss->num_ents_reserved;
|
||||
ss->num_ents_reserved = br_read_var_uint(br);
|
||||
i64 reserve_diff = (i64)ss->num_ents_reserved - (i64)old_num_ents_reserved;
|
||||
if (reserve_diff > 0) {
|
||||
arena_push_array(&ss->ents_arena, struct sim_ent, reserve_diff);
|
||||
for (u64 i = old_num_ents_reserved; i < ss->num_ents_reserved; ++i) {
|
||||
struct sim_ent *e = &ss->ents[i];
|
||||
*e = *sim_ent_nil();
|
||||
e->ss = ss;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (u64 i = 0; i < ss->num_ents_reserved; ++i) {
|
||||
struct sim_ent *e = &ss->ents[i];
|
||||
sim_ent_decode(dec, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,9 @@
|
||||
#include "sim_ent.h"
|
||||
#include "sim_client.h"
|
||||
|
||||
struct sim_encoder;
|
||||
struct sim_decoder;
|
||||
|
||||
struct sim_snapshot_store {
|
||||
b32 valid;
|
||||
struct arena arena;
|
||||
@ -21,8 +24,6 @@ struct sim_snapshot_store {
|
||||
};
|
||||
|
||||
struct sim_snapshot {
|
||||
/* Managed by store */
|
||||
struct arena arena;
|
||||
b32 valid;
|
||||
u64 tick;
|
||||
struct sim_snapshot_store *store;
|
||||
@ -32,6 +33,8 @@ struct sim_snapshot {
|
||||
u64 prev_tick;
|
||||
u64 next_tick;
|
||||
|
||||
struct arena arena;
|
||||
|
||||
/* Real time (increases with clock assuming no lag) */
|
||||
i64 real_dt_ns;
|
||||
i64 real_time_ns;
|
||||
@ -103,11 +106,19 @@ INLINE struct sim_snapshot_store *sim_snapshot_store_nil(void)
|
||||
* Snapshot
|
||||
* ========================== */
|
||||
|
||||
/* Alloc */
|
||||
struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct sim_snapshot *src, u64 tick);
|
||||
void sim_snapshot_release(struct sim_snapshot *sim_snapshot);
|
||||
|
||||
/* Lookup */
|
||||
struct sim_snapshot *sim_snapshot_from_tick(struct sim_snapshot_store *store, u64 tick);
|
||||
|
||||
/* Lerp */
|
||||
struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *store, struct sim_snapshot *ss0, struct sim_snapshot *ss1, f64 blend);
|
||||
|
||||
/* Encode / decode */
|
||||
void sim_snapshot_encode(struct sim_encoder *enc, struct sim_snapshot *ss0, struct sim_snapshot *ss1);
|
||||
void sim_snapshot_decode(struct sim_decoder *dec, struct sim_snapshot *ss);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
114
src/user.c
114
src/user.c
@ -2,7 +2,6 @@
|
||||
#include "app.h"
|
||||
#include "sim.h"
|
||||
#include "sim_ent.h"
|
||||
#include "sim_encode.h"
|
||||
#include "sim_snapshot.h"
|
||||
#include "renderer.h"
|
||||
#include "font.h"
|
||||
@ -22,6 +21,7 @@
|
||||
#include "log.h"
|
||||
#include "sock.h"
|
||||
#include "host.h"
|
||||
#include "byteio.h"
|
||||
|
||||
struct bind_state {
|
||||
b32 is_held; /* Is this bind held down this frame */
|
||||
@ -422,7 +422,7 @@ INTERNAL void user_update(void)
|
||||
}
|
||||
|
||||
for (struct sim_event *event = sim_events.first; event; event = event->next) {
|
||||
u64 tick = event->tick;
|
||||
u64 event_tick = event->tick;
|
||||
enum sim_event_kind kind = event->kind;
|
||||
|
||||
switch (kind) {
|
||||
@ -438,21 +438,42 @@ INTERNAL void user_update(void)
|
||||
|
||||
case SIM_EVENT_KIND_SNAPSHOT:
|
||||
{
|
||||
#if 1
|
||||
struct sim_snapshot *existing = sim_snapshot_from_tick(G.sim_snapshot_store, tick);
|
||||
if (!existing->valid && tick > G.world->tick) {
|
||||
u64 delta_src_tick = 0;
|
||||
struct sim_snapshot *delta_src = sim_snapshot_from_tick(G.sim_snapshot_store, delta_src_tick);
|
||||
ASSERT(delta_src->tick == delta_src_tick); /* User should always have src tick present */
|
||||
|
||||
struct string encoded = event->snapshot_data;
|
||||
struct sim_snapshot *ss = sim_snapshot_alloc(G.sim_snapshot_store, delta_src, tick);
|
||||
sim_decode_snapshot(encoded, ss);
|
||||
ss->received_at_ns = G.real_time_ns;
|
||||
#if 0
|
||||
if (event_tick > G.world->tick) {
|
||||
u64 ss0_tick = event->snapshot_tick_start;
|
||||
u64 ss1_tick = event->snapshot_tick_end;
|
||||
struct sim_snapshot *ss0 = sim_snapshot_from_tick(G.sim_snapshot_store, ss0_tick);
|
||||
struct sim_snapshot *ss1 = sim_snapshot_from_tick(G.sim_snapshot_store, ss1_tick);
|
||||
if (ss0->tick == ss0_tick) {
|
||||
if (!ss1->valid) {
|
||||
ss1 = sim_snapshot_alloc(G.sim_snapshot_store, ss0, ss1_tick);
|
||||
sim_snapshot_decode(event->snapshot_encoded, ss1);
|
||||
ss1->received_at_ns = G.real_time_ns;
|
||||
}
|
||||
} else {
|
||||
/* User should always have src tick present */
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct string encoded = event->snapshot_data;
|
||||
sim_decode_snapshot(encoded, &G.world, tick);
|
||||
if (event_tick > G.world->tick) {
|
||||
u64 ss0_tick = event->snapshot_tick_start;
|
||||
u64 ss1_tick = event->snapshot_tick_end;
|
||||
struct sim_snapshot *ss0 = sim_snapshot_from_tick(G.sim_snapshot_store, ss0_tick);
|
||||
struct sim_snapshot *ss1 = sim_snapshot_from_tick(G.sim_snapshot_store, ss1_tick);
|
||||
if (ss0->tick == ss0_tick) {
|
||||
if (!ss1->valid) {
|
||||
ss1 = sim_snapshot_alloc(G.sim_snapshot_store, ss0, ss1_tick);
|
||||
ss1->received_at_ns = G.real_time_ns;
|
||||
struct sim_decoder decoder = ZI;
|
||||
decoder.br = br_from_buffer(event->snapshot_encoded);
|
||||
sim_snapshot_decode(&decoder, ss1);
|
||||
}
|
||||
} else {
|
||||
/* User should always have src tick present */
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} break;
|
||||
|
||||
@ -470,6 +491,11 @@ INTERNAL void user_update(void)
|
||||
G.local_sim_last_known_time_ns = newest_snapshot->real_time_ns;
|
||||
G.local_sim_last_known_tick = newest_snapshot->tick;
|
||||
|
||||
/* This is the ack tick that we know the sim has received our ack of.
|
||||
* Therefore we must keep it around or else risk the server sending us
|
||||
* a snapshot delta for a snapshot we've released. */
|
||||
u64 oldest_possible_delta_base_tick = sim_client_from_handle(newest_snapshot, newest_snapshot->local_client)->ack_tick;
|
||||
|
||||
/* Predict local sim time based on last received snapshot time,
|
||||
* then smooth it out to prevent sudden jumps in rendering due
|
||||
* to variance in snapshot receive time. */
|
||||
@ -478,6 +504,7 @@ INTERNAL void user_update(void)
|
||||
i64 time_since_newest_tick_ns = G.real_time_ns - newest_snapshot->received_at_ns;
|
||||
G.local_sim_predicted_time_ns = newest_snapshot->real_time_ns + time_since_newest_tick_ns;
|
||||
G.local_sim_predicted_time_smoothed_ns += G.real_dt_ns;
|
||||
/* FIXME: Signed overflow check */
|
||||
G.local_sim_predicted_time_smoothed_ns += (G.local_sim_predicted_time_ns - G.local_sim_predicted_time_smoothed_ns) * sim_time_smoothed_correction_rate;
|
||||
|
||||
#if USER_INTERP_ENABLED
|
||||
@ -487,28 +514,24 @@ INTERNAL void user_update(void)
|
||||
struct sim_snapshot *left_snapshot = sim_snapshot_nil();
|
||||
struct sim_snapshot *right_snapshot = newest_snapshot;
|
||||
{
|
||||
struct sim_snapshot *snapshot = sim_snapshot_from_tick(G.sim_snapshot_store, G.sim_snapshot_store->first_tick);
|
||||
while (snapshot->valid) {
|
||||
i64 ss_time_ns = snapshot->real_time_ns;
|
||||
u64 next_tick = snapshot->next_tick;
|
||||
struct sim_snapshot *ss = sim_snapshot_from_tick(G.sim_snapshot_store, G.sim_snapshot_store->first_tick);
|
||||
while (ss->valid) {
|
||||
u64 next_tick = ss->next_tick;
|
||||
i64 ss_time_ns = ss->real_time_ns;
|
||||
if (ss_time_ns < render_time_ns && ss_time_ns > left_snapshot->real_time_ns) {
|
||||
if (left_snapshot->valid) {
|
||||
/* Snapshot no longer needed since render time has passed, release it */
|
||||
if (left_snapshot->valid && left_snapshot->tick < oldest_possible_delta_base_tick) {
|
||||
/* Snapshot no longer needed since render time has passed & it's older than any delta's we may receive, release it. */
|
||||
sim_snapshot_release(left_snapshot);
|
||||
}
|
||||
left_snapshot = snapshot;
|
||||
left_snapshot = ss;
|
||||
}
|
||||
if (ss_time_ns > render_time_ns && ss_time_ns < right_snapshot->real_time_ns) {
|
||||
right_snapshot = snapshot;
|
||||
right_snapshot = ss;
|
||||
}
|
||||
snapshot = sim_snapshot_from_tick(G.sim_snapshot_store, next_tick);
|
||||
ss = sim_snapshot_from_tick(G.sim_snapshot_store, next_tick);
|
||||
}
|
||||
}
|
||||
|
||||
if (G.world->valid) {
|
||||
sim_snapshot_release(G.world);
|
||||
}
|
||||
|
||||
/* Create world from blended snapshots */
|
||||
if (left_snapshot->valid && right_snapshot->valid) {
|
||||
f64 blend = (f64)(render_time_ns - left_snapshot->real_time_ns) / (f64)(right_snapshot->real_time_ns - left_snapshot->real_time_ns);
|
||||
@ -518,17 +541,30 @@ INTERNAL void user_update(void)
|
||||
} else if (right_snapshot->valid) {
|
||||
G.world = sim_snapshot_alloc(G.world_snapshot_store, right_snapshot, right_snapshot->tick);
|
||||
}
|
||||
|
||||
/* Release all other render snapshots */
|
||||
{
|
||||
struct sim_snapshot *ss = sim_snapshot_from_tick(G.world_snapshot_store, G.world_snapshot_store->first_tick);
|
||||
while (ss->valid) {
|
||||
u64 next_tick = ss->next_tick;
|
||||
if (ss != G.world) {
|
||||
sim_snapshot_release(ss);
|
||||
}
|
||||
ss = sim_snapshot_from_tick(G.world_snapshot_store, next_tick);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Release sim snapshots all except for newest tick */
|
||||
{
|
||||
struct sim_snapshot *snapshot = sim_snapshot_from_tick(G.sim_snapshot_store, G.sim_snapshot_store->first_tick);
|
||||
while (snapshot->valid) {
|
||||
u64 next_tick = snapshot->next_tick;
|
||||
if (snapshot->tick != newest_snapshot->tick) {
|
||||
sim_snapshot_release(snapshot);
|
||||
struct sim_snapshot *ss = sim_snapshot_from_tick(G.sim_snapshot_store, G.sim_snapshot_store->first_tick);
|
||||
while (ss->valid) {
|
||||
u64 next_tick = ss->next_tick;
|
||||
if (ss->tick != newest_snapshot->tick && ss->tick < oldest_possible_delta_base_tick) {
|
||||
sim_snapshot_release(ss);
|
||||
}
|
||||
snapshot = sim_snapshot_from_tick(G.sim_snapshot_store, next_tick);
|
||||
ss = sim_snapshot_from_tick(G.sim_snapshot_store, next_tick);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1491,10 +1527,10 @@ INTERNAL void user_update(void)
|
||||
if (font) {
|
||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Read from local sim: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1000 / 1000, 2)));
|
||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Read from local sim: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1000 / 1000, 3)));
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Sent to local sim: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_sent.last_second * 8 / 1000 / 1000, 2)));
|
||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Sent to local sim: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_sent.last_second * 8 / 1000 / 1000, 3)));
|
||||
pos.y += spacing;
|
||||
pos.y += spacing;
|
||||
|
||||
@ -1521,10 +1557,10 @@ INTERNAL void user_update(void)
|
||||
pos.y += spacing;
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory usage: %F MiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_committed) / 1024 / 1024, 2)));
|
||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory usage: %F MiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_committed) / 1024 / 1024, 3)));
|
||||
pos.y += spacing;
|
||||
|
||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Virtual memory usage: %F TiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_reserved) / 1024 / 1024 / 1024 / 1024, 2)));
|
||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Virtual memory usage: %F TiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_reserved) / 1024 / 1024 / 1024 / 1024, 3)));
|
||||
pos.y += spacing;
|
||||
pos.y += spacing;
|
||||
|
||||
@ -1589,7 +1625,7 @@ INTERNAL void user_update(void)
|
||||
{
|
||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||
|
||||
struct string cmds_str = sim_string_from_cmds(temp.arena, cmd_list);
|
||||
struct string cmds_str = sim_string_from_cmds(temp.arena, cmd_list, G.local_sim_last_known_tick);
|
||||
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, cmds_str, 0);
|
||||
|
||||
arena_temp_end(temp);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user