refactor client store into snapshot
This commit is contained in:
parent
c7315327f4
commit
e1a1006b32
@ -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 draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr);
|
||||||
struct phys_startup_receipt phys_sr = phys_startup();
|
struct phys_startup_receipt phys_sr = phys_startup();
|
||||||
struct sim_ent_startup_receipt sim_ent_sr = sim_ent_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 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);
|
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
|
||||||
|
|
||||||
(UNUSED)user_sr;
|
(UNUSED)user_sr;
|
||||||
|
|||||||
24
src/sim.c
24
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 phys_startup_receipt *phys_sr,
|
||||||
struct host_startup_receipt *host_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct sim_ent_startup_receipt *sim_ent_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 sim_snapshot_startup_receipt *sim_snapshot_sr,
|
||||||
u16 host_port)
|
u16 host_port)
|
||||||
{
|
{
|
||||||
@ -39,7 +38,6 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
|||||||
(UNUSED)phys_sr;
|
(UNUSED)phys_sr;
|
||||||
(UNUSED)host_sr;
|
(UNUSED)host_sr;
|
||||||
(UNUSED)sim_ent_sr;
|
(UNUSED)sim_ent_sr;
|
||||||
(UNUSED)sim_client_sr;
|
|
||||||
(UNUSED)sim_snapshot_sr;
|
(UNUSED)sim_snapshot_sr;
|
||||||
|
|
||||||
/* Intialize host */
|
/* 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) {
|
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
|
||||||
enum sim_cmd_kind kind = cmd->kind;
|
enum sim_cmd_kind kind = cmd->kind;
|
||||||
struct host_channel_id channel_id = cmd->channel_id;
|
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)) {
|
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 */
|
/* TODO: Create player ent not here */
|
||||||
/* FIXME: Player ent never released upon disconnect */
|
/* FIXME: Player ent never released upon disconnect */
|
||||||
struct sim_ent *player_ent = spawn_test_player(ctx);
|
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 */
|
/* 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;
|
struct sim_cmd *cmd = sim_cmds.first;
|
||||||
while (cmd) {
|
while (cmd) {
|
||||||
struct sim_cmd *next = cmd->next;
|
struct sim_cmd *next = cmd->next;
|
||||||
struct host_channel_id channel_id = cmd->channel_id;
|
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) {
|
if (client->valid) {
|
||||||
struct sim_cmd_list *cmd_list = &client_cmds[client->handle.idx];
|
struct sim_cmd_list *cmd_list = &client_cmds[client->handle.idx];
|
||||||
if (cmd_list->last) {
|
if (cmd_list->last) {
|
||||||
@ -561,8 +559,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
/* Process client cmds */
|
/* Process client cmds */
|
||||||
for (u64 i = 0; i < ctx->world->client_store->num_reserved; ++i) {
|
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
|
||||||
struct sim_client *client = &ctx->world->client_store->clients[i];
|
struct sim_client *client = &ctx->world->clients[i];
|
||||||
if (client->valid) {
|
if (client->valid) {
|
||||||
struct host_channel_id channel_id = client->channel_id;
|
struct host_channel_id channel_id = client->channel_id;
|
||||||
struct sim_cmd_list cmds = client_cmds[client->handle.idx];
|
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_is_valid_and_active(ent)) continue;
|
||||||
|
|
||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
|
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) {
|
if (client->valid) {
|
||||||
ent->control = client->control;
|
ent->control = client->control;
|
||||||
/* TODO: Move this */
|
/* 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
|
* Create mouse joints from client debug drag
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 i = 0; i < ctx->world->client_store->num_reserved; ++i) {
|
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
|
||||||
struct sim_client *client = &ctx->world->client_store->clients[i];
|
struct sim_client *client = &ctx->world->clients[i];
|
||||||
if (client->valid) {
|
if (client->valid) {
|
||||||
struct v2 cursor = client->cursor_pos;
|
struct v2 cursor = client->cursor_pos;
|
||||||
b32 start_dragging = client->dbg_drag_start;
|
b32 start_dragging = client->dbg_drag_start;
|
||||||
@ -1350,8 +1348,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
|
|||||||
* Publish tick
|
* Publish tick
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 i = 0; i < ctx->world->client_store->num_reserved; ++i) {
|
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
|
||||||
struct sim_client *client = &ctx->world->client_store->clients[i];
|
struct sim_client *client = &ctx->world->clients[i];
|
||||||
if (client->valid) {
|
if (client->valid) {
|
||||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,6 @@ struct sprite_startup_receipt;
|
|||||||
struct phys_startup_receipt;
|
struct phys_startup_receipt;
|
||||||
struct host_startup_receipt;
|
struct host_startup_receipt;
|
||||||
struct sim_ent_startup_receipt;
|
struct sim_ent_startup_receipt;
|
||||||
struct sim_client_startup_receipt;
|
|
||||||
struct sim_snapshot_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 phys_startup_receipt *phys_sr,
|
||||||
struct host_startup_receipt *host_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct sim_ent_startup_receipt *sim_ent_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 sim_snapshot_startup_receipt *sim_snapshot_sr,
|
||||||
u16 host_port);
|
u16 host_port);
|
||||||
|
|
||||||
|
|||||||
157
src/sim_client.c
157
src/sim_client.c
@ -1,128 +1,23 @@
|
|||||||
#include "sim_client.h"
|
#include "sim_client.h"
|
||||||
|
#include "sim_snapshot.h"
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "arena.h"
|
#include "arena.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "arena.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
|
* 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)
|
INTERNAL u64 hash_from_channel_id(struct host_channel_id channel_id)
|
||||||
{
|
{
|
||||||
return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&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) {
|
if (handle.gen != 0 && handle.idx < ss->num_clients_reserved) {
|
||||||
struct sim_client *client = &store->clients[handle.idx];
|
struct sim_client *client = &ss->clients[handle.idx];
|
||||||
if (client->handle.gen == handle.gen) {
|
if (client->handle.gen == handle.gen) {
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
@ -130,13 +25,13 @@ struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct
|
|||||||
return sim_client_nil();
|
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();
|
struct sim_client *res = sim_client_nil();
|
||||||
u64 channel_hash = hash_from_channel_id(channel_id);
|
u64 channel_hash = hash_from_channel_id(channel_id);
|
||||||
u64 bucket_index = channel_hash % store->num_channel_lookup_buckets;
|
u64 bucket_index = channel_hash % ss->num_client_lookup_buckets;
|
||||||
struct sim_client_channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index];
|
struct sim_client_lookup_bucket *bucket = &ss->client_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)) {
|
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) {
|
if (client->channel_hash == channel_hash) {
|
||||||
res = client;
|
res = client;
|
||||||
break;
|
break;
|
||||||
@ -145,21 +40,21 @@ struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, st
|
|||||||
return res;
|
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_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) {
|
if (client->valid) {
|
||||||
store->first_free_client = client->next_free;
|
ss->first_free_client = client->next_free;
|
||||||
handle = client->handle;
|
handle = client->handle;
|
||||||
++handle.gen;
|
++handle.gen;
|
||||||
} else {
|
} else {
|
||||||
client = arena_push(&store->arena, struct sim_client);
|
client = arena_push(&ss->clients_arena, struct sim_client);
|
||||||
handle.gen = 1;
|
handle.gen = 1;
|
||||||
handle.idx = store->num_reserved;
|
handle.idx = ss->num_clients_reserved;
|
||||||
++store->num_reserved;
|
++ss->num_clients_reserved;
|
||||||
}
|
}
|
||||||
++store->num_allocated;
|
++ss->num_clients_allocated;
|
||||||
*client = *sim_client_nil();
|
*client = *sim_client_nil();
|
||||||
client->valid = true;
|
client->valid = true;
|
||||||
client->handle = handle;
|
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;
|
client->channel_hash = channel_hash;
|
||||||
|
|
||||||
/* Insert into channel lookup */
|
/* Insert into channel lookup */
|
||||||
u64 bucket_index = channel_hash % store->num_channel_lookup_buckets;
|
u64 bucket_index = channel_hash % ss->num_client_lookup_buckets;
|
||||||
struct sim_client_channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index];
|
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) {
|
if (prev_in_bucket->valid) {
|
||||||
prev_in_bucket->next_in_bucket = client->handle;
|
prev_in_bucket->next_in_bucket = client->handle;
|
||||||
client->prev_in_bucket = prev_in_bucket->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)
|
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->valid = false;
|
||||||
++client->handle.gen;
|
++client->handle.gen;
|
||||||
client->next_free = store->first_free_client;
|
client->next_free = ss->first_free_client;
|
||||||
store->first_free_client = client->handle;
|
ss->first_free_client = client->handle;
|
||||||
--store->num_allocated;
|
--ss->num_clients_allocated;
|
||||||
|
|
||||||
/* Remove from channel lookup */
|
/* Remove from channel lookup */
|
||||||
u64 bucket_index = client->channel_hash % store->num_channel_lookup_buckets;
|
u64 bucket_index = client->channel_hash % ss->num_client_lookup_buckets;
|
||||||
struct sim_client_channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index];
|
struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index];
|
||||||
struct sim_client *prev = sim_client_from_handle(store, client->prev_in_bucket);
|
struct sim_client *prev = sim_client_from_handle(ss, client->prev_in_bucket);
|
||||||
struct sim_client *next = sim_client_from_handle(store, client->next_in_bucket);
|
struct sim_client *next = sim_client_from_handle(ss, client->next_in_bucket);
|
||||||
if (prev->valid) {
|
if (prev->valid) {
|
||||||
prev->next_in_bucket = next->handle;
|
prev->next_in_bucket = next->handle;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -6,10 +6,17 @@
|
|||||||
#define SIM_CLIENT_NIL_HANDLE ((struct sim_client_handle) { .gen = 0, .idx = 0 })
|
#define SIM_CLIENT_NIL_HANDLE ((struct sim_client_handle) { .gen = 0, .idx = 0 })
|
||||||
|
|
||||||
struct sim_client_channel_lookup_bucket;
|
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 {
|
struct sim_client {
|
||||||
b32 valid;
|
b32 valid;
|
||||||
struct sim_client_handle handle;
|
struct sim_client_handle handle;
|
||||||
|
struct sim_snapshot *ss;
|
||||||
|
|
||||||
struct host_channel_id channel_id;
|
struct host_channel_id channel_id;
|
||||||
u64 channel_hash;
|
u64 channel_hash;
|
||||||
@ -29,42 +36,15 @@ struct sim_client {
|
|||||||
struct sim_ent_handle dbg_drag_joint_ent;
|
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)
|
INLINE struct sim_client *sim_client_nil(void)
|
||||||
{
|
{
|
||||||
extern READONLY struct sim_client **_g_sim_client_nil;
|
extern READONLY struct sim_client **_g_sim_client_nil;
|
||||||
return *_g_sim_client_nil;
|
return *_g_sim_client_nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE struct sim_client_store *sim_client_store_nil(void)
|
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);
|
||||||
extern READONLY struct sim_client_store **_g_sim_client_store_nil;
|
struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id);
|
||||||
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);
|
|
||||||
void sim_client_release(struct sim_client *client);
|
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_lerp(struct sim_client *c, struct sim_client *c0, struct sim_client *c1, f64 blend);
|
||||||
|
|||||||
347
src/sim_encode.c
347
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.gen);
|
||||||
bw_write_var_uint(&bw, client->handle.idx);
|
bw_write_var_uint(&bw, client->handle.idx);
|
||||||
|
|
||||||
/* Client store */
|
/* Client s*/
|
||||||
u64 num_clients = snapshot->client_store->num_reserved;
|
u64 num_clients = snapshot->num_clients_reserved;
|
||||||
bw_write_var_uint(&bw, num_clients);
|
bw_write_var_uint(&bw, num_clients);
|
||||||
|
|
||||||
struct string clients_src = ZI;
|
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;
|
clients_src.len = sizeof(struct sim_client) * num_clients;
|
||||||
br_write_bytes(&bw, clients_src);
|
br_write_bytes(&bw, clients_src);
|
||||||
|
|
||||||
@ -269,17 +269,17 @@ void sim_decode_snapshot(struct string str, struct sim_snapshot *snapshot)
|
|||||||
|
|
||||||
/* Client store */
|
/* Client store */
|
||||||
u64 num_clients = br_read_var_uint(&br);
|
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);
|
arena_push_array(&snapshot->clients_arena, struct sim_client, num_clients - snapshot->num_clients_reserved);
|
||||||
snapshot->client_store->num_reserved = num_clients;
|
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));
|
struct sim_client *clients_src = br_seek(&br, num_clients * sizeof(struct sim_client));
|
||||||
if (clients_src) {
|
if (clients_src) {
|
||||||
for (u64 i = 0; i < num_clients; ++i) {
|
for (u64 i = 0; i < num_clients; ++i) {
|
||||||
struct sim_client *src = &clients_src[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) {
|
if (dst->valid) {
|
||||||
++snapshot->client_store->num_allocated;
|
++snapshot->num_clients_allocated;
|
||||||
}
|
}
|
||||||
*dst = *src;
|
*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
|
||||||
|
|||||||
@ -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);
|
void sim_decode_snapshot(struct string str, struct sim_snapshot *snapshot);
|
||||||
|
|
||||||
#endif
|
#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
|
||||||
|
|||||||
@ -5,8 +5,7 @@
|
|||||||
#include "scratch.h"
|
#include "scratch.h"
|
||||||
|
|
||||||
#define TICK_LOOKUP_BUCKETS 31
|
#define TICK_LOOKUP_BUCKETS 31
|
||||||
|
#define CLIENT_LOOKUP_BUCKETS 127
|
||||||
INTERNAL void sim_snapshot_release_internal(struct sim_snapshot *snapshot);
|
|
||||||
|
|
||||||
struct sim_snapshot_lookup_bucket {
|
struct sim_snapshot_lookup_bucket {
|
||||||
struct sim_snapshot *first;
|
struct sim_snapshot *first;
|
||||||
@ -21,8 +20,12 @@ GLOBAL struct {
|
|||||||
struct arena nil_arena;
|
struct arena nil_arena;
|
||||||
struct sim_snapshot_store *nil_snapshot_store;
|
struct sim_snapshot_store *nil_snapshot_store;
|
||||||
struct sim_snapshot *nil_snapshot;
|
struct sim_snapshot *nil_snapshot;
|
||||||
|
|
||||||
|
struct sim_client *nil_client;
|
||||||
} G = ZI, DEBUG_ALIAS(G, G_sim_snapshot);
|
} G = ZI, DEBUG_ALIAS(G, G_sim_snapshot);
|
||||||
|
|
||||||
|
READONLY struct sim_client **_g_sim_client_nil = &G.nil_client;
|
||||||
|
|
||||||
/* Accessed via `sim_snapshot_nil()` */
|
/* Accessed via `sim_snapshot_nil()` */
|
||||||
READONLY struct sim_snapshot **_g_sim_snapshot_nil = &G.nil_snapshot;
|
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 = arena_push_zero(&G.nil_arena, struct sim_snapshot);
|
||||||
G.nil_snapshot->valid = false;
|
G.nil_snapshot->valid = false;
|
||||||
G.nil_snapshot->store = sim_snapshot_store_nil();
|
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_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);
|
arena_set_readonly(&G.nil_arena);
|
||||||
return (struct sim_snapshot_startup_receipt ) { 0 };
|
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 */
|
/* Release snapshot internal memory */
|
||||||
struct sim_snapshot *ss = sim_snapshot_from_tick(store, store->first_tick);
|
struct sim_snapshot *ss = sim_snapshot_from_tick(store, store->first_tick);
|
||||||
while ((ss = sim_snapshot_from_tick(store, ss->next_tick))->valid) {
|
while (ss->valid) {
|
||||||
sim_snapshot_release_internal(ss);
|
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;
|
ss = store->first_free_snapshot;
|
||||||
while ((ss = ss->next_free)) {
|
while (ss) {
|
||||||
sim_snapshot_release_internal(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 */
|
/* Release store */
|
||||||
arena_release(&store->arena);
|
arena_release(&store->arena);
|
||||||
}
|
}
|
||||||
@ -91,31 +104,41 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_snapshot_store *store, struct
|
|||||||
return sim_snapshot_nil();
|
return sim_snapshot_nil();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_client_store *client_store = NULL;
|
|
||||||
struct sim_ent_store *ent_store = NULL;
|
|
||||||
struct sim_snapshot *ss;
|
struct sim_snapshot *ss;
|
||||||
{
|
{
|
||||||
ss = store->first_free_snapshot;
|
struct arena arena = ZI;
|
||||||
if (ss) {
|
struct arena clients_arena = ZI;
|
||||||
store->first_free_snapshot = ss->next_free;
|
struct sim_ent_store *ent_store = NULL;
|
||||||
client_store = ss->client_store;
|
{
|
||||||
ent_store = ss->ent_store;
|
ss = store->first_free_snapshot;
|
||||||
} else {
|
if (ss) {
|
||||||
ss = arena_push(&store->arena, struct sim_snapshot);
|
/* Re-use existing snasphot arenas */
|
||||||
/* NOTE: These should be released in `sim_snapshot_release_internal` */
|
store->first_free_snapshot = ss->next_free;
|
||||||
ent_store = sim_ent_store_alloc(GIGABYTE(64), true);
|
arena = ss->arena;
|
||||||
client_store = sim_client_store_alloc(GIGABYTE(64));
|
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->tick = tick;
|
||||||
ss->valid = true;
|
ss->valid = true;
|
||||||
ss->store = store;
|
ss->store = store;
|
||||||
ss->client_store = client_store;
|
|
||||||
ss->ent_store = ent_store;
|
|
||||||
++store->num_ticks;
|
++store->num_ticks;
|
||||||
|
|
||||||
/* Copy src */
|
/* Copy src info */
|
||||||
ss->real_dt_ns = src->real_dt_ns;
|
ss->real_dt_ns = src->real_dt_ns;
|
||||||
ss->real_time_ns = src->real_time_ns;
|
ss->real_time_ns = src->real_time_ns;
|
||||||
ss->world_timescale = src->world_timescale;
|
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->received_at_ns = src->received_at_ns;
|
||||||
ss->continuity_gen = src->continuity_gen;
|
ss->continuity_gen = src->continuity_gen;
|
||||||
ss->local_client = src->local_client;
|
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);
|
sim_ent_store_copy(ss->ent_store, src->ent_store);
|
||||||
|
|
||||||
/* Release duplicate tick if it exists */
|
/* Release duplicate tick if it exists */
|
||||||
@ -226,12 +270,6 @@ void sim_snapshot_release(struct sim_snapshot *ss)
|
|||||||
--store->num_ticks;
|
--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
|
* Lookup
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -292,11 +330,11 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_snapshot_store *sto
|
|||||||
/* Blend clients */
|
/* Blend clients */
|
||||||
{
|
{
|
||||||
__profscope(snapshot_lerp_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) {
|
for (u64 i = 0; i < num_clients; ++i) {
|
||||||
struct sim_client *c = &ss->client_store->clients[i];
|
struct sim_client *c = &ss->clients[i];
|
||||||
struct sim_client *c0 = &ss0->client_store->clients[i];
|
struct sim_client *c0 = &ss0->clients[i];
|
||||||
struct sim_client *c1 = &ss1->client_store->clients[i];
|
struct sim_client *c1 = &ss1->clients[i];
|
||||||
sim_client_lerp(c, c0, c1, blend);
|
sim_client_lerp(c, c0, c1, blend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ struct sim_snapshot_store {
|
|||||||
|
|
||||||
struct sim_snapshot {
|
struct sim_snapshot {
|
||||||
/* Managed by store */
|
/* Managed by store */
|
||||||
|
struct arena arena;
|
||||||
b32 valid;
|
b32 valid;
|
||||||
u64 tick;
|
u64 tick;
|
||||||
struct sim_snapshot_store *store;
|
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 */
|
/* Which client in the client store represents the local host in the original snapshot */
|
||||||
struct sim_client_handle local_client;
|
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;
|
struct sim_ent_store *ent_store;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -161,7 +161,6 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
struct phys_startup_receipt *phys_sr,
|
struct phys_startup_receipt *phys_sr,
|
||||||
struct host_startup_receipt *host_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct sim_ent_startup_receipt *sim_ent_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 sim_snapshot_startup_receipt *sim_snapshot_sr,
|
||||||
struct string connect_address_str,
|
struct string connect_address_str,
|
||||||
struct sys_window *window)
|
struct sys_window *window)
|
||||||
@ -176,8 +175,6 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
(UNUSED)mixer_sr;
|
(UNUSED)mixer_sr;
|
||||||
(UNUSED)phys_sr;
|
(UNUSED)phys_sr;
|
||||||
(UNUSED)host_sr;
|
(UNUSED)host_sr;
|
||||||
(UNUSED)sim_ent_sr;
|
|
||||||
(UNUSED)sim_client_sr;
|
|
||||||
(UNUSED)sim_snapshot_sr;
|
(UNUSED)sim_snapshot_sr;
|
||||||
|
|
||||||
G.arena = arena_alloc(GIGABYTE(64));
|
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);
|
sys_window_register_event_callback(G.window, &window_event_callback);
|
||||||
|
|
||||||
if (connect_address_str.len == 0) {
|
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.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"));
|
G.local_sim_thread = sys_thread_alloc(&user_local_sim_thread_entry_point, G.local_sim_ctx, LIT("[P2] Local sim thread"));
|
||||||
} else {
|
} else {
|
||||||
@ -638,7 +635,7 @@ INTERNAL void user_update(void)
|
|||||||
* Find local entities
|
* 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_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);
|
struct sim_ent *local_camera = sim_ent_from_handle(G.world->ent_store, local_client->camera_ent);
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,6 @@ struct mixer_startup_receipt;
|
|||||||
struct phys_startup_receipt;
|
struct phys_startup_receipt;
|
||||||
struct host_startup_receipt;
|
struct host_startup_receipt;
|
||||||
struct sim_ent_startup_receipt;
|
struct sim_ent_startup_receipt;
|
||||||
struct sim_client_startup_receipt;
|
|
||||||
struct sim_snapshot_startup_receipt;
|
struct sim_snapshot_startup_receipt;
|
||||||
|
|
||||||
enum user_bind_kind {
|
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 phys_startup_receipt *phys_sr,
|
||||||
struct host_startup_receipt *host_sr,
|
struct host_startup_receipt *host_sr,
|
||||||
struct sim_ent_startup_receipt *sim_ent_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 sim_snapshot_startup_receipt *sim_snapshot_sr,
|
||||||
struct string connect_address_str,
|
struct string connect_address_str,
|
||||||
struct sys_window *window);
|
struct sys_window *window);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user