replace entity handles with uids

This commit is contained in:
jacob 2025-02-24 11:41:36 -06:00
parent fca945736b
commit 944be252c5
12 changed files with 510 additions and 494 deletions

16
.natvis
View File

@ -44,6 +44,22 @@
<Type Name = "uid"> <Type Name = "uid">
<DisplayString>[{(u32)(hi >> 32), xb}]{((u32)(hi &amp; 0xFFFFFFFF)), xb}{lo, xb}</DisplayString> <DisplayString>[{(u32)(hi >> 32), xb}]{((u32)(hi &amp; 0xFFFFFFFF)), xb}{lo, xb}</DisplayString>
<Expand>
<Item Name="hi">hi, x</Item>
<Item Name="lo">lo, x</Item>
</Expand>
</Type>
<Type Name = "sim_ent_id">
<DisplayString Condition="uid.hi == 0 &amp;&amp; uid.lo == 0">[NIL]</DisplayString>
<DisplayString Condition="uid.hi == 0x66a36cc2bcc752da &amp;&amp; uid.lo == 0x6c286c09b366eae6">[ROOT]</DisplayString>
<DisplayString>[{(u32)(uid.hi >> 32), xb}]</DisplayString>
</Type>
<Type Name = "sim_ent">
<DisplayString Condition="(valid == 0 || (id.uid.hi == 0 &amp;&amp; id.uid.lo == 0)) &amp;&amp; this != *_g_sim_ent_nil">~~~MISMATCH~~~ {id}</DisplayString>
<DisplayString Condition="valid == 1 &amp;&amp; (id.uid.hi == 0 || id.uid.lo == 0)">~~~MISMATCH~~~ {id}</DisplayString>
<DisplayString>{id}</DisplayString>
</Type> </Type>
<Type Name = "String"> <Type Name = "String">

View File

@ -442,16 +442,15 @@ struct pcm {
i16 *samples; i16 *samples;
}; };
struct sim_ent_handle {
u64 idx;
u64 gen;
};
struct sim_client_handle { struct sim_client_handle {
u32 idx; u32 idx;
u32 gen; u32 gen;
}; };
struct sim_ent_id {
struct uid uid;
};
struct space_entry_handle { struct space_entry_handle {
u64 idx; u64 idx;
u64 gen; u64 gen;

View File

@ -48,7 +48,7 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
struct sim_snapshot *ss = ctx->sim_step_ctx->world; struct sim_snapshot *ss = ctx->sim_step_ctx->world;
struct space *space = ctx->sim_step_ctx->accel->space; struct space *space = ctx->sim_step_ctx->accel->space;
struct sim_ent *root = sim_ent_from_handle(ss, SIM_ENT_ROOT_HANDLE); struct sim_ent *root = sim_ent_from_id(ss, SIM_ENT_ROOT_ID);
u64 tick = ss->tick; u64 tick = ss->tick;
for (u64 check0_index = 0; check0_index < ss->num_ents_reserved; ++check0_index) { for (u64 check0_index = 0; check0_index < ss->num_ents_reserved; ++check0_index) {
@ -64,20 +64,20 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
struct space_iter iter = space_iter_begin_aabb(space, aabb); struct space_iter iter = space_iter_begin_aabb(space, aabb);
struct space_entry *space_entry; struct space_entry *space_entry;
while ((space_entry = space_iter_next(&iter))) { while ((space_entry = space_iter_next(&iter))) {
struct sim_ent *check1 = sim_ent_from_handle(ss, space_entry->ent); struct sim_ent *check1 = sim_ent_from_id(ss, space_entry->ent);
if (check1 == check0) continue; if (check1 == check0) continue;
if (!sim_ent_is_valid_and_active(check1)) continue; if (!sim_ent_is_valid_and_active(check1)) continue;
if (!(sim_ent_has_prop(check1, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(check1, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue; if (!(sim_ent_has_prop(check1, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(check1, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue;
if (check1->local_collider.count <= 0) continue; if (check1->local_collider.count <= 0) continue;
/* Deterministic order based on entity index */ /* Deterministic order based on entity id */
struct sim_ent *e0; struct sim_ent *e0;
struct sim_ent *e1; struct sim_ent *e1;
struct xform e0_xf; struct xform e0_xf;
struct xform e1_xf; struct xform e1_xf;
struct collider_shape e0_collider; struct collider_shape e0_collider;
struct collider_shape e1_collider; struct collider_shape e1_collider;
if (check0_index < check1->handle.idx) { if (check0->id.uid.hi < check1->id.uid.hi) {
e0 = check0; e0 = check0;
e1 = check1; e1 = check1;
e0_xf = check0_xf; e0_xf = check0_xf;
@ -93,8 +93,8 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
e1_collider = check0_collider; e1_collider = check0_collider;
} }
struct uid constraint_uid = uid_combine(uid_combine(SIM_ENT_BASIS_UID_CONTACT, e0->uid), e1->uid); struct sim_ent_id constraint_id = sim_ent_contact_constraint_id_from_contacting_ids(e0->id, e1->id);
struct sim_ent *constraint_ent = sim_ent_from_uid(ss, constraint_uid); struct sim_ent *constraint_ent = sim_ent_from_id(ss, constraint_id);
if (constraint_ent->valid) { if (constraint_ent->valid) {
if (constraint_ent->contact_constraint_data.last_phys_iteration >= phys_iteration) { if (constraint_ent->contact_constraint_data.last_phys_iteration >= phys_iteration) {
@ -117,9 +117,9 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
if (!constraint_ent->valid) { if (!constraint_ent->valid) {
/* Create constraint */ /* Create constraint */
{ {
constraint_ent = sim_ent_alloc_local_with_uid(root, constraint_uid); constraint_ent = sim_ent_alloc_local_with_id(root, constraint_id);
constraint_ent->contact_constraint_data.e1 = e1->handle; constraint_ent->contact_constraint_data.e0 = e0->id;
constraint_ent->contact_constraint_data.e0 = e0->handle; constraint_ent->contact_constraint_data.e1 = e1->id;
constraint_ent->contact_constraint_data.skip_solve = sim_ent_has_prop(e0, SIM_ENT_PROP_SENSOR) || sim_ent_has_prop(e1, SIM_ENT_PROP_SENSOR) constraint_ent->contact_constraint_data.skip_solve = sim_ent_has_prop(e0, SIM_ENT_PROP_SENSOR) || sim_ent_has_prop(e1, SIM_ENT_PROP_SENSOR)
|| !(sim_ent_has_prop(e0, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_DYNAMIC)); || !(sim_ent_has_prop(e0, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_DYNAMIC));
sim_ent_enable_prop(constraint_ent, SIM_ENT_PROP_ACTIVE); sim_ent_enable_prop(constraint_ent, SIM_ENT_PROP_ACTIVE);
@ -134,8 +134,8 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
struct phys_collision_data *data = arena_push_zero(arena, struct phys_collision_data); struct phys_collision_data *data = arena_push_zero(arena, struct phys_collision_data);
++res.count; ++res.count;
data->constraint = &constraint_ent->contact_constraint_data; data->constraint = &constraint_ent->contact_constraint_data;
data->e0 = e0->handle; data->e0 = e0->id;
data->e1 = e1->handle; data->e1 = e1->id;
data->normal = collider_res.normal; data->normal = collider_res.normal;
data->dt = elapsed_dt; data->dt = elapsed_dt;
@ -227,7 +227,7 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
struct sim_ent *dbg_ent = sim_ent_nil(); struct sim_ent *dbg_ent = sim_ent_nil();
struct sim_lookup_entry *dbg_entry = sim_lookup_get(debug_lookup, key); struct sim_lookup_entry *dbg_entry = sim_lookup_get(debug_lookup, key);
if (dbg_entry) { if (dbg_entry) {
dbg_ent = sim_ent_from_handle(ss, dbg_entry->entity); dbg_ent = sim_ent_from_id(ss, dbg_entry->entity);
} }
if (!dbg_ent->valid) { if (!dbg_ent->valid) {
@ -280,8 +280,8 @@ void phys_prepare_contacts(struct phys_step_ctx *ctx, u64 phys_iteration)
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data; struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
u32 num_points = constraint->num_points; u32 num_points = constraint->num_points;
struct sim_ent *e0 = sim_ent_from_handle(ss, constraint->e0); struct sim_ent *e0 = sim_ent_from_id(ss, constraint->e0);
struct sim_ent *e1 = sim_ent_from_handle(ss, constraint->e1); struct sim_ent *e1 = sim_ent_from_id(ss, constraint->e1);
if (constraint->last_phys_iteration >= phys_iteration && num_points > 0 && sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) { if (constraint->last_phys_iteration >= phys_iteration && num_points > 0 && sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
struct v2 normal = constraint->normal; struct v2 normal = constraint->normal;
struct v2 tangent = v2_perp(normal); struct v2 tangent = v2_perp(normal);
@ -361,8 +361,8 @@ void phys_prepare_contacts(struct phys_step_ctx *ctx, u64 phys_iteration)
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;
struct sim_ent *e0 = sim_ent_from_handle(ss, dbg->e0); struct sim_ent *e0 = sim_ent_from_id(ss, dbg->e0);
struct sim_ent *e1 = sim_ent_from_handle(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_is_valid_and_active(e0) || !sim_ent_is_valid_and_active(e1)
@ -398,8 +398,8 @@ void phys_warm_start_contacts(struct phys_step_ctx *ctx)
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data; struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
u32 num_points = constraint->num_points; u32 num_points = constraint->num_points;
struct sim_ent *e0 = sim_ent_from_handle(ss, constraint->e0); struct sim_ent *e0 = sim_ent_from_id(ss, constraint->e0);
struct sim_ent *e1 = sim_ent_from_handle(ss, constraint->e1); struct sim_ent *e1 = sim_ent_from_id(ss, constraint->e1);
if (num_points > 0 && sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1) && !constraint->skip_solve) { if (num_points > 0 && sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1) && !constraint->skip_solve) {
struct xform e0_xf = sim_ent_get_xform(e0); struct xform e0_xf = sim_ent_get_xform(e0);
@ -452,8 +452,8 @@ void phys_solve_contacts(struct phys_step_ctx *ctx, f32 dt, b32 apply_bias)
struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data; struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data;
struct sim_ent *e0 = sim_ent_from_handle(ss, constraint->e0); struct sim_ent *e0 = sim_ent_from_id(ss, constraint->e0);
struct sim_ent *e1 = sim_ent_from_handle(ss, constraint->e1); struct sim_ent *e1 = sim_ent_from_id(ss, constraint->e1);
struct v2 v0 = e0->linear_velocity; struct v2 v0 = e0->linear_velocity;
struct v2 v1 = e1->linear_velocity; struct v2 v1 = e1->linear_velocity;
@ -583,8 +583,8 @@ void phys_prepare_motor_joints(struct phys_step_ctx *ctx)
struct phys_motor_joint *joint = &joint_ent->motor_joint_data; struct phys_motor_joint *joint = &joint_ent->motor_joint_data;
struct sim_ent *e0 = sim_ent_from_handle(ss, joint->e0); struct sim_ent *e0 = sim_ent_from_id(ss, joint->e0);
struct sim_ent *e1 = sim_ent_from_handle(ss, joint->e1); struct sim_ent *e1 = sim_ent_from_id(ss, joint->e1);
if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) { if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
struct xform e0_xf = sim_ent_get_xform(e0); struct xform e0_xf = sim_ent_get_xform(e0);
@ -647,8 +647,8 @@ void phys_warm_start_motor_joints(struct phys_step_ctx *ctx)
struct phys_motor_joint *joint = &joint_ent->motor_joint_data; struct phys_motor_joint *joint = &joint_ent->motor_joint_data;
struct sim_ent *e0 = sim_ent_from_handle(ss, joint->e0); struct sim_ent *e0 = sim_ent_from_id(ss, joint->e0);
struct sim_ent *e1 = sim_ent_from_handle(ss, joint->e1); struct sim_ent *e1 = sim_ent_from_id(ss, joint->e1);
struct xform e0_xf = sim_ent_get_xform(e0); struct xform e0_xf = sim_ent_get_xform(e0);
struct xform e1_xf = sim_ent_get_xform(e1); struct xform e1_xf = sim_ent_get_xform(e1);
@ -679,8 +679,8 @@ void phys_solve_motor_joints(struct phys_step_ctx *ctx, f32 dt)
struct phys_motor_joint *joint = &joint_ent->motor_joint_data; struct phys_motor_joint *joint = &joint_ent->motor_joint_data;
struct sim_ent *e0 = sim_ent_from_handle(ss, joint->e0); struct sim_ent *e0 = sim_ent_from_id(ss, joint->e0);
struct sim_ent *e1 = sim_ent_from_handle(ss, joint->e1); struct sim_ent *e1 = sim_ent_from_id(ss, joint->e1);
struct xform e0_xf = sim_ent_get_xform(e0); struct xform e0_xf = sim_ent_get_xform(e0);
struct xform e1_xf = sim_ent_get_xform(e1); struct xform e1_xf = sim_ent_get_xform(e1);
@ -771,7 +771,7 @@ void phys_prepare_mouse_joints(struct phys_step_ctx *ctx)
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue; if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue;
struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data; struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data;
struct sim_ent *ent = sim_ent_from_handle(ss, joint->target); struct sim_ent *ent = sim_ent_from_id(ss, joint->target);
if (sim_ent_is_valid_and_active(ent)) { if (sim_ent_is_valid_and_active(ent)) {
struct xform xf = sim_ent_get_xform(ent); struct xform xf = sim_ent_get_xform(ent);
@ -818,7 +818,7 @@ void phys_warm_start_mouse_joints(struct phys_step_ctx *ctx)
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue; if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue;
struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data; struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data;
struct sim_ent *ent = sim_ent_from_handle(ss, joint->target); struct sim_ent *ent = sim_ent_from_id(ss, joint->target);
if (sim_ent_is_valid_and_active(ent)) { if (sim_ent_is_valid_and_active(ent)) {
f32 inv_m = joint->inv_m; f32 inv_m = joint->inv_m;
f32 inv_i = joint->inv_i; f32 inv_i = joint->inv_i;
@ -840,7 +840,7 @@ void phys_solve_mouse_joints(struct phys_step_ctx *ctx, f32 dt)
if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue; if (!sim_ent_has_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT)) continue;
struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data; struct phys_mouse_joint *joint = &joint_ent->mouse_joint_data;
struct sim_ent *ent = sim_ent_from_handle(ss, joint->target); struct sim_ent *ent = sim_ent_from_id(ss, joint->target);
if (sim_ent_is_valid_and_active(ent)) { if (sim_ent_is_valid_and_active(ent)) {
struct v2 v = ent->linear_velocity; struct v2 v = ent->linear_velocity;
f32 w = ent->angular_velocity; f32 w = ent->angular_velocity;
@ -1003,7 +1003,7 @@ f32 phys_determine_earliest_toi_for_bullets(struct phys_step_ctx *ctx, f32 step_
struct space_iter iter = space_iter_begin_aabb(space, combined_aabb); struct space_iter iter = space_iter_begin_aabb(space, combined_aabb);
struct space_entry *entry; struct space_entry *entry;
while ((entry = space_iter_next(&iter))) { while ((entry = space_iter_next(&iter))) {
struct sim_ent *e1 = sim_ent_from_handle(ss, entry->ent); struct sim_ent *e1 = sim_ent_from_id(ss, entry->ent);
if (e1 == e0) continue; if (e1 == e0) continue;
if (!sim_ent_is_valid_and_active(e1)) continue; if (!sim_ent_is_valid_and_active(e1)) continue;
if (!(sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue; if (!(sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_DYNAMIC) || sim_ent_has_prop(e1, SIM_ENT_PROP_PHYSICAL_KINEMATIC))) continue;
@ -1040,7 +1040,7 @@ void phys_update_aabbs(struct phys_step_ctx *ctx)
struct xform xf = sim_ent_get_xform(ent); struct xform xf = sim_ent_get_xform(ent);
struct space_entry *space_entry = space_entry_from_handle(space, ent->space_handle); struct space_entry *space_entry = space_entry_from_handle(space, ent->space_handle);
if (!space_entry->valid) { if (!space_entry->valid) {
space_entry = space_entry_alloc(space, ent->handle); space_entry = space_entry_alloc(space, ent->id);
ent->space_handle = space_entry->handle; ent->space_handle = space_entry->handle;
} }
struct aabb aabb = collider_aabb_from_collider(&ent->local_collider, xf); struct aabb aabb = collider_aabb_from_collider(&ent->local_collider, xf);

View File

@ -11,8 +11,8 @@ struct sim_step_ctx;
struct phys_contact_constraint; struct phys_contact_constraint;
struct phys_collision_data { struct phys_collision_data {
struct phys_contact_constraint *constraint; struct phys_contact_constraint *constraint;
struct sim_ent_handle e0; struct sim_ent_id e0;
struct sim_ent_handle e1; struct sim_ent_id e1;
struct v2 point; struct v2 point;
struct v2 normal; /* Normal of the collision from e0 to e1 */ struct v2 normal; /* Normal of the collision from e0 to e1 */
struct v2 vrel; /* Relative velocity at point of collision */ struct v2 vrel; /* Relative velocity at point of collision */
@ -68,8 +68,8 @@ struct phys_contact_point {
struct phys_contact_constraint { struct phys_contact_constraint {
u64 last_phys_iteration; /* To avoid checking collisions for the same constraint twice in one tick */ u64 last_phys_iteration; /* To avoid checking collisions for the same constraint twice in one tick */
b32 skip_solve; b32 skip_solve;
struct sim_ent_handle e0; struct sim_ent_id e0;
struct sim_ent_handle e1; struct sim_ent_id e1;
f32 inv_m0; f32 inv_m0;
f32 inv_m1; f32 inv_m1;
f32 inv_i0; f32 inv_i0;
@ -87,8 +87,8 @@ struct phys_contact_constraint {
}; };
struct phys_collision_debug { struct phys_collision_debug {
struct sim_ent_handle e0; struct sim_ent_id e0;
struct sim_ent_handle e1; struct sim_ent_id e1;
struct collider_collision_points_result res; struct collider_collision_points_result res;
struct phys_contact_point points[2]; struct phys_contact_point points[2];
@ -111,16 +111,16 @@ void phys_solve_contacts(struct phys_step_ctx *ctx, f32 dt, b32 apply_bias);
* ========================== */ * ========================== */
struct phys_motor_joint_def { struct phys_motor_joint_def {
struct sim_ent_handle e0; struct sim_ent_id e0;
struct sim_ent_handle e1; struct sim_ent_id e1;
f32 correction_rate; f32 correction_rate;
f32 max_force; f32 max_force;
f32 max_torque; f32 max_torque;
}; };
struct phys_motor_joint { struct phys_motor_joint {
struct sim_ent_handle e0; struct sim_ent_id e0;
struct sim_ent_handle e1; struct sim_ent_id e1;
f32 correction_rate; f32 correction_rate;
f32 max_force; f32 max_force;
f32 max_torque; f32 max_torque;
@ -150,14 +150,14 @@ void phys_solve_motor_joints(struct phys_step_ctx *ctx, f32 dt);
* ========================== */ * ========================== */
struct phys_mouse_joint_def { struct phys_mouse_joint_def {
struct sim_ent_handle target; struct sim_ent_id target;
struct v2 point_local_start; struct v2 point_local_start;
struct v2 point_local_end; struct v2 point_local_end;
f32 max_force; f32 max_force;
}; };
struct phys_mouse_joint { struct phys_mouse_joint {
struct sim_ent_handle target; struct sim_ent_id target;
struct v2 point_local_start; struct v2 point_local_start;
struct v2 point_local_end; struct v2 point_local_end;
struct math_spring_result linear_softness; struct math_spring_result linear_softness;

View File

@ -25,7 +25,7 @@
#define CLIENT_LOOKUP_BUCKETS 127 #define CLIENT_LOOKUP_BUCKETS 127
#define TICK_LOOKUP_BUCKETS 127 #define TICK_LOOKUP_BUCKETS 127
#define UID_LOOKUP_BUCKETS 4096 #define ID_LOOKUP_BUCKETS 4096
/* ========================== * /* ========================== *
* Startup * Startup
@ -73,7 +73,7 @@ struct sim_startup_receipt sim_startup(void)
G.nil_ent = arena_push_zero(&G.nil_arena, struct sim_ent); G.nil_ent = arena_push_zero(&G.nil_arena, struct sim_ent);
G.nil_ent->ss = sim_snapshot_nil(); G.nil_ent->ss = sim_snapshot_nil();
G.nil_ent->valid = false; G.nil_ent->valid = false;
G.nil_ent->handle = SIM_ENT_NIL_HANDLE; G.nil_ent->id = SIM_ENT_NIL_ID;
G.nil_ent->_local_xform = XFORM_IDENT; G.nil_ent->_local_xform = XFORM_IDENT;
G.nil_ent->_xform = XFORM_IDENT; G.nil_ent->_xform = XFORM_IDENT;
G.nil_ent->_is_xform_dirty = false; G.nil_ent->_is_xform_dirty = false;
@ -305,18 +305,18 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_client *client, struct sim_sn
ss->sim_dt_ns = src->sim_dt_ns; ss->sim_dt_ns = src->sim_dt_ns;
ss->sim_time_ns = src->sim_time_ns; ss->sim_time_ns = src->sim_time_ns;
ss->continuity_gen = src->continuity_gen; ss->continuity_gen = src->continuity_gen;
ss->local_client_ent_uid = src->local_client_ent_uid; ss->local_client_ent = src->local_client_ent;
ss->phys_iteration = src->phys_iteration; ss->phys_iteration = src->phys_iteration;
/* Copy uid lookup buckets */ /* Copy id lookup buckets */
ss->num_uid_buckets = src->num_uid_buckets > 0 ? src->num_uid_buckets : UID_LOOKUP_BUCKETS; ss->num_id_buckets = src->num_id_buckets > 0 ? src->num_id_buckets : ID_LOOKUP_BUCKETS;
ss->uid_buckets = arena_push_array(&ss->arena, struct sim_ent_bucket, ss->num_uid_buckets); ss->id_buckets = arena_push_array(&ss->arena, struct sim_ent_bucket, ss->num_id_buckets);
if (src->num_uid_buckets > 0) { if (src->num_id_buckets > 0) {
for (u64 i = 0; i < src->num_uid_buckets; ++i) { for (u64 i = 0; i < src->num_id_buckets; ++i) {
ss->uid_buckets[i] = src->uid_buckets[i]; ss->id_buckets[i] = src->id_buckets[i];
} }
} else { } else {
MEMZERO(ss->uid_buckets, sizeof(*ss->uid_buckets) * ss->num_uid_buckets); MEMZERO(ss->id_buckets, sizeof(*ss->id_buckets) * ss->num_id_buckets);
} }
/* Copy entities */ /* Copy entities */
@ -325,17 +325,28 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_client *client, struct sim_sn
ss->num_ents_reserved = src->num_ents_reserved; ss->num_ents_reserved = src->num_ents_reserved;
ss->ents = arena_push_array(&ss->ents_arena, struct sim_ent, ss->num_ents_reserved); ss->ents = arena_push_array(&ss->ents_arena, struct sim_ent, ss->num_ents_reserved);
if (ss->num_ents_reserved == 0) { if (ss->num_ents_reserved == 0) {
/* Create root ent if copying from nil snapshot */ /* Copying from nil snapshot, need to create blank & root entity */
/* Push blank ent at index 0 (because index 0 is never valid anyway since it maps to sim_ent_nil()) */
{
arena_push_zero(&ss->ents_arena, struct sim_ent);
++ss->num_ents_allocated;
++ss->num_ents_reserved;
}
/* Push root ent with constant id */
{
struct sim_ent *root = arena_push(&ss->ents_arena, struct sim_ent); struct sim_ent *root = arena_push(&ss->ents_arena, struct sim_ent);
*root = *sim_ent_nil(); *root = *sim_ent_nil();
root->ss = ss; root->ss = ss;
root->handle = SIM_ENT_ROOT_HANDLE;
root->valid = true; root->valid = true;
root->is_root = true; root->is_root = true;
root->mass_unscaled = F32_INFINITY; root->mass_unscaled = F32_INFINITY;
root->inertia_unscaled = F32_INFINITY; root->inertia_unscaled = F32_INFINITY;
sim_ent_set_id(root, SIM_ENT_ROOT_ID);
++ss->num_ents_allocated; ++ss->num_ents_allocated;
++ss->num_ents_reserved; ++ss->num_ents_reserved;
}
} else { } else {
for (u64 i = 0; i < ss->num_ents_reserved; ++i) { for (u64 i = 0; i < ss->num_ents_reserved; ++i) {
struct sim_ent *dst_ent = &ss->ents[i]; struct sim_ent *dst_ent = &ss->ents[i];
@ -574,6 +585,43 @@ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_client *client, str
return ss; return ss;
} }
/* ========================== *
* Snapshot sync
* ========================== */
/* Syncs entity data between snapshots */
void sim_snapshot_sync(struct sim_snapshot *local_ss, struct sim_snapshot *remote_ss)
{
__prof;
/* FIXME: Only sync cmds from non-master remote */
struct sim_ent *local_root = sim_ent_from_id(local_ss, SIM_ENT_ROOT_ID);
struct sim_ent *remote_root = sim_ent_from_id(remote_ss, SIM_ENT_ROOT_ID);
struct sim_client_handle remote_client_handle = remote_ss->client->handle;
/* Create new ents from remote */
for (struct sim_ent *remote_top = sim_ent_from_id(remote_ss, remote_root->first); remote_top->valid; remote_top = sim_ent_from_id(remote_ss, remote_top->next)) {
sim_ent_sync_alloc_tree(local_root, remote_top);
}
/* Sync ents with remote */
for (u64 i = 0; 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) && sim_client_handle_eq(local_ent->sync_src_client, remote_client_handle)) {
struct sim_ent *remote_ent = sim_ent_from_id(remote_ss, local_ent->id);
if (remote_ent->valid) {
/* Copy all ent data from remote */
sim_ent_sync(local_ent, remote_ent);
} else {
/* Remote ent is no longer valid / networked, release it */
sim_ent_enable_prop(local_ent, SIM_ENT_PROP_RELEASE);
sim_ent_disable_prop(local_ent, SIM_ENT_PROP_SYNC_DST);
}
}
}
sim_ent_release_all_with_prop(local_ss, SIM_ENT_PROP_RELEASE);
}
/* ========================== * /* ========================== *
* Snapshot encode * Snapshot encode
* ========================== */ * ========================== */
@ -588,7 +636,7 @@ void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_client *receiver,
bw_write_uv(bw, ss1->continuity_gen); bw_write_uv(bw, ss1->continuity_gen);
bw_write_uv(bw, ss1->phys_iteration); bw_write_uv(bw, ss1->phys_iteration);
bw_write_uid(bw, receiver->ent_uid); bw_write_uid(bw, receiver->ent_id.uid);
/* Ents */ /* Ents */
if (ss1->num_ents_allocated == ss0->num_ents_allocated) { if (ss1->num_ents_allocated == ss0->num_ents_allocated) {
@ -627,7 +675,7 @@ void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss)
ss->continuity_gen = br_read_uv(br); ss->continuity_gen = br_read_uv(br);
ss->phys_iteration = br_read_uv(br); ss->phys_iteration = br_read_uv(br);
ss->local_client_ent_uid = br_read_uid(br); ss->local_client_ent = (struct sim_ent_id) { .uid = br_read_uid(br) };
/* Ents */ /* Ents */
if (br_read_bit(br)) { if (br_read_bit(br)) {
@ -648,6 +696,7 @@ void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss)
} }
for (u64 i = 0; i < ss->num_ents_reserved; ++i) { for (u64 i = 0; i < ss->num_ents_reserved; ++i) {
struct sim_ent *e = &ss->ents[i]; struct sim_ent *e = &ss->ents[i];
e->ss = ss;
sim_ent_decode(br, e); sim_ent_decode(br, e);
} }
} }

View File

@ -3,9 +3,6 @@
#define SIM_CLIENT_NIL_HANDLE ((struct sim_client_handle) { .gen = 0, .idx = 0 }) #define SIM_CLIENT_NIL_HANDLE ((struct sim_client_handle) { .gen = 0, .idx = 0 })
/* UID magic number bases (to be used in conjunction with random UIDs in deterministic UID combinations) */
#define SIM_ENT_BASIS_UID_CONTACT (UID(0x6a2a5d2dbecf534f, 0x0a8ca7c372a015af))
/* Absolute layers */ /* Absolute layers */
#define SIM_LAYER_FLOOR_DECALS (-300) #define SIM_LAYER_FLOOR_DECALS (-300)
#define SIM_LAYER_BULLETS (-200) #define SIM_LAYER_BULLETS (-200)
@ -82,8 +79,8 @@ struct sim_client {
struct sim_client_handle next_in_bucket; struct sim_client_handle next_in_bucket;
struct sim_client_handle prev_in_bucket; struct sim_client_handle prev_in_bucket;
/* The client entity's uid in the master sim (if relevant) */ /* The client entity's id in the master sim (if relevant) */
struct uid ent_uid; struct sim_ent_id ent_id;
/* This is the highest confirmed tick of ours that we know this client has received */ /* This is the highest confirmed tick of ours that we know this client has received */
u64 ack; u64 ack;
@ -174,18 +171,18 @@ struct sim_snapshot {
/* The last physics iteration (used for tracking contact lifetime) */ /* The last physics iteration (used for tracking contact lifetime) */
u64 phys_iteration; u64 phys_iteration;
struct uid local_client_ent_uid; /* The uid of the receiver's client ent */ struct sim_ent_id local_client_ent; /* The id of the receiver's client ent */
/* Uid lookup */ /* Id lookup */
struct sim_ent_bucket *uid_buckets; struct sim_ent_bucket *id_buckets;
u64 num_uid_buckets; u64 num_id_buckets;
/* Entities */ /* Entities */
struct arena ents_arena; struct arena ents_arena;
struct sim_ent *ents; struct sim_ent *ents;
struct sim_ent_handle first_free_ent; u32 first_free_ent;
u64 num_ents_allocated; u32 num_ents_allocated;
u64 num_ents_reserved; u32 num_ents_reserved;
}; };
INLINE struct sim_snapshot *sim_snapshot_nil(void) INLINE struct sim_snapshot *sim_snapshot_nil(void)
@ -210,6 +207,9 @@ struct sim_snapshot *sim_snapshot_from_closest_tick_gte(struct sim_client *clien
/* Lerp */ /* Lerp */
struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_client *client, struct sim_snapshot *ss0, struct sim_snapshot *ss1, f64 blend); struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_client *client, struct sim_snapshot *ss0, struct sim_snapshot *ss1, f64 blend);
/* Sync */
void sim_snapshot_sync(struct sim_snapshot *local_ss, struct sim_snapshot *remote_ss);
/* Encode / decode */ /* Encode / decode */
void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_client *receiver, struct sim_snapshot *ss0, struct sim_snapshot *ss1); void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_client *receiver, struct sim_snapshot *ss0, struct sim_snapshot *ss1);
void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss); void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss);

View File

@ -4,29 +4,43 @@
#include "bitbuff.h" #include "bitbuff.h"
#include "uid.h" #include "uid.h"
/* Id magic number constants (to be used in conjunction with ent ids in deterministic id combinations) */
#define SIM_ENT_CONTACT_BASIS_ID (UID(0x6a2a5d2dbecf534f, 0x0a8ca7c372a015af))
INTERNAL u32 index_from_ent(struct sim_snapshot *ss, struct sim_ent *ent)
{
return ent - ss->ents;
}
INTERNAL struct sim_ent *ent_from_index(struct sim_snapshot *ss, u32 index)
{
if (index > 0 && index < ss->num_ents_reserved) {
return &ss->ents[index];
} else {
return sim_ent_nil();
}
}
/* ========================== * /* ========================== *
* 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 *sim_ent_alloc_raw(struct sim_snapshot *ss)
{ {
struct sim_ent *ent = NULL; struct sim_ent *ent;
struct sim_ent_handle handle = ZI; if (ss->first_free_ent > 0 && ss->first_free_ent < ss->num_ents_reserved) {
if (ss->first_free_ent.gen) {
/* Reuse from free list */; /* Reuse from free list */;
ent = sim_ent_from_handle(ss, ss->first_free_ent); ent = &ss->ents[ss->first_free_ent];
handle = ent->handle;
++handle.gen;
ss->first_free_ent = ent->next_free; ss->first_free_ent = ent->next_free;
} else { } else {
/* Make new */ /* Make new */
ent = arena_push(&ss->ents_arena, struct sim_ent); ent = arena_push(&ss->ents_arena, struct sim_ent);
handle = (struct sim_ent_handle) { .gen = 1, .idx = ss->num_ents_reserved++ }; ++ss->num_ents_reserved;
} }
*ent = *sim_ent_nil(); *ent = *sim_ent_nil();
ent->ss = ss; ent->ss = ss;
ent->valid = true; ent->valid = true;
ent->handle = handle;
ent->_is_xform_dirty = true; ent->_is_xform_dirty = true;
++ss->num_ents_allocated; ++ss->num_ents_allocated;
return ent; return ent;
@ -38,21 +52,21 @@ struct sim_ent *sim_ent_alloc_local(struct sim_ent *parent)
ASSERT(parent->valid); 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);
sim_ent_link_parent(e, parent); sim_ent_set_id(e, sim_ent_random_id());
sim_ent_set_uid(e, uid_rand()); sim_ent_link_parent(e, parent);
return e; return e;
} }
struct sim_ent *sim_ent_alloc_local_with_uid(struct sim_ent *parent, struct uid uid) struct sim_ent *sim_ent_alloc_local_with_id(struct sim_ent *parent, struct sim_ent_id id)
{ {
ASSERT(parent->valid); 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);
sim_ent_link_parent(e, parent); sim_ent_set_id(e, id);
sim_ent_set_uid(e, uid); sim_ent_link_parent(e, parent);
return e; return e;
} }
@ -62,28 +76,28 @@ 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);
sim_ent_link_parent(e, parent); sim_ent_set_id(e, sim_ent_random_id());
sim_ent_set_uid(e, uid_rand());
sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_SRC); sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_SRC);
e->sync_src_client = ss->client->handle; e->sync_src_client = ss->client->handle;
sim_ent_link_parent(e, parent);
return e; return e;
} }
/* Allocates a new entity that will sync with incoming net src ents containing uid, and coming from the specified client */ /* Allocates a new entity that will sync with incoming net src ents containing uid, and coming from the specified client */
struct sim_ent *sim_ent_alloc_sync_dst(struct sim_ent *parent, struct sim_client_handle client_handle, struct uid uid) struct sim_ent *sim_ent_alloc_sync_dst(struct sim_ent *parent, struct sim_client_handle client_handle, struct sim_ent_id 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);
sim_ent_link_parent(e, parent); sim_ent_set_id(e, id);
sim_ent_set_uid(e, uid);
sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_DST); sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_DST);
e->sync_src_client = client_handle; e->sync_src_client = client_handle;
sim_ent_link_parent(e, parent);
return e; return e;
} }
@ -91,27 +105,28 @@ void sim_ent_release_raw(struct sim_ent *ent)
{ {
struct sim_snapshot *ss = ent->ss; struct sim_snapshot *ss = ent->ss;
/* Release children */ /* Release children */
struct sim_ent_handle first_handle = ent->first; struct sim_ent *child = sim_ent_from_id(ss, ent->first);
if (first_handle.gen) { while (child->valid) {
for (struct sim_ent *child = sim_ent_from_handle(ss, first_handle); child->valid; child = sim_ent_from_handle(ss, child->next)) { struct sim_ent *next = sim_ent_from_id(ss, child->next);
sim_ent_release_raw(child); sim_ent_release_raw(child);
} child = next;
} }
/* Release uid */ /* Release uid */
sim_ent_set_uid(ent, UID(0, 0)); sim_ent_set_id(ent, SIM_ENT_NIL_ID);
/* Release */ /* Release */
++ent->handle.gen;
ent->valid = false; ent->valid = false;
ent->next_free = ss->first_free_ent; ent->next_free = ss->first_free_ent;
ss->first_free_ent = ent->handle; ss->first_free_ent = index_from_ent(ss, ent);
--ss->num_ents_allocated; --ss->num_ents_allocated;
} }
void sim_ent_release(struct sim_ent *ent) void sim_ent_release(struct sim_ent *ent)
{ {
if (ent->parent.gen) { struct sim_snapshot *ss = ent->ss;
struct sim_ent *parent = sim_ent_from_id(ss, ent->parent);
if (parent->valid) {
sim_ent_unlink_from_parent(ent); sim_ent_unlink_from_parent(ent);
} }
sim_ent_release_raw(ent); sim_ent_release_raw(ent);
@ -156,78 +171,84 @@ void sim_ent_activate(struct sim_ent *ent, u64 current_tick)
} }
/* ========================== * /* ========================== *
* Uid * Ent id
* ========================== */ * ========================== */
INLINE u64 hash_from_uid(struct uid uid) INTERNAL struct sim_ent_bucket *bucket_from_id(struct sim_snapshot *ss, struct sim_ent_id id)
{ {
/* Just use lower 64 bits of uid since it's already randomnized */ return &ss->id_buckets[id.uid.lo % ss->num_id_buckets];
return uid.lo;
} }
void sim_ent_set_uid(struct sim_ent *ent, struct uid uid) /* NOTE: This should only really happen during ent allocation (it doesn't make sense for an allocated ent's id to change) */
void sim_ent_set_id(struct sim_ent *ent, struct sim_ent_id id)
{ {
struct sim_snapshot *ss = ent->ss; struct sim_snapshot *ss = ent->ss;
struct sim_ent_bucket *buckets = ss->uid_buckets; struct sim_ent_id old_id = ent->id;
u64 num_uid_buckets = ss->num_uid_buckets; if (!sim_ent_id_eq(old_id, id)) {
struct uid old_uid = ent->uid;
/* Release old from lookup */ /* Release old from lookup */
if (!uid_is_zero(old_uid)) { if (!sim_ent_id_eq(old_id, SIM_ENT_NIL_ID)) {
u64 hash = hash_from_uid(old_uid); struct sim_ent_bucket *bucket = bucket_from_id(ss, old_id);
struct sim_ent_bucket *bucket = &buckets[hash % num_uid_buckets]; u32 prev_index = 0;
u32 next_index = 0;
u32 e_index = bucket->first;
struct sim_ent *prev = sim_ent_nil(); struct sim_ent *prev = sim_ent_nil();
struct sim_ent *next = sim_ent_nil(); struct sim_ent *next = sim_ent_nil();
struct sim_ent *e = sim_ent_from_handle(ss, bucket->first); struct sim_ent *e = ent_from_index(ss, e_index);
while (e->valid) { while (e->valid) {
next = sim_ent_from_handle(ss, e->next_in_uid_bucket); next_index = e->next_in_id_bucket;
if (uid_eq(e->uid, old_uid)) { next = ent_from_index(ss, next_index);
if (sim_ent_id_eq(e->id, old_id)) {
break; break;
} }
prev_index = e_index;
prev = e; prev = e;
e_index = next_index;
e = next; e = next;
} }
if (e->valid) { if (e->valid) {
if (prev->valid) { if (prev->valid) {
prev->next_in_uid_bucket = next->handle; prev->next_in_id_bucket = next_index;
} else { } else {
bucket->first = next->handle; bucket->first = next_index;
} }
if (next->valid) { if (next->valid) {
next->prev_in_uid_bucket = prev->handle; next->prev_in_id_bucket = prev_index;
} else { } else {
bucket->last = prev->handle; bucket->last = prev_index;
} }
} else {
/* Old id not in bucket, this should be impossible. */
ASSERT(false);
} }
} }
/* Insert new uid into lookup */ /* Insert new id into lookup */
if (!uid_is_zero(uid)) { if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID)) {
u64 hash = hash_from_uid(uid); struct sim_ent_bucket *bucket = bucket_from_id(ss, id);
struct sim_ent_bucket *bucket = &buckets[hash % num_uid_buckets]; u32 ent_index = index_from_ent(ss, ent);
struct sim_ent *last = sim_ent_from_handle(ss, bucket->last); struct sim_ent *last = ent_from_index(ss, bucket->last);
if (last->valid) { if (last->valid) {
last->next_in_uid_bucket = ent->handle; last->next_in_id_bucket = ent_index;
ent->prev_in_id_bucket = bucket->last;
} else { } else {
bucket->first = ent->handle; bucket->first = ent_index;
ent->prev_in_id_bucket = 0;
} }
ent->prev_in_uid_bucket = last->handle; bucket->last = ent_index;
bucket->last = ent->handle;
} }
ent->uid = uid; ent->id = id;
} }
struct sim_ent *sim_ent_from_uid(struct sim_snapshot *ss, struct uid uid) }
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();
u64 num_buckets = ss->num_uid_buckets; if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID) && ss->valid) {
if (num_buckets > 0 && !uid_is_zero(uid)) { struct sim_ent_bucket *bucket = bucket_from_id(ss, id);
u64 hash = hash_from_uid(uid); for (struct sim_ent *e = ent_from_index(ss, bucket->first); e->valid; e = ent_from_index(ss, e->next_in_id_bucket)) {
struct sim_ent_bucket *bucket = &ss->uid_buckets[hash % num_buckets]; if (sim_ent_id_eq(e->id, id)) {
for (struct sim_ent *e = sim_ent_from_handle(ss, bucket->first); e->valid; e = sim_ent_from_handle(ss, e->next_in_uid_bucket)) {
if (uid_eq(e->uid, uid)) {
res = e; res = e;
break; break;
} }
@ -236,22 +257,25 @@ struct sim_ent *sim_ent_from_uid(struct sim_snapshot *ss, struct uid uid)
return res; return res;
} }
struct sim_ent_id sim_ent_random_id(void)
{
struct sim_ent_id res = ZI;
res.uid = uid_rand();
return res;
}
/* Returns the deterministic id of the contact constraint ent id that should be produced from e0 & e1 colliding */
struct sim_ent_id sim_ent_contact_constraint_id_from_contacting_ids(struct sim_ent_id id0, struct sim_ent_id id1)
{
struct sim_ent_id res = ZI;
res.uid = uid_combine(uid_combine(SIM_ENT_CONTACT_BASIS_ID, id0.uid), id1.uid);
return res;
}
/* ========================== * /* ========================== *
* Ent query * Ent query
* ========================== */ * ========================== */
/* Returns a valid ent or read-only nil ent. Always safe to read result, need to check `valid` to write. */
struct sim_ent *sim_ent_from_handle(struct sim_snapshot *ss, struct sim_ent_handle handle)
{
if (handle.gen != 0 && handle.idx < ss->num_ents_reserved) {
struct sim_ent *ent = &ss->ents[handle.idx];
if (ent->handle.gen == handle.gen) {
return ent;
}
}
return sim_ent_nil();
}
struct sim_ent *sim_ent_find_first_match_one(struct sim_snapshot *ss, enum sim_ent_prop prop) struct sim_ent *sim_ent_find_first_match_one(struct sim_snapshot *ss, enum sim_ent_prop prop)
{ {
u64 count = ss->num_ents_reserved; u64 count = ss->num_ents_reserved;
@ -295,32 +319,31 @@ void sim_ent_link_parent(struct sim_ent *ent, struct sim_ent *parent)
{ {
struct sim_snapshot *ss = ent->ss; struct sim_snapshot *ss = ent->ss;
if (ent->parent.gen) { struct sim_ent *old_parent = sim_ent_from_id(ss, ent->parent);
if (old_parent->valid) {
/* Unlink from current parent */ /* Unlink from current parent */
sim_ent_unlink_from_parent(ent); sim_ent_unlink_from_parent(ent);
} }
struct sim_ent_handle handle = ent->handle; struct sim_ent_id ent_id = ent->id;
struct sim_ent_handle parent_handle = parent->handle; struct sim_ent_id last_child_id = parent->last;
struct sim_ent *last_child = sim_ent_from_id(ss, last_child_id);
ent->parent = parent_handle;
struct sim_ent_handle last_child_handle = parent->last;
struct sim_ent *last_child = sim_ent_from_handle(ss, last_child_handle);
if (last_child->valid) { if (last_child->valid) {
ent->prev = last_child_handle; ent->prev = last_child_id;
last_child->next = handle; last_child->next = ent_id;
} else { } else {
parent->first = handle; parent->first = ent_id;
} }
parent->last = handle; parent->last = ent_id;
if (parent->is_root) { if (parent->is_root) {
ent->is_top = true; ent->is_top = true;
ent->top = handle; ent->top = ent_id;
} else { } else {
ent->top = parent->top; ent->top = parent->top;
} }
ent->parent = parent->id;
} }
/* NOTE: Entity will be dangling after calling this, should re-link to root ent. */ /* NOTE: Entity will be dangling after calling this, should re-link to root ent. */
@ -328,24 +351,24 @@ void sim_ent_unlink_from_parent(struct sim_ent *ent)
{ {
struct sim_snapshot *ss = ent->ss; struct sim_snapshot *ss = ent->ss;
struct sim_ent_handle parent_handle = ent->parent; struct sim_ent_id parent_id = ent->parent;
struct sim_ent *parent = sim_ent_from_handle(ss, parent_handle); struct sim_ent *parent = sim_ent_from_id(ss, parent_id);
struct sim_ent *prev = sim_ent_from_handle(ss, ent->prev); struct sim_ent *prev = sim_ent_from_id(ss, ent->prev);
struct sim_ent *next = sim_ent_from_handle(ss, ent->next); struct sim_ent *next = sim_ent_from_id(ss, ent->next);
/* Unlink from parent & siblings */ /* Unlink from parent & siblings */
if (prev->valid) { if (prev->valid) {
prev->next = next->handle; prev->next = next->id;
} else { } else {
parent->first = next->handle; parent->first = next->id;
} }
if (next->valid) { if (next->valid) {
next->prev = prev->handle; next->prev = prev->id;
} else { } else {
parent->last = prev->handle; parent->last = prev->id;
} }
ent->prev = sim_ent_nil()->handle; ent->prev = SIM_ENT_NIL_ID;
ent->next = sim_ent_nil()->handle; ent->next = SIM_ENT_NIL_ID;
} }
/* ========================== * /* ========================== *
@ -354,7 +377,7 @@ void sim_ent_unlink_from_parent(struct sim_ent *ent)
INTERNAL void sim_ent_mark_child_xforms_dirty(struct sim_snapshot *ss, struct sim_ent *ent) INTERNAL void sim_ent_mark_child_xforms_dirty(struct sim_snapshot *ss, struct sim_ent *ent)
{ {
for (struct sim_ent *child = sim_ent_from_handle(ss, ent->first); child->valid; child = sim_ent_from_handle(ss, child->next)) { for (struct sim_ent *child = sim_ent_from_id(ss, ent->first); child->valid; child = sim_ent_from_id(ss, child->next)) {
if (child->_is_xform_dirty) { if (child->_is_xform_dirty) {
break; break;
} else { } else {
@ -371,7 +394,7 @@ INTERNAL struct xform sim_ent_get_xform_internal(struct sim_snapshot *ss, struct
if (ent->is_top) { if (ent->is_top) {
xf = ent->_local_xform; xf = ent->_local_xform;
} else { } else {
struct sim_ent *parent = sim_ent_from_handle(ss, ent->parent); struct sim_ent *parent = sim_ent_from_id(ss, ent->parent);
xf = sim_ent_get_xform_internal(ss, parent); xf = sim_ent_get_xform_internal(ss, parent);
xf = xform_mul(xf, ent->_local_xform); xf = xform_mul(xf, ent->_local_xform);
ent->_xform = xf; ent->_xform = xf;
@ -393,7 +416,7 @@ struct xform sim_ent_get_xform(struct sim_ent *ent)
xf = ent->_local_xform; xf = ent->_local_xform;
} else { } else {
struct sim_snapshot *ss = ent->ss; struct sim_snapshot *ss = ent->ss;
struct sim_ent *parent = sim_ent_from_handle(ss, ent->parent); struct sim_ent *parent = sim_ent_from_id(ss, ent->parent);
xf = sim_ent_get_xform_internal(ss, parent); xf = sim_ent_get_xform_internal(ss, parent);
xf = xform_mul(xf, ent->_local_xform); xf = xform_mul(xf, ent->_local_xform);
ent->_xform = xf; ent->_xform = xf;
@ -420,7 +443,7 @@ void sim_ent_set_xform(struct sim_ent *ent, struct xform xf)
if (ent->is_top) { if (ent->is_top) {
ent->_local_xform = xf; ent->_local_xform = xf;
} else { } else {
struct sim_ent *parent = sim_ent_from_handle(ss, ent->parent); struct sim_ent *parent = sim_ent_from_id(ss, ent->parent);
struct xform parent_global = sim_ent_get_xform_internal(ss, parent); struct xform parent_global = sim_ent_get_xform_internal(ss, parent);
ent->_local_xform = xform_mul(xform_invert(parent_global), xf); ent->_local_xform = xform_mul(xform_invert(parent_global), xf);
} }
@ -490,7 +513,7 @@ void sim_ent_apply_torque(struct sim_ent *ent, f32 torque)
void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64 blend) void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64 blend)
{ {
if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1) if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)
&& e0->handle.gen == e1->handle.gen && sim_ent_id_eq(e0->id, e1->id)
&& e0->continuity_gen == e1->continuity_gen) { && e0->continuity_gen == e1->continuity_gen) {
e->_local_xform = xform_lerp(e0->_local_xform, e1->_local_xform, blend); e->_local_xform = xform_lerp(e0->_local_xform, e1->_local_xform, blend);
@ -523,6 +546,59 @@ void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64
} }
} }
/* ========================== *
* Ent sync
* ========================== */
/* Walks a local & remote ent tree and allocates any missing net dst ents from remote src ents */
void sim_ent_sync_alloc_tree(struct sim_ent *local_parent, struct sim_ent *remote)
{
__prof;
if (sim_ent_has_prop(remote, SIM_ENT_PROP_SYNC_SRC)) {
struct sim_snapshot *local_ss = local_parent->ss;
struct sim_snapshot *remote_ss = remote->ss;
struct sim_client_handle remote_client_handle = remote_ss->client->handle;
struct sim_ent_id id = remote->id;
struct sim_ent *local_ent = sim_ent_from_id(local_ss, id);
if (!local_ent->valid) {
local_ent = sim_ent_alloc_sync_dst(local_parent, remote_client_handle, id);
}
for (struct sim_ent *remote_child = sim_ent_from_id(remote_ss, remote->first); remote_child->valid; remote_child = sim_ent_from_id(remote_ss, remote_child->next)) {
sim_ent_sync_alloc_tree(local_ent, remote_child);
}
}
}
/* Copies data between two synced entities */
void sim_ent_sync(struct sim_ent *local, struct sim_ent *remote)
{
struct sim_ent old = *local;
MEMCPY_STRUCT(local, remote);
/* Why would 2 ents w/ different uids ever be synced? */
ASSERT(sim_ent_id_eq(local->id, old.id));
local->ss = old.ss;
local->sync_src_client = remote->ss->client->handle;
/* Keep local tree */
local->parent = old.parent;
local->prev = old.prev;
local->next = old.next;
local->first = old.first;
local->last = old.last;
local->top = old.top;
/* Keep indices */
local->next_in_id_bucket = old.next_in_id_bucket;
local->prev_in_id_bucket = old.prev_in_id_bucket;
local->next_free = old.next_free;
sim_ent_disable_prop(local, SIM_ENT_PROP_SYNC_SRC);
sim_ent_enable_prop(local, SIM_ENT_PROP_SYNC_DST);
}
/* ========================== * /* ========================== *
* Ent encode * Ent encode
* ========================== */ * ========================== */
@ -562,26 +638,30 @@ void sim_ent_encode(struct bitbuff_writer *bw, struct sim_ent *e0, struct sim_en
void sim_ent_decode(struct bitbuff_reader *br, struct sim_ent *e) void sim_ent_decode(struct bitbuff_reader *br, struct sim_ent *e)
{ {
struct sim_snapshot *ss = e->ss; struct sim_ent decoded = *e;
{
struct uid old_uid = e->uid;
u64 pos = 0; u64 pos = 0;
while (pos < sizeof(*e)) { while (pos < sizeof(decoded)) {
u8 *chunk = (u8 *)e + pos; u8 *chunk = (u8 *)&decoded + pos;
if (br_read_bit(br)) { if (br_read_bit(br)) {
u64 chunk_size = min_u64(pos + 8, sizeof(*e)) - pos; u64 chunk_size = min_u64(pos + 8, sizeof(decoded)) - pos;
u64 bits = br_read_ubits(br, 64); u64 bits = br_read_ubits(br, 64);
MEMCPY(chunk, &bits, chunk_size); MEMCPY(chunk, &bits, chunk_size);
} }
pos += 8; pos += 8;
} }
struct uid new_uid = e->uid;
e->uid = old_uid;
if (!uid_eq(old_uid, new_uid)) {
sim_ent_set_uid(e, new_uid);
} }
decoded.ss = e->ss;
e->ss = ss; if (e->valid && !decoded.valid) {
sim_ent_release(e);
} else {
struct sim_ent_id old_id = e->id;
struct sim_ent_id new_id = decoded.id;
MEMCPY_STRUCT(e, &decoded);
e->id = old_id;
if (!sim_ent_id_eq(old_id, new_id)) {
sim_ent_set_id(e, new_id);
}
}
} }

View File

@ -6,8 +6,8 @@
#include "mixer.h" #include "mixer.h"
#include "phys.h" #include "phys.h"
#define SIM_ENT_NIL_HANDLE ((struct sim_ent_handle){ .gen = 0, .idx = 0 }) #define SIM_ENT_NIL_ID ((struct sim_ent_id) { UID(0, 0) })
#define SIM_ENT_ROOT_HANDLE ((struct sim_ent_handle){ .gen = 1, .idx = 0 }) #define SIM_ENT_ROOT_ID ((struct sim_ent_id) { UID(0x66a36cc2bcc752da, 0x6c286c09b366eae6) })
struct bitbuff_writer; struct bitbuff_writer;
struct bitbuff_reader; struct bitbuff_reader;
@ -59,16 +59,13 @@ enum sim_ent_prop {
}; };
struct sim_ent { struct sim_ent {
struct sim_snapshot *ss;
/* ====================================================================== */ /* ====================================================================== */
/* Metadata */ /* Metadata */
struct sim_snapshot *ss;
b32 valid; /* Is this ent allocated in memory that can be written to (can always be read) */ b32 valid; /* Is this ent allocated in memory that can be written to (can always be read) */
struct sim_ent_id id;
struct sim_ent_handle handle;
struct uid uid;
u64 props[(SIM_ENT_PROP_COUNT + 63) / 64]; u64 props[(SIM_ENT_PROP_COUNT + 63) / 64];
u64 continuity_gen; u64 continuity_gen;
@ -78,20 +75,20 @@ struct sim_ent {
/* Is ent a child of the root ent */ /* Is ent a child of the root ent */
b32 is_top; b32 is_top;
/* The handle of the top level parent of the ent tree (if ent is top then this will be its own handle) */ /* The id of the top level parent of the ent tree (if ent is top then this point to itself) */
struct sim_ent_handle top; struct sim_ent_id top;
/* Tree */ /* Tree */
struct sim_ent_handle parent; struct sim_ent_id parent;
struct sim_ent_handle next; struct sim_ent_id next;
struct sim_ent_handle prev; struct sim_ent_id prev;
struct sim_ent_handle first; struct sim_ent_id first;
struct sim_ent_handle last; struct sim_ent_id last;
struct sim_ent_handle next_in_uid_bucket; /* Lists keyed by index in snapshot ent array */
struct sim_ent_handle prev_in_uid_bucket; u32 next_in_id_bucket;
u32 prev_in_id_bucket;
struct sim_ent_handle next_free; u32 next_free;
/* ====================================================================== */ /* ====================================================================== */
/* Sync */ /* Sync */
@ -99,7 +96,7 @@ struct sim_ent {
/* SIM_ENT_PROP_SYNC_SRC */ /* SIM_ENT_PROP_SYNC_SRC */
/* SIM_ENT_PROP_SYNC_DST */ /* SIM_ENT_PROP_SYNC_DST */
/* Handle of the client that this ent was synced from */ /* Handle of the client that this ent was synced from (if any) */
struct sim_client_handle sync_src_client; struct sim_client_handle sync_src_client;
/* ====================================================================== */ /* ====================================================================== */
@ -129,9 +126,9 @@ struct sim_ent {
/* FIXME: Lerp */ /* FIXME: Lerp */
struct sim_ent_handle cmd_client; struct sim_ent_id cmd_client;
struct sim_control cmd_control; struct sim_control cmd_control;
struct uid cmd_hovered_ent_uid; struct sim_ent_id cmd_hovered_ent;
/* ====================================================================== */ /* ====================================================================== */
/* Client */ /* Client */
@ -145,11 +142,11 @@ struct sim_ent {
struct sim_control client_control; struct sim_control client_control;
struct v2 client_cursor_pos; struct v2 client_cursor_pos;
struct sim_ent_handle client_hovered_ent; struct sim_ent_id client_hovered_ent;
struct sim_ent_handle client_control_ent; struct sim_ent_id client_control_ent;
struct sim_ent_handle client_camera_ent; struct sim_ent_id client_camera_ent;
struct sim_ent_handle client_dbg_drag_joint_ent; struct sim_ent_id client_dbg_drag_joint_ent;
b32 client_dbg_drag_start; b32 client_dbg_drag_start;
b32 client_dbg_drag_stop; b32 client_dbg_drag_stop;
@ -187,7 +184,7 @@ struct sim_ent {
/* SIM_ENT_PROP_CONTROLLED */ /* SIM_ENT_PROP_CONTROLLED */
struct sim_ent_handle controlling_client; struct sim_ent_id controlling_client;
f32 control_force; /* How much force is applied to achieve desired control movement */ f32 control_force; /* How much force is applied to achieve desired control movement */
f32 control_force_max_speed; /* Maximum linear velocity achieved by force (m/s) */ f32 control_force_max_speed; /* Maximum linear velocity achieved by force (m/s) */
@ -196,8 +193,8 @@ struct sim_ent {
struct sim_control control; struct sim_control control;
struct sim_ent_handle move_joint; struct sim_ent_id move_joint;
struct sim_ent_handle aim_joint; struct sim_ent_id aim_joint;
/* ====================================================================== */ /* ====================================================================== */
/* Physics */ /* Physics */
@ -211,7 +208,7 @@ struct sim_ent {
f32 mass_unscaled; /* Mass of ent in kg before any transformations */ f32 mass_unscaled; /* Mass of ent in kg before any transformations */
f32 inertia_unscaled; /* Inertia of ent in kg*m^2 before any transformations */ f32 inertia_unscaled; /* Inertia of ent in kg*m^2 before any transformations */
struct sim_ent_handle ground_friction_joint; struct sim_ent_id ground_friction_joint;
f32 linear_ground_friction; f32 linear_ground_friction;
f32 angular_ground_friction; f32 angular_ground_friction;
@ -253,7 +250,7 @@ struct sim_ent {
/* ====================================================================== */ /* ====================================================================== */
/* Equip */ /* Equip */
struct sim_ent_handle equipped; struct sim_ent_id equipped;
/* ====================================================================== */ /* ====================================================================== */
/* Triggers */ /* Triggers */
@ -265,8 +262,8 @@ struct sim_ent {
/* ====================================================================== */ /* ====================================================================== */
/* Bullet */ /* Bullet */
struct sim_ent_handle bullet_src; struct sim_ent_id bullet_src;
struct sim_ent_handle bullet_tracer; struct sim_ent_id bullet_tracer;
struct v2 bullet_src_pos; struct v2 bullet_src_pos;
struct v2 bullet_src_dir; struct v2 bullet_src_dir;
f32 bullet_impulse; f32 bullet_impulse;
@ -312,7 +309,7 @@ struct sim_ent {
/* Camera */ /* Camera */
/* SIM_ENT_PROP_CAMERA */ /* SIM_ENT_PROP_CAMERA */
struct sim_ent_handle camera_follow; struct sim_ent_id camera_follow;
struct xform camera_quad_xform; struct xform camera_quad_xform;
f32 camera_lerp; /* Rate at which camera xform approaches target xform */ f32 camera_lerp; /* Rate at which camera xform approaches target xform */
@ -334,19 +331,10 @@ struct sim_ent_prop_array {
}; };
struct sim_ent_bucket { struct sim_ent_bucket {
struct sim_ent_handle first; u32 first;
struct sim_ent_handle last; u32 last;
}; };
/* ========================== *
* Handle helpers
* ========================== */
INLINE b32 sim_ent_handle_eq(struct sim_ent_handle a, struct sim_ent_handle b)
{
return a.gen == b.gen && a.idx == b.idx;
}
/* ========================== * /* ========================== *
* Nil * Nil
* ========================== */ * ========================== */
@ -399,9 +387,9 @@ 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 *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_uid(struct sim_ent *parent, struct uid uid); 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_client_handle client_handle, struct uid uid); struct sim_ent *sim_ent_alloc_sync_dst(struct sim_ent *parent, struct sim_client_handle client_handle, struct sim_ent_id 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);
@ -410,13 +398,14 @@ void sim_ent_release_all_with_prop(struct sim_snapshot *ss, enum sim_ent_prop pr
/* Activate */ /* Activate */
void sim_ent_activate(struct sim_ent *ent, u64 current_tick); void sim_ent_activate(struct sim_ent *ent, u64 current_tick);
/* Uid */ /* Id */
INLINE b32 sim_ent_id_eq(struct sim_ent_id a, struct sim_ent_id b) { return uid_eq(a.uid, b.uid); }
void sim_ent_set_uid(struct sim_ent *ent, struct uid uid); void sim_ent_set_id(struct sim_ent *ent, struct sim_ent_id id);
struct sim_ent *sim_ent_from_uid(struct sim_snapshot *ss, struct uid uid); struct sim_ent *sim_ent_from_id(struct sim_snapshot *ss, struct sim_ent_id id);
struct sim_ent_id sim_ent_random_id(void);
struct sim_ent_id sim_ent_contact_constraint_id_from_contacting_ids(struct sim_ent_id id0, struct sim_ent_id id1);
/* Query */ /* Query */
struct sim_ent *sim_ent_from_handle(struct sim_snapshot *ss, struct sim_ent_handle handle);
struct sim_ent *sim_ent_find_first_match_one(struct sim_snapshot *ss, enum sim_ent_prop prop); struct sim_ent *sim_ent_find_first_match_one(struct sim_snapshot *ss, enum sim_ent_prop prop);
struct sim_ent *sim_ent_find_first_match_all(struct sim_snapshot *ss, struct sim_ent_prop_array props); struct sim_ent *sim_ent_find_first_match_all(struct sim_snapshot *ss, struct sim_ent_prop_array props);
@ -442,6 +431,10 @@ void sim_ent_apply_torque(struct sim_ent *ent, f32 torque);
/* Lerp */ /* Lerp */
void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64 blend); void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64 blend);
/* Sync */
void sim_ent_sync_alloc_tree(struct sim_ent *local_parent, struct sim_ent *remote);
void sim_ent_sync(struct sim_ent *local, struct sim_ent *remote);
/* Encode / decode */ /* Encode / decode */
void sim_ent_encode(struct bitbuff_writer *bw, struct sim_ent *e0, struct sim_ent *e1); void sim_ent_encode(struct bitbuff_writer *bw, struct sim_ent *e0, struct sim_ent *e1);
void sim_ent_decode(struct bitbuff_reader *br, struct sim_ent *e); void sim_ent_decode(struct bitbuff_reader *br, struct sim_ent *e);

View File

@ -53,7 +53,7 @@ void sim_accel_reset(struct sim_snapshot *ss, struct sim_accel *accel)
INTERNAL void spawn_test_entities(struct sim_snapshot *world, struct v2 offset) INTERNAL void spawn_test_entities(struct sim_snapshot *world, struct v2 offset)
{ {
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE); struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID);
root->mass_unscaled = F32_INFINITY; root->mass_unscaled = F32_INFINITY;
root->inertia_unscaled = F32_INFINITY; root->inertia_unscaled = F32_INFINITY;
@ -129,7 +129,7 @@ INTERNAL void spawn_test_entities(struct sim_snapshot *world, struct v2 offset)
INTERNAL struct sim_ent *spawn_test_player(struct sim_snapshot *world) INTERNAL struct sim_ent *spawn_test_player(struct sim_snapshot *world)
{ {
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE); struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID);
/* Player */ /* Player */
struct sim_ent *player_ent = sim_ent_nil(); struct sim_ent *player_ent = sim_ent_nil();
@ -200,7 +200,7 @@ INTERNAL struct sim_ent *spawn_test_player(struct sim_snapshot *world)
e->trigger_delay = 1.0f / 10.0f; e->trigger_delay = 1.0f / 10.0f;
//e->trigger_delay = 1.0f / 100.0f; //e->trigger_delay = 1.0f / 100.0f;
player_ent->equipped = e->handle; player_ent->equipped = e->id;
} }
return player_ent; return player_ent;
@ -208,7 +208,7 @@ INTERNAL struct sim_ent *spawn_test_player(struct sim_snapshot *world)
INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_snapshot *world, struct sim_ent *player_ent) INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_snapshot *world, struct sim_ent *player_ent)
{ {
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE); struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID);
struct sim_ent *camera_ent = sim_ent_nil(); struct sim_ent *camera_ent = sim_ent_nil();
if (player_ent->valid) { if (player_ent->valid) {
@ -217,7 +217,7 @@ INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_snapshot *world, st
sim_ent_enable_prop(camera_ent, SIM_ENT_PROP_CAMERA); sim_ent_enable_prop(camera_ent, SIM_ENT_PROP_CAMERA);
sim_ent_enable_prop(camera_ent, SIM_ENT_PROP_CAMERA_ACTIVE); sim_ent_enable_prop(camera_ent, SIM_ENT_PROP_CAMERA_ACTIVE);
camera_ent->camera_follow = player_ent->handle; camera_ent->camera_follow = player_ent->id;
f32 width = (f32)DEFAULT_CAMERA_WIDTH; f32 width = (f32)DEFAULT_CAMERA_WIDTH;
f32 height = (f32)DEFAULT_CAMERA_HEIGHT; f32 height = (f32)DEFAULT_CAMERA_HEIGHT;
@ -244,14 +244,14 @@ INTERNAL void test_clear_level(struct sim_snapshot *world)
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, step_ctx) INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, step_ctx)
{ {
struct sim_snapshot *world = step_ctx->world; struct sim_snapshot *world = step_ctx->world;
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE); struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID);
for (u64 i = 0; i < collision_data_array.count; ++i) { for (u64 i = 0; i < collision_data_array.count; ++i) {
struct phys_collision_data *data = &collision_data_array.a[i]; struct phys_collision_data *data = &collision_data_array.a[i];
struct phys_contact_constraint *constraint = data->constraint; struct phys_contact_constraint *constraint = data->constraint;
struct sim_ent *e0 = sim_ent_from_handle(world, data->e0); struct sim_ent *e0 = sim_ent_from_id(world, data->e0);
struct sim_ent *e1 = sim_ent_from_handle(world, data->e1); struct sim_ent *e1 = sim_ent_from_id(world, data->e1);
if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) { if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
/* Bullet hit entity */ /* Bullet hit entity */
@ -267,9 +267,9 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, st
normal = v2_neg(normal); normal = v2_neg(normal);
vrel = v2_neg(vrel); vrel = v2_neg(vrel);
} }
struct sim_ent *src = sim_ent_from_handle(world, bullet->bullet_src); struct sim_ent *src = sim_ent_from_id(world, bullet->bullet_src);
if (bullet->bullet_has_hit || sim_ent_handle_eq(src->top, target->top)) { if (bullet->bullet_has_hit || sim_ent_id_eq(src->top, target->top)) {
/* Ignore collision if bullet already spent or if weapon and /* Ignore collision if bullet already spent or if weapon and
* target share same top level parent */ * target share same top level parent */
/* NOTE: Since bullet is most likely just a sensor skip_solve is probably already true */ /* NOTE: Since bullet is most likely just a sensor skip_solve is probably already true */
@ -282,7 +282,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, st
sim_ent_enable_prop(bullet, SIM_ENT_PROP_RELEASE); sim_ent_enable_prop(bullet, SIM_ENT_PROP_RELEASE);
/* Update tracer */ /* Update tracer */
struct sim_ent *tracer = sim_ent_from_handle(world, bullet->bullet_tracer); struct sim_ent *tracer = sim_ent_from_id(world, bullet->bullet_tracer);
if (sim_ent_is_valid_and_active(tracer)) { if (sim_ent_is_valid_and_active(tracer)) {
struct xform xf = sim_ent_get_xform(tracer); struct xform xf = sim_ent_get_xform(tracer);
xf.og = point; xf.og = point;
@ -349,7 +349,7 @@ void sim_step(struct sim_step_ctx *ctx)
struct sprite_scope *sprite_frame_scope = sprite_scope_begin(); struct sprite_scope *sprite_frame_scope = sprite_scope_begin();
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE); struct sim_ent *root = sim_ent_from_id(world, SIM_ENT_ROOT_ID);
/* ========================== * /* ========================== *
* Release entities at beginning of frame * Release entities at beginning of frame
@ -401,9 +401,9 @@ void sim_step(struct sim_step_ctx *ctx)
if (!sim_ent_is_valid_and_active(cmd_ent)) continue; if (!sim_ent_is_valid_and_active(cmd_ent)) continue;
if (sim_ent_has_prop(cmd_ent, SIM_ENT_PROP_CMD_CONTROL)) { if (sim_ent_has_prop(cmd_ent, SIM_ENT_PROP_CMD_CONTROL)) {
struct sim_ent *client_ent = sim_ent_from_handle(world, cmd_ent->cmd_client); struct sim_ent *client_ent = sim_ent_from_id(world, cmd_ent->cmd_client);
if (sim_ent_is_valid_and_active(client_ent)) { if (sim_ent_is_valid_and_active(client_ent)) {
if (!ctx->is_master && !uid_eq(client_ent->uid, world->local_client_ent_uid)) { if (!ctx->is_master && !sim_ent_id_eq(client_ent->id, world->local_client_ent)) {
/* We are not the master and the command is not our own, skip processing */ /* We are not the master and the command is not our own, skip processing */
continue; continue;
} }
@ -423,16 +423,16 @@ void sim_step(struct sim_step_ctx *ctx)
/* Determine cursor pos from focus */ /* Determine cursor pos from focus */
{ {
struct sim_ent_handle client_control_ent_handle = 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_handle(world, client_control_ent_handle); struct sim_ent *client_control_ent = sim_ent_from_id(world, client_control_ent_id);
if (client_control_ent->valid || sim_ent_handle_eq(client_control_ent_handle, SIM_ENT_NIL_HANDLE)) { if (client_control_ent->valid || sim_ent_id_eq(client_control_ent_id, SIM_ENT_NIL_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);
} }
} }
/* Dereference hovered ent */ /* Dereference hovered ent */
client_ent->client_hovered_ent = sim_ent_from_uid(world, cmd_ent->cmd_hovered_ent_uid)->handle; client_ent->client_hovered_ent = cmd_ent->cmd_hovered_ent;
u32 flags = control->flags; u32 flags = control->flags;
if (flags & SIM_CONTROL_FLAG_DRAG) { if (flags & SIM_CONTROL_FLAG_DRAG) {
@ -474,17 +474,17 @@ void sim_step(struct sim_step_ctx *ctx)
if (!sim_ent_is_valid_and_active(ent)) continue; if (!sim_ent_is_valid_and_active(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CLIENT)) { if (sim_ent_has_prop(ent, SIM_ENT_PROP_CLIENT)) {
/* FIXME: Ents never released when client disconnects */ /* FIXME: Ents never released when client disconnects */
struct sim_ent *control_ent = sim_ent_from_handle(world, ent->client_control_ent); struct sim_ent *control_ent = sim_ent_from_id(world, ent->client_control_ent);
if (!control_ent->valid) { if (!control_ent->valid) {
control_ent = spawn_test_player(world); control_ent = spawn_test_player(world);
sim_ent_enable_prop(control_ent, SIM_ENT_PROP_CONTROLLED); sim_ent_enable_prop(control_ent, SIM_ENT_PROP_CONTROLLED);
ent->client_control_ent = control_ent->handle; ent->client_control_ent = control_ent->id;
control_ent->controlling_client = ent->handle; control_ent->controlling_client = ent->id;
} }
struct sim_ent *camera_ent = sim_ent_from_handle(world, ent->client_camera_ent); struct sim_ent *camera_ent = sim_ent_from_id(world, ent->client_camera_ent);
if (!camera_ent->valid) { if (!camera_ent->valid) {
camera_ent = spawn_test_player_camera(world, control_ent); camera_ent = spawn_test_player_camera(world, control_ent);
ent->client_camera_ent = camera_ent->handle; ent->client_camera_ent = camera_ent->id;
} }
} }
} }
@ -500,7 +500,7 @@ void sim_step(struct sim_step_ctx *ctx)
if (!sim_ent_should_simulate(ent)) continue; if (!sim_ent_should_simulate(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) { if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
struct sim_ent *client_ent = sim_ent_from_handle(world, ent->controlling_client); struct sim_ent *client_ent = sim_ent_from_id(world, ent->controlling_client);
if (client_ent->valid) { if (client_ent->valid) {
ent->control = client_ent->client_control; ent->control = client_ent->client_control;
/* TODO: Move this */ /* TODO: Move this */
@ -624,7 +624,7 @@ void sim_step(struct sim_step_ctx *ctx)
if (!sim_ent_should_simulate(ent)) continue; if (!sim_ent_should_simulate(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ATTACHED)) continue; if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ATTACHED)) continue;
struct sim_ent *parent = sim_ent_from_handle(world, ent->parent); struct sim_ent *parent = sim_ent_from_id(world, ent->parent);
struct sprite_tag parent_sprite = parent->sprite; struct sprite_tag parent_sprite = parent->sprite;
struct sprite_sheet *parent_sheet = sprite_sheet_from_tag_await(sprite_frame_scope, parent_sprite); struct sprite_sheet *parent_sheet = sprite_sheet_from_tag_await(sprite_frame_scope, parent_sprite);
@ -701,7 +701,7 @@ void sim_step(struct sim_step_ctx *ctx)
if (!sim_ent_should_simulate(ent)) continue; if (!sim_ent_should_simulate(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED)) { if (sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED)) {
struct sim_ent *eq = sim_ent_from_handle(world, ent->equipped); struct sim_ent *eq = sim_ent_from_id(world, ent->equipped);
if (sim_ent_is_valid_and_active(eq)) { if (sim_ent_is_valid_and_active(eq)) {
sim_ent_enable_prop(eq, SIM_ENT_PROP_TRIGGERED_THIS_TICK); sim_ent_enable_prop(eq, SIM_ENT_PROP_TRIGGERED_THIS_TICK);
} }
@ -738,7 +738,7 @@ void sim_step(struct sim_step_ctx *ctx)
{ {
bullet = sim_ent_alloc_sync_src(root); bullet = sim_ent_alloc_sync_src(root);
bullet->bullet_src = ent->handle; bullet->bullet_src = ent->id;
bullet->bullet_src_pos = rel_pos; bullet->bullet_src_pos = rel_pos;
bullet->bullet_src_dir = rel_dir; bullet->bullet_src_dir = rel_dir;
//bullet->bullet_impulse = 0.75f; //bullet->bullet_impulse = 0.75f;
@ -768,7 +768,7 @@ void sim_step(struct sim_step_ctx *ctx)
tracer->layer = SIM_LAYER_TRACERS; tracer->layer = SIM_LAYER_TRACERS;
sim_ent_enable_prop(tracer, SIM_ENT_PROP_TRACER); sim_ent_enable_prop(tracer, SIM_ENT_PROP_TRACER);
bullet->bullet_tracer = tracer->handle; bullet->bullet_tracer = tracer->id;
} }
} }
} }
@ -783,18 +783,18 @@ void sim_step(struct sim_step_ctx *ctx)
if (!sim_ent_should_simulate(ent)) continue; if (!sim_ent_should_simulate(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) { if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
struct sim_ent *joint_ent = sim_ent_from_handle(world, ent->move_joint); struct sim_ent *joint_ent = sim_ent_from_id(world, ent->move_joint);
if (!sim_ent_is_valid_and_active(joint_ent)) { if (!sim_ent_is_valid_and_active(joint_ent)) {
joint_ent = sim_ent_alloc_local(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;
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT);
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE);
ent->move_joint = joint_ent->handle; ent->move_joint = joint_ent->id;
struct phys_motor_joint_def def = ZI; struct phys_motor_joint_def def = ZI;
def.e0 = joint_ent->handle; /* Re-using joint entity as e0 */ def.e0 = joint_ent->id; /* Re-using joint entity as e0 */
def.e1 = ent->handle; def.e1 = ent->id;
def.correction_rate = 0; def.correction_rate = 0;
def.max_force = ent->control_force; def.max_force = ent->control_force;
def.max_torque = 0; def.max_torque = 0;
@ -814,14 +814,14 @@ void sim_step(struct sim_step_ctx *ctx)
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) { for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index]; struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue; if (!sim_ent_is_valid_and_active(ent)) continue;
//if (!sim_ent_should_simulate(ent)) continue; if (!sim_ent_should_simulate(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) { if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
struct xform xf = sim_ent_get_xform(ent); struct xform xf = sim_ent_get_xform(ent);
struct xform sprite_xf = xform_mul(xf, ent->sprite_local_xform); struct xform sprite_xf = xform_mul(xf, ent->sprite_local_xform);
/* Retrieve / create aim joint */ /* Retrieve / create aim joint */
struct sim_ent *joint_ent = sim_ent_from_handle(world, ent->aim_joint); struct sim_ent *joint_ent = sim_ent_from_id(world, ent->aim_joint);
if (!sim_ent_is_valid_and_active(joint_ent)) { if (!sim_ent_is_valid_and_active(joint_ent)) {
joint_ent = sim_ent_alloc_local(root); joint_ent = sim_ent_alloc_local(root);
joint_ent->mass_unscaled = F32_INFINITY; joint_ent->mass_unscaled = F32_INFINITY;
@ -829,11 +829,11 @@ void sim_step(struct sim_step_ctx *ctx)
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_PHYSICAL_KINEMATIC); /* Since we'll be setting velocity manually */ sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_PHYSICAL_KINEMATIC); /* Since we'll be setting velocity manually */
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT);
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE);
ent->aim_joint = joint_ent->handle; ent->aim_joint = joint_ent->id;
struct phys_motor_joint_def def = ZI; struct phys_motor_joint_def def = ZI;
def.e0 = joint_ent->handle; /* Re-using joint entity as e0 */ def.e0 = joint_ent->id; /* Re-using joint entity as e0 */
def.e1 = ent->handle; def.e1 = ent->id;
def.max_force = 0; def.max_force = 0;
def.max_torque = ent->control_torque; def.max_torque = ent->control_torque;
joint_ent->motor_joint_data = phys_motor_joint_from_def(def); joint_ent->motor_joint_data = phys_motor_joint_from_def(def);
@ -911,11 +911,11 @@ void sim_step(struct sim_step_ctx *ctx)
if (!sim_ent_should_simulate(ent)) continue; if (!sim_ent_should_simulate(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue; if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
struct sim_ent *joint_ent = sim_ent_from_handle(world, ent->ground_friction_joint); struct sim_ent *joint_ent = sim_ent_from_id(world, ent->ground_friction_joint);
struct phys_motor_joint_def def = ZI; struct phys_motor_joint_def def = ZI;
def.e0 = root->handle; def.e0 = root->id;
def.e1 = ent->handle; def.e1 = ent->id;
def.correction_rate = 0; def.correction_rate = 0;
def.max_force = ent->linear_ground_friction; def.max_force = ent->linear_ground_friction;
def.max_torque = ent->angular_ground_friction; def.max_torque = ent->angular_ground_friction;
@ -925,7 +925,7 @@ void sim_step(struct sim_step_ctx *ctx)
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT);
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE);
joint_ent->motor_joint_data = phys_motor_joint_from_def(def); joint_ent->motor_joint_data = phys_motor_joint_from_def(def);
ent->ground_friction_joint = joint_ent->handle; ent->ground_friction_joint = joint_ent->id;
} }
} }
} }
@ -944,13 +944,13 @@ void sim_step(struct sim_step_ctx *ctx)
b32 start_dragging = client_ent->client_dbg_drag_start; b32 start_dragging = client_ent->client_dbg_drag_start;
b32 stop_dragging = client_ent->client_dbg_drag_stop; b32 stop_dragging = client_ent->client_dbg_drag_stop;
struct sim_ent *joint_ent = sim_ent_from_handle(world, client_ent->client_dbg_drag_joint_ent); struct sim_ent *joint_ent = sim_ent_from_id(world, client_ent->client_dbg_drag_joint_ent);
struct sim_ent *target_ent = sim_ent_from_handle(world, joint_ent->mouse_joint_data.target); struct sim_ent *target_ent = sim_ent_from_id(world, joint_ent->mouse_joint_data.target);
if (stop_dragging) { if (stop_dragging) {
target_ent = sim_ent_nil(); target_ent = sim_ent_nil();
} else if (start_dragging) { } else if (start_dragging) {
target_ent = sim_ent_from_handle(world, client_ent->client_hovered_ent); target_ent = sim_ent_from_id(world, client_ent->client_hovered_ent);
} }
if (sim_ent_is_valid_and_active(target_ent)) { if (sim_ent_is_valid_and_active(target_ent)) {
@ -959,7 +959,7 @@ void sim_step(struct sim_step_ctx *ctx)
joint_ent = sim_ent_alloc_local(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->handle; client_ent->client_dbg_drag_joint_ent = joint_ent->id;
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOUSE_JOINT);
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE); sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_ACTIVE);
} }
@ -967,8 +967,8 @@ void sim_step(struct sim_step_ctx *ctx)
f32 mass = target_ent->mass_unscaled * math_fabs(xform_get_determinant(xf)); f32 mass = target_ent->mass_unscaled * math_fabs(xform_get_determinant(xf));
struct phys_mouse_joint_def def = ZI; struct phys_mouse_joint_def def = ZI;
def.target = target_ent->handle; def.target = target_ent->id;
if (sim_ent_handle_eq(joint_ent->mouse_joint_data.target, target_ent->handle)) { if (sim_ent_id_eq(joint_ent->mouse_joint_data.target, target_ent->id)) {
def.point_local_start = joint_ent->mouse_joint_data.point_local_start; def.point_local_start = joint_ent->mouse_joint_data.point_local_start;
} else { } else {
def.point_local_start = xform_invert_mul_v2(xf, cursor); def.point_local_start = xform_invert_mul_v2(xf, cursor);
@ -977,7 +977,7 @@ void sim_step(struct sim_step_ctx *ctx)
def.max_force = mass * 1000; def.max_force = mass * 1000;
joint_ent->mouse_joint_data = phys_mouse_joint_from_def(def); joint_ent->mouse_joint_data = phys_mouse_joint_from_def(def);
} else if (sim_ent_is_valid_and_active(joint_ent)) { } else if (sim_ent_is_valid_and_active(joint_ent)) {
joint_ent->mouse_joint_data.target = target_ent->handle; joint_ent->mouse_joint_data.target = target_ent->id;
} }
} }
@ -1028,7 +1028,7 @@ void sim_step(struct sim_step_ctx *ctx)
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_BULLET)) continue; if (!sim_ent_has_prop(ent, SIM_ENT_PROP_BULLET)) continue;
if (ent->activation_tick == world->tick) { if (ent->activation_tick == world->tick) {
struct sim_ent *src = sim_ent_from_handle(world, ent->bullet_src); struct sim_ent *src = sim_ent_from_id(world, ent->bullet_src);
struct xform src_xf = sim_ent_get_xform(src); struct xform src_xf = sim_ent_get_xform(src);
struct v2 pos = xform_mul_v2(src_xf, ent->bullet_src_pos); struct v2 pos = xform_mul_v2(src_xf, ent->bullet_src_pos);
@ -1039,7 +1039,7 @@ void sim_step(struct sim_step_ctx *ctx)
/* Add shooter velocity to bullet */ /* Add shooter velocity to bullet */
{ {
/* TODO: Add angular velocity as well? */ /* TODO: Add angular velocity as well? */
struct sim_ent *top = sim_ent_from_handle(ss_blended, src->top); struct sim_ent *top = sim_ent_from_id(ss_blended, src->top);
impulse = v2_add(impulse, v2_mul(top->linear_velocity, dt)); impulse = v2_add(impulse, v2_mul(top->linear_velocity, dt));
} }
#endif #endif
@ -1051,7 +1051,7 @@ void sim_step(struct sim_step_ctx *ctx)
sim_ent_apply_linear_impulse_to_center(ent, impulse); sim_ent_apply_linear_impulse_to_center(ent, impulse);
/* Initialize tracer */ /* Initialize tracer */
struct sim_ent *tracer = sim_ent_from_handle(world, ent->bullet_tracer); struct sim_ent *tracer = sim_ent_from_id(world, ent->bullet_tracer);
if (sim_ent_is_valid_and_active(tracer)) { if (sim_ent_is_valid_and_active(tracer)) {
sim_ent_set_xform(tracer, xf); sim_ent_set_xform(tracer, xf);
sim_ent_enable_prop(tracer, SIM_ENT_PROP_PHYSICAL_KINEMATIC); sim_ent_enable_prop(tracer, SIM_ENT_PROP_PHYSICAL_KINEMATIC);
@ -1087,7 +1087,7 @@ void sim_step(struct sim_step_ctx *ctx)
/* Camera follow */ /* Camera follow */
{ {
struct sim_ent *follow = sim_ent_from_handle(world, ent->camera_follow); struct sim_ent *follow = sim_ent_from_id(world, ent->camera_follow);
f32 aspect_ratio = 1.0; f32 aspect_ratio = 1.0;
{ {
@ -1163,7 +1163,7 @@ void sim_step(struct sim_step_ctx *ctx)
--stack_count; --stack_count;
i32 parent_layer = parent->final_layer; i32 parent_layer = parent->final_layer;
for (struct sim_ent *child = sim_ent_from_handle(world, parent->first); child->valid; child = sim_ent_from_handle(world, child->next)) { for (struct sim_ent *child = sim_ent_from_id(world, parent->first); child->valid; child = sim_ent_from_id(world, child->next)) {
if (sim_ent_is_valid_and_active(child) && sim_ent_should_simulate(child)) { if (sim_ent_is_valid_and_active(child) && sim_ent_should_simulate(child)) {
child->final_layer = parent_layer + child->layer; child->final_layer = parent_layer + child->layer;
*arena_push(temp.arena, struct sim_ent *) = child; *arena_push(temp.arena, struct sim_ent *) = child;

View File

@ -272,7 +272,7 @@ struct space_entry *space_entry_from_handle(struct space *space, struct space_en
return entry; return entry;
} }
struct space_entry *space_entry_alloc(struct space *space, struct sim_ent_handle entity) struct space_entry *space_entry_alloc(struct space *space, struct sim_ent_id ent)
{ {
struct space_entry *entry = NULL; struct space_entry *entry = NULL;
struct space_entry_handle handle = ZI; struct space_entry_handle handle = ZI;
@ -289,7 +289,7 @@ struct space_entry *space_entry_alloc(struct space *space, struct sim_ent_handle
MEMZERO_STRUCT(entry); MEMZERO_STRUCT(entry);
entry->valid = true; entry->valid = true;
entry->handle = handle; entry->handle = handle;
entry->ent = entity; entry->ent = ent;
return entry; return entry;
} }

View File

@ -11,7 +11,7 @@ struct space_entry {
struct space_cell_node *last_node; struct space_cell_node *last_node;
struct aabb aabb; struct aabb aabb;
struct sim_ent_handle ent; struct sim_ent_id ent;
struct space_entry *next_free; struct space_entry *next_free;
}; };
@ -121,7 +121,7 @@ struct space_cell *space_get_cell(struct space *space, struct v2i32 cell_pos);
* ========================== */ * ========================== */
struct space_entry *space_entry_from_handle(struct space *space, struct space_entry_handle handle); struct space_entry *space_entry_from_handle(struct space *space, struct space_entry_handle handle);
struct space_entry *space_entry_alloc(struct space *space, struct sim_ent_handle entity); struct space_entry *space_entry_alloc(struct space *space, struct sim_ent_id entity);
void space_entry_release(struct space_entry *entry); void space_entry_release(struct space_entry *entry);
void space_entry_update_aabb(struct space_entry *entry, struct aabb new_aabb); void space_entry_update_aabb(struct space_entry *entry, struct aabb new_aabb);

View File

@ -86,7 +86,7 @@ GLOBAL struct {
/* User -> local sim */ /* User -> local sim */
struct sys_mutex user_sim_cmd_mutex; struct sys_mutex user_sim_cmd_mutex;
struct sim_control user_sim_cmd_control; struct sim_control user_sim_cmd_control;
struct uid user_sim_cmd_hovered_ent_uid; struct sim_ent_id user_hovered_ent;
u64 last_user_sim_cmd_gen; u64 last_user_sim_cmd_gen;
u64 user_sim_cmd_gen; u64 user_sim_cmd_gen;
@ -348,20 +348,17 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e
struct string res = ZI; struct string res = ZI;
res.text = arena_dry_push(arena, u8); res.text = arena_dry_push(arena, u8);
res.len += string_format(arena, LIT("<%F>"), FMT_HANDLE(ent->handle)).len; res.len += string_format(arena, LIT("[%F]"), FMT_UID(ent->id.uid)).len;
res.len += string_format(arena, LIT(" [%F]\n"), FMT_UID(ent->uid)).len;
{ {
res.len += string_copy(arena, LIT("net: ")).len;
b32 transmitting = sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_SRC); b32 transmitting = sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_SRC);
b32 receiving = sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_DST); b32 receiving = sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_DST);
if (transmitting & receiving) { if (transmitting & receiving) {
res.len += string_copy(arena, LIT(" synced (send & recv)")).len; res.len += string_copy(arena, LIT(" networked (sending & receiving)")).len;
} else if (transmitting) { } else if (transmitting) {
res.len += string_copy(arena, LIT(" synced (send)")).len; res.len += string_copy(arena, LIT(" networked (sending)")).len;
} else if (receiving) { } else if (receiving) {
res.len += string_copy(arena, LIT(" synced (recv)")).len; res.len += string_copy(arena, LIT(" networked (receiving)")).len;
} else { } else {
res.len += string_copy(arena, LIT(" local")).len; res.len += string_copy(arena, LIT(" local")).len;
} }
@ -385,26 +382,26 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e
res.len += string_copy(arena, LIT("\n")).len; res.len += string_copy(arena, LIT("\n")).len;
} }
if (!sim_ent_handle_eq(ent->parent, SIM_ENT_ROOT_HANDLE)) { if (!sim_ent_id_eq(ent->parent, SIM_ENT_ROOT_ID)) {
res.len += string_format(arena, LIT("parent: <%F>\n"), FMT_HANDLE(ent->parent)).len; res.len += string_format(arena, LIT("parent: <%F>\n"), FMT_UID(ent->parent.uid)).len;
} }
if (!sim_ent_handle_eq(ent->next, SIM_ENT_NIL_HANDLE) || !sim_ent_handle_eq(ent->prev, SIM_ENT_NIL_HANDLE)) { if (!sim_ent_id_eq(ent->next, SIM_ENT_NIL_ID) || !sim_ent_id_eq(ent->prev, SIM_ENT_NIL_ID)) {
res.len += string_format(arena, LIT("prev: <%F>\n"), FMT_HANDLE(ent->prev)).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_HANDLE(ent->next)).len; res.len += string_format(arena, LIT("next: <%F>\n"), FMT_UID(ent->next.uid)).len;
} }
if (!sim_ent_handle_eq(ent->first, SIM_ENT_NIL_HANDLE) || !sim_ent_handle_eq(ent->last, SIM_ENT_NIL_HANDLE)) { if (!sim_ent_id_eq(ent->first, SIM_ENT_NIL_ID) || !sim_ent_id_eq(ent->last, SIM_ENT_NIL_ID)) {
struct sim_ent *child = sim_ent_from_handle(ss, ent->first); struct sim_ent *child = sim_ent_from_id(ss, ent->first);
if (!sim_ent_handle_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_HANDLE(ent->first)).len; res.len += string_format(arena, LIT("first child: <%F>\n"), FMT_UID(ent->first.uid)).len;
res.len += string_format(arena, LIT("last child: <%F>\n"), FMT_HANDLE(ent->last)).len; res.len += string_format(arena, LIT("last child: <%F>\n"), FMT_UID(ent->last.uid)).len;
} }
while (child->valid) { while (child->valid) {
res.len += string_copy(arena, LIT("\nCHILD\n")).len; res.len += string_copy(arena, LIT("\nCHILD\n")).len;
struct string child_text = get_ent_debug_text(scratch.arena, child); struct string child_text = get_ent_debug_text(scratch.arena, child);
res.len += string_indent(arena, child_text, 4).len; res.len += string_indent(arena, child_text, 4).len;
child = sim_ent_from_handle(ss, child->next); child = sim_ent_from_id(ss, child->next);
} }
} }
@ -694,9 +691,9 @@ INTERNAL void user_update(void)
* Find local entities * Find local entities
* ========================== */ * ========================== */
struct sim_ent *local_client_ent = sim_ent_from_uid(G.ss_blended, G.ss_blended->local_client_ent_uid); struct sim_ent *local_client_ent = sim_ent_from_id(G.ss_blended, G.ss_blended->local_client_ent);
struct sim_ent *local_player = sim_ent_from_handle(G.ss_blended, local_client_ent->client_control_ent); struct sim_ent *local_player = sim_ent_from_id(G.ss_blended, local_client_ent->client_control_ent);
struct sim_ent *local_camera = sim_ent_from_handle(G.ss_blended, local_client_ent->client_camera_ent); struct sim_ent *local_camera = sim_ent_from_id(G.ss_blended, local_client_ent->client_camera_ent);
/* ========================== * /* ========================== *
* Find hovered entity * Find hovered entity
@ -739,7 +736,7 @@ INTERNAL void user_update(void)
i64 frequency_ns = NS_FROM_SECONDS(0.01f); i64 frequency_ns = NS_FROM_SECONDS(0.01f);
f32 shake = ent->shake; f32 shake = ent->shake;
if (shake > 0) { if (shake > 0) {
u64 basis = hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&ent->handle)); u64 basis = ent->id.uid.lo;
u64 angle_seed0 = basis + (u64)(G.ss_blended->sim_time_ns / frequency_ns); u64 angle_seed0 = basis + (u64)(G.ss_blended->sim_time_ns / frequency_ns);
u64 angle_seed1 = angle_seed0 + 1; u64 angle_seed1 = angle_seed0 + 1;
f32 angle0 = rng_noise_f32(angle_seed0, 0, TAU); f32 angle0 = rng_noise_f32(angle_seed0, 0, TAU);
@ -927,7 +924,7 @@ INTERNAL void user_update(void)
struct sprite_tag sprite = ent->sprite; struct sprite_tag sprite = ent->sprite;
struct sim_ent *parent = sim_ent_from_handle(G.ss_blended, ent->parent); struct sim_ent *parent = sim_ent_from_id(G.ss_blended, ent->parent);
struct xform xf = sim_ent_get_xform(ent); struct xform xf = sim_ent_get_xform(ent);
struct xform parent_xf = sim_ent_get_xform(parent); struct xform parent_xf = sim_ent_get_xform(parent);
@ -1113,8 +1110,8 @@ INTERNAL void user_update(void)
/* Draw contact constraint */ /* Draw contact constraint */
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) { if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) {
struct phys_contact_constraint *data = &ent->contact_constraint_data; struct phys_contact_constraint *data = &ent->contact_constraint_data;
struct sim_ent *e0 = sim_ent_from_handle(G.ss_blended, data->e0); struct sim_ent *e0 = sim_ent_from_id(G.ss_blended, data->e0);
struct sim_ent *e1 = sim_ent_from_handle(G.ss_blended, data->e1); struct sim_ent *e1 = sim_ent_from_id(G.ss_blended, data->e1);
(UNUSED)e0; (UNUSED)e0;
(UNUSED)e1; (UNUSED)e1;
@ -1187,8 +1184,8 @@ INTERNAL void user_update(void)
if (sim_ent_has_prop(ent, SIM_ENT_PROP_COLLISION_DEBUG)) { if (sim_ent_has_prop(ent, SIM_ENT_PROP_COLLISION_DEBUG)) {
struct phys_collision_debug *data = &ent->collision_debug_data; struct phys_collision_debug *data = &ent->collision_debug_data;
struct collider_collision_points_result collider_res = data->res; struct collider_collision_points_result collider_res = data->res;
struct sim_ent *e0 = sim_ent_from_handle(G.ss_blended, data->e0); struct sim_ent *e0 = sim_ent_from_id(G.ss_blended, data->e0);
struct sim_ent *e1 = sim_ent_from_handle(G.ss_blended, data->e1); struct sim_ent *e1 = sim_ent_from_id(G.ss_blended, data->e1);
struct collider_shape e0_collider = e0->local_collider; struct collider_shape e0_collider = e0->local_collider;
struct collider_shape e1_collider = e1->local_collider; struct collider_shape e1_collider = e1->local_collider;
(UNUSED)e0_collider; (UNUSED)e0_collider;
@ -1526,7 +1523,7 @@ INTERNAL void user_update(void)
u32 old_flags = G.user_sim_cmd_control.flags; u32 old_flags = G.user_sim_cmd_control.flags;
G.user_sim_cmd_control = control; G.user_sim_cmd_control = control;
G.user_sim_cmd_control.flags |= old_flags; G.user_sim_cmd_control.flags |= old_flags;
G.user_sim_cmd_hovered_ent_uid = hovered_ent->uid; G.user_hovered_ent = hovered_ent->id;
sys_mutex_unlock(&lock); sys_mutex_unlock(&lock);
} }
} }
@ -1833,124 +1830,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_thread_entry_point, arg)
#define translate(fieldname) local->fieldname = _translate(local_ss, remote_ss, remote->fieldname)
INTERNAL struct sim_ent_handle _translate(struct sim_snapshot *local_ss, struct sim_snapshot *remote_ss, struct sim_ent_handle remote_ent_handle)
{
struct sim_ent_handle local_handle = SIM_ENT_NIL_HANDLE;
struct sim_ent *remote_ent = sim_ent_from_handle(remote_ss, remote_ent_handle);
if (remote_ent->valid) {
struct uid uid = remote_ent->uid;
struct sim_ent *local_ent = sim_ent_from_uid(local_ss, uid);
local_handle = local_ent->handle;
}
return local_handle;
}
INTERNAL void sim_ent_sync_tree(struct sim_ent *local, struct sim_ent *remote)
{
struct sim_snapshot *local_ss = local->ss;
struct sim_snapshot *remote_ss = remote->ss;
struct sim_client_handle remote_client_handle = remote_ss->client->handle;
struct sim_ent old = *local;
MEMCPY_STRUCT(local, remote);
/* Why would 2 ents w/ different uids ever be synced? */
ASSERT(uid_eq(local->uid, old.uid));
sim_ent_disable_prop(local, SIM_ENT_PROP_SYNC_SRC);
sim_ent_enable_prop(local, SIM_ENT_PROP_SYNC_DST);
/* Keep non-remote handles */
local->ss = old.ss;
local->handle = old.handle;
local->sync_src_client = remote_client_handle;
local->uid = old.uid;
local->parent = old.parent;
local->prev = old.prev;
local->next = old.next;
local->first = old.first;
local->last = old.last;
local->top = old.top;
local->next_in_uid_bucket = old.next_in_uid_bucket;
local->prev_in_uid_bucket = old.prev_in_uid_bucket;
local->next_free = old.next_free;
/* Translate remote handles */
translate(client_control_ent);
translate(client_camera_ent);
translate(client_hovered_ent);
translate(client_dbg_drag_joint_ent);
translate(controlling_client);
translate(move_joint);
translate(aim_joint);
translate(ground_friction_joint);
translate(equipped);
translate(bullet_src);
translate(bullet_tracer);
translate(camera_follow);
}
/* Walks a local & remote ent tree and allocates net dst ents from remote src ents */
INTERNAL void sim_ent_alloc_any_new_sync_dsts(struct sim_ent *local_parent, struct sim_ent *remote)
{
__prof;
if (sim_ent_has_prop(remote, SIM_ENT_PROP_SYNC_SRC)) {
struct sim_snapshot *local_ss = local_parent->ss;
struct sim_snapshot *remote_ss = remote->ss;
struct sim_client_handle remote_client_handle = remote_ss->client->handle;
struct uid uid = remote->uid;
struct sim_ent *local_ent = sim_ent_from_uid(local_ss, uid);
if (!local_ent->valid) {
local_ent = sim_ent_alloc_sync_dst(local_parent, remote_client_handle, uid);
}
for (struct sim_ent *remote_child = sim_ent_from_handle(remote_ss, remote->first); remote_child->valid; remote_child = sim_ent_from_handle(remote_ss, remote_child->next)) {
sim_ent_alloc_any_new_sync_dsts(local_ent, remote_child);
}
}
}
INTERNAL void sim_snapshot_sync(struct sim_snapshot *local_ss, struct sim_snapshot *remote_ss)
{
__prof;
/* FIXME: Only sync cmds from non-master remote */
struct sim_ent *local_root = sim_ent_from_handle(local_ss, SIM_ENT_ROOT_HANDLE);
struct sim_ent *remote_root = sim_ent_from_handle(remote_ss, SIM_ENT_ROOT_HANDLE);
struct sim_client_handle remote_client_handle = remote_ss->client->handle;
/* Create new ents from remote */
for (struct sim_ent *remote_top = sim_ent_from_handle(remote_ss, remote_root->first); remote_top->valid; remote_top = sim_ent_from_handle(remote_ss, remote_top->next)) {
sim_ent_alloc_any_new_sync_dsts(local_root, remote_top);
}
/* Sync ents with remote */
for (u64 i = 0; 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) && sim_client_handle_eq(local_ent->sync_src_client, remote_client_handle)) {
struct sim_ent *remote_ent = sim_ent_from_uid(remote_ss, local_ent->uid);
if (remote_ent->valid) {
/* Copy all ent data from remote */
sim_ent_sync_tree(local_ent, remote_ent);
} else {
/* Remote ent is no longer valid / networked, release it */
sim_ent_enable_prop(local_ent, SIM_ENT_PROP_RELEASE);
sim_ent_disable_prop(local_ent, SIM_ENT_PROP_SYNC_DST);
}
}
}
sim_ent_release_all_with_prop(local_ss, SIM_ENT_PROP_RELEASE);
}
@ -2166,8 +2045,8 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
/* Create user input */ /* 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 *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, step_tick);; struct sim_snapshot *user_input_ss = sim_snapshot_alloc(user_input_client, prev_user_input_ss, step_tick);
struct sim_ent *user_input_root = sim_ent_from_handle(user_input_ss, SIM_ENT_ROOT_HANDLE); struct sim_ent *user_input_root = sim_ent_from_id(user_input_ss, SIM_ENT_ROOT_ID);
/* Find / create local control cmd ent */ /* 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); 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) { if (!control_cmd_ent->valid) {
@ -2179,7 +2058,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
{ {
struct sys_lock lock = sys_mutex_lock_e(&G.user_sim_cmd_mutex); 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_control = G.user_sim_cmd_control;
control_cmd_ent->cmd_hovered_ent_uid = G.user_sim_cmd_hovered_ent_uid; control_cmd_ent->cmd_hovered_ent = G.user_hovered_ent;
++G.user_sim_cmd_gen; ++G.user_sim_cmd_gen;
sys_mutex_unlock(&lock); sys_mutex_unlock(&lock);
} }
@ -2189,24 +2068,24 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
struct sim_snapshot *prev_local_ss = sim_snapshot_from_tick(local_client, local_client->last_tick); 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); struct sim_snapshot *local_ss = sim_snapshot_alloc(local_client, prev_local_ss, step_tick);
/* Sync remote ents with client */ /* Sync remote ents to local */
{ {
struct sim_ent *local_root = sim_ent_from_handle(local_ss, SIM_ENT_ROOT_HANDLE); struct sim_ent *local_root = sim_ent_from_id(local_ss, SIM_ENT_ROOT_ID);
for (u64 client_index = 0; client_index < store->num_clients_reserved; ++client_index) { for (u64 client_index = 0; client_index < store->num_clients_reserved; ++client_index) {
struct sim_client *client = &store->clients[client_index]; struct sim_client *client = &store->clients[client_index];
if (client->valid) { if (client->valid) {
/* Create client ent if necessary */ /* Create client ent if necessary */
if (is_master && client != publish_client && client != local_client && client != master_client) { if (is_master && client != publish_client && client != local_client && client != master_client) {
struct sim_ent *client_ent = sim_ent_from_uid(local_ss, client->ent_uid); struct sim_ent *client_ent = sim_ent_from_id(local_ss, client->ent_id);
if (!client_ent->valid) { if (!client_ent->valid) {
/* FIXME: Client ent never released upon disconnect */ /* FIXME: Client ent never released upon disconnect */
client_ent = sim_ent_alloc_sync_src(local_root); client_ent = sim_ent_alloc_sync_src(local_root);
client_ent->client_handle = client->handle; client_ent->client_handle = client->handle;
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_CLIENT); sim_ent_enable_prop(client_ent, SIM_ENT_PROP_CLIENT);
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_ACTIVE); sim_ent_enable_prop(client_ent, SIM_ENT_PROP_ACTIVE);
client->ent_uid = client_ent->uid; client->ent_id = client_ent->id;
if (client == user_input_client) { if (client == user_input_client) {
local_ss->local_client_ent_uid = client_ent->uid; local_ss->local_client_ent = client_ent->id;
} }
} }
} }
@ -2218,7 +2097,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
if (client_ss->valid) { if (client_ss->valid) {
sim_snapshot_sync(local_ss, client_ss); sim_snapshot_sync(local_ss, client_ss);
if (!is_master && client == master_client) { if (!is_master && client == master_client) {
local_ss->local_client_ent_uid = client_ss->local_client_ent_uid; local_ss->local_client_ent = client_ss->local_client_ent;
} }
} }
} }
@ -2232,8 +2111,8 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
struct sim_ent *ent = &local_ss->ents[i]; struct sim_ent *ent = &local_ss->ents[i];
if (ent->valid && sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_DST)) { if (ent->valid && sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_DST)) {
struct sim_client *src_client = sim_client_from_handle(store, ent->sync_src_client); struct sim_client *src_client = sim_client_from_handle(store, ent->sync_src_client);
struct sim_ent *client_ent = sim_ent_from_uid(local_ss, src_client->ent_uid); struct sim_ent *client_ent = sim_ent_from_id(local_ss, src_client->ent_id);
ent->cmd_client = client_ent->handle; ent->cmd_client = client_ent->id;
} }
} }
} else { } else {
@ -2426,7 +2305,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
/* TODO: Double buffer */ /* TODO: Double buffer */
struct sys_lock lock = sys_mutex_lock_e(&G.local_to_user_client_mutex); 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_ss, local_ss->tick); struct sim_snapshot *copy_ss = sim_snapshot_alloc(G.local_to_user_client, local_ss, local_ss->tick);
copy_ss->local_client_ent_uid = local_ss->local_client_ent_uid; copy_ss->local_client_ent = local_ss->local_client_ent;
i64 publish_ns = sys_time_ns(); i64 publish_ns = sys_time_ns();
copy_ss->publish_dt_ns = publish_ns - last_publish_ns; copy_ss->publish_dt_ns = publish_ns - last_publish_ns;
copy_ss->publish_time_ns = publish_ns; copy_ss->publish_time_ns = publish_ns;