From 50da5f1bc6ce02a5df8b1295aea9bc0c70e33912 Mon Sep 17 00:00:00 2001 From: jacob Date: Tue, 25 Feb 2025 11:55:07 -0600 Subject: [PATCH] prediction progress --- src/sim_step.c | 100 +++++++++++++++++++++++--- src/sim_step.h | 9 ++- src/user.c | 187 ++++++++++++++++++++++++------------------------- 3 files changed, 188 insertions(+), 108 deletions(-) diff --git a/src/sim_step.c b/src/sim_step.c index 4f084a44..e29ec174 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -334,16 +334,21 @@ void sim_step(struct sim_step_ctx *ctx) __prof; struct temp_arena scratch = scratch_begin_no_conflict(); + b32 is_master = ctx->is_master; struct sim_snapshot *world = ctx->world; + + struct sim_client_store *client_store = world->client->store; + struct sim_client *world_client = world->client; + 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; + i64 sim_dt_ns = ctx->sim_dt_ns; /* ========================== * * Begin frame * ========================== */ - //sys_sleep_precise(rng_rand_f32(0, 0.050)); - //sys_sleep_precise(0.050); - world->sim_dt_ns = max_i64(0, sim_dt_ns); world->sim_time_ns += world->sim_dt_ns; f32 sim_dt = SECONDS_FROM_NS(world->sim_dt_ns); @@ -352,6 +357,69 @@ void sim_step(struct sim_step_ctx *ctx) struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID); + /* ========================== * + * Sync remote ents + * ========================== */ + + { + 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) { + /* Create client ent if necessary */ + if (is_master) { + struct sim_ent *client_ent = sim_ent_from_id(world, client->ent_id); + if (!client_ent->valid) { + /* FIXME: Client ent never released upon disconnect */ + client_ent = sim_ent_alloc_sync_src(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_SYNC_PREDICT); + sim_ent_enable_prop(client_ent, SIM_ENT_PROP_ACTIVE); + client->ent_id = client_ent->id; + if (client == user_input_client) { + user_input_client->ent_id = client_ent->id; + world_client->ent_id = client_ent->id; + world->local_client_ent = client_ent->id; + } + } + } + + /* Sync ents from client */ + { + struct sim_snapshot *src_ss = sim_snapshot_from_tick(client, world->tick); + if (src_ss->valid) { + sim_snapshot_sync(world, src_ss); + if (client == master_client) { + world_client->ent_id = src_ss->local_client_ent; + world->local_client_ent = src_ss->local_client_ent; + } + } + } + } + } + + /* Mark incoming cmds with correct client */ + for (u64 i = 0; i < world->num_ents_reserved; ++i) { + struct sim_ent *ent = &world->ents[i]; + if (ent->valid && sim_ent_has_prop(ent, SIM_ENT_PROP_CMD_CONTROL) && sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_DST)) { + struct sim_client *src_client = sim_client_from_handle(client_store, ent->sync_src_client); + ent->cmd_client = src_client->ent_id; + } + } + + /* Mark any locally created CMDs as sync sources */ + if (!is_master) { + for (u64 i = 0; i < world->num_ents_reserved; ++i) { + struct sim_ent *ent = &world->ents[i]; + if (sim_ent_is_valid_and_active(ent) && sim_ent_has_prop(ent, SIM_ENT_PROP_CMD_CONTROL)) { + if (!sim_ent_id_eq(ent->cmd_client, SIM_ENT_NIL_ID) && sim_ent_id_eq(ent->cmd_client, world->local_client_ent)) { + sim_ent_enable_prop(ent, SIM_ENT_PROP_SYNC_SRC); + } + } + } + } + } + /* ========================== * * Release entities at beginning of frame * ========================== */ @@ -403,7 +471,7 @@ void sim_step(struct sim_step_ctx *ctx) if (sim_ent_has_prop(cmd_ent, SIM_ENT_PROP_CMD_CONTROL)) { struct sim_ent *client_ent = sim_ent_from_id(world, cmd_ent->cmd_client); if (sim_ent_should_simulate(client_ent)) { - if (!ctx->is_master && !sim_ent_id_eq(client_ent->id, world->local_client_ent)) { + if (!is_master && !sim_ent_id_eq(client_ent->id, world->local_client_ent)) { /* We are not the master and the command is not our own, skip processing */ continue; } @@ -468,7 +536,7 @@ void sim_step(struct sim_step_ctx *ctx) * Create client player ents * ========================== */ - if (ctx->is_master) { + if (is_master) { for (u64 i = 0; i < world->num_ents_reserved; ++i) { struct sim_ent *ent = &world->ents[i]; if (!sim_ent_should_simulate(ent)) continue; @@ -778,7 +846,7 @@ void sim_step(struct sim_step_ctx *ctx) if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) { struct sim_ent *joint_ent = sim_ent_from_id(world, ent->move_joint); - if (ctx->is_master && !sim_ent_is_valid_and_active(joint_ent)) { + if (is_master && !sim_ent_is_valid_and_active(joint_ent)) { joint_ent = sim_ent_alloc_sync_src(root); joint_ent->mass_unscaled = F32_INFINITY; joint_ent->inertia_unscaled = F32_INFINITY; @@ -821,7 +889,7 @@ void sim_step(struct sim_step_ctx *ctx) /* Retrieve / create aim joint */ struct sim_ent *joint_ent = sim_ent_from_id(world, ent->aim_joint); - if (ctx->is_master && !sim_ent_is_valid_and_active(joint_ent)) { + if (is_master && !sim_ent_is_valid_and_active(joint_ent)) { joint_ent = sim_ent_alloc_sync_src(root); joint_ent->mass_unscaled = F32_INFINITY; joint_ent->inertia_unscaled = F32_INFINITY; @@ -925,7 +993,7 @@ void sim_step(struct sim_step_ctx *ctx) def.max_force = ent->linear_ground_friction; def.max_torque = ent->angular_ground_friction; if (joint_ent->motor_joint_data.max_force != def.max_force || joint_ent->motor_joint_data.max_torque != def.max_torque) { - if (ctx->is_master && !sim_ent_is_valid_and_active(joint_ent)) { + if (is_master && !sim_ent_is_valid_and_active(joint_ent)) { joint_ent = sim_ent_alloc_sync_src(root); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE); @@ -943,7 +1011,7 @@ void sim_step(struct sim_step_ctx *ctx) * Create mouse joints from client debug drag * ========================== */ - if (ctx->is_master) { + if (is_master) { for (u64 i = 0; i < world->num_ents_reserved; ++i) { struct sim_ent *client_ent = &world->ents[i]; if (!sim_ent_should_simulate(client_ent)) continue; @@ -1187,6 +1255,20 @@ void sim_step(struct sim_step_ctx *ctx) sim_ent_release_all_with_prop(world, SIM_ENT_PROP_RELEASE); + /* ========================== * + * 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, publish_client->last_tick); + pub_world = sim_snapshot_alloc(publish_client, prev_pub_world, world->tick); + pub_world->local_client_ent = world->local_client_ent; + sim_snapshot_sync(pub_world, world); + } + } + /* ========================== * * End frame * ========================== */ diff --git a/src/sim_step.h b/src/sim_step.h index d352dd80..48dac031 100644 --- a/src/sim_step.h +++ b/src/sim_step.h @@ -27,8 +27,13 @@ void sim_accel_reset(struct sim_snapshot *ss, struct sim_accel *accel); struct sim_step_ctx { b32 is_master; struct sim_accel *accel; - struct sim_snapshot *world; - i64 sim_dt_ns; + + struct sim_snapshot *world; /* The world to simulate */ + i64 sim_dt_ns; /* How much sim time should progress */ + + struct sim_client *user_input_client; /* The client that contains input from the user thread */ + struct sim_client *master_client; /* The master client to read snapshots from (nil if world is master) */ + struct sim_client *publish_client; /* The publish client to write syncable state to (nil if skipping publish) */ }; void sim_step(struct sim_step_ctx *ctx); diff --git a/src/user.c b/src/user.c index 644d7b9b..4410da04 100644 --- a/src/user.c +++ b/src/user.c @@ -1896,7 +1896,22 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) struct sim_client *master_client = sim_client_nil(); /* Stores snapshots received from master (if relevant) */ b32 initialized_from_master = false; - u64 step_tick = 0; + + + + + + + u64 ahead = 0; + if (!is_master) { + ahead = 50; + } + + + + + + i64 last_publish_ns = 0; i64 last_tick_ns = 0; i64 step_dt_ns = NS_FROM_SECONDS(1) / SIM_TICKS_PER_SECOND; @@ -1909,7 +1924,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) sleep_frame(last_tick_ns, compute_dt_ns); last_tick_ns = sys_time_ns(); } - ++step_tick; /* Read net messages */ struct sim_decode_queue queue = ZI; @@ -2046,10 +2060,9 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) if (!is_master && !initialized_from_master) { if (master_client->valid && master_client->last_tick > 0) { - step_tick = master_client->last_tick; + //step_tick = master_client->last_tick; initialized_from_master = true; } else { - step_tick = 0; goto skip_step; } } @@ -2057,7 +2070,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, step_tick); + struct sim_snapshot *user_input_ss = sim_snapshot_alloc(user_input_client, prev_user_input_ss, local_client->last_tick + ahead + 1); 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); @@ -2077,61 +2090,15 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) } } +#if 0 /* Allocate local snapshot */ struct sim_snapshot *prev_local_ss = sim_snapshot_from_tick(local_client, local_client->last_tick); struct sim_snapshot *local_ss = sim_snapshot_alloc(local_client, prev_local_ss, step_tick); - - /* Sync remote ents to local */ - { - struct sim_ent *local_root = sim_ent_from_id(local_ss, SIM_ENT_ROOT_ID); - for (u64 client_index = 0; client_index < store->num_clients_reserved; ++client_index) { - struct sim_client *client = &store->clients[client_index]; - if (client->valid) { - /* Create client ent if necessary */ - if (is_master && client != publish_client && client != local_client && client != master_client) { - struct sim_ent *client_ent = sim_ent_from_id(local_ss, client->ent_id); - if (!client_ent->valid) { - /* FIXME: Client ent never released upon disconnect */ - client_ent = sim_ent_alloc_sync_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_SYNC_PREDICT); - sim_ent_enable_prop(client_ent, SIM_ENT_PROP_ACTIVE); - client->ent_id = client_ent->id; - if (client == user_input_client) { - user_input_client->ent_id = client_ent->id; - local_client->ent_id = client_ent->id; - local_ss->local_client_ent = client_ent->id; - } - } - } - - - /* Sync w/ client */ - if (client != publish_client && client != local_client) { - struct sim_snapshot *client_ss = sim_snapshot_from_tick(client, step_tick); - if (client_ss->valid) { - sim_snapshot_sync(local_ss, client_ss); - if (!is_master && client == master_client) { - user_input_client->ent_id = client_ss->local_client_ent; - local_client->ent_id = client_ss->local_client_ent; - local_ss->local_client_ent = client_ss->local_client_ent; - } - } - } - } - } - } - - /* Point 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_CMD_CONTROL) && sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_DST)) { - struct sim_client *src_client = sim_client_from_handle(store, ent->sync_src_client); - struct sim_ent *client_ent = sim_ent_from_id(local_ss, src_client->ent_id); - ent->cmd_client = client_ent->id; - } + for (u64 i = 0; i < ahead; ++i) { + struct sim_snapshot *prev_predict_ss = sim_snapshot_from_tick(local_client, local_ss->tick + i); + sim_snapshot_alloc(local_client, prev_predict_ss, prev_predict_ss->tick + 1); } +#endif /* Release unneeded received snapshots */ u64 oldest_client_ack = 0; @@ -2139,7 +2106,8 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) 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); + //u64 keep_tick = max_u64(min_u64(client->double_ack, step_tick), 1); + u64 keep_tick = 1; sim_snapshot_release_ticks_in_range(client, 0, keep_tick - 1); } if (client->ack < oldest_client_ack || oldest_client_ack == 0) { @@ -2160,18 +2128,25 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) 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; + u64 keep_range = 500; 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); } } + /* Release unneeded user input snapshots */ + sim_snapshot_release_ticks_in_range(user_input_client, 0, local_client->last_tick - 1); + + + + + + + + @@ -2181,53 +2156,70 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) /* Step */ +#if 0 { struct sim_step_ctx step_ctx = ZI; step_ctx.is_master = is_master; - step_ctx.accel = &accel; - step_ctx.world = local_ss; step_ctx.sim_dt_ns = step_dt_ns; - sim_step(&step_ctx); - } + step_ctx.accel = &accel; + step_ctx.user_input_client = user_input_client; + step_ctx.master_client = master_client; + step_ctx.publish_client = publish_client; - - - - - /* Signal any locally created CMDs as sync sources */ - for (u64 i = 0; i < local_ss->num_ents_reserved; ++i) { - struct sim_ent *ent = &local_ss->ents[i]; - if (sim_ent_is_valid_and_active(ent) && sim_ent_has_prop(ent, SIM_ENT_PROP_CMD_CONTROL)) { - if (!sim_ent_id_eq(ent->cmd_client, SIM_ENT_NIL_ID) && sim_ent_id_eq(ent->cmd_client, local_ss->local_client_ent)) { - sim_ent_enable_prop(ent, SIM_ENT_PROP_SYNC_SRC); + if (is_master) { + ctx.prev_world = sim_snapshot_from_tick(local_client, local_client->last_tick); + sim_step(&step_ctx); + } else { + for (u64 i = 0; i < ahead; ++i) { + ctx.prev_world = sim_snapshot_from_tick(local_client, master_client->last_tick + i); + sim_step(&step_ctx); } } } - - - - - - - - - - - - - - - /* Construct publishable snapshot */ +#else { - struct sim_snapshot *pub_ss; + 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) { - pub_ss = sim_snapshot_alloc(publish_client, sim_snapshot_from_tick(publish_client, publish_client->last_tick), local_ss->tick); + 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); + sim_step(&ctx); } else { - pub_ss = sim_snapshot_alloc(publish_client, sim_snapshot_from_tick(publish_client, publish_client->last_tick), local_ss->tick + 5); + struct sim_snapshot *master_ss = sim_snapshot_from_tick(master_client, master_client->last_tick); + if (master_ss->valid) { + struct sim_snapshot *prev_world = sim_snapshot_alloc(local_client, master_ss, master_ss->tick); + for (u64 i = 0; i < ahead; ++i) { + ctx.world = sim_snapshot_alloc(local_client, prev_world, prev_world->tick + 1); + sim_step(&ctx); + prev_world = ctx.world; + } + } } - sim_snapshot_sync(pub_ss, local_ss); } +#endif + + + + + + + + + + + + + + @@ -2282,15 +2274,16 @@ 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_ss, local_ss->tick); - copy_ss->local_client_ent = local_ss->local_client_ent; + 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_ss->tick - 1); + sim_snapshot_release_ticks_in_range(G.local_to_user_client, 0, local_world->tick - 1); sys_mutex_unlock(&lock); }