diff --git a/src/config.h b/src/config.h index 929d6213..2fbb4e60 100644 --- a/src/config.h +++ b/src/config.h @@ -60,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 1 +#define BITBUFF_DEBUG RTC #define BITBUFF_TEST RTC /* If enabled, things like network writes & memory allocations will be tracked in a global statistics struct */ diff --git a/src/sim.h b/src/sim.h index 2cab1ca6..a371b858 100644 --- a/src/sim.h +++ b/src/sim.h @@ -88,7 +88,7 @@ struct sim_client { /* 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) */ + * therefore can be released) */ u64 double_ack; /* This is the highest tick of their's that we have received */ diff --git a/src/sim_step.c b/src/sim_step.c index 9be58014..88cf85e1 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -340,7 +340,6 @@ void sim_step(struct sim_step_ctx *ctx) struct sim_client *user_input_client = ctx->user_input_client; struct sim_client *publish_client = ctx->publish_client; struct sim_client *master_client = ctx->master_client; - (UNUSED)master_client; i64 sim_dt_ns = ctx->sim_dt_ns; @@ -357,13 +356,14 @@ void sim_step(struct sim_step_ctx *ctx) struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID); /* ========================== * - * Sync remote ents + * Sync ents from cmd producing clients * ========================== */ { + /* FIXME: Ensure only cmds are synced to master client */ for (u64 client_index = 0; client_index < client_store->num_clients_reserved; ++client_index) { struct sim_client *client = &client_store->clients[client_index]; - if (client->valid && client != world_client && client != publish_client) { + if (client->valid && client != master_client && client != world_client && client != publish_client) { struct sim_ent *client_ent = sim_ent_from_id(world, client->ent_id); /* Create client ent if necessary */ @@ -1259,19 +1259,16 @@ void sim_step(struct sim_step_ctx *ctx) * Sync to publish client * ========================== */ - if (publish_client->valid) { - struct sim_snapshot *pub_world = sim_snapshot_from_tick(publish_client, world->tick); - if (!pub_world->valid) { - struct sim_snapshot *prev_pub_world = sim_snapshot_from_tick(publish_client, world->tick - 1); - pub_world = sim_snapshot_alloc(publish_client, prev_pub_world, world->tick); - /* Sync */ - sim_snapshot_sync_ents(pub_world, world, world_client->ent_id); - pub_world->sim_dt_ns = world->sim_dt_ns; - pub_world->sim_time_ns = world->sim_time_ns; - pub_world->continuity_gen = world->continuity_gen; - pub_world->phys_iteration = world->phys_iteration; - pub_world->local_client_ent = world->local_client_ent; - } + if (publish_client->valid && world->tick > publish_client->last_tick) { + struct sim_snapshot *prev_pub_world = sim_snapshot_from_tick(publish_client, publish_client->last_tick); + struct sim_snapshot *pub_world = sim_snapshot_alloc(publish_client, prev_pub_world, world->tick); + /* Sync */ + sim_snapshot_sync_ents(pub_world, world, world_client->ent_id); + pub_world->sim_dt_ns = world->sim_dt_ns; + pub_world->sim_time_ns = world->sim_time_ns; + pub_world->continuity_gen = world->continuity_gen; + pub_world->phys_iteration = world->phys_iteration; + pub_world->local_client_ent = world->local_client_ent; } /* ========================== * diff --git a/src/user.c b/src/user.c index b0d87abe..534fba1d 100644 --- a/src/user.c +++ b/src/user.c @@ -97,7 +97,7 @@ GLOBAL struct { /* Rolling window of local sim -> user publish time deltas */ i64 last_local_to_user_snapshot_published_at_ns; - i64 local_to_user_snapshot_publish_dts_ns[50]; + i64 local_to_user_snapshot_publish_dts_ns[10]; i64 local_to_user_snapshot_publish_dts_index; i64 average_local_to_user_snapshot_publish_dt_ns; @@ -1943,7 +1943,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) struct temp_arena scratch = scratch_begin_no_conflict(); { __profscope(local_sim_sleep); - sleep_frame(last_tick_ns, step_dt_ns * compute_timescale); + sleep_frame(last_tick_ns, step_dt_ns / compute_timescale); last_tick_ns = sys_time_ns(); } @@ -2004,7 +2004,8 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) if (base_ss->tick == base_tick) { if (is_master) { /* Queue incoming slave client snapshot for decoding */ - b32 should_decode = tick == client->highest_received_tick + 1 || client->highest_received_tick == 0; + //b32 should_decode = tick == client->highest_received_tick + 1 || client->highest_received_tick == 0; + b32 should_decode = tick > client->highest_received_tick; if (should_decode) { struct sim_ss_decode_node *node = arena_push_zero(scratch.arena, struct sim_ss_decode_node); node->client = client; @@ -2131,44 +2132,32 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) /* Release unneeded user input snapshots */ sim_snapshot_release_ticks_in_range(user_input_client, 0, local_client->first_tick - 1); + u64 sim_base_tick = local_client->last_tick; + u64 sim_to_tick = sim_base_tick + 1; if (master_client->valid) { last_tick_from_master = master_client->last_tick; last_ticks_ahead_from_master = master_client->ack - last_tick_from_master; - if (last_ticks_ahead_from_master > 4) { + if (math_abs_i64(last_ticks_ahead_from_master) > 50) { + /* We're too far from master time, snap to last sim time */ + i64 rtt_ns = master_client->rtt_ns; + f64 rtt_tick_ratio = (f64)(rtt_ns + (step_dt_ns - 1)) / (f64)step_dt_ns; + i64 num_predict_ticks = math_round_to_int64(rtt_tick_ratio) + 2; + sim_base_tick = last_tick_from_master; + sim_to_tick = last_tick_from_master + num_predict_ticks; + sim_snapshot_release_ticks_in_range(local_client, sim_base_tick + 1, U64_MAX); + sim_snapshot_release_ticks_in_range(user_input_client, sim_base_tick + 1, U64_MAX); + compute_timescale = 1.1; + } else if (last_ticks_ahead_from_master > 4) { + /* Slow down time to bring sim time closer to master time */ compute_timescale = 0.9; } else if (last_ticks_ahead_from_master < 2) { + /* Speed up time to give master more inputs to work with */ compute_timescale = 1.1; } else { compute_timescale = 1; } } -#if 0 - /* Determine step tick */ - u64 desired_step_tick = 0; - if (is_master) { - desired_step_tick = local_client->last_tick + 1; - } else { - i64 rtt_ns = master_client->rtt_ns; - f64 rtt_tick_ratio = (f64)(rtt_ns + (step_dt_ns - 1)) / (f64)step_dt_ns; - i64 num_predict_ticks = math_round_to_int64(rtt_tick_ratio); - num_predict_ticks += 2; /* Jitter buffer */ - desired_step_tick = master_client->last_tick + num_predict_ticks; - } -#else - /* Snap to master sim tick if too far */ - i64 num_sim_ticks = 1; - if (!is_master && math_abs_i64(last_ticks_ahead_from_master) > 50) { - i64 rtt_ns = master_client->rtt_ns; - f64 rtt_tick_ratio = (f64)(rtt_ns + (step_dt_ns - 1)) / (f64)step_dt_ns; - i64 num_predict_ticks = math_round_to_int64(rtt_tick_ratio) + 2; - i64 desired_step_tick = master_client->last_tick + num_predict_ticks; - sim_snapshot_release_ticks_in_range(local_client, desired_step_tick, U64_MAX); - sim_snapshot_release_ticks_in_range(user_input_client, desired_step_tick, U64_MAX); - num_sim_ticks = desired_step_tick - num_sim_ticks; - } -#endif - @@ -2177,7 +2166,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) /* 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, local_client->last_tick + num_sim_ticks); + struct sim_snapshot *user_input_ss = sim_snapshot_alloc(user_input_client, prev_user_input_ss, sim_to_tick); struct sim_ent *user_input_root = sim_ent_from_id(user_input_ss, SIM_ENT_ROOT_ID); /* 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); @@ -2214,6 +2203,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) /* Step */ +#if 1 { struct sim_step_ctx ctx = ZI; ctx.is_master = is_master; @@ -2225,9 +2215,40 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) ctx.publish_client = publish_client; if (is_master) { - u64 prev_tick = local_client->last_tick; - struct sim_snapshot *prev_world = sim_snapshot_from_tick(local_client, prev_tick); - ctx.world = sim_snapshot_alloc(local_client, prev_world, prev_tick + 1); + ASSERT(sim_to_tick == sim_base_tick + 1); + struct sim_snapshot *prev_world = sim_snapshot_from_tick(local_client, sim_base_tick); + ctx.world = sim_snapshot_alloc(local_client, prev_world, sim_to_tick); + sim_step(&ctx); + } else { + struct sim_snapshot *master_ss = sim_snapshot_from_tick(master_client, sim_base_tick); + if (master_ss->valid) { + local_client->ent_id = master_ss->local_client_ent; + user_input_client->ent_id = master_ss->local_client_ent; + + struct sim_snapshot *prev_world = sim_snapshot_alloc(local_client, master_ss, master_ss->tick); + + while (prev_world->tick < sim_to_tick) { + ctx.world = sim_snapshot_alloc(local_client, prev_world, prev_world->tick + 1); + sim_step(&ctx); + prev_world = ctx.world; + } + } + } + } +#else + { + struct sim_step_ctx ctx = ZI; + ctx.is_master = is_master; + ctx.sim_dt_ns = step_dt_ns; + ctx.accel = &accel; + + ctx.user_input_client = user_input_client; + ctx.master_client = master_client; + ctx.publish_client = publish_client; + + if (is_master) { + struct sim_snapshot *prev_world = sim_snapshot_from_tick(local_client, sim_base_tick); + ctx.world = sim_snapshot_alloc(local_client, prev_world, sim_base_tick + 1); sim_step(&ctx); } else { struct sim_snapshot *master_ss = sim_snapshot_from_tick(master_client, master_client->last_tick); @@ -2246,6 +2267,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) } } } +#endif @@ -2314,16 +2336,18 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) /* Copy local snapshot to user client */ { - struct sim_snapshot *local_world = sim_snapshot_from_tick(local_client, local_client->last_tick); - /* TODO: Double buffer */ - struct sys_lock lock = sys_mutex_lock_e(&G.local_to_user_client_mutex); - struct sim_snapshot *copy_ss = sim_snapshot_alloc(G.local_to_user_client, local_world, local_world->tick); - i64 publish_ns = sys_time_ns(); - copy_ss->publish_dt_ns = publish_ns - last_publish_ns; - copy_ss->publish_time_ns = publish_ns; - last_publish_ns = publish_ns; - sim_snapshot_release_ticks_in_range(G.local_to_user_client, 0, local_world->tick - 1); - sys_mutex_unlock(&lock); + struct sim_snapshot *local_ss = sim_snapshot_from_tick(local_client, local_client->last_tick); + if (local_ss->valid) { + /* TODO: Double buffer */ + struct sys_lock lock = sys_mutex_lock_e(&G.local_to_user_client_mutex); + struct sim_snapshot *copy_ss = sim_snapshot_alloc(G.local_to_user_client, local_ss, local_ss->tick); + i64 publish_ns = sys_time_ns(); + copy_ss->publish_dt_ns = publish_ns - last_publish_ns; + copy_ss->publish_time_ns = publish_ns; + last_publish_ns = publish_ns; + sim_snapshot_release_ticks_in_range(G.local_to_user_client, 0, local_ss->tick - 1); + sys_mutex_unlock(&lock); + } } skip_step: