prediction progress

This commit is contained in:
jacob 2025-02-25 18:41:39 -06:00
parent 79b32b187a
commit a364f311d1
4 changed files with 99 additions and 108 deletions

View File

@ -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
* ========================== */

View File

@ -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
* ========================== */

View File

@ -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;

View File

@ -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);