From 1dc1c42678ba1f1bc4b3d26045ff75273f6af934 Mon Sep 17 00:00:00 2001 From: jacob Date: Sat, 22 Feb 2025 23:20:42 -0600 Subject: [PATCH] prediction progress --- src/bitbuff.c | 20 ++-- src/config.h | 10 +- src/phys.c | 4 +- src/sim.c | 33 +++++-- src/sim.h | 12 ++- src/sim_ent.c | 7 +- src/sim_ent.h | 2 + src/sim_step.c | 35 ++----- src/sim_step.h | 3 - src/string.c | 23 +++-- src/string.h | 4 +- src/user.c | 249 ++++++++++++++++++++++++++++++++++++------------- 12 files changed, 268 insertions(+), 134 deletions(-) diff --git a/src/bitbuff.c b/src/bitbuff.c index 0a3d8da5..5693a1c5 100644 --- a/src/bitbuff.c +++ b/src/bitbuff.c @@ -20,9 +20,8 @@ enum dbg_magic { DBG_MAGIC_IV = 0x981f, DBG_MAGIC_F32 = 0x56F9, DBG_MAGIC_F64 = 0x7053, - DBG_MAGIC_U128 = 0xa24e, + DBG_MAGIC_U128 = 0xA24E, DBG_MAGIC_STRING = 0x7866, - DBG_MAGIC_BYTES = 0x8B90 }; INTERNAL void bw_write_ubits_nomagic(struct bitbuff_writer *bw, u64 value, u8 num_bits); @@ -202,7 +201,11 @@ b32 bw_check_overflow_bits(struct bitbuff_writer *bw, u64 num_bits) /* Align the pos to the next byte */ void bw_align(struct bitbuff_writer *bw) { - _dbg_write_magic(bw, DBG_MAGIC_ALIGN, 0); +#if BITBUFF_DEBUG + if ((bw->cur_bit & 7) != 0) { + _dbg_write_magic(bw, DBG_MAGIC_ALIGN, 0); + } +#endif bw->cur_bit += (8 - (bw->cur_bit & 7)) & 7; } @@ -330,8 +333,8 @@ void bw_write_f64(struct bitbuff_writer *bw, f64 value) void bw_write_u128(struct bitbuff_writer *bw, u128 value) { _dbg_write_magic(bw, DBG_MAGIC_U128, 128); - bw_write_ubits(bw, U128_LO(value), 64); bw_write_ubits(bw, U128_HI(value), 64); + bw_write_ubits(bw, U128_LO(value), 64); } void bw_write_string(struct bitbuff_writer *bw, struct string s) @@ -343,8 +346,6 @@ void bw_write_string(struct bitbuff_writer *bw, struct string s) void bw_write_bytes(struct bitbuff_writer *bw, struct string bytes) { - _dbg_write_magic(bw, DBG_MAGIC_BYTES, 0); - /* Align start of bytes */ bw_align(bw); @@ -440,7 +441,11 @@ b32 br_check_overflow_bits(struct bitbuff_reader *br, u64 num_bits) /* Align the pos to the next byte */ void br_align(struct bitbuff_reader *br) { - _dbg_read_magic(br, DBG_MAGIC_ALIGN, 0); +#if BITBUFF_DEBUG + if ((br->cur_bit & 7) != 0) { + _dbg_read_magic(br, DBG_MAGIC_ALIGN, 0); + } +#endif br->cur_bit += (8 - (br->cur_bit & 7)) & 7; } @@ -608,7 +613,6 @@ void br_read_bytes(struct bitbuff_reader *br, struct string out) /* NULL will return on bitbuff overflow, result should be checked. */ u8 *br_read_bytes_raw(struct bitbuff_reader *br, u64 num_bytes) { - _dbg_read_magic(br, DBG_MAGIC_BYTES, 0); br_align(br); u64 num_bits = num_bytes << 3; diff --git a/src/config.h b/src/config.h index 236cb173..d59b20fd 100644 --- a/src/config.h +++ b/src/config.h @@ -33,7 +33,7 @@ #define SPACE_CELL_BUCKETS_SQRT (256) #define SPACE_CELL_SIZE 1.0f -#define SIM_TICKS_PER_SECOND 50 +#define SIM_TICKS_PER_SECOND 100 #define SIM_TIMESCALE 1 #define SIM_PHYSICS_SUBSTEPS 4 @@ -45,10 +45,8 @@ #define SIM_SPAWN_TESTENT 0 #define SIM_PLAYER_AIM 1 -//#define SIM_MAX_LINEAR_VELOCITY 500 -//#define SIM_MAX_ANGULAR_VELOCITY (TAU * 20) -#define SIM_MAX_LINEAR_VELOCITY F32_INFINITY -#define SIM_MAX_ANGULAR_VELOCITY F32_INFINITY +#define SIM_MAX_LINEAR_VELOCITY 500 +#define SIM_MAX_ANGULAR_VELOCITY (TAU * 20) /* How many ticks back in time should the user blend between? * = * @@ -62,7 +60,7 @@ #define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 0 /* If enabled, bitbuffs will insert/verify magic numbers & length for each read & write */ -#define BITBUFF_DEBUG RTC +#define BITBUFF_DEBUG 0 #define BITBUFF_TEST RTC /* ========================== * diff --git a/src/phys.c b/src/phys.c index 8c3e24b6..ecea8596 100644 --- a/src/phys.c +++ b/src/phys.c @@ -128,7 +128,7 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a if (!sim_ent_is_valid_and_active(constraint_ent)) { /* Create constraint */ { - constraint_ent = sim_ent_alloc_net_src(root); + constraint_ent = sim_ent_alloc_local(root); constraint_ent->contact_constraint_data.e1 = e1->handle; constraint_ent->contact_constraint_data.e0 = e0->handle; constraint_ent->contact_constraint_data.skip_solve = sim_ent_has_prop(e0, SIM_ENT_PROP_SENSOR) || sim_ent_has_prop(e1, SIM_ENT_PROP_SENSOR) @@ -245,7 +245,7 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a if (!dbg_ent->valid) { /* FIXME: Entity never released */ - dbg_ent = sim_ent_alloc_net_src(root); + dbg_ent = sim_ent_alloc_local(root); sim_ent_enable_prop(dbg_ent, SIM_ENT_PROP_COLLISION_DEBUG); sim_lookup_set(debug_lookup, key, dbg_ent->handle); } diff --git a/src/sim.c b/src/sim.c index 6214777c..74ba8b58 100644 --- a/src/sim.c +++ b/src/sim.c @@ -284,8 +284,8 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_client *client, struct sim_sn arena = ss->arena; } else { /* Arenas allocated here will be released with client */ - arena = arena_alloc(GIGABYTE(8)); - ents_arena = arena_alloc(GIGABYTE(8)); + arena = arena_alloc(GIGABYTE(1)); + ents_arena = arena_alloc(GIGABYTE(1)); } } arena_reset(&arena); @@ -311,8 +311,12 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_client *client, struct sim_sn /* Copy netid lookup buckets */ ss->num_netid_buckets = src->num_netid_buckets > 0 ? src->num_netid_buckets : NETID_LOOKUP_BUCKETS; ss->netid_buckets = arena_push_array(&ss->arena, struct sim_ent_bucket, ss->num_netid_buckets); - for (u64 i = 0; i < src->num_netid_buckets; ++i) { - ss->netid_buckets[i] = src->netid_buckets[i]; + if (src->num_netid_buckets > 0) { + for (u64 i = 0; i < src->num_netid_buckets; ++i) { + ss->netid_buckets[i] = src->netid_buckets[i]; + } + } else { + MEMZERO(ss->netid_buckets, sizeof(*ss->netid_buckets) * ss->num_netid_buckets); } /* Copy entities */ @@ -500,6 +504,23 @@ struct sim_snapshot *sim_snapshot_from_closest_tick_lte(struct sim_client *clien return ss; } +/* Returns the snapshot at nearest valid tick >= supplied tick */ +struct sim_snapshot *sim_snapshot_from_closest_tick_gte(struct sim_client *client, u64 tick) +{ + struct sim_snapshot *ss = sim_snapshot_from_tick(client, tick); + if (!ss->valid) { + /* Degenerate to linear search */ + ss = sim_snapshot_from_tick(client, client->first_tick); + while (ss->valid) { + if (ss->tick >= tick) { + break; + } + ss = sim_snapshot_from_tick(client, ss->next_tick); + } + } + return ss; +} + /* ========================== * * Snapshot lerp * ========================== */ @@ -555,7 +576,7 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_client *client, str * Snapshot encode * ========================== */ -void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_ent *receiver_client, struct sim_snapshot *ss0, struct sim_snapshot *ss1) +void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_client *receiver, struct sim_snapshot *ss0, struct sim_snapshot *ss1) { __prof; @@ -565,7 +586,7 @@ void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_ent *receiver_cli bw_write_uv(bw, ss1->continuity_gen); bw_write_uv(bw, ss1->phys_iteration); - bw_write_u128(bw, sim_ent_get_netid(receiver_client).v); + bw_write_u128(bw, receiver->client_ent_netid.v); /* Ents */ if (ss1->num_ents_allocated == ss0->num_ents_allocated) { diff --git a/src/sim.h b/src/sim.h index 08e34ce4..6b4796ab 100644 --- a/src/sim.h +++ b/src/sim.h @@ -79,17 +79,20 @@ struct sim_client { struct sim_client_handle next_in_bucket; struct sim_client_handle prev_in_bucket; - /* The client entity's net id in the master sim (if one is present) */ + /* The client entity's net id in the master sim (if relevant) */ struct sim_netid client_ent_netid; - /* This is the last confirmed tick of ours that we know this client has received */ + /* This is the highest confirmed tick of ours that we know this client has received */ u64 ack; - /* This is the last confirmed ack of ours that we know this client has received (this + /* This is the highest confirmed ack of ours that we know this client has received (this * can be used to determine which client ticks will no longer be delta encoded from and * can therefore be released) */ u64 double_ack; + /* This is the highest tick of their's that we have received */ + u64 highest_received_tick; + /* Snapshots sorted by tick (low to high) */ u64 first_tick; u64 last_tick; @@ -199,12 +202,13 @@ void sim_snapshot_release_ticks_in_range(struct sim_client *client, u64 start, u /* Lookup */ struct sim_snapshot *sim_snapshot_from_tick(struct sim_client *client, u64 tick); struct sim_snapshot *sim_snapshot_from_closest_tick_lte(struct sim_client *client, u64 tick); +struct sim_snapshot *sim_snapshot_from_closest_tick_gte(struct sim_client *client, u64 tick); /* Lerp */ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_client *client, struct sim_snapshot *ss0, struct sim_snapshot *ss1, f64 blend); /* Encode / decode */ -void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_ent *receiver_client, struct sim_snapshot *ss0, struct sim_snapshot *ss1); +void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_client *receiver, struct sim_snapshot *ss0, struct sim_snapshot *ss1); void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss); /* ========================== * diff --git a/src/sim_ent.c b/src/sim_ent.c index 490c6768..b32d5900 100644 --- a/src/sim_ent.c +++ b/src/sim_ent.c @@ -108,7 +108,8 @@ void sim_ent_release(struct sim_ent *ent) INLINE u64 hash_from_netid(struct sim_netid netid) { - return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&netid)); + /* Just use lower 64 bits of netid since it's already randomnized */ + return U128_LO(netid.v); } struct sim_netid sim_ent_get_netid(struct sim_ent *ent) @@ -174,7 +175,7 @@ struct sim_ent *sim_ent_from_netid(struct sim_snapshot *ss, struct sim_netid net { struct sim_ent *res = sim_ent_nil(); u64 num_buckets = ss->num_netid_buckets; - if (num_buckets > 0) { + if (num_buckets > 0 && !sim_netid_eq(netid, SIM_NETID_NIL)) { u64 hash = hash_from_netid(netid); struct sim_ent_bucket *bucket = &ss->netid_buckets[hash % num_buckets]; for (struct sim_ent *e = sim_ent_from_handle(ss, bucket->first); e->valid; e = sim_ent_from_handle(ss, e->next_in_netid_bucket)) { @@ -540,7 +541,7 @@ void sim_ent_decode(struct bitbuff_reader *br, struct sim_ent *e) } struct sim_netid new_netid = sim_ent_get_netid(e); - + e->_netid = old_netid; if (!sim_netid_eq(old_netid, new_netid)) { sim_ent_set_netid(e, new_netid); } diff --git a/src/sim_ent.h b/src/sim_ent.h index 8b408bd8..57ab85cc 100644 --- a/src/sim_ent.h +++ b/src/sim_ent.h @@ -132,6 +132,7 @@ struct sim_ent { struct sim_ent_handle cmd_client; struct sim_control cmd_control; + struct sim_netid cmd_hovered_ent_netid; /* ====================================================================== */ /* Client */ @@ -145,6 +146,7 @@ struct sim_ent { struct sim_control client_control; struct v2 client_cursor_pos; + struct sim_ent_handle client_hovered_ent; struct sim_ent_handle client_control_ent; struct sim_ent_handle client_camera_ent; diff --git a/src/sim_step.c b/src/sim_step.c index 024dfc96..71a1b915 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -124,16 +124,6 @@ void sim_lookup_remove(struct sim_lookup *l, struct sim_lookup_entry *entry) l->first_free_entry = entry; } -struct sim_lookup_key sim_lookup_key_from_client_and_ent_handles(struct sim_client_handle client_handle, struct sim_ent_handle ent_handle) -{ - struct sim_lookup_key key = ZI; - struct string b0 = STRING_FROM_STRUCT(&client_handle); - struct string b1 = STRING_FROM_STRUCT(&ent_handle); - key.hash = hash_fnv64(HASH_FNV64_BASIS, b0); - key.hash = hash_fnv64(key.hash, b1); - return key; -} - struct sim_lookup_key sim_lookup_key_from_two_handles(struct sim_ent_handle h0, struct sim_ent_handle h1) { struct sim_lookup_key key = ZI; @@ -144,13 +134,6 @@ struct sim_lookup_key sim_lookup_key_from_two_handles(struct sim_ent_handle h0, return key; } -struct sim_lookup_key sim_lookup_key_from_client_handle(struct sim_client_handle handle) -{ - struct sim_lookup_key key = ZI; - key.hash = hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&handle)); - return key; -} - /* ========================== * * Sim accel * ========================== */ @@ -159,7 +142,6 @@ struct sim_accel sim_accel_alloc(void) { struct sim_accel accel = ZI; accel.space = space_alloc(1, 256); - accel.client_lookup = sim_lookup_alloc(4096); accel.contact_lookup = sim_lookup_alloc(4096); #if COLLIDER_DEBUG accel.collision_debug_lookup = sim_lookup_alloc(4096); @@ -173,7 +155,6 @@ void sim_accel_release(struct sim_accel *accel) sim_lookup_release(&accel->collision_debug_lookup); #endif sim_lookup_release(&accel->contact_lookup); - sim_lookup_release(&accel->client_lookup); space_release(accel->space); } @@ -182,7 +163,6 @@ void sim_accel_rebuild(struct sim_snapshot *ss, struct sim_accel *accel) /* FIXME: Rebuild collision debug lookup */ space_reset(accel->space); - sim_lookup_reset(&accel->client_lookup); sim_lookup_reset(&accel->contact_lookup); /* Reset ent space handles */ @@ -198,10 +178,6 @@ void sim_accel_rebuild(struct sim_snapshot *ss, struct sim_accel *accel) for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) { struct sim_ent *ent = &ss->ents[sim_ent_index]; if (!sim_ent_is_valid_and_active(ent)) continue; - if (sim_ent_has_prop(ent, SIM_ENT_PROP_CLIENT)) { - struct sim_lookup_key key = sim_lookup_key_from_client_handle(ent->client_handle); - sim_lookup_set(&accel->client_lookup, key, ent->handle); - } if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) { struct sim_lookup_key contact_lookup_key = sim_lookup_key_from_two_handles(ent->contact_constraint_data.e0, ent->contact_constraint_data.e1); sim_lookup_set(&accel->contact_lookup, contact_lookup_key, ent->handle); @@ -223,7 +199,8 @@ INTERNAL void spawn_test_entities(struct sim_snapshot *world, struct v2 offset) /* Enemy */ { - struct sim_ent *e = sim_ent_alloc_net_src(root); + //struct sim_ent *e = sim_ent_alloc_net_src(root); + struct sim_ent *e = sim_ent_alloc_local(root); struct v2 pos = V2(1, -2); pos = v2_add(pos, offset); @@ -689,6 +666,9 @@ void sim_step(struct sim_step_ctx *ctx) } } + /* Dereference hovered ent */ + client_ent->client_hovered_ent = sim_ent_from_netid(world, cmd_ent->cmd_hovered_ent_netid)->handle; + u32 flags = control->flags; if (flags & SIM_CONTROL_FLAG_DRAG) { if (!(old_control.flags & SIM_CONTROL_FLAG_DRAG)) { @@ -1192,6 +1172,7 @@ void sim_step(struct sim_step_ctx *ctx) struct sim_ent *target_ent = sim_ent_from_handle(world, joint_ent->mouse_joint_data.target); if (start_dragging) { +#if 0 struct xform mouse_xf = xform_from_pos(cursor); struct collider_shape mouse_shape = ZI; mouse_shape.points[0] = V2(0, 0); @@ -1213,7 +1194,11 @@ void sim_step(struct sim_step_ctx *ctx) } } } +#else + target_ent = sim_ent_from_handle(world, client_ent->client_hovered_ent); +#endif } + if (stop_dragging) { target_ent = sim_ent_nil(); } diff --git a/src/sim_step.h b/src/sim_step.h index 9ef8cb59..5938b7d5 100644 --- a/src/sim_step.h +++ b/src/sim_step.h @@ -45,9 +45,7 @@ void sim_lookup_set(struct sim_lookup *l, struct sim_lookup_key key, struct sim_ void sim_lookup_remove(struct sim_lookup *l, struct sim_lookup_entry *entry); -struct sim_lookup_key sim_lookup_key_from_client_and_ent_handles(struct sim_client_handle client_handle, struct sim_ent_handle ent_handle); struct sim_lookup_key sim_lookup_key_from_two_handles(struct sim_ent_handle h0, struct sim_ent_handle h1); -struct sim_lookup_key sim_lookup_key_from_client_handle(struct sim_client_handle handle); /* ========================== * * Sim accel @@ -58,7 +56,6 @@ struct sim_lookup_key sim_lookup_key_from_client_handle(struct sim_client_handle struct sim_accel { struct space *space; - struct sim_lookup client_lookup; struct sim_lookup contact_lookup; #if COLLIDER_DEBUG struct sim_lookup collision_debug_lookup; diff --git a/src/string.c b/src/string.c index cbfc13ab..585b1880 100644 --- a/src/string.c +++ b/src/string.c @@ -36,7 +36,7 @@ struct string string_from_char(struct arena *arena, char c) }; } -struct string string_from_uint(struct arena *arena, u64 n, u32 base) +struct string string_from_uint(struct arena *arena, u64 n, u64 base, u64 zfill) { /* Base too large */ ASSERT(base <= (ARRAY_COUNT(INT_CHARS) - 1)); @@ -52,6 +52,11 @@ struct string string_from_uint(struct arena *arena, u64 n, u32 base) n /= base; } while (n > 0); + while (len < zfill) { + string_from_char(scratch.arena, '0'); + ++len; + } + /* Reverse text into final string */ u8 *final_text = arena_push_array(arena, u8, len); for (u64 i = 0; i < len; ++i) { @@ -66,7 +71,7 @@ struct string string_from_uint(struct arena *arena, u64 n, u32 base) }; } -struct string string_from_int(struct arena *arena, i64 n, u32 base) +struct string string_from_int(struct arena *arena, i64 n, u64 base, u64 zfill) { u8 *final_text = arena_dry_push(arena, u8); u8 len = 0; @@ -77,7 +82,7 @@ struct string string_from_int(struct arena *arena, i64 n, u32 base) n = -n; } /* Push unsigned number */ - struct string uint_str = string_from_uint(arena, n, base); + struct string uint_str = string_from_uint(arena, n, base, zfill); return (struct string) { .len = len + uint_str.len, .text = final_text @@ -87,7 +92,7 @@ struct string string_from_int(struct arena *arena, i64 n, u32 base) struct string string_from_ptr(struct arena *arena, void *ptr) { struct string prepend = string_copy(arena, LIT("0x")); - struct string uint_str = string_from_uint(arena, (u64)ptr, 16); + struct string uint_str = string_from_uint(arena, (u64)ptr, 16, sizeof(ptr)); return (struct string) { .len = prepend.len + uint_str.len, .text = prepend.text @@ -164,9 +169,9 @@ struct string string_from_handle(struct arena *arena, u64 v0, u64 v1) struct string res = ZI; res.text = arena_dry_push(arena, u8); res.len += string_copy(arena, LIT("h")).len; - res.len += string_from_uint(arena, v0, 16).len; + res.len += string_from_uint(arena, v0, 16, 0).len; res.len += string_copy(arena, LIT("x")).len; - res.len += string_from_uint(arena, v1, 16).len; + res.len += string_from_uint(arena, v1, 16, 0).len; return res; } @@ -458,15 +463,15 @@ struct string string_formatv(struct arena *arena, struct string fmt, va_list arg } break; case FMT_TYPE_UINT: { - parsed_str = string_from_uint(arena, arg.value.uint, 10); + parsed_str = string_from_uint(arena, arg.value.uint, 10, 0); } break; case FMT_TYPE_SINT: { - parsed_str = string_from_int(arena, arg.value.sint, 10); + parsed_str = string_from_int(arena, arg.value.sint, 10, 0); } break; case FMT_TYPE_HEX: { - parsed_str = string_from_uint(arena, arg.value.sint, 16); + parsed_str = string_from_uint(arena, arg.value.sint, 16, 0); } break; case FMT_TYPE_PTR: { diff --git a/src/string.h b/src/string.h index 6aed1fa4..b7d07646 100644 --- a/src/string.h +++ b/src/string.h @@ -11,8 +11,8 @@ struct string_array { * ========================== */ struct string string_from_char(struct arena *arena, char c); -struct string string_from_uint(struct arena *arena, u64 n, u32 base); -struct string string_from_int(struct arena *arena, i64 n, u32 base); +struct string string_from_uint(struct arena *arena, u64 n, u64 base, u64 zfill); +struct string string_from_int(struct arena *arena, i64 n, u64 base, u64 zfill); struct string string_from_ptr(struct arena *arena, void *ptr); struct string string_from_float(struct arena *arena, f64 f, u32 precision); struct string string_from_handle(struct arena *arena, u64 v0, u64 v1); diff --git a/src/user.c b/src/user.c index bfb85f8c..d141f9e0 100644 --- a/src/user.c +++ b/src/user.c @@ -86,6 +86,7 @@ GLOBAL struct { /* User -> local sim */ struct sys_mutex user_sim_cmd_mutex; struct sim_control user_sim_cmd_control; + struct sim_netid user_sim_cmd_hovered_ent_netid; u64 last_user_sim_cmd_gen; u64 user_sim_cmd_gen; @@ -347,6 +348,31 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e struct string res = ZI; res.text = arena_dry_push(arena, u8); + { + res.len += string_copy(arena, LIT("net: ")).len; + + struct sim_netid netid = sim_ent_get_netid(ent); + if (!sim_netid_eq(netid, SIM_NETID_NIL)) { + res.len += string_copy(arena, LIT(" [")).len; + res.len += string_from_uint(arena, (U128_HI(netid.v) >> 36) & 0xFFFFFFF, 16, 7).len; + res.len += string_copy(arena, LIT("]")).len; + } + + b32 transmitting = sim_ent_has_prop(ent, SIM_ENT_PROP_NET_SRC); + b32 receiving = sim_ent_has_prop(ent, SIM_ENT_PROP_NET_DST); + if (transmitting & receiving) { + res.len += string_copy(arena, LIT(" recv & send")).len; + } else if (transmitting) { + res.len += string_copy(arena, LIT(" send")).len; + } else if (receiving) { + res.len += string_copy(arena, LIT(" recv")).len; + } else { + res.len += string_copy(arena, LIT(" local")).len; + } + + res.len += string_copy(arena, LIT("\n")).len; + } + { res.len += string_copy(arena, LIT("props: 0x")).len; for (u64 chunk_index = ARRAY_COUNT(ent->props); chunk_index-- > 0;) { @@ -363,18 +389,6 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e res.len += string_copy(arena, LIT("\n")).len; } - { - struct sim_netid netid = sim_ent_get_netid(ent); - if (!sim_netid_eq(netid, SIM_NETID_NIL)) { - res.len += string_copy(arena, LIT("net id: 0x")).len; - u64 hi = U128_HI(netid.v); - u64 lo = U128_LO(netid.v); - res.len += string_from_uint(arena, hi, 16).len; - res.len += string_from_uint(arena, lo, 16).len; - res.len += string_copy(arena, LIT("\n")).len; - } - } - if (!sim_ent_handle_eq(ent->parent, SIM_ENT_ROOT_HANDLE)) { res.len += string_format(arena, LIT("parent: <%F>\n"), FMT_HANDLE(ent->parent)).len; } @@ -608,7 +622,6 @@ INTERNAL void user_update(void) for (u64 ent_index = 0; ent_index < events.count; ++ent_index) { struct sys_event *event = &events.events[ent_index]; - if (event->kind == SYS_EVENT_KIND_QUIT) { app_exit(); } @@ -1517,6 +1530,7 @@ INTERNAL void user_update(void) u32 old_flags = G.user_sim_cmd_control.flags; G.user_sim_cmd_control = control; G.user_sim_cmd_control.flags |= old_flags; + G.user_sim_cmd_hovered_ent_netid = sim_ent_get_netid(hovered_ent); sys_mutex_unlock(&lock); } } @@ -1850,6 +1864,7 @@ INTERNAL void sim_ent_sync_remote(struct sim_ent *local, struct sim_ent *remote) local->ss = old.ss; local->handle = old.handle; local->net_src_client = remote_client_handle; + local->_netid = old._netid; local->parent = old.parent; local->prev = old.prev; local->next = old.next; @@ -1863,6 +1878,7 @@ INTERNAL void sim_ent_sync_remote(struct sim_ent *local, struct sim_ent *remote) /* Translate remote handles */ translate(client_control_ent); translate(client_camera_ent); + translate(client_hovered_ent); translate(client_dbg_drag_joint_ent); translate(controlling_client); translate(move_joint); @@ -1940,7 +1956,18 @@ INTERNAL void sim_snapshot_sync_remote_ents(struct sim_snapshot *local_ss, struc +struct sim_decode_node { + struct sim_client *client; + u64 tick; + u64 base_tick; + struct string tmp_encoded; + struct sim_decode_node *next; +}; +struct sim_decode_queue { + struct sim_decode_node *first; + struct sim_decode_node *last; +}; INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) @@ -1973,7 +2000,9 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) struct sim_client *user_input_client = sim_client_alloc(store); /* Stores snapshots containing commands to be published to both local & master clients */ struct sim_client *local_client = sim_client_alloc(store); /* Stores snapshots produced locally */ struct sim_client *publish_client = sim_client_alloc(store); /* Stores versions of local snapshots that will be published to remote sims */ + struct sim_client *master_client = sim_client_nil(); /* Stores snapshots received from master (if relevant) */ + b32 initialized_from_master = false; u64 step_tick = 0; i64 last_publish_ns = 0; @@ -1991,6 +2020,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) ++step_tick; /* Read net messages */ + struct sim_decode_queue queue = ZI; { host_update(host); struct host_event_array host_events = host_pop_events(scratch.arena, host); @@ -2037,26 +2067,54 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) struct bitbuff_reader decoder_br = br_from_bitbuff(&decoder_bb); u64 base_tick = br_read_uv(&decoder_br); u64 tick = br_read_uv(&decoder_br); - if (tick > client->last_tick) { - struct sim_snapshot *base_ss = sim_snapshot_from_tick(client, base_tick); - if (base_ss->tick == base_tick) { - if (client == master_client || (tick == client->last_tick + 1 || tick > client->last_tick + 100)) { - /* Alloc & decode snapshot */ - struct sim_snapshot *ss = sim_snapshot_alloc(client, base_ss, tick); - sim_snapshot_decode(&decoder_br, ss); - for (u64 i = 0; i < ss->num_ents_reserved; ++i) { - struct sim_ent *ent = &ss->ents[i]; - if (ent->valid && sim_ent_has_prop(ent, SIM_ENT_PROP_NET_DST)) { - sim_ent_disable_prop(ent, SIM_ENT_PROP_NET_DST); - sim_ent_enable_prop(ent, SIM_ENT_PROP_NET_SRC); - } + + struct string tmp_encoded = ZI; + tmp_encoded.len = br_num_bytes_left(&decoder_br); + tmp_encoded.text = br_read_bytes_raw(&decoder_br, tmp_encoded.len); + if (!tmp_encoded.text) tmp_encoded.len = 0; + + struct sim_snapshot *base_ss = sim_snapshot_from_tick(client, base_tick); + if (base_ss->tick == base_tick) { + if (is_master) { + /* Decode incoming slave client snapshots */ + b32 should_decode = tick == client->highest_received_tick + 1 || client->highest_received_tick == 0; + if (should_decode) { + struct sim_decode_node *node = arena_push_zero(scratch.arena, struct sim_decode_node); + node->client = client; + node->tick = tick; + node->base_tick = base_tick; + node->tmp_encoded = tmp_encoded; + if (queue.last) { + queue.last->next = node; + } else { + queue.first = node; + } + queue.last = node; + if (tick > client->highest_received_tick) { + client->highest_received_tick = tick; } } } else { - /* We do not have the tick that the incoming delta is based from */ - ASSERT(false); + /* Decode incoming master client snapshots (only the newest one) */ + b32 should_decode = tick > client->highest_received_tick; + if (should_decode) { + struct sim_decode_node *node = queue.first ? queue.first : arena_push_zero(scratch.arena, struct sim_decode_node); + node->client = client; + node->tick = tick; + node->base_tick = base_tick; + node->tmp_encoded = tmp_encoded; + queue.first = node; + queue.last = node; + if (tick > client->highest_received_tick) { + client->highest_received_tick = tick; + } + } } + } else { + /* We do not have the tick that the incoming delta is based from */ + ASSERT(false); } + tmp_encoded_len = br_read_uv(&msg_br); } } @@ -2067,16 +2125,47 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) } } - if (master_client->valid) { - if (master_client->last_tick > step_tick && (master_client->last_tick - step_tick) > 50) { + /* Decode incoming snapshots */ + for (struct sim_decode_node *n = queue.first; n; n = n->next) { + struct sim_client *client = n->client; + u64 base_tick = n->base_tick; + u64 tick = n->tick; + struct sim_snapshot *base_ss = sim_snapshot_from_tick(client, base_tick); + if (base_ss->tick == base_tick) { + struct bitbuff bb = bitbuff_from_string(n->tmp_encoded); + struct bitbuff_reader br = br_from_bitbuff(&bb); + + /* Alloc & decode snapshot */ + struct sim_snapshot *ss = sim_snapshot_alloc(client, base_ss, tick); + sim_snapshot_decode(&br, ss); + for (u64 i = 0; i < ss->num_ents_reserved; ++i) { + struct sim_ent *ent = &ss->ents[i]; + if (ent->valid && sim_ent_has_prop(ent, SIM_ENT_PROP_NET_DST)) { + sim_ent_disable_prop(ent, SIM_ENT_PROP_NET_DST); + sim_ent_enable_prop(ent, SIM_ENT_PROP_NET_SRC); + } + } + } else { + /* We do not have the tick that the incoming delta is based from. + * This decode should never have been queued in the first place. */ + ASSERT(false); + } + } + + if (!is_master && !initialized_from_master) { + if (master_client->valid && master_client->last_tick > 0) { step_tick = master_client->last_tick; + initialized_from_master = true; + } else { + step_tick = 0; + goto skip_step; } } /* Create user input */ { struct sim_snapshot *prev_user_input_ss = sim_snapshot_from_tick(user_input_client, user_input_client->last_tick); - struct sim_snapshot *user_input_ss = sim_snapshot_alloc(user_input_client, prev_user_input_ss, step_tick + 50); + struct sim_snapshot *user_input_ss = sim_snapshot_alloc(user_input_client, prev_user_input_ss, step_tick);; struct sim_ent *user_input_root = sim_ent_from_handle(user_input_ss, SIM_ENT_ROOT_HANDLE); /* Find / create local control cmd ent */ struct sim_ent *control_cmd_ent = sim_ent_find_first_match_one(user_input_ss, SIM_ENT_PROP_CMD_CONTROL); @@ -2089,6 +2178,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) { struct sys_lock lock = sys_mutex_lock_e(&G.user_sim_cmd_mutex); control_cmd_ent->cmd_control = G.user_sim_cmd_control; + control_cmd_ent->cmd_hovered_ent_netid = G.user_sim_cmd_hovered_ent_netid; ++G.user_sim_cmd_gen; sys_mutex_unlock(&lock); } @@ -2109,16 +2199,14 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) if (client->valid) { /* Create client ent if necessary */ if (is_master && client != publish_client && client != local_client && client != master_client) { - struct sim_lookup_key key = sim_lookup_key_from_client_handle(client->handle); - struct sim_lookup_entry *client_entry = sim_lookup_get(&accel.client_lookup, key); - struct sim_ent *client_ent = client_entry ? sim_ent_from_handle(local_ss, client_entry->ent) : sim_ent_nil(); + struct sim_ent *client_ent = sim_ent_from_netid(local_ss, client->client_ent_netid); if (!client_ent->valid) { /* FIXME: Client ent never released upon disconnect */ client_ent = sim_ent_alloc_net_src(local_root); client_ent->client_handle = client->handle; sim_ent_enable_prop(client_ent, SIM_ENT_PROP_CLIENT); sim_ent_enable_prop(client_ent, SIM_ENT_PROP_ACTIVE); - sim_lookup_set(&accel.client_lookup, key, client_ent->handle); + client->client_ent_netid = sim_ent_get_netid(client_ent); if (client == user_input_client) { local_ss->local_client_netid = sim_ent_get_netid(client_ent); } @@ -2140,36 +2228,65 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) } } - /* Point incoming client cmds to correct client ents */ if (is_master) { + /* Point incoming client cmds to correct client ents */ for (u64 i = 0; i < local_ss->num_ents_reserved; ++i) { struct sim_ent *ent = &local_ss->ents[i]; if (ent->valid && sim_ent_has_prop(ent, SIM_ENT_PROP_NET_DST)) { - struct sim_ent *client_ent = sim_ent_nil(); - { - struct sim_client_handle src_client = ent->net_src_client; - struct sim_lookup_key key = sim_lookup_key_from_client_handle(src_client); - struct sim_lookup_entry *client_entry = sim_lookup_get(&accel.client_lookup, key); - client_ent = client_entry ? sim_ent_from_handle(local_ss, client_entry->ent) : sim_ent_nil(); - } + struct sim_client *src_client = sim_client_from_handle(store, ent->net_src_client); + struct sim_ent *client_ent = sim_ent_from_netid(local_ss, src_client->client_ent_netid); ent->cmd_client = client_ent->handle; } } - } - - /* Release unneeded snapshots */ - for (u64 i = 0; i < store->num_clients_reserved; ++i) { - struct sim_client *client = &store->clients[i]; - if (client->valid) { - u64 keep_count = 100; - if (client->last_tick > keep_count) { - u64 keep_tick = client->last_tick - keep_count; - sim_snapshot_release_ticks_in_range(client, 0, keep_tick - 1); + } else { + /* Mark all local commands as networked */ + for (u64 i = 0; i < local_ss->num_ents_reserved; ++i) { + struct sim_ent *ent = &local_ss->ents[i]; + if (ent->valid && sim_ent_has_prop(ent, SIM_ENT_PROP_CMD_CONTROL) && sim_ent_has_prop(ent, SIM_ENT_PROP_NET_DST)) { + sim_ent_enable_prop(ent, SIM_ENT_PROP_NET_SRC); } } } - /* Release unneeded snapshots */ + /* Release unneeded received snapshots */ + u64 oldest_client_ack = 0; + for (u64 i = 0; i < store->num_clients_reserved; ++i) { + struct sim_client *client = &store->clients[i]; + if (client->valid && client != local_client && client != publish_client && client != user_input_client) { + if (client->double_ack > 0) { + u64 keep_tick = max_u64(min_u64(client->double_ack, step_tick), 1); + sim_snapshot_release_ticks_in_range(client, 0, keep_tick - 1); + } + if (client->ack < oldest_client_ack || oldest_client_ack == 0) { + oldest_client_ack = client->ack; + } + } + } + + /* Release unneeded published snapshots */ + { + u64 keep_tick = oldest_client_ack; + if (keep_tick == 0 && publish_client->last_tick > 0) { + keep_tick = publish_client->last_tick - 1; + } + if (keep_tick > 0) { + --keep_tick; + } + sim_snapshot_release_ticks_in_range(publish_client, 0, keep_tick); + } + + /* Release unneeded user input snapshots */ + sim_snapshot_release_ticks_in_range(user_input_client, 0, step_tick - 1); + + /* Release old local snapshots */ + { + u64 keep_range = 100; + if (local_client->last_tick > keep_range) { + u64 keep_tick = local_client->last_tick - keep_range; + sim_snapshot_release_ticks_in_range(local_client, 0, keep_tick); + } + } + #if 0 #if 0 u64 oldest_client_ack = 0; @@ -2245,7 +2362,12 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) } #else { - struct sim_snapshot *pub_ss = sim_snapshot_alloc(publish_client, sim_snapshot_from_tick(publish_client, publish_client->last_tick), local_ss->tick); + struct sim_snapshot *pub_ss; + if (is_master) { + pub_ss = sim_snapshot_alloc(publish_client, sim_snapshot_from_tick(publish_client, publish_client->last_tick), local_ss->tick); + } else { + pub_ss = sim_snapshot_alloc(publish_client, sim_snapshot_from_tick(publish_client, publish_client->last_tick), local_ss->tick + 5); + } sim_snapshot_sync_remote_ents(pub_ss, local_ss); } #endif @@ -2273,23 +2395,16 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) for (u64 i = 0; i < store->num_clients_reserved; ++i) { struct sim_client *client = &store->clients[i]; if (client->valid && client != user_input_client && client != local_client && client != publish_client) { - struct sim_ent *client_ent = sim_ent_nil(); - { - struct sim_lookup_key key = sim_lookup_key_from_client_handle(client->handle); - struct sim_lookup_entry *client_entry = sim_lookup_get(&accel.client_lookup, key); - client_ent = client_entry ? sim_ent_from_handle(local_ss, client_entry->ent) : sim_ent_nil(); - } - struct bitbuff_writer msg_bw = bw_from_bitbuff(&msg_writer_bb); - bw_write_uv(&msg_bw, client->last_tick); /* ack */ - bw_write_uv(&msg_bw, client->ack); /* double ack */ + bw_write_uv(&msg_bw, client->highest_received_tick); /* ack */ + bw_write_uv(&msg_bw, client->ack); /* double ack */ struct sim_snapshot *base_ss = sim_snapshot_from_tick(publish_client, client->ack); struct sim_snapshot *publish_ss; if (client == master_client) { /* If sending to master, start sending all snapshots since last ack */ - publish_ss = sim_snapshot_from_tick(publish_client, base_ss->tick + 1); + publish_ss = sim_snapshot_from_closest_tick_gte(publish_client, base_ss->tick + 1); } else { /* If sending to slave, only send latest snapshot */ publish_ss = sim_snapshot_from_tick(publish_client, publish_client->last_tick); @@ -2301,7 +2416,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) { bw_write_uv(&snapshot_bw, base_ss->tick); bw_write_uv(&snapshot_bw, publish_ss->tick); - sim_snapshot_encode(&snapshot_bw, client_ent, base_ss, publish_ss); + sim_snapshot_encode(&snapshot_bw, client, base_ss, publish_ss); tmp_snapshot_encoded.len = bw_num_bytes_written(&snapshot_bw); tmp_snapshot_encoded.text = bw_get_written_raw(&snapshot_bw); } @@ -2332,6 +2447,8 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) sys_mutex_unlock(&lock); } + skip_step: + /* Send host messages */ host_update(host); __profframe("Local sim");