prediction progress
This commit is contained in:
parent
79b32b187a
commit
a364f311d1
12
src/host.c
12
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
|
||||
* ========================== */
|
||||
|
||||
@ -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
|
||||
* ========================== */
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
188
src/user.c
188
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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user