diff --git a/src/host.c b/src/host.c index e9895256..eea5ef05 100644 --- a/src/host.c +++ b/src/host.c @@ -75,6 +75,8 @@ struct host_channel { struct host_msg_assembler *least_recent_msg_assembler; struct host_msg_assembler *most_recent_msg_assembler; + i64 rtt_ns; + u64 last_sent_msg_id; u64 their_acked_seq; u64 our_acked_seq; @@ -616,6 +618,16 @@ void host_queue_write(struct host *host, struct host_channel_id channel_id, stru cmd->write_reliable = flags & HOST_WRITE_FLAG_RELIABLE; } +/* ========================== * + * Info + * ========================== */ + +i64 host_get_channel_rtt_ns(struct host *host, struct host_channel_id channel_id) +{ + struct host_channel *channel = host_single_channel_from_id(host, channel_id); + return channel->rtt_ns; +} + /* ========================== * * Update * ========================== */ diff --git a/src/host.h b/src/host.h index 423d961e..f5d1a950 100644 --- a/src/host.h +++ b/src/host.h @@ -124,6 +124,12 @@ void host_queue_disconnect(struct host *host, struct host_channel_id channel_id) void host_queue_write(struct host *host, struct host_channel_id channel_id, struct string msg, u32 flags); +/* ========================== * + * Info + * ========================== */ + +i64 host_get_channel_rtt_ns(struct host *host, struct host_channel_id channel_id); + /* ========================== * * Update * ========================== */ diff --git a/src/sim.h b/src/sim.h index fea9ac63..2cab1ca6 100644 --- a/src/sim.h +++ b/src/sim.h @@ -72,6 +72,7 @@ struct sim_client { struct arena snapshots_arena; + i64 rtt_ns; /* Round trip time of the client (if networked) */ struct host_channel_id channel_id; u64 channel_hash; diff --git a/src/user.c b/src/user.c index b824d5a0..ca43a741 100644 --- a/src/user.c +++ b/src/user.c @@ -125,37 +125,37 @@ GLOBAL struct { * Bind state * ========================== */ -/* TODO: Remove this */ + /* TODO: Remove this */ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = { - [SYS_BTN_W] = USER_BIND_KIND_MOVE_UP, - [SYS_BTN_S] = USER_BIND_KIND_MOVE_DOWN, - [SYS_BTN_A] = USER_BIND_KIND_MOVE_LEFT, - [SYS_BTN_D] = USER_BIND_KIND_MOVE_RIGHT, - [SYS_BTN_ALT] = USER_BIND_KIND_WALK, - [SYS_BTN_M1] = USER_BIND_KIND_FIRE, + [SYS_BTN_W] = USER_BIND_KIND_MOVE_UP, + [SYS_BTN_S] = USER_BIND_KIND_MOVE_DOWN, + [SYS_BTN_A] = USER_BIND_KIND_MOVE_LEFT, + [SYS_BTN_D] = USER_BIND_KIND_MOVE_RIGHT, + [SYS_BTN_ALT] = USER_BIND_KIND_WALK, + [SYS_BTN_M1] = USER_BIND_KIND_FIRE, /* Testing */ - [SYS_BTN_M2] = USER_BIND_KIND_DEBUG_DRAG, - [SYS_BTN_C] = USER_BIND_KIND_DEBUG_CLEAR, - [SYS_BTN_V] = USER_BIND_KIND_DEBUG_SPAWN, - [SYS_BTN_N] = USER_BIND_KIND_DEBUG_STEP, - [SYS_BTN_F1] = USER_BIND_KIND_DEBUG_PAUSE, - [SYS_BTN_F2] = USER_BIND_KIND_DEBUG_CAMERA, - [SYS_BTN_F3] = USER_BIND_KIND_DEBUG_DRAW, - [SYS_BTN_F11] = USER_BIND_KIND_FULLSCREEN, - [SYS_BTN_MWHEELUP] = USER_BIND_KIND_ZOOM_IN, - [SYS_BTN_MWHEELDOWN] = USER_BIND_KIND_ZOOM_OUT, - [SYS_BTN_M3] = USER_BIND_KIND_PAN, - [SYS_BTN_CTRL] = USER_BIND_KIND_CTRL_TEST, + [SYS_BTN_M2] = USER_BIND_KIND_DEBUG_DRAG, + [SYS_BTN_C] = USER_BIND_KIND_DEBUG_CLEAR, + [SYS_BTN_V] = USER_BIND_KIND_DEBUG_SPAWN, + [SYS_BTN_N] = USER_BIND_KIND_DEBUG_STEP, + [SYS_BTN_F1] = USER_BIND_KIND_DEBUG_PAUSE, + [SYS_BTN_F2] = USER_BIND_KIND_DEBUG_CAMERA, + [SYS_BTN_F3] = USER_BIND_KIND_DEBUG_DRAW, + [SYS_BTN_F11] = USER_BIND_KIND_FULLSCREEN, + [SYS_BTN_MWHEELUP] = USER_BIND_KIND_ZOOM_IN, + [SYS_BTN_MWHEELDOWN] = USER_BIND_KIND_ZOOM_OUT, + [SYS_BTN_M3] = USER_BIND_KIND_PAN, + [SYS_BTN_CTRL] = USER_BIND_KIND_CTRL_TEST, #if RTC /* Debug */ - [SYS_BTN_FORWARD_SLASH] = USER_BIND_KIND_RESET_COLLIDER_GJK_STEPS, - [SYS_BTN_COMMA] = USER_BIND_KIND_DECR_COLLIDER_GJK_STEPS, - [SYS_BTN_PERIOD] = USER_BIND_KIND_INCR_COLLIDER_GJK_STEPS + [SYS_BTN_FORWARD_SLASH] = USER_BIND_KIND_RESET_COLLIDER_GJK_STEPS, + [SYS_BTN_COMMA] = USER_BIND_KIND_DECR_COLLIDER_GJK_STEPS, + [SYS_BTN_PERIOD] = USER_BIND_KIND_INCR_COLLIDER_GJK_STEPS #endif }; @@ -169,7 +169,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) INTERNAL SYS_WINDOW_EVENT_CALLBACK_FUNC_DEF(window_event_callback, event); struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, - struct renderer_startup_receipt *renderer_sr, + struct renderer_startup_receipt *renderer_sr, struct font_startup_receipt *font_sr, struct sprite_startup_receipt *sprite_sr, struct draw_startup_receipt *draw_sr, @@ -296,13 +296,13 @@ INTERNAL SYS_WINDOW_EVENT_CALLBACK_FUNC_DEF(window_event_callback, event) * Debug draw * ========================== */ -/* TODO: remove this (testing) */ + /* TODO: remove this (testing) */ INTERNAL void debug_draw_xform(struct xform xf, u32 color_x, u32 color_y) { f32 thickness = 2.f; f32 arrowhead_len = 15.f; - struct v2 pos = xform_mul_v2(G.world_to_ui_xf, xf.og); + struct v2 pos = xform_mul_v2(G.world_to_ui_xf, xf.og); struct v2 x_ray = xform_basis_mul_v2(G.world_to_ui_xf, xform_get_right(xf)); struct v2 y_ray = xform_basis_mul_v2(G.world_to_ui_xf, xform_get_up(xf)); @@ -327,11 +327,11 @@ INTERNAL void debug_draw_movement(struct sim_ent *ent) u32 color_vel = RGBA_32_F(1, 0.5, 0, 1); - struct xform xf = sim_ent_get_xform(ent); - struct v2 velocity = ent->linear_velocity; + struct xform xf = sim_ent_get_xform(ent); + struct v2 velocity = ent->linear_velocity; - struct v2 pos = xform_mul_v2(G.world_to_ui_xf, xf.og); - struct v2 vel_ray = xform_basis_mul_v2(G.world_to_ui_xf, velocity); + struct v2 pos = xform_mul_v2(G.world_to_ui_xf, xf.og); + struct v2 vel_ray = xform_basis_mul_v2(G.world_to_ui_xf, velocity); if (v2_len(vel_ray) > 0.00001) { draw_arrow_ray(G.ui_cmd_buffer, pos, vel_ray, thickness, arrow_len, color_vel); @@ -683,7 +683,7 @@ INTERNAL void user_update(void) * Update user state from binds * ========================== */ - /* Test fullscreen */ + /* Test fullscreen */ { struct bind_state state = G.bind_states[USER_BIND_KIND_FULLSCREEN]; if (state.num_presses) { @@ -774,7 +774,7 @@ INTERNAL void user_update(void) * Update ui from camera * ========================== */ - /* Calculate ui dimensions */ + /* Calculate ui dimensions */ if (G.debug_camera) { G.ui_size = G.screen_size; G.ui_screen_offset = V2(0, 0); @@ -1895,7 +1895,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) struct sim_accel accel = sim_accel_alloc(); struct sim_client_store *store = sim_client_store_alloc(); - 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 *user_input_client = sim_client_alloc(store); /* Stores snapshots containing commands to be published to local client */ 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 */ @@ -1906,18 +1906,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) - - - 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; @@ -2068,52 +2056,19 @@ 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; initialized_from_master = true; } else { 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, local_client->last_tick + 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); - if (!control_cmd_ent->valid) { - control_cmd_ent = sim_ent_alloc_sync_src(user_input_root); - control_cmd_ent->predictor = user_input_ss->local_client_ent; - sim_ent_enable_prop(control_cmd_ent, SIM_ENT_PROP_CMD_CONTROL); - control_cmd_ent->predictor = user_input_client->ent_id; - sim_ent_activate(control_cmd_ent, user_input_ss->tick); - } - /* Update local control cmd ent */ - { - 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 = G.user_hovered_ent; - ++G.user_sim_cmd_gen; - sys_mutex_unlock(&lock); - } - } - -#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); - 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 */ + /* Update networked clients */ 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) { + client->rtt_ns = host_get_channel_rtt_ns(host, client->channel_id); + /* Release unneeded received snapshots */ if (client->double_ack > 0) { //u64 keep_tick = max_u64(min_u64(client->double_ack, step_tick), 1); u64 keep_tick = 1; @@ -2139,7 +2094,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) /* Release old local snapshots */ { - u64 keep_range = 500; + u64 keep_range = 250; 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); @@ -2152,6 +2107,45 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) + /* Determine step tick */ + u64 desired_step_tick = 0; + if (is_master) { + desired_step_tick = local_client->last_tick + 1; + } else { + i64 half_rtt_ns = master_client->rtt_ns / 2; + i64 num_predict_ticks = (half_rtt_ns + (step_dt_ns - 1)) / step_dt_ns; /* Half rtt in ticks */ + num_predict_ticks += 2; /* Jitter buffer */ + desired_step_tick = master_client->last_tick + num_predict_ticks; + } + + + /* 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 + 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); + if (!control_cmd_ent->valid) { + control_cmd_ent = sim_ent_alloc_sync_src(user_input_root); + control_cmd_ent->predictor = user_input_ss->local_client_ent; + sim_ent_enable_prop(control_cmd_ent, SIM_ENT_PROP_CMD_CONTROL); + control_cmd_ent->predictor = user_input_client->ent_id; + sim_ent_activate(control_cmd_ent, user_input_ss->tick); + } + /* Update local control cmd ent */ + { + 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 = G.user_hovered_ent; + ++G.user_sim_cmd_gen; + sys_mutex_unlock(&lock); + } + } + + + + @@ -2165,28 +2159,6 @@ 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.sim_dt_ns = step_dt_ns; - step_ctx.accel = &accel; - - step_ctx.user_input_client = user_input_client; - step_ctx.master_client = master_client; - step_ctx.publish_client = publish_client; - - 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); - } - } - } -#else { struct sim_step_ctx ctx = ZI; ctx.is_master = is_master; @@ -2208,9 +2180,10 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) 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); - for (u64 i = 0; i < ahead; ++i) { + /* FIXME: Don't take use desired_step_tick at face value. Dilate compute_dt to work towards it. */ + i64 num_predict_ticks = desired_step_tick - master_ss->tick; + for (i64 i = 0; i < num_predict_ticks; ++i) { ctx.world = sim_snapshot_alloc(local_client, prev_world, prev_world->tick + 1); sim_step(&ctx); prev_world = ctx.world; @@ -2218,7 +2191,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) } } } -#endif @@ -2289,7 +2261,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) { struct sim_snapshot *local_world = sim_snapshot_from_tick(local_client, local_client->last_tick); - /* TODO: Double buffer */ + /* 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(); @@ -2300,7 +2272,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) sys_mutex_unlock(&lock); } - skip_step: + skip_step: /* Send host messages */ host_update(host);