debug follow

This commit is contained in:
jacob 2025-02-27 18:07:49 -06:00
parent 55a4b904e0
commit 7e7e6a8f87
11 changed files with 141 additions and 81 deletions

BIN
res/graphics/tim.ase (Stored with Git LFS)

Binary file not shown.

View File

@ -450,7 +450,6 @@ struct sim_client_handle {
struct sim_ent_id {
struct uid uid;
};
INLINE b32 sim_ent_id_eq(struct sim_ent_id a, struct sim_ent_id b) { return uid_eq(a.uid, b.uid); }
struct space_entry_handle {
u64 idx;

View File

@ -59,7 +59,7 @@
#define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 0
/* If enabled, bitbuffs will insert/verify magic numbers & length for each read & write */
#define BITBUFF_DEBUG RTC
#define BITBUFF_DEBUG 0
#define BITBUFF_TEST RTC
/* If enabled, things like network writes & memory allocations will be tracked in a global statistics struct */

View File

@ -274,7 +274,7 @@ void phys_prepare_contacts(struct phys_step_ctx *ctx, u64 phys_iteration)
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *constraint_ent = &ss->ents[sim_ent_index];
if (!sim_ent_is_valid_and_active(constraint_ent)) continue;
if (!sim_ent_should_simulate(constraint_ent)) continue;
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
@ -371,7 +371,7 @@ void phys_prepare_contacts(struct phys_step_ctx *ctx, u64 phys_iteration)
struct sim_lookup *debug_lookup = ctx->debug_lookup;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *dbg_ent = &ss->ents[sim_ent_index];
if (!sim_ent_is_valid_and_active(dbg_ent)) continue;
if (!sim_ent_should_simulate(dbg_ent)) continue;
if (!sim_ent_has_prop(dbg_ent, SIM_ENT_PROP_COLLISION_DEBUG)) continue;
struct phys_collision_debug *dbg = &dbg_ent->collision_debug_data;
@ -379,7 +379,7 @@ void phys_prepare_contacts(struct phys_step_ctx *ctx, u64 phys_iteration)
struct sim_ent *e1 = sim_ent_from_id(ss, dbg->e1);
if (!sim_ent_is_valid_and_active(e0) || !sim_ent_is_valid_and_active(e1)
if (!sim_ent_should_simulate(e0) || !sim_ent_should_simulate(e1)
|| !(sim_ent_has_prop(e0, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e0, SIM_ENT_PROP_PHYSICAL_KINEMATIC))
|| !(sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) {
/* Mark dbg ent for removal */
@ -406,7 +406,7 @@ void phys_warm_start_contacts(struct phys_step_ctx *ctx)
struct sim_snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *constraint_ent = &ss->ents[sim_ent_index];
if (!sim_ent_is_valid_and_active(constraint_ent)) continue;
if (!sim_ent_should_simulate(constraint_ent)) continue;
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
@ -461,7 +461,7 @@ void phys_solve_contacts(struct phys_step_ctx *ctx, f32 dt, b32 apply_bias)
struct sim_snapshot *ss = ctx->sim_step_ctx->world;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *constraint_ent = &ss->ents[sim_ent_index];
if (!sim_ent_is_valid_and_active(constraint_ent)) continue;
if (!sim_ent_should_simulate(constraint_ent)) continue;
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;

View File

@ -620,7 +620,7 @@ void sim_snapshot_sync_ents(struct sim_snapshot *local_ss, struct sim_snapshot *
for (u64 i = 2; i < local_ss->num_ents_reserved; ++i) {
struct sim_ent *local_ent = &local_ss->ents[i];
if (local_ent->valid && sim_ent_has_prop(local_ent, SIM_ENT_PROP_SYNC_DST)) {
b32 should_sync = sim_ent_id_eq(local_ent->owner, remote_client_ent) || sim_ent_id_eq(remote_client_ent, SIM_ENT_NIL_ID);
b32 should_sync = sim_ent_id_eq(local_ent->owner, remote_client_ent) || sim_ent_id_is_nil(remote_client_ent);
if (should_sync) {
struct sim_ent *remote_ent = sim_ent_from_id(remote_ss, local_ent->id);
if (remote_ent->valid) {

View File

@ -72,7 +72,9 @@ struct sim_client {
struct arena snapshots_arena;
i64 rtt_ns; /* Round trip time of the client (if networked) */
/* Round trip time of the client (if networked) */
i64 rtt_ns;
struct host_channel_id channel_id;
u64 channel_hash;

View File

@ -25,9 +25,11 @@ INTERNAL struct sim_ent *ent_from_index(struct sim_snapshot *ss, u32 index)
* Ent allocation
* ========================== */
/* Allocates an entity with no parent & no id (these must be set immediately after by the caller) */
struct sim_ent *sim_ent_alloc_raw(struct sim_snapshot *ss)
struct sim_ent *sim_ent_alloc_raw(struct sim_snapshot *ss, struct sim_ent *parent, struct sim_ent_id id)
{
ASSERT(parent->valid);
ASSERT(ss->valid);
ASSERT(ss == parent->ss);
struct sim_ent *ent;
if (ss->first_free_ent > 0 && ss->first_free_ent < ss->num_ents_reserved) {
/* Reuse from free list */;
@ -44,61 +46,56 @@ struct sim_ent *sim_ent_alloc_raw(struct sim_snapshot *ss)
ent->owner = ss->client->ent_id;
ent->_is_xform_dirty = true;
++ss->num_ents_allocated;
sim_ent_set_id(ent, id);
sim_ent_link_parent(ent, parent);
return ent;
}
/* Allocates a new entity that will not sync */
struct sim_ent *sim_ent_alloc_local(struct sim_ent *parent)
{
ASSERT(parent->valid);
struct sim_snapshot *ss = parent->ss;
struct sim_ent *e = sim_ent_alloc_raw(ss);
sim_ent_set_id(e, sim_ent_random_id());
sim_ent_link_parent(e, parent);
struct sim_ent *e = sim_ent_alloc_raw(ss, parent, sim_ent_random_id());
e->owner = ss->local_client_ent;
return e;
}
struct sim_ent *sim_ent_alloc_local_with_id(struct sim_ent *parent, struct sim_ent_id id)
{
ASSERT(parent->valid);
struct sim_snapshot *ss = parent->ss;
struct sim_ent *e = sim_ent_alloc_raw(ss);
sim_ent_set_id(e, id);
sim_ent_link_parent(e, parent);
struct sim_ent *e = sim_ent_alloc_raw(ss, parent, id);
e->owner = ss->local_client_ent;
return e;
}
/* Allocates a new entity with a random uid to be synced to clients */
/* Allocates a new entity to be synced to clients */
struct sim_ent *sim_ent_alloc_sync_src(struct sim_ent *parent)
{
struct sim_snapshot *ss = parent->ss;
struct sim_ent *e = sim_ent_alloc_raw(ss);
sim_ent_set_id(e, sim_ent_random_id());
struct sim_ent *e = sim_ent_alloc_raw(ss, parent, sim_ent_random_id());
sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_SRC);
e->owner = ss->local_client_ent;
return e;
}
sim_ent_link_parent(e, parent);
struct sim_ent *sim_ent_alloc_sync_src_with_id(struct sim_ent *parent, struct sim_ent_id id)
{
struct sim_snapshot *ss = parent->ss;
struct sim_ent *e = sim_ent_alloc_raw(ss, parent, id);
sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_SRC);
e->owner = ss->local_client_ent;
return e;
}
/* Allocates a new entity that will sync with incoming net src ents containing id, and coming from the specified owner */
struct sim_ent *sim_ent_alloc_sync_dst(struct sim_ent *parent, struct sim_ent_id ent_id, struct sim_ent_id owner_client_ent_id)
struct sim_ent *sim_ent_alloc_sync_dst(struct sim_ent *parent, struct sim_ent_id ent_id, struct sim_ent_id owner_id)
{
struct sim_snapshot *ss = parent->ss;
struct sim_ent *e = sim_ent_alloc_raw(ss);
sim_ent_set_id(e, ent_id);
sim_ent_link_parent(e, parent);
struct sim_ent *e = sim_ent_alloc_raw(ss, parent, ent_id);
sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_DST);
e->owner = owner_client_ent_id;
e->owner = owner_id;
return e;
}
@ -187,7 +184,7 @@ void sim_ent_set_id(struct sim_ent *ent, struct sim_ent_id id)
struct sim_ent_id old_id = ent->id;
if (!sim_ent_id_eq(old_id, id)) {
/* Release old from lookup */
if (!sim_ent_id_eq(old_id, SIM_ENT_NIL_ID)) {
if (!sim_ent_id_is_nil(old_id)) {
struct sim_ent_bin *bin = bin_from_id(ss, old_id);
u32 prev_index = 0;
u32 next_index = 0;
@ -224,7 +221,7 @@ void sim_ent_set_id(struct sim_ent *ent, struct sim_ent_id id)
}
/* Insert new id into lookup */
if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID)) {
if (!sim_ent_id_is_nil(id)) {
#if RTC
{
struct sim_ent *existing = sim_ent_from_id(ss, id);
@ -254,7 +251,7 @@ void sim_ent_set_id(struct sim_ent *ent, struct sim_ent_id id)
struct sim_ent *sim_ent_from_id(struct sim_snapshot *ss, struct sim_ent_id id)
{
struct sim_ent *res = sim_ent_nil();
if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID) && ss->valid) {
if (!sim_ent_id_is_nil(id) && ss->valid) {
struct sim_ent_bin *bin = bin_from_id(ss, id);
for (struct sim_ent *e = ent_from_index(ss, bin->first); e->valid; e = ent_from_index(ss, e->next_in_id_bin)) {
if (sim_ent_id_eq(e->id, id)) {

View File

@ -154,7 +154,8 @@ struct sim_ent {
b32 client_dbg_drag_stop;
/* Client round-trip-time to server */
i64 client_rtt_ns;
i64 client_last_rtt_ns;
f64 client_average_rtt_seconds;
/* ====================================================================== */
/* Collider */
@ -351,6 +352,20 @@ INLINE struct sim_ent *sim_ent_nil(void)
return *_g_sim_ent_nil;
}
/* ========================== *
* Id helpers
* ========================== */
INLINE b32 sim_ent_id_eq(struct sim_ent_id a, struct sim_ent_id b)
{
return uid_eq(a.uid, b.uid);
}
INLINE b32 sim_ent_id_is_nil(struct sim_ent_id id)
{
return uid_eq(id.uid, SIM_ENT_NIL_ID.uid);
}
/* ========================== *
* Property helpers
* ========================== */
@ -409,11 +424,12 @@ INLINE b32 sim_ent_should_simulate(struct sim_ent *ent)
* ========================== */
/* Alloc */
struct sim_ent *sim_ent_alloc_raw(struct sim_snapshot *ss);
struct sim_ent *sim_ent_alloc_raw(struct sim_snapshot *ss, struct sim_ent *parent, struct sim_ent_id id);
struct sim_ent *sim_ent_alloc_local(struct sim_ent *parent);
struct sim_ent *sim_ent_alloc_local_with_id(struct sim_ent *parent, struct sim_ent_id id);
struct sim_ent *sim_ent_alloc_sync_src(struct sim_ent *parent);
struct sim_ent *sim_ent_alloc_sync_dst(struct sim_ent *parent, struct sim_ent_id ent_id, struct sim_ent_id owner_client_ent_id);
struct sim_ent *sim_ent_alloc_sync_src_with_id(struct sim_ent *parent, struct sim_ent_id id);
struct sim_ent *sim_ent_alloc_sync_dst(struct sim_ent *parent, struct sim_ent_id ent_id, struct sim_ent_id owner_id);
void sim_ent_release_raw(struct sim_ent *ent);
void sim_ent_release(struct sim_ent *ent);

View File

@ -75,7 +75,7 @@ INTERNAL void spawn_test_entities(struct sim_step_ctx *ctx, struct v2 offset)
e->layer = SIM_LAYER_SHOULDERS;
sim_ent_enable_prop(e, SIM_ENT_PROP_PHYSICAL_DYNAMIC);
e->mass_unscaled = 10;
e->mass_unscaled = 100;
e->inertia_unscaled = 10;
e->linear_ground_friction = 250;
e->angular_ground_friction = 200;
@ -392,7 +392,11 @@ void sim_step(struct sim_step_ctx *ctx)
/* Update rtt */
if (is_master && client_ent->valid) {
client_ent->client_rtt_ns = client->rtt_ns;
client_ent->client_last_rtt_ns = client->rtt_ns;
f64 avg = client_ent->client_average_rtt_seconds;
avg -= avg / 200;
avg += SECONDS_FROM_NS(client->rtt_ns) / 200;
client_ent->client_average_rtt_seconds = avg;
}
/* Sync ents from client */
@ -427,7 +431,7 @@ void sim_step(struct sim_step_ctx *ctx)
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)) {
if (!sim_ent_id_is_nil(ent->cmd_client) && sim_ent_id_eq(ent->cmd_client, world->local_client_ent)) {
sim_ent_enable_prop(ent, SIM_ENT_PROP_SYNC_SRC);
}
}
@ -508,7 +512,7 @@ void sim_step(struct sim_step_ctx *ctx)
{
struct sim_ent_id client_control_ent_id = client_ent->client_control_ent;
struct sim_ent *client_control_ent = sim_ent_from_id(world, client_control_ent_id);
if (client_control_ent->valid || sim_ent_id_eq(client_control_ent_id, SIM_ENT_NIL_ID)) {
if (client_control_ent->valid || sim_ent_id_is_nil(client_control_ent_id)) {
/* Only update cursor pos if focus ent is valid (or nil) */
client_ent->client_cursor_pos = v2_add(sim_ent_get_xform(client_control_ent).og, client_ent->client_control.focus);
}
@ -620,7 +624,7 @@ void sim_step(struct sim_step_ctx *ctx)
frame_index = span.start;
}
if (span.end > span.start + 1) {
if (span.end > span.start) {
struct sprite_sheet_frame frame = sprite_sheet_get_frame(sheet, frame_index);
while (time_in_frame > frame.duration) {
time_in_frame -= frame.duration;
@ -1040,7 +1044,7 @@ void sim_step(struct sim_step_ctx *ctx)
if (sim_ent_should_simulate(target_ent)) {
if (!sim_ent_is_valid_and_active(joint_ent)) {
/* FIXME: Joint ent may never release */
joint_ent = sim_ent_alloc_sync_src(root);
joint_ent = sim_ent_alloc_local(root);
joint_ent->mass_unscaled = F32_INFINITY;
joint_ent->inertia_unscaled = F32_INFINITY;
client_ent->client_dbg_drag_joint_ent = joint_ent->id;

View File

@ -73,6 +73,7 @@ GLOBAL struct {
struct bind_state bind_states[USER_BIND_KIND_COUNT];
struct sim_ent_id debug_following;
b32 debug_camera;
b32 debug_camera_panning;
struct v2 debug_camera_pan_start;
@ -141,6 +142,7 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = {
[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_Q] = USER_BIND_KIND_DEBUG_FOLLOW,
[SYS_BTN_F1] = USER_BIND_KIND_DEBUG_PAUSE,
[SYS_BTN_F2] = USER_BIND_KIND_DEBUG_CAMERA,
[SYS_BTN_F3] = USER_BIND_KIND_DEBUG_DRAW,
@ -388,7 +390,7 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e
res.len += string_format(arena, LIT("parent: [%F]\n"), FMT_UID(ent->parent.uid)).len;
}
if (!sim_ent_id_eq(ent->next, SIM_ENT_NIL_ID) || !sim_ent_id_eq(ent->prev, SIM_ENT_NIL_ID)) {
if (!sim_ent_id_is_nil(ent->next) || !sim_ent_id_is_nil(ent->prev)) {
res.len += string_format(arena, LIT("prev: [%F]\n"), FMT_UID(ent->prev.uid)).len;
res.len += string_format(arena, LIT("next: [%F]\n"), FMT_UID(ent->next.uid)).len;
}
@ -404,7 +406,7 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e
res.len += string_format(arena, LIT("angular velocity: %F\n"), FMT_FLOAT_P(angular_velocity, 3)).len;
/* Children */
if (!sim_ent_id_eq(ent->first, SIM_ENT_NIL_ID) || !sim_ent_id_eq(ent->last, SIM_ENT_NIL_ID)) {
if (!sim_ent_id_is_nil(ent->first) || !sim_ent_id_is_nil(ent->last)) {
struct sim_ent *child = sim_ent_from_id(ss, ent->first);
if (!sim_ent_id_eq(ent->first, ent->last) || !child->valid) {
res.len += string_format(arena, LIT("first child: [%F]\n"), FMT_UID(ent->first.uid)).len;
@ -679,28 +681,6 @@ INTERNAL void user_update(void)
}
}
/* ========================== *
* Update user state from binds
* ========================== */
/* Test fullscreen */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_FULLSCREEN];
if (state.num_presses) {
struct sys_window_settings settings = sys_window_get_settings(G.window);
settings.flags ^= SYS_WINDOW_SETTINGS_FLAG_FULLSCREEN;
sys_window_update_settings(G.window, &settings);
}
}
if (G.bind_states[USER_BIND_KIND_DEBUG_DRAW].num_presses > 0) {
G.debug_draw = !G.debug_draw;
}
if (G.bind_states[USER_BIND_KIND_DEBUG_CAMERA].num_presses > 0) {
G.debug_camera = !G.debug_camera;
}
/* ========================== *
* Find local entities
* ========================== */
@ -738,6 +718,55 @@ INTERNAL void user_update(void)
}
}
/* ========================== *
* Update user state from binds
* ========================== */
/* Test fullscreen */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_FULLSCREEN];
if (state.num_presses) {
struct sys_window_settings settings = sys_window_get_settings(G.window);
settings.flags ^= SYS_WINDOW_SETTINGS_FLAG_FULLSCREEN;
sys_window_update_settings(G.window, &settings);
}
}
if (G.bind_states[USER_BIND_KIND_DEBUG_DRAW].num_presses > 0) {
G.debug_draw = !G.debug_draw;
}
if (G.bind_states[USER_BIND_KIND_DEBUG_CAMERA].num_presses > 0) {
G.debug_camera = !G.debug_camera;
}
{
if (G.bind_states[USER_BIND_KIND_DEBUG_FOLLOW].num_presses > 0) {
if (sim_ent_id_is_nil(G.debug_following)) {
G.debug_following = hovered_ent->id;
} else {
G.debug_following = SIM_ENT_NIL_ID;
}
}
if (!sim_ent_id_is_nil(G.debug_following)) {
struct sim_ent *follow_ent = sim_ent_from_id(G.ss_blended, G.debug_following);
struct sim_ent *follow_camera = sim_ent_nil();
for (u64 i = 0; i < G.ss_blended->num_ents_reserved; ++i) {
struct sim_ent *ent = &G.ss_blended->ents[i];
struct sim_ent *ent_camera_follow = sim_ent_from_id(G.ss_blended, ent->camera_follow);
if (ent_camera_follow->valid && ent_camera_follow == follow_ent) {
follow_camera = ent;
break;
}
}
if (follow_camera->valid) {
local_camera = follow_camera;
} else {
G.debug_following = SIM_ENT_NIL_ID;
}
}
}
/* ========================== *
* Apply shake
* ========================== */
@ -1645,7 +1674,10 @@ INTERNAL void user_update(void)
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Network write: %F mbit/s"), FMT_FLOAT_P((f64)G.net_bytes_sent.last_second * 8 / 1000 / 1000, 3)));
pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Ping: %F ms"), FMT_FLOAT_P(SECONDS_FROM_NS(local_client_ent->client_rtt_ns) * 1000, 3)));
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Ping (real): %F ms"), FMT_FLOAT_P(SECONDS_FROM_NS(local_client_ent->client_last_rtt_ns) * 1000, 3)));
pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Ping (average): %F ms"), FMT_FLOAT_P(local_client_ent->client_average_rtt_seconds * 1000, 3)));
pos.y += spacing;
pos.y += spacing;
@ -2266,7 +2298,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
u64 master_tick = master_client->last_tick;
struct sim_snapshot *master_ss = sim_snapshot_from_tick(master_client, master_tick);
struct sim_ent *master_client_ent = sim_ent_find_first_match_one(master_ss, SIM_ENT_PROP_CLIENT_IS_MASTER);
user_input_client->ent_id = master_ss->local_client_ent;
local_client->ent_id = master_ss->local_client_ent;
@ -2288,23 +2319,33 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
/* We want to simulate the ahead of the server to predict client input.
* How many ticks ahead we want to simulate is a balance between added latency and the server not receiving our inputs on time.
* We can take the server's last sent ack - server tick to determine how many cmds of ours the server has buffered.
*
* If this buffer gets too low (because we are lagging behind or the connection is unstable), meaning the server is not getting our input on time:
* - Dilate local compute time (not sim time) to increase the rate at which we predict & produce cmds, until the server's ack indicates a buffer size within desired range.
*
* If this buffer gets too large (because the client predicts too far ahead), meaning unneeded latency is being introduced:
* - Dilate local compute time to decrease the rate at which we predict & produce cmds until the server's ack indicates a buffer size within desired range.
*/
{
i64 cmds_ahead_on_master = (i64)master_client->ack - (i64)master_client->last_tick;
if (math_abs_i64(cmds_ahead_on_master) > 50) {
/* Cmds are too far from master time, snap step end tick */
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 num_predict_ticks = math_round_to_int64(rtt_tick_ratio) + 5;
step_end_tick = step_base_tick + num_predict_ticks;
compute_timescale = 1.1;
} else if (cmds_ahead_on_master > 2) {
/* Slow down simulation rate to bring sim time closer to master time */
compute_timescale = 0.9;
compute_timescale = 0.95;
} else if (cmds_ahead_on_master < 1) {
/* Speed up simulation rate to give master more inputs to work with */
compute_timescale = 1.1;
compute_timescale = 1.05;
} else {
/* Server's cmd buffer is in a healthy range */
compute_timescale = 1;
}
}

View File

@ -28,6 +28,7 @@ enum user_bind_kind {
USER_BIND_KIND_DEBUG_CLEAR,
USER_BIND_KIND_DEBUG_SPAWN,
USER_BIND_KIND_DEBUG_FOLLOW,
USER_BIND_KIND_DEBUG_DRAW,
USER_BIND_KIND_DEBUG_CAMERA,
USER_BIND_KIND_DEBUG_PAUSE,