From e1a1006b328b74a7b5adccafe125496abc6493e7 Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 11 Feb 2025 12:07:38 -0600 Subject: [PATCH] refactor client store into snapshot --- src/app.c | 3 +- src/sim.c | 24 ++-- src/sim.h | 2 - src/sim_client.c | 157 ++++---------------- src/sim_client.h | 40 ++---- src/sim_encode.c | 347 +++++++++++++++++++++++++++++++++++++++++++-- src/sim_encode.h | 41 ++++++ src/sim_snapshot.c | 108 +++++++++----- src/sim_snapshot.h | 12 +- src/user.c | 7 +- src/user.h | 2 - 11 files changed, 514 insertions(+), 229 deletions(-) diff --git a/src/app.c b/src/app.c index d9b7ef3f..122cd953 100644 --- a/src/app.c +++ b/src/app.c @@ -226,9 +226,8 @@ void app_entry_point(struct string args_str) struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr); struct phys_startup_receipt phys_sr = phys_startup(); struct sim_ent_startup_receipt sim_ent_sr = sim_ent_startup(); - struct sim_client_startup_receipt sim_client_sr = sim_client_startup(); struct sim_snapshot_startup_receipt sim_snapshot_sr = sim_snapshot_startup(); - struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &phys_sr, &host_sr, &sim_ent_sr, &sim_client_sr, &sim_snapshot_sr, args_str, &window); + struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &phys_sr, &host_sr, &sim_ent_sr, &sim_snapshot_sr, args_str, &window); struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr); (UNUSED)user_sr; diff --git a/src/sim.c b/src/sim.c index 19ef479f..23ac927c 100644 --- a/src/sim.c +++ b/src/sim.c @@ -27,7 +27,6 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr, struct phys_startup_receipt *phys_sr, struct host_startup_receipt *host_sr, struct sim_ent_startup_receipt *sim_ent_sr, - struct sim_client_startup_receipt *sim_client_sr, struct sim_snapshot_startup_receipt *sim_snapshot_sr, u16 host_port) { @@ -39,7 +38,6 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr, (UNUSED)phys_sr; (UNUSED)host_sr; (UNUSED)sim_ent_sr; - (UNUSED)sim_client_sr; (UNUSED)sim_snapshot_sr; /* Intialize host */ @@ -519,9 +517,9 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns) for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) { enum sim_cmd_kind kind = cmd->kind; struct host_channel_id channel_id = cmd->channel_id; - struct sim_client *client = sim_client_from_channel_id(ctx->world->client_store, channel_id); + struct sim_client *client = sim_client_from_channel_id(ctx->world, channel_id); if (!client->valid && kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id)) { - client = sim_client_alloc(ctx->world->client_store, channel_id); + client = sim_client_alloc(ctx->world, channel_id); /* TODO: Create player ent not here */ /* FIXME: Player ent never released upon disconnect */ struct sim_ent *player_ent = spawn_test_player(ctx); @@ -534,13 +532,13 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns) } /* Split cmds by client */ - client_cmds = arena_push_array_zero(scratch.arena, struct sim_cmd_list, ctx->world->client_store->num_reserved); + client_cmds = arena_push_array_zero(scratch.arena, struct sim_cmd_list, ctx->world->num_clients_reserved); { struct sim_cmd *cmd = sim_cmds.first; while (cmd) { struct sim_cmd *next = cmd->next; struct host_channel_id channel_id = cmd->channel_id; - struct sim_client *client = sim_client_from_channel_id(ctx->world->client_store, channel_id); + struct sim_client *client = sim_client_from_channel_id(ctx->world, channel_id); if (client->valid) { struct sim_cmd_list *cmd_list = &client_cmds[client->handle.idx]; if (cmd_list->last) { @@ -561,8 +559,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns) * ========================== */ /* Process client cmds */ - for (u64 i = 0; i < ctx->world->client_store->num_reserved; ++i) { - struct sim_client *client = &ctx->world->client_store->clients[i]; + for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) { + struct sim_client *client = &ctx->world->clients[i]; if (client->valid) { struct host_channel_id channel_id = client->channel_id; struct sim_cmd_list cmds = client_cmds[client->handle.idx]; @@ -654,7 +652,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns) if (!sim_ent_is_valid_and_active(ent)) continue; if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) { - struct sim_client *client = sim_client_from_handle(ctx->world->client_store, ent->controlling_client); + struct sim_client *client = sim_client_from_handle(ctx->world, ent->controlling_client); if (client->valid) { ent->control = client->control; /* TODO: Move this */ @@ -1075,8 +1073,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns) * Create mouse joints from client debug drag * ========================== */ - for (u64 i = 0; i < ctx->world->client_store->num_reserved; ++i) { - struct sim_client *client = &ctx->world->client_store->clients[i]; + for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) { + struct sim_client *client = &ctx->world->clients[i]; if (client->valid) { struct v2 cursor = client->cursor_pos; b32 start_dragging = client->dbg_drag_start; @@ -1350,8 +1348,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns) * Publish tick * ========================== */ - for (u64 i = 0; i < ctx->world->client_store->num_reserved; ++i) { - struct sim_client *client = &ctx->world->client_store->clients[i]; + 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); diff --git a/src/sim.h b/src/sim.h index f31b668f..02a8ace8 100644 --- a/src/sim.h +++ b/src/sim.h @@ -8,7 +8,6 @@ struct sprite_startup_receipt; struct phys_startup_receipt; struct host_startup_receipt; struct sim_ent_startup_receipt; -struct sim_client_startup_receipt; struct sim_snapshot_startup_receipt; /* ========================== * @@ -151,7 +150,6 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr, struct phys_startup_receipt *phys_sr, struct host_startup_receipt *host_sr, struct sim_ent_startup_receipt *sim_ent_sr, - struct sim_client_startup_receipt *sim_client_sr, struct sim_snapshot_startup_receipt *sim_snapshot_sr, u16 host_port); diff --git a/src/sim_client.c b/src/sim_client.c index a1597805..5394aa49 100644 --- a/src/sim_client.c +++ b/src/sim_client.c @@ -1,128 +1,23 @@ #include "sim_client.h" +#include "sim_snapshot.h" #include "host.h" #include "arena.h" #include "util.h" #include "arena.h" -/* FIXME: Default client pointers to nil */ - -#define CHANNEL_LOOKUP_BUCKETS 4096 - -/* Offset in bytes from start of store struct to start of clients array in store arena */ -#define STORE_CLIENTS_OFFSET (sizeof(struct sim_client_store) + (sizeof(struct sim_client_channel_lookup_bucket) * CHANNEL_LOOKUP_BUCKETS)) - -struct sim_client_channel_lookup_bucket { - struct sim_client_handle first; - struct sim_client_handle last; -}; - -/* ========================== * - * Startup - * ========================== */ - -GLOBAL struct { - struct sim_client *nil_client; - struct sim_client_store *nil_store; -} G = ZI, DEBUG_ALIAS(G, G_sim_client); - -/* Accessed via sim_client_nil() */ -READONLY struct sim_client **_g_sim_client_nil = &G.nil_client; - -/* Accessed via sim_client_store_nil() */ -READONLY struct sim_client_store **_g_sim_client_store_nil = &G.nil_store; - -struct sim_client_startup_receipt sim_client_startup(void) -{ - /* Setup nil store */ - G.nil_store = sim_client_store_alloc(GIGABYTE(1)); - - /* Setup nil client */ - G.nil_client = arena_push_zero(&G.nil_store->arena, struct sim_client); - G.nil_client->handle = SIM_CLIENT_NIL_HANDLE; - ++G.nil_store->num_allocated; - ++G.nil_store->num_reserved; - MEMZERO_STRUCT(G.nil_client); - - G.nil_client->valid = false;; - G.nil_store->valid = false; - - arena_set_readonly(&G.nil_store->arena); - return (struct sim_client_startup_receipt) { 0 }; -} - -/* ========================== * - * Store - * ========================== */ - -struct sim_client_store *sim_client_store_alloc(u64 arena_reserve) -{ - struct sim_client_store *store; - { - struct arena arena = arena_alloc(arena_reserve); - store = arena_push_zero(&arena, struct sim_client_store); - store->arena = arena; - } - store->valid = true; - - store->num_channel_lookup_buckets = CHANNEL_LOOKUP_BUCKETS; - store->channel_lookup_buckets = arena_push_array_zero(&store->arena, struct sim_client_channel_lookup_bucket, store->num_channel_lookup_buckets); - - store->clients = arena_dry_push(&store->arena, struct sim_client); - ASSERT((u8 *)store->clients - (u8 *)store == STORE_CLIENTS_OFFSET); /* Offset must be correct */ - - return store; -} - -void sim_client_store_copy(struct sim_client_store *dst, struct sim_client_store *src) -{ - i64 commit_diff = (i64)src->arena.pos - (i64)dst->arena.pos; - if (commit_diff > 0) { - arena_push_array(&dst->arena, u8, commit_diff); - } - arena_pop_to(&dst->arena, src->arena.pos); - - dst->num_channel_lookup_buckets = src->num_channel_lookup_buckets; - dst->channel_lookup_buckets = (struct sim_client_channel_lookup_bucket *)((u8 *)dst + ((u8 *)src->channel_lookup_buckets - (u8 *)src)); - - dst->first_free_client = src->first_free_client; - dst->clients = (struct sim_client *)((u8 *)dst + ((u8 *)src->clients - (u8 *)src)); - dst->num_allocated = src->num_allocated; - dst->num_reserved = src->num_reserved; - - MEMCPY(dst->channel_lookup_buckets, src->channel_lookup_buckets, sizeof(*src->channel_lookup_buckets) * src->num_channel_lookup_buckets); - MEMCPY(dst->clients, src->clients, sizeof(*src->clients) * src->num_reserved); -} - -void sim_client_store_release(struct sim_client_store *store) -{ - arena_release(&store->arena); -} - /* ========================== * * Client * ========================== */ -struct sim_client_store *sim_client_store_from_client(struct sim_client *client) -{ - if (client->valid) { - u64 first_client_addr = (u64)(client - client->handle.idx); - struct sim_client_store *client_store = (struct sim_client_store *)(first_client_addr - STORE_CLIENTS_OFFSET); - ASSERT(client_store->clients == (struct sim_client *)first_client_addr); - return client_store; - } else { - return sim_client_store_nil(); - } -} - INTERNAL u64 hash_from_channel_id(struct host_channel_id channel_id) { return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&channel_id)); } -struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct sim_client_handle handle) +struct sim_client *sim_client_from_handle(struct sim_snapshot *ss, struct sim_client_handle handle) { - if (handle.gen != 0 && handle.idx < store->num_reserved) { - struct sim_client *client = &store->clients[handle.idx]; + if (handle.gen != 0 && handle.idx < ss->num_clients_reserved) { + struct sim_client *client = &ss->clients[handle.idx]; if (client->handle.gen == handle.gen) { return client; } @@ -130,13 +25,13 @@ struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct return sim_client_nil(); } -struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id) +struct sim_client *sim_client_from_channel_id(struct sim_snapshot *ss, struct host_channel_id channel_id) { struct sim_client *res = sim_client_nil(); u64 channel_hash = hash_from_channel_id(channel_id); - u64 bucket_index = channel_hash % store->num_channel_lookup_buckets; - struct sim_client_channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; - for (struct sim_client *client = sim_client_from_handle(store, bucket->first); client->valid; client = sim_client_from_handle(store, client->next_in_bucket)) { + u64 bucket_index = channel_hash % ss->num_client_lookup_buckets; + struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index]; + for (struct sim_client *client = sim_client_from_handle(ss, bucket->first); client->valid; client = sim_client_from_handle(ss, client->next_in_bucket)) { if (client->channel_hash == channel_hash) { res = client; break; @@ -145,21 +40,21 @@ struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, st return res; } -struct sim_client *sim_client_alloc(struct sim_client_store *store, struct host_channel_id channel_id) +struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id) { struct sim_client_handle handle = ZI; - struct sim_client *client = sim_client_from_handle(store, store->first_free_client); + struct sim_client *client = sim_client_from_handle(ss, ss->first_free_client); if (client->valid) { - store->first_free_client = client->next_free; + ss->first_free_client = client->next_free; handle = client->handle; ++handle.gen; } else { - client = arena_push(&store->arena, struct sim_client); + client = arena_push(&ss->clients_arena, struct sim_client); handle.gen = 1; - handle.idx = store->num_reserved; - ++store->num_reserved; + handle.idx = ss->num_clients_reserved; + ++ss->num_clients_reserved; } - ++store->num_allocated; + ++ss->num_clients_allocated; *client = *sim_client_nil(); client->valid = true; client->handle = handle; @@ -169,10 +64,10 @@ struct sim_client *sim_client_alloc(struct sim_client_store *store, struct host_ client->channel_hash = channel_hash; /* Insert into channel lookup */ - u64 bucket_index = channel_hash % store->num_channel_lookup_buckets; - struct sim_client_channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; + u64 bucket_index = channel_hash % ss->num_client_lookup_buckets; + struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index]; { - struct sim_client *prev_in_bucket = sim_client_from_handle(store, bucket->last); + struct sim_client *prev_in_bucket = sim_client_from_handle(ss, bucket->last); if (prev_in_bucket->valid) { prev_in_bucket->next_in_bucket = client->handle; client->prev_in_bucket = prev_in_bucket->handle; @@ -187,18 +82,18 @@ struct sim_client *sim_client_alloc(struct sim_client_store *store, struct host_ void sim_client_release(struct sim_client *client) { - struct sim_client_store *store = sim_client_store_from_client(client); + struct sim_snapshot *ss = client->ss; client->valid = false; ++client->handle.gen; - client->next_free = store->first_free_client; - store->first_free_client = client->handle; - --store->num_allocated; + client->next_free = ss->first_free_client; + ss->first_free_client = client->handle; + --ss->num_clients_allocated; /* Remove from channel lookup */ - u64 bucket_index = client->channel_hash % store->num_channel_lookup_buckets; - struct sim_client_channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; - struct sim_client *prev = sim_client_from_handle(store, client->prev_in_bucket); - struct sim_client *next = sim_client_from_handle(store, client->next_in_bucket); + u64 bucket_index = client->channel_hash % ss->num_client_lookup_buckets; + struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index]; + struct sim_client *prev = sim_client_from_handle(ss, client->prev_in_bucket); + struct sim_client *next = sim_client_from_handle(ss, client->next_in_bucket); if (prev->valid) { prev->next_in_bucket = next->handle; } else { diff --git a/src/sim_client.h b/src/sim_client.h index f9792743..40fa6af7 100644 --- a/src/sim_client.h +++ b/src/sim_client.h @@ -6,10 +6,17 @@ #define SIM_CLIENT_NIL_HANDLE ((struct sim_client_handle) { .gen = 0, .idx = 0 }) struct sim_client_channel_lookup_bucket; +struct sim_snapshot; + +struct sim_client_lookup_bucket { + struct sim_client_handle first; + struct sim_client_handle last; +}; struct sim_client { b32 valid; struct sim_client_handle handle; + struct sim_snapshot *ss; struct host_channel_id channel_id; u64 channel_hash; @@ -29,42 +36,15 @@ struct sim_client { struct sim_ent_handle dbg_drag_joint_ent; }; -struct sim_client_store { - b32 valid; - struct arena arena; - - struct sim_client_channel_lookup_bucket *channel_lookup_buckets; - u64 num_channel_lookup_buckets; - - struct sim_client_handle first_free_client; - struct sim_client *clients; - u64 num_allocated; - u64 num_reserved; -}; - INLINE struct sim_client *sim_client_nil(void) { extern READONLY struct sim_client **_g_sim_client_nil; return *_g_sim_client_nil; } -INLINE struct sim_client_store *sim_client_store_nil(void) -{ - extern READONLY struct sim_client_store **_g_sim_client_store_nil; - return *_g_sim_client_store_nil; -} - -struct sim_client_startup_receipt { i32 _; }; -struct sim_client_startup_receipt sim_client_startup(void); - -struct sim_client_store *sim_client_store_alloc(u64 arena_reserve); -void sim_client_store_copy(struct sim_client_store *dst, struct sim_client_store *src); -void sim_client_store_release(struct sim_client_store *store); - -struct sim_client_store *sim_client_store_from_client(struct sim_client *client); -struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct sim_client_handle handle); -struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id); -struct sim_client *sim_client_alloc(struct sim_client_store *store, struct host_channel_id channel_id); +struct sim_client *sim_client_from_handle(struct sim_snapshot *ss, struct sim_client_handle handle); +struct sim_client *sim_client_from_channel_id(struct sim_snapshot *ss, struct host_channel_id channel_id); +struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id); 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); diff --git a/src/sim_encode.c b/src/sim_encode.c index 2b543a3f..d5f9f013 100644 --- a/src/sim_encode.c +++ b/src/sim_encode.c @@ -229,12 +229,12 @@ struct string sim_encode_snapshot(struct arena *arena, struct sim_client *client 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; + /* 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->client_store->clients; + clients_src.text = (u8 *)snapshot->clients; clients_src.len = sizeof(struct sim_client) * num_clients; br_write_bytes(&bw, clients_src); @@ -269,17 +269,17 @@ void sim_decode_snapshot(struct string str, struct sim_snapshot *snapshot) /* 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; + arena_push_array(&snapshot->clients_arena, struct sim_client, num_clients - snapshot->num_clients_reserved); + snapshot->num_clients_reserved = num_clients; - snapshot->client_store->num_allocated = 0; + 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->client_store->clients[i]; + struct sim_client *dst = &snapshot->clients[i]; if (dst->valid) { - ++snapshot->client_store->num_allocated; + ++snapshot->num_clients_allocated; } *dst = *src; } @@ -303,3 +303,334 @@ void sim_decode_snapshot(struct string str, struct sim_snapshot *snapshot) } } } + + + + + + + + + + + + + + + + + + +#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->ent_store->num_reserved; ++i) { + bw_write_u8(bw, 1); + struct sim_ent *ent = &snapshot->ent_store->entities[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->ent_store); + read_entity = br_read_u8(br); + }f +} +#endif diff --git a/src/sim_encode.h b/src/sim_encode.h index 9bc328ab..42e5f175 100644 --- a/src/sim_encode.h +++ b/src/sim_encode.h @@ -21,3 +21,44 @@ struct string sim_encode_snapshot(struct arena *arena, struct sim_client *client 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 diff --git a/src/sim_snapshot.c b/src/sim_snapshot.c index 7499f75a..90c2f141 100644 --- a/src/sim_snapshot.c +++ b/src/sim_snapshot.c @@ -5,8 +5,7 @@ #include "scratch.h" #define TICK_LOOKUP_BUCKETS 31 - -INTERNAL void sim_snapshot_release_internal(struct sim_snapshot *snapshot); +#define CLIENT_LOOKUP_BUCKETS 127 struct sim_snapshot_lookup_bucket { struct sim_snapshot *first; @@ -21,8 +20,12 @@ GLOBAL struct { struct arena nil_arena; struct sim_snapshot_store *nil_snapshot_store; struct sim_snapshot *nil_snapshot; + + struct sim_client *nil_client; } G = ZI, DEBUG_ALIAS(G, G_sim_snapshot); +READONLY struct sim_client **_g_sim_client_nil = &G.nil_client; + /* Accessed via `sim_snapshot_nil()` */ READONLY struct sim_snapshot **_g_sim_snapshot_nil = &G.nil_snapshot; @@ -39,9 +42,12 @@ struct sim_snapshot_startup_receipt sim_snapshot_startup(void) G.nil_snapshot = arena_push_zero(&G.nil_arena, struct sim_snapshot); G.nil_snapshot->valid = false; G.nil_snapshot->store = sim_snapshot_store_nil(); - G.nil_snapshot->client_store = sim_client_store_nil(); G.nil_snapshot->ent_store = sim_ent_store_nil(); + G.nil_client = arena_push_zero(&G.nil_arena, struct sim_client); + G.nil_client->valid = false; + G.nil_client->ss = sim_snapshot_nil(); + arena_set_readonly(&G.nil_arena); return (struct sim_snapshot_startup_receipt ) { 0 }; } @@ -68,14 +74,21 @@ 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 = sim_snapshot_from_tick(store, ss->next_tick))->valid) { - sim_snapshot_release_internal(ss); + while (ss->valid) { + struct sim_snapshot *next = sim_snapshot_from_tick(store, ss->next_tick); + sim_ent_store_release(ss->ent_store); + arena_release(&ss->clients_arena); + arena_release(&ss->arena); + ss = next; } ss = store->first_free_snapshot; - while ((ss = ss->next_free)) { - sim_snapshot_release_internal(ss); + while (ss) { + struct sim_snapshot *next = ss->next_free; + sim_ent_store_release(ss->ent_store); + arena_release(&ss->clients_arena); + arena_release(&ss->arena); + ss = next; } - /* Release store */ arena_release(&store->arena); } @@ -91,31 +104,41 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct return sim_snapshot_nil(); } - struct sim_client_store *client_store = NULL; - struct sim_ent_store *ent_store = NULL; struct sim_snapshot *ss; { - ss = store->first_free_snapshot; - if (ss) { - store->first_free_snapshot = ss->next_free; - client_store = ss->client_store; - ent_store = ss->ent_store; - } else { - ss = arena_push(&store->arena, struct sim_snapshot); - /* NOTE: These should be released in `sim_snapshot_release_internal` */ - ent_store = sim_ent_store_alloc(GIGABYTE(64), true); - client_store = sim_client_store_alloc(GIGABYTE(64)); + struct arena arena = ZI; + struct arena clients_arena = ZI; + struct sim_ent_store *ent_store = NULL; + { + ss = store->first_free_snapshot; + if (ss) { + /* Re-use existing snasphot arenas */ + store->first_free_snapshot = ss->next_free; + arena = ss->arena; + clients_arena = ss->clients_arena; + ent_store = ss->ent_store; + arena_reset(&ss->arena); + arena_reset(&ss->clients_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)); + ent_store = sim_ent_store_alloc(GIGABYTE(64), true); + ss = arena_push(&arena, struct sim_snapshot); + } + MEMZERO_STRUCT(ss); } - MEMZERO_STRUCT(ss); + ss->arena = arena; + ss->clients_arena = clients_arena; + ss->ent_store = ent_store; } + ss->tick = tick; ss->valid = true; ss->store = store; - ss->client_store = client_store; - ss->ent_store = ent_store; ++store->num_ticks; - /* Copy src */ + /* Copy src info */ ss->real_dt_ns = src->real_dt_ns; ss->real_time_ns = src->real_time_ns; ss->world_timescale = src->world_timescale; @@ -124,7 +147,28 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct ss->received_at_ns = src->received_at_ns; ss->continuity_gen = src->continuity_gen; ss->local_client = src->local_client; - sim_client_store_copy(ss->client_store, src->client_store); + + /* Copy src clients */ + if (src->num_client_lookup_buckets > 0) { + ss->num_client_lookup_buckets = src->num_client_lookup_buckets; + ss->client_lookup_buckets = arena_push_array(&ss->arena, struct sim_client_lookup_bucket, ss->num_client_lookup_buckets); + MEMCPY(ss->client_lookup_buckets, src->client_lookup_buckets, sizeof(*ss->client_lookup_buckets) * ss->num_client_lookup_buckets); + } else { + ss->num_client_lookup_buckets = CLIENT_LOOKUP_BUCKETS; + ss->client_lookup_buckets = arena_push_array_zero(&ss->arena, struct sim_client_lookup_bucket, ss->num_client_lookup_buckets); + } + ss->first_free_client = src->first_free_client; + ss->num_clients_allocated = src->num_clients_allocated; + ss->num_clients_reserved = src->num_clients_reserved; + ss->clients = arena_push_array(&ss->clients_arena, struct sim_client, ss->num_clients_reserved); + for (u64 i = 0; i < ss->num_clients_reserved; ++i) { + struct sim_client *dst_client = &ss->clients[i]; + struct sim_client *src_client = &src->clients[i]; + *dst_client = *src_client; + dst_client->ss = ss; + } + + /* Copy src entities */ sim_ent_store_copy(ss->ent_store, src->ent_store); /* Release duplicate tick if it exists */ @@ -226,12 +270,6 @@ void sim_snapshot_release(struct sim_snapshot *ss) --store->num_ticks; } -INTERNAL void sim_snapshot_release_internal(struct sim_snapshot *snapshot) -{ - sim_client_store_release(snapshot->client_store); - sim_ent_store_release(snapshot->ent_store); -} - /* ========================== * * Lookup * ========================== */ @@ -292,11 +330,11 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *sto /* Blend clients */ { __profscope(snapshot_lerp_clients); - u64 num_clients = min_u64(ss0->client_store->num_reserved, ss1->client_store->num_reserved); + u64 num_clients = min_u64(ss0->num_clients_reserved, ss1->num_clients_reserved); for (u64 i = 0; i < num_clients; ++i) { - struct sim_client *c = &ss->client_store->clients[i]; - struct sim_client *c0 = &ss0->client_store->clients[i]; - struct sim_client *c1 = &ss1->client_store->clients[i]; + struct sim_client *c = &ss->clients[i]; + struct sim_client *c0 = &ss0->clients[i]; + struct sim_client *c1 = &ss1->clients[i]; sim_client_lerp(c, c0, c1, blend); } } diff --git a/src/sim_snapshot.h b/src/sim_snapshot.h index 30382aaf..0a470cb0 100644 --- a/src/sim_snapshot.h +++ b/src/sim_snapshot.h @@ -22,6 +22,7 @@ struct sim_snapshot_store { struct sim_snapshot { /* Managed by store */ + struct arena arena; b32 valid; u64 tick; struct sim_snapshot_store *store; @@ -49,7 +50,16 @@ struct sim_snapshot { /* Which client in the client store represents the local host in the original snapshot */ struct sim_client_handle local_client; - struct sim_client_store *client_store; + /* Clients */ + struct sim_client_lookup_bucket *client_lookup_buckets; + u64 num_client_lookup_buckets; + struct arena clients_arena; + struct sim_client *clients; + struct sim_client_handle first_free_client; + u64 num_clients_allocated; + u64 num_clients_reserved; + + /* Entities */ struct sim_ent_store *ent_store; }; diff --git a/src/user.c b/src/user.c index 0a92cf05..59bbf0cc 100644 --- a/src/user.c +++ b/src/user.c @@ -161,7 +161,6 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, struct phys_startup_receipt *phys_sr, struct host_startup_receipt *host_sr, struct sim_ent_startup_receipt *sim_ent_sr, - struct sim_client_startup_receipt *sim_client_sr, struct sim_snapshot_startup_receipt *sim_snapshot_sr, struct string connect_address_str, struct sys_window *window) @@ -176,8 +175,6 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, (UNUSED)mixer_sr; (UNUSED)phys_sr; (UNUSED)host_sr; - (UNUSED)sim_ent_sr; - (UNUSED)sim_client_sr; (UNUSED)sim_snapshot_sr; G.arena = arena_alloc(GIGABYTE(64)); @@ -204,7 +201,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, sys_window_register_event_callback(G.window, &window_event_callback); if (connect_address_str.len == 0) { - G.local_sim_ctx = sim_ctx_alloc(sprite_sr, phys_sr, host_sr, sim_ent_sr, sim_client_sr, sim_snapshot_sr, 12345); + G.local_sim_ctx = sim_ctx_alloc(sprite_sr, phys_sr, host_sr, sim_ent_sr, sim_snapshot_sr, 12345); G.connect_address_str = LIT("127.0.0.1:12345"); G.local_sim_thread = sys_thread_alloc(&user_local_sim_thread_entry_point, G.local_sim_ctx, LIT("[P2] Local sim thread")); } else { @@ -638,7 +635,7 @@ INTERNAL void user_update(void) * Find local entities * ========================== */ - struct sim_client *local_client = sim_client_from_handle(G.world->client_store, G.world->local_client); + struct sim_client *local_client = sim_client_from_handle(G.world, G.world->local_client); struct sim_ent *local_player = sim_ent_from_handle(G.world->ent_store, local_client->control_ent); struct sim_ent *local_camera = sim_ent_from_handle(G.world->ent_store, local_client->camera_ent); diff --git a/src/user.h b/src/user.h index a0bc26db..4c17dbd2 100644 --- a/src/user.h +++ b/src/user.h @@ -13,7 +13,6 @@ struct mixer_startup_receipt; struct phys_startup_receipt; struct host_startup_receipt; struct sim_ent_startup_receipt; -struct sim_client_startup_receipt; struct sim_snapshot_startup_receipt; enum user_bind_kind { @@ -64,7 +63,6 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, struct phys_startup_receipt *phys_sr, struct host_startup_receipt *host_sr, struct sim_ent_startup_receipt *sim_ent_sr, - struct sim_client_startup_receipt *sim_client_sr, struct sim_snapshot_startup_receipt *sim_snapshot_sr, struct string connect_address_str, struct sys_window *window);