debug follow
This commit is contained in:
parent
55a4b904e0
commit
7e7e6a8f87
BIN
res/graphics/tim.ase
(Stored with Git LFS)
BIN
res/graphics/tim.ase
(Stored with Git LFS)
Binary file not shown.
@ -450,7 +450,6 @@ struct sim_client_handle {
|
|||||||
struct sim_ent_id {
|
struct sim_ent_id {
|
||||||
struct uid uid;
|
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 {
|
struct space_entry_handle {
|
||||||
u64 idx;
|
u64 idx;
|
||||||
|
|||||||
@ -59,7 +59,7 @@
|
|||||||
#define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 0
|
#define COLLIDER_DEBUG_DETAILED_DRAW_MENKOWSKI 0
|
||||||
|
|
||||||
/* If enabled, bitbuffs will insert/verify magic numbers & length for each read & write */
|
/* 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
|
#define BITBUFF_TEST RTC
|
||||||
|
|
||||||
/* If enabled, things like network writes & memory allocations will be tracked in a global statistics struct */
|
/* If enabled, things like network writes & memory allocations will be tracked in a global statistics struct */
|
||||||
|
|||||||
10
src/phys.c
10
src/phys.c
@ -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) {
|
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];
|
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;
|
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
|
||||||
|
|
||||||
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
|
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;
|
struct sim_lookup *debug_lookup = ctx->debug_lookup;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
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];
|
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;
|
if (!sim_ent_has_prop(dbg_ent, SIM_ENT_PROP_COLLISION_DEBUG)) continue;
|
||||||
|
|
||||||
struct phys_collision_debug *dbg = &dbg_ent->collision_debug_data;
|
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);
|
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(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))) {
|
|| !(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 */
|
/* 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;
|
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) {
|
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];
|
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;
|
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
|
||||||
|
|
||||||
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
|
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;
|
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) {
|
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];
|
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;
|
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
|
||||||
|
|
||||||
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
|
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
|
||||||
|
|||||||
@ -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) {
|
for (u64 i = 2; i < local_ss->num_ents_reserved; ++i) {
|
||||||
struct sim_ent *local_ent = &local_ss->ents[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)) {
|
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) {
|
if (should_sync) {
|
||||||
struct sim_ent *remote_ent = sim_ent_from_id(remote_ss, local_ent->id);
|
struct sim_ent *remote_ent = sim_ent_from_id(remote_ss, local_ent->id);
|
||||||
if (remote_ent->valid) {
|
if (remote_ent->valid) {
|
||||||
|
|||||||
@ -72,7 +72,9 @@ struct sim_client {
|
|||||||
|
|
||||||
struct arena snapshots_arena;
|
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;
|
struct host_channel_id channel_id;
|
||||||
u64 channel_hash;
|
u64 channel_hash;
|
||||||
|
|
||||||
|
|||||||
@ -25,9 +25,11 @@ INTERNAL struct sim_ent *ent_from_index(struct sim_snapshot *ss, u32 index)
|
|||||||
* Ent allocation
|
* 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 *parent, struct sim_ent_id id)
|
||||||
struct sim_ent *sim_ent_alloc_raw(struct sim_snapshot *ss)
|
|
||||||
{
|
{
|
||||||
|
ASSERT(parent->valid);
|
||||||
|
ASSERT(ss->valid);
|
||||||
|
ASSERT(ss == parent->ss);
|
||||||
struct sim_ent *ent;
|
struct sim_ent *ent;
|
||||||
if (ss->first_free_ent > 0 && ss->first_free_ent < ss->num_ents_reserved) {
|
if (ss->first_free_ent > 0 && ss->first_free_ent < ss->num_ents_reserved) {
|
||||||
/* Reuse from free list */;
|
/* 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->owner = ss->client->ent_id;
|
||||||
ent->_is_xform_dirty = true;
|
ent->_is_xform_dirty = true;
|
||||||
++ss->num_ents_allocated;
|
++ss->num_ents_allocated;
|
||||||
|
|
||||||
|
sim_ent_set_id(ent, id);
|
||||||
|
sim_ent_link_parent(ent, parent);
|
||||||
|
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocates a new entity that will not sync */
|
/* Allocates a new entity that will not sync */
|
||||||
struct sim_ent *sim_ent_alloc_local(struct sim_ent *parent)
|
struct sim_ent *sim_ent_alloc_local(struct sim_ent *parent)
|
||||||
{
|
{
|
||||||
ASSERT(parent->valid);
|
|
||||||
struct sim_snapshot *ss = parent->ss;
|
struct sim_snapshot *ss = parent->ss;
|
||||||
struct sim_ent *e = sim_ent_alloc_raw(ss);
|
struct sim_ent *e = sim_ent_alloc_raw(ss, parent, sim_ent_random_id());
|
||||||
sim_ent_set_id(e, sim_ent_random_id());
|
e->owner = ss->local_client_ent;
|
||||||
|
|
||||||
sim_ent_link_parent(e, parent);
|
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_ent *sim_ent_alloc_local_with_id(struct sim_ent *parent, struct sim_ent_id id)
|
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_snapshot *ss = parent->ss;
|
||||||
struct sim_ent *e = sim_ent_alloc_raw(ss);
|
struct sim_ent *e = sim_ent_alloc_raw(ss, parent, id);
|
||||||
sim_ent_set_id(e, id);
|
e->owner = ss->local_client_ent;
|
||||||
|
|
||||||
sim_ent_link_parent(e, parent);
|
|
||||||
|
|
||||||
return e;
|
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_ent *sim_ent_alloc_sync_src(struct sim_ent *parent)
|
||||||
{
|
{
|
||||||
struct sim_snapshot *ss = parent->ss;
|
struct sim_snapshot *ss = parent->ss;
|
||||||
struct sim_ent *e = sim_ent_alloc_raw(ss);
|
struct sim_ent *e = sim_ent_alloc_raw(ss, parent, sim_ent_random_id());
|
||||||
sim_ent_set_id(e, sim_ent_random_id());
|
|
||||||
|
|
||||||
sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_SRC);
|
sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_SRC);
|
||||||
e->owner = ss->local_client_ent;
|
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;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocates a new entity that will sync with incoming net src ents containing id, and coming from the specified owner */
|
/* 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_snapshot *ss = parent->ss;
|
||||||
struct sim_ent *e = sim_ent_alloc_raw(ss);
|
struct sim_ent *e = sim_ent_alloc_raw(ss, parent, ent_id);
|
||||||
sim_ent_set_id(e, ent_id);
|
|
||||||
|
|
||||||
sim_ent_link_parent(e, parent);
|
|
||||||
|
|
||||||
sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_DST);
|
sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_DST);
|
||||||
e->owner = owner_client_ent_id;
|
e->owner = owner_id;
|
||||||
|
|
||||||
return e;
|
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;
|
struct sim_ent_id old_id = ent->id;
|
||||||
if (!sim_ent_id_eq(old_id, id)) {
|
if (!sim_ent_id_eq(old_id, id)) {
|
||||||
/* Release old from lookup */
|
/* 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);
|
struct sim_ent_bin *bin = bin_from_id(ss, old_id);
|
||||||
u32 prev_index = 0;
|
u32 prev_index = 0;
|
||||||
u32 next_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 */
|
/* Insert new id into lookup */
|
||||||
if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID)) {
|
if (!sim_ent_id_is_nil(id)) {
|
||||||
#if RTC
|
#if RTC
|
||||||
{
|
{
|
||||||
struct sim_ent *existing = sim_ent_from_id(ss, id);
|
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 *sim_ent_from_id(struct sim_snapshot *ss, struct sim_ent_id id)
|
||||||
{
|
{
|
||||||
struct sim_ent *res = sim_ent_nil();
|
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);
|
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)) {
|
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)) {
|
if (sim_ent_id_eq(e->id, id)) {
|
||||||
|
|||||||
@ -154,7 +154,8 @@ struct sim_ent {
|
|||||||
b32 client_dbg_drag_stop;
|
b32 client_dbg_drag_stop;
|
||||||
|
|
||||||
/* Client round-trip-time to server */
|
/* Client round-trip-time to server */
|
||||||
i64 client_rtt_ns;
|
i64 client_last_rtt_ns;
|
||||||
|
f64 client_average_rtt_seconds;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
/* Collider */
|
/* Collider */
|
||||||
@ -351,6 +352,20 @@ INLINE struct sim_ent *sim_ent_nil(void)
|
|||||||
return *_g_sim_ent_nil;
|
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
|
* Property helpers
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -409,11 +424,12 @@ INLINE b32 sim_ent_should_simulate(struct sim_ent *ent)
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
/* Alloc */
|
/* 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(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_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_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_raw(struct sim_ent *ent);
|
||||||
void sim_ent_release(struct sim_ent *ent);
|
void sim_ent_release(struct sim_ent *ent);
|
||||||
|
|||||||
@ -75,7 +75,7 @@ INTERNAL void spawn_test_entities(struct sim_step_ctx *ctx, struct v2 offset)
|
|||||||
e->layer = SIM_LAYER_SHOULDERS;
|
e->layer = SIM_LAYER_SHOULDERS;
|
||||||
|
|
||||||
sim_ent_enable_prop(e, SIM_ENT_PROP_PHYSICAL_DYNAMIC);
|
sim_ent_enable_prop(e, SIM_ENT_PROP_PHYSICAL_DYNAMIC);
|
||||||
e->mass_unscaled = 10;
|
e->mass_unscaled = 100;
|
||||||
e->inertia_unscaled = 10;
|
e->inertia_unscaled = 10;
|
||||||
e->linear_ground_friction = 250;
|
e->linear_ground_friction = 250;
|
||||||
e->angular_ground_friction = 200;
|
e->angular_ground_friction = 200;
|
||||||
@ -392,7 +392,11 @@ void sim_step(struct sim_step_ctx *ctx)
|
|||||||
|
|
||||||
/* Update rtt */
|
/* Update rtt */
|
||||||
if (is_master && client_ent->valid) {
|
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 */
|
/* 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) {
|
for (u64 i = 0; i < world->num_ents_reserved; ++i) {
|
||||||
struct sim_ent *ent = &world->ents[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_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);
|
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_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);
|
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) */
|
/* 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);
|
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;
|
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);
|
struct sprite_sheet_frame frame = sprite_sheet_get_frame(sheet, frame_index);
|
||||||
while (time_in_frame > frame.duration) {
|
while (time_in_frame > frame.duration) {
|
||||||
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_should_simulate(target_ent)) {
|
||||||
if (!sim_ent_is_valid_and_active(joint_ent)) {
|
if (!sim_ent_is_valid_and_active(joint_ent)) {
|
||||||
/* FIXME: Joint ent may never release */
|
/* 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->mass_unscaled = F32_INFINITY;
|
||||||
joint_ent->inertia_unscaled = F32_INFINITY;
|
joint_ent->inertia_unscaled = F32_INFINITY;
|
||||||
client_ent->client_dbg_drag_joint_ent = joint_ent->id;
|
client_ent->client_dbg_drag_joint_ent = joint_ent->id;
|
||||||
|
|||||||
101
src/user.c
101
src/user.c
@ -73,6 +73,7 @@ GLOBAL struct {
|
|||||||
|
|
||||||
struct bind_state bind_states[USER_BIND_KIND_COUNT];
|
struct bind_state bind_states[USER_BIND_KIND_COUNT];
|
||||||
|
|
||||||
|
struct sim_ent_id debug_following;
|
||||||
b32 debug_camera;
|
b32 debug_camera;
|
||||||
b32 debug_camera_panning;
|
b32 debug_camera_panning;
|
||||||
struct v2 debug_camera_pan_start;
|
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_C] = USER_BIND_KIND_DEBUG_CLEAR,
|
||||||
[SYS_BTN_V] = USER_BIND_KIND_DEBUG_SPAWN,
|
[SYS_BTN_V] = USER_BIND_KIND_DEBUG_SPAWN,
|
||||||
[SYS_BTN_N] = USER_BIND_KIND_DEBUG_STEP,
|
[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_F1] = USER_BIND_KIND_DEBUG_PAUSE,
|
||||||
[SYS_BTN_F2] = USER_BIND_KIND_DEBUG_CAMERA,
|
[SYS_BTN_F2] = USER_BIND_KIND_DEBUG_CAMERA,
|
||||||
[SYS_BTN_F3] = USER_BIND_KIND_DEBUG_DRAW,
|
[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;
|
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("prev: [%F]\n"), FMT_UID(ent->prev.uid)).len;
|
||||||
res.len += string_format(arena, LIT("next: [%F]\n"), FMT_UID(ent->next.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;
|
res.len += string_format(arena, LIT("angular velocity: %F\n"), FMT_FLOAT_P(angular_velocity, 3)).len;
|
||||||
|
|
||||||
/* Children */
|
/* 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);
|
struct sim_ent *child = sim_ent_from_id(ss, ent->first);
|
||||||
if (!sim_ent_id_eq(ent->first, ent->last) || !child->valid) {
|
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;
|
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
|
* 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
|
* 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)));
|
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;
|
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;
|
||||||
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;
|
u64 master_tick = master_client->last_tick;
|
||||||
struct sim_snapshot *master_ss = sim_snapshot_from_tick(master_client, master_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);
|
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;
|
user_input_client->ent_id = master_ss->local_client_ent;
|
||||||
local_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;
|
i64 cmds_ahead_on_master = (i64)master_client->ack - (i64)master_client->last_tick;
|
||||||
if (math_abs_i64(cmds_ahead_on_master) > 50) {
|
if (math_abs_i64(cmds_ahead_on_master) > 50) {
|
||||||
/* Cmds are too far from master time, snap step end tick */
|
/* Cmds are too far from master time, snap step end tick */
|
||||||
i64 rtt_ns = master_client->rtt_ns;
|
i64 rtt_ns = master_client->rtt_ns;
|
||||||
f64 rtt_tick_ratio = (f64)(rtt_ns + (step_dt_ns - 1)) / (f64)step_dt_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;
|
step_end_tick = step_base_tick + num_predict_ticks;
|
||||||
compute_timescale = 1.1;
|
compute_timescale = 1.1;
|
||||||
} else if (cmds_ahead_on_master > 2) {
|
} else if (cmds_ahead_on_master > 2) {
|
||||||
/* Slow down simulation rate to bring sim time closer to master time */
|
/* 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) {
|
} else if (cmds_ahead_on_master < 1) {
|
||||||
/* Speed up simulation rate to give master more inputs to work with */
|
/* Speed up simulation rate to give master more inputs to work with */
|
||||||
compute_timescale = 1.1;
|
compute_timescale = 1.05;
|
||||||
} else {
|
} else {
|
||||||
|
/* Server's cmd buffer is in a healthy range */
|
||||||
compute_timescale = 1;
|
compute_timescale = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,7 @@ enum user_bind_kind {
|
|||||||
|
|
||||||
USER_BIND_KIND_DEBUG_CLEAR,
|
USER_BIND_KIND_DEBUG_CLEAR,
|
||||||
USER_BIND_KIND_DEBUG_SPAWN,
|
USER_BIND_KIND_DEBUG_SPAWN,
|
||||||
|
USER_BIND_KIND_DEBUG_FOLLOW,
|
||||||
USER_BIND_KIND_DEBUG_DRAW,
|
USER_BIND_KIND_DEBUG_DRAW,
|
||||||
USER_BIND_KIND_DEBUG_CAMERA,
|
USER_BIND_KIND_DEBUG_CAMERA,
|
||||||
USER_BIND_KIND_DEBUG_PAUSE,
|
USER_BIND_KIND_DEBUG_PAUSE,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user