diff --git a/.natvis b/.natvis index 4429a90a..4de6c0ef 100644 --- a/.natvis +++ b/.natvis @@ -44,6 +44,22 @@ [{(u32)(hi >> 32), xb}]{((u32)(hi & 0xFFFFFFFF)), xb}{lo, xb} + + hi, x + lo, x + + + + + [NIL] + [ROOT] + [{(u32)(uid.hi >> 32), xb}] + + + + ~~~MISMATCH~~~ {id} + ~~~MISMATCH~~~ {id} + {id} diff --git a/src/common.h b/src/common.h index 889ce865..e8d31664 100644 --- a/src/common.h +++ b/src/common.h @@ -442,16 +442,15 @@ struct pcm { i16 *samples; }; -struct sim_ent_handle { - u64 idx; - u64 gen; -}; - struct sim_client_handle { u32 idx; u32 gen; }; +struct sim_ent_id { + struct uid uid; +}; + struct space_entry_handle { u64 idx; u64 gen; diff --git a/src/phys.c b/src/phys.c index ce96c8b8..db19d9ef 100644 --- a/src/phys.c +++ b/src/phys.c @@ -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 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; 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_entry *space_entry; 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 (!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 (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 *e1; struct xform e0_xf; struct xform e1_xf; struct collider_shape e0_collider; struct collider_shape e1_collider; - if (check0_index < check1->handle.idx) { + if (check0->id.uid.hi < check1->id.uid.hi) { e0 = check0; e1 = check1; 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; } - struct uid constraint_uid = uid_combine(uid_combine(SIM_ENT_BASIS_UID_CONTACT, e0->uid), e1->uid); - struct sim_ent *constraint_ent = sim_ent_from_uid(ss, constraint_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_id(ss, constraint_id); if (constraint_ent->valid) { 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) { /* Create constraint */ { - constraint_ent = sim_ent_alloc_local_with_uid(root, constraint_uid); - constraint_ent->contact_constraint_data.e1 = e1->handle; - constraint_ent->contact_constraint_data.e0 = e0->handle; + constraint_ent = sim_ent_alloc_local_with_id(root, constraint_id); + constraint_ent->contact_constraint_data.e0 = e0->id; + 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) || !(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); @@ -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); ++res.count; data->constraint = &constraint_ent->contact_constraint_data; - data->e0 = e0->handle; - data->e1 = e1->handle; + data->e0 = e0->id; + data->e1 = e1->id; data->normal = collider_res.normal; 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_lookup_entry *dbg_entry = sim_lookup_get(debug_lookup, key); 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) { @@ -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; u32 num_points = constraint->num_points; - struct sim_ent *e0 = sim_ent_from_handle(ss, constraint->e0); - struct sim_ent *e1 = sim_ent_from_handle(ss, constraint->e1); + struct sim_ent *e0 = sim_ent_from_id(ss, constraint->e0); + 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)) { struct v2 normal = constraint->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; struct phys_collision_debug *dbg = &dbg_ent->collision_debug_data; - struct sim_ent *e0 = sim_ent_from_handle(ss, dbg->e0); - struct sim_ent *e1 = sim_ent_from_handle(ss, dbg->e1); + struct sim_ent *e0 = sim_ent_from_id(ss, dbg->e0); + 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) @@ -398,8 +398,8 @@ void phys_warm_start_contacts(struct phys_step_ctx *ctx) struct phys_contact_constraint *constraint = &constraint_ent->contact_constraint_data; u32 num_points = constraint->num_points; - struct sim_ent *e0 = sim_ent_from_handle(ss, constraint->e0); - struct sim_ent *e1 = sim_ent_from_handle(ss, constraint->e1); + struct sim_ent *e0 = sim_ent_from_id(ss, constraint->e0); + 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) { 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 sim_ent *e0 = sim_ent_from_handle(ss, constraint->e0); - struct sim_ent *e1 = sim_ent_from_handle(ss, constraint->e1); + struct sim_ent *e0 = sim_ent_from_id(ss, constraint->e0); + struct sim_ent *e1 = sim_ent_from_id(ss, constraint->e1); struct v2 v0 = e0->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 sim_ent *e0 = sim_ent_from_handle(ss, joint->e0); - struct sim_ent *e1 = sim_ent_from_handle(ss, joint->e1); + struct sim_ent *e0 = sim_ent_from_id(ss, joint->e0); + 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)) { 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 sim_ent *e0 = sim_ent_from_handle(ss, joint->e0); - struct sim_ent *e1 = sim_ent_from_handle(ss, joint->e1); + struct sim_ent *e0 = sim_ent_from_id(ss, joint->e0); + struct sim_ent *e1 = sim_ent_from_id(ss, joint->e1); struct xform e0_xf = sim_ent_get_xform(e0); 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 sim_ent *e0 = sim_ent_from_handle(ss, joint->e0); - struct sim_ent *e1 = sim_ent_from_handle(ss, joint->e1); + struct sim_ent *e0 = sim_ent_from_id(ss, joint->e0); + struct sim_ent *e1 = sim_ent_from_id(ss, joint->e1); struct xform e0_xf = sim_ent_get_xform(e0); 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; 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)) { 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; 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)) { f32 inv_m = joint->inv_m; 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; 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)) { struct v2 v = ent->linear_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_entry *entry; 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 (!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; @@ -1040,7 +1040,7 @@ void phys_update_aabbs(struct phys_step_ctx *ctx) struct xform xf = sim_ent_get_xform(ent); struct space_entry *space_entry = space_entry_from_handle(space, ent->space_handle); 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; } struct aabb aabb = collider_aabb_from_collider(&ent->local_collider, xf); diff --git a/src/phys.h b/src/phys.h index 64e4bcd7..73d7e29e 100644 --- a/src/phys.h +++ b/src/phys.h @@ -11,8 +11,8 @@ struct sim_step_ctx; struct phys_contact_constraint; struct phys_collision_data { struct phys_contact_constraint *constraint; - struct sim_ent_handle e0; - struct sim_ent_handle e1; + struct sim_ent_id e0; + struct sim_ent_id e1; struct v2 point; struct v2 normal; /* Normal of the collision from e0 to e1 */ struct v2 vrel; /* Relative velocity at point of collision */ @@ -68,8 +68,8 @@ struct phys_contact_point { struct phys_contact_constraint { u64 last_phys_iteration; /* To avoid checking collisions for the same constraint twice in one tick */ b32 skip_solve; - struct sim_ent_handle e0; - struct sim_ent_handle e1; + struct sim_ent_id e0; + struct sim_ent_id e1; f32 inv_m0; f32 inv_m1; f32 inv_i0; @@ -87,8 +87,8 @@ struct phys_contact_constraint { }; struct phys_collision_debug { - struct sim_ent_handle e0; - struct sim_ent_handle e1; + struct sim_ent_id e0; + struct sim_ent_id e1; struct collider_collision_points_result res; 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 sim_ent_handle e0; - struct sim_ent_handle e1; + struct sim_ent_id e0; + struct sim_ent_id e1; f32 correction_rate; f32 max_force; f32 max_torque; }; struct phys_motor_joint { - struct sim_ent_handle e0; - struct sim_ent_handle e1; + struct sim_ent_id e0; + struct sim_ent_id e1; f32 correction_rate; f32 max_force; 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 sim_ent_handle target; + struct sim_ent_id target; struct v2 point_local_start; struct v2 point_local_end; f32 max_force; }; struct phys_mouse_joint { - struct sim_ent_handle target; + struct sim_ent_id target; struct v2 point_local_start; struct v2 point_local_end; struct math_spring_result linear_softness; diff --git a/src/sim.c b/src/sim.c index 13c400f8..2fdbd32a 100644 --- a/src/sim.c +++ b/src/sim.c @@ -25,7 +25,7 @@ #define CLIENT_LOOKUP_BUCKETS 127 #define TICK_LOOKUP_BUCKETS 127 -#define UID_LOOKUP_BUCKETS 4096 +#define ID_LOOKUP_BUCKETS 4096 /* ========================== * * 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->ss = sim_snapshot_nil(); 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->_xform = XFORM_IDENT; 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_time_ns = src->sim_time_ns; 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; - /* Copy uid lookup buckets */ - ss->num_uid_buckets = src->num_uid_buckets > 0 ? src->num_uid_buckets : UID_LOOKUP_BUCKETS; - ss->uid_buckets = arena_push_array(&ss->arena, struct sim_ent_bucket, ss->num_uid_buckets); - if (src->num_uid_buckets > 0) { - for (u64 i = 0; i < src->num_uid_buckets; ++i) { - ss->uid_buckets[i] = src->uid_buckets[i]; + /* Copy id lookup buckets */ + ss->num_id_buckets = src->num_id_buckets > 0 ? src->num_id_buckets : ID_LOOKUP_BUCKETS; + ss->id_buckets = arena_push_array(&ss->arena, struct sim_ent_bucket, ss->num_id_buckets); + if (src->num_id_buckets > 0) { + for (u64 i = 0; i < src->num_id_buckets; ++i) { + ss->id_buckets[i] = src->id_buckets[i]; } } 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 */ @@ -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->ents = arena_push_array(&ss->ents_arena, struct sim_ent, ss->num_ents_reserved); if (ss->num_ents_reserved == 0) { - /* Create root ent if copying from nil snapshot */ - struct sim_ent *root = arena_push(&ss->ents_arena, struct sim_ent); - *root = *sim_ent_nil(); - root->ss = ss; - root->handle = SIM_ENT_ROOT_HANDLE; - root->valid = true; - root->is_root = true; - root->mass_unscaled = F32_INFINITY; - root->inertia_unscaled = F32_INFINITY; - ++ss->num_ents_allocated; - ++ss->num_ents_reserved; + /* 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); + *root = *sim_ent_nil(); + root->ss = ss; + root->valid = true; + root->is_root = true; + root->mass_unscaled = F32_INFINITY; + root->inertia_unscaled = F32_INFINITY; + sim_ent_set_id(root, SIM_ENT_ROOT_ID); + ++ss->num_ents_allocated; + ++ss->num_ents_reserved; + } } else { for (u64 i = 0; i < ss->num_ents_reserved; ++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; } +/* ========================== * + * 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 * ========================== */ @@ -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->phys_iteration); - bw_write_uid(bw, receiver->ent_uid); + bw_write_uid(bw, receiver->ent_id.uid); /* Ents */ 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->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 */ 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) { struct sim_ent *e = &ss->ents[i]; + e->ss = ss; sim_ent_decode(br, e); } } diff --git a/src/sim.h b/src/sim.h index d808b35f..a1e6e8e2 100644 --- a/src/sim.h +++ b/src/sim.h @@ -3,9 +3,6 @@ #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 */ #define SIM_LAYER_FLOOR_DECALS (-300) #define SIM_LAYER_BULLETS (-200) @@ -82,8 +79,8 @@ struct sim_client { struct sim_client_handle next_in_bucket; struct sim_client_handle prev_in_bucket; - /* The client entity's uid in the master sim (if relevant) */ - struct uid ent_uid; + /* The client entity's id in the master sim (if relevant) */ + struct sim_ent_id ent_id; /* This is the highest confirmed tick of ours that we know this client has received */ u64 ack; @@ -174,18 +171,18 @@ struct sim_snapshot { /* The last physics iteration (used for tracking contact lifetime) */ 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 */ - struct sim_ent_bucket *uid_buckets; - u64 num_uid_buckets; + /* Id lookup */ + struct sim_ent_bucket *id_buckets; + u64 num_id_buckets; /* Entities */ struct arena ents_arena; struct sim_ent *ents; - struct sim_ent_handle first_free_ent; - u64 num_ents_allocated; - u64 num_ents_reserved; + u32 first_free_ent; + u32 num_ents_allocated; + u32 num_ents_reserved; }; 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 */ 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 */ 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); diff --git a/src/sim_ent.c b/src/sim_ent.c index de43b447..b935b61a 100644 --- a/src/sim_ent.c +++ b/src/sim_ent.c @@ -4,29 +4,43 @@ #include "bitbuff.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 * ========================== */ +/* 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 *ent = NULL; - struct sim_ent_handle handle = ZI; - if (ss->first_free_ent.gen) { + struct sim_ent *ent; + if (ss->first_free_ent > 0 && ss->first_free_ent < ss->num_ents_reserved) { /* Reuse from free list */; - ent = sim_ent_from_handle(ss, ss->first_free_ent); - handle = ent->handle; - ++handle.gen; + ent = &ss->ents[ss->first_free_ent]; ss->first_free_ent = ent->next_free; } else { /* Make new */ 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->ss = ss; ent->valid = true; - ent->handle = handle; ent->_is_xform_dirty = true; ++ss->num_ents_allocated; return ent; @@ -38,21 +52,21 @@ struct sim_ent *sim_ent_alloc_local(struct sim_ent *parent) ASSERT(parent->valid); struct sim_snapshot *ss = parent->ss; struct sim_ent *e = sim_ent_alloc_raw(ss); - sim_ent_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; } -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); struct sim_snapshot *ss = parent->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; } @@ -62,28 +76,28 @@ struct sim_ent *sim_ent_alloc_sync_src(struct sim_ent *parent) { struct sim_snapshot *ss = parent->ss; struct sim_ent *e = sim_ent_alloc_raw(ss); - sim_ent_link_parent(e, parent); - - sim_ent_set_uid(e, uid_rand()); + sim_ent_set_id(e, sim_ent_random_id()); sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_SRC); e->sync_src_client = ss->client->handle; + sim_ent_link_parent(e, parent); + return e; } /* 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_ent *e = sim_ent_alloc_raw(ss); - sim_ent_link_parent(e, parent); - - sim_ent_set_uid(e, uid); + sim_ent_set_id(e, id); sim_ent_enable_prop(e, SIM_ENT_PROP_SYNC_DST); e->sync_src_client = client_handle; + sim_ent_link_parent(e, parent); + return e; } @@ -91,27 +105,28 @@ void sim_ent_release_raw(struct sim_ent *ent) { struct sim_snapshot *ss = ent->ss; /* Release children */ - struct sim_ent_handle first_handle = ent->first; - if (first_handle.gen) { - for (struct sim_ent *child = sim_ent_from_handle(ss, first_handle); child->valid; child = sim_ent_from_handle(ss, child->next)) { - sim_ent_release_raw(child); - } + struct sim_ent *child = sim_ent_from_id(ss, ent->first); + while (child->valid) { + struct sim_ent *next = sim_ent_from_id(ss, child->next); + sim_ent_release_raw(child); + child = next; } /* Release uid */ - sim_ent_set_uid(ent, UID(0, 0)); + sim_ent_set_id(ent, SIM_ENT_NIL_ID); /* Release */ - ++ent->handle.gen; ent->valid = false; 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; } 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_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 uid.lo; + return &ss->id_buckets[id.uid.lo % ss->num_id_buckets]; } -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_ent_bucket *buckets = ss->uid_buckets; - u64 num_uid_buckets = ss->num_uid_buckets; - - struct uid old_uid = ent->uid; - - /* Release old from lookup */ - if (!uid_is_zero(old_uid)) { - u64 hash = hash_from_uid(old_uid); - struct sim_ent_bucket *bucket = &buckets[hash % num_uid_buckets]; - struct sim_ent *prev = sim_ent_nil(); - struct sim_ent *next = sim_ent_nil(); - struct sim_ent *e = sim_ent_from_handle(ss, bucket->first); - while (e->valid) { - next = sim_ent_from_handle(ss, e->next_in_uid_bucket); - if (uid_eq(e->uid, old_uid)) { - break; + struct sim_ent_id old_id = ent->id; + if (!sim_ent_id_eq(old_id, id)) { + /* Release old from lookup */ + if (!sim_ent_id_eq(old_id, SIM_ENT_NIL_ID)) { + struct sim_ent_bucket *bucket = bucket_from_id(ss, old_id); + u32 prev_index = 0; + u32 next_index = 0; + u32 e_index = bucket->first; + struct sim_ent *prev = sim_ent_nil(); + struct sim_ent *next = sim_ent_nil(); + struct sim_ent *e = ent_from_index(ss, e_index); + while (e->valid) { + next_index = e->next_in_id_bucket; + next = ent_from_index(ss, next_index); + if (sim_ent_id_eq(e->id, old_id)) { + break; + } + prev_index = e_index; + prev = e; + e_index = next_index; + e = next; } - prev = e; - e = next; - } - if (e->valid) { - if (prev->valid) { - prev->next_in_uid_bucket = next->handle; + if (e->valid) { + if (prev->valid) { + prev->next_in_id_bucket = next_index; + } else { + bucket->first = next_index; + } + if (next->valid) { + next->prev_in_id_bucket = prev_index; + } else { + bucket->last = prev_index; + } } else { - bucket->first = next->handle; - } - if (next->valid) { - next->prev_in_uid_bucket = prev->handle; - } else { - bucket->last = prev->handle; + /* Old id not in bucket, this should be impossible. */ + ASSERT(false); } } + + /* Insert new id into lookup */ + if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID)) { + struct sim_ent_bucket *bucket = bucket_from_id(ss, id); + u32 ent_index = index_from_ent(ss, ent); + struct sim_ent *last = ent_from_index(ss, bucket->last); + if (last->valid) { + last->next_in_id_bucket = ent_index; + ent->prev_in_id_bucket = bucket->last; + } else { + bucket->first = ent_index; + ent->prev_in_id_bucket = 0; + } + bucket->last = ent_index; + } + + ent->id = id; } - /* Insert new uid into lookup */ - if (!uid_is_zero(uid)) { - u64 hash = hash_from_uid(uid); - struct sim_ent_bucket *bucket = &buckets[hash % num_uid_buckets]; - struct sim_ent *last = sim_ent_from_handle(ss, bucket->last); - if (last->valid) { - last->next_in_uid_bucket = ent->handle; - } else { - bucket->first = ent->handle; - } - ent->prev_in_uid_bucket = last->handle; - bucket->last = ent->handle; - } - - ent->uid = uid; } -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(); - u64 num_buckets = ss->num_uid_buckets; - if (num_buckets > 0 && !uid_is_zero(uid)) { - u64 hash = hash_from_uid(uid); - struct sim_ent_bucket *bucket = &ss->uid_buckets[hash % num_buckets]; - 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)) { + if (!sim_ent_id_eq(id, SIM_ENT_NIL_ID) && ss->valid) { + struct sim_ent_bucket *bucket = bucket_from_id(ss, id); + for (struct sim_ent *e = ent_from_index(ss, bucket->first); e->valid; e = ent_from_index(ss, e->next_in_id_bucket)) { + if (sim_ent_id_eq(e->id, id)) { res = e; break; } @@ -236,22 +257,25 @@ struct sim_ent *sim_ent_from_uid(struct sim_snapshot *ss, struct uid uid) 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 * ========================== */ -/* 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) { 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; - if (ent->parent.gen) { + struct sim_ent *old_parent = sim_ent_from_id(ss, ent->parent); + if (old_parent->valid) { /* Unlink from current parent */ sim_ent_unlink_from_parent(ent); } - struct sim_ent_handle handle = ent->handle; - struct sim_ent_handle parent_handle = parent->handle; - - 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); + struct sim_ent_id ent_id = ent->id; + struct sim_ent_id last_child_id = parent->last; + struct sim_ent *last_child = sim_ent_from_id(ss, last_child_id); if (last_child->valid) { - ent->prev = last_child_handle; - last_child->next = handle; + ent->prev = last_child_id; + last_child->next = ent_id; } else { - parent->first = handle; + parent->first = ent_id; } - parent->last = handle; + parent->last = ent_id; if (parent->is_root) { ent->is_top = true; - ent->top = handle; + ent->top = ent_id; } else { ent->top = parent->top; } + + ent->parent = parent->id; } /* 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_ent_handle parent_handle = ent->parent; - struct sim_ent *parent = sim_ent_from_handle(ss, parent_handle); - struct sim_ent *prev = sim_ent_from_handle(ss, ent->prev); - struct sim_ent *next = sim_ent_from_handle(ss, ent->next); + struct sim_ent_id parent_id = ent->parent; + struct sim_ent *parent = sim_ent_from_id(ss, parent_id); + struct sim_ent *prev = sim_ent_from_id(ss, ent->prev); + struct sim_ent *next = sim_ent_from_id(ss, ent->next); /* Unlink from parent & siblings */ if (prev->valid) { - prev->next = next->handle; + prev->next = next->id; } else { - parent->first = next->handle; + parent->first = next->id; } if (next->valid) { - next->prev = prev->handle; + next->prev = prev->id; } else { - parent->last = prev->handle; + parent->last = prev->id; } - ent->prev = sim_ent_nil()->handle; - ent->next = sim_ent_nil()->handle; + ent->prev = SIM_ENT_NIL_ID; + 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) { - 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) { break; } else { @@ -371,7 +394,7 @@ INTERNAL struct xform sim_ent_get_xform_internal(struct sim_snapshot *ss, struct if (ent->is_top) { xf = ent->_local_xform; } 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 = xform_mul(xf, ent->_local_xform); ent->_xform = xf; @@ -393,7 +416,7 @@ struct xform sim_ent_get_xform(struct sim_ent *ent) xf = ent->_local_xform; } else { 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 = xform_mul(xf, ent->_local_xform); ent->_xform = xf; @@ -420,7 +443,7 @@ void sim_ent_set_xform(struct sim_ent *ent, struct xform xf) if (ent->is_top) { ent->_local_xform = xf; } 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); 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) { 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) { 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 * ========================== */ @@ -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) { - struct sim_snapshot *ss = e->ss; - - struct uid old_uid = e->uid; - - u64 pos = 0; - while (pos < sizeof(*e)) { - u8 *chunk = (u8 *)e + pos; - if (br_read_bit(br)) { - u64 chunk_size = min_u64(pos + 8, sizeof(*e)) - pos; - u64 bits = br_read_ubits(br, 64); - MEMCPY(chunk, &bits, chunk_size); + struct sim_ent decoded = *e; + { + u64 pos = 0; + while (pos < sizeof(decoded)) { + u8 *chunk = (u8 *)&decoded + pos; + if (br_read_bit(br)) { + u64 chunk_size = min_u64(pos + 8, sizeof(decoded)) - pos; + u64 bits = br_read_ubits(br, 64); + MEMCPY(chunk, &bits, chunk_size); + } + pos += 8; } - pos += 8; } + decoded.ss = e->ss; - struct uid new_uid = e->uid; - e->uid = old_uid; - if (!uid_eq(old_uid, new_uid)) { - sim_ent_set_uid(e, new_uid); + 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); + } } - - e->ss = ss; } diff --git a/src/sim_ent.h b/src/sim_ent.h index a297e21b..040e2bdd 100644 --- a/src/sim_ent.h +++ b/src/sim_ent.h @@ -6,8 +6,8 @@ #include "mixer.h" #include "phys.h" -#define SIM_ENT_NIL_HANDLE ((struct sim_ent_handle){ .gen = 0, .idx = 0 }) -#define SIM_ENT_ROOT_HANDLE ((struct sim_ent_handle){ .gen = 1, .idx = 0 }) +#define SIM_ENT_NIL_ID ((struct sim_ent_id) { UID(0, 0) }) +#define SIM_ENT_ROOT_ID ((struct sim_ent_id) { UID(0x66a36cc2bcc752da, 0x6c286c09b366eae6) }) struct bitbuff_writer; struct bitbuff_reader; @@ -59,16 +59,13 @@ enum sim_ent_prop { }; struct sim_ent { + struct sim_snapshot *ss; + /* ====================================================================== */ /* Metadata */ - struct sim_snapshot *ss; - b32 valid; /* Is this ent allocated in memory that can be written to (can always be read) */ - - struct sim_ent_handle handle; - struct uid uid; - + struct sim_ent_id id; u64 props[(SIM_ENT_PROP_COUNT + 63) / 64]; u64 continuity_gen; @@ -78,20 +75,20 @@ struct sim_ent { /* Is ent a child of the root ent */ 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) */ - struct sim_ent_handle top; + /* The id of the top level parent of the ent tree (if ent is top then this point to itself) */ + struct sim_ent_id top; /* Tree */ - struct sim_ent_handle parent; - struct sim_ent_handle next; - struct sim_ent_handle prev; - struct sim_ent_handle first; - struct sim_ent_handle last; + struct sim_ent_id parent; + struct sim_ent_id next; + struct sim_ent_id prev; + struct sim_ent_id first; + struct sim_ent_id last; - struct sim_ent_handle next_in_uid_bucket; - struct sim_ent_handle prev_in_uid_bucket; - - struct sim_ent_handle next_free; + /* Lists keyed by index in snapshot ent array */ + u32 next_in_id_bucket; + u32 prev_in_id_bucket; + u32 next_free; /* ====================================================================== */ /* Sync */ @@ -99,7 +96,7 @@ struct sim_ent { /* SIM_ENT_PROP_SYNC_SRC */ /* 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; /* ====================================================================== */ @@ -129,9 +126,9 @@ struct sim_ent { /* FIXME: Lerp */ - struct sim_ent_handle cmd_client; + struct sim_ent_id cmd_client; struct sim_control cmd_control; - struct uid cmd_hovered_ent_uid; + struct sim_ent_id cmd_hovered_ent; /* ====================================================================== */ /* Client */ @@ -145,11 +142,11 @@ struct sim_ent { struct sim_control client_control; struct v2 client_cursor_pos; - struct sim_ent_handle client_hovered_ent; - struct sim_ent_handle client_control_ent; - struct sim_ent_handle client_camera_ent; + struct sim_ent_id client_hovered_ent; + struct sim_ent_id client_control_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_stop; @@ -187,7 +184,7 @@ struct sim_ent { /* 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_max_speed; /* Maximum linear velocity achieved by force (m/s) */ @@ -196,8 +193,8 @@ struct sim_ent { struct sim_control control; - struct sim_ent_handle move_joint; - struct sim_ent_handle aim_joint; + struct sim_ent_id move_joint; + struct sim_ent_id aim_joint; /* ====================================================================== */ /* Physics */ @@ -211,7 +208,7 @@ struct sim_ent { f32 mass_unscaled; /* Mass of ent in kg 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 angular_ground_friction; @@ -253,7 +250,7 @@ struct sim_ent { /* ====================================================================== */ /* Equip */ - struct sim_ent_handle equipped; + struct sim_ent_id equipped; /* ====================================================================== */ /* Triggers */ @@ -265,8 +262,8 @@ struct sim_ent { /* ====================================================================== */ /* Bullet */ - struct sim_ent_handle bullet_src; - struct sim_ent_handle bullet_tracer; + struct sim_ent_id bullet_src; + struct sim_ent_id bullet_tracer; struct v2 bullet_src_pos; struct v2 bullet_src_dir; f32 bullet_impulse; @@ -312,7 +309,7 @@ struct sim_ent { /* Camera */ /* SIM_ENT_PROP_CAMERA */ - struct sim_ent_handle camera_follow; + struct sim_ent_id camera_follow; struct xform camera_quad_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_handle first; - struct sim_ent_handle last; + u32 first; + 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 * ========================== */ @@ -399,9 +387,9 @@ INLINE b32 sim_ent_should_simulate(struct sim_ent *ent) /* Alloc */ struct sim_ent *sim_ent_alloc_raw(struct sim_snapshot *ss); struct sim_ent *sim_ent_alloc_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_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(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 */ void sim_ent_activate(struct sim_ent *ent, u64 current_tick); -/* Uid */ - -void sim_ent_set_uid(struct sim_ent *ent, struct uid uid); -struct sim_ent *sim_ent_from_uid(struct sim_snapshot *ss, struct uid 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_id(struct sim_ent *ent, struct sim_ent_id id); +struct sim_ent *sim_ent_from_id(struct sim_snapshot *ss, struct sim_ent_id id); +struct sim_ent_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 */ -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_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 */ 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 */ 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); diff --git a/src/sim_step.c b/src/sim_step.c index 2f954d8d..51c3b5a0 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -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) { - 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->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) { - 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 */ 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 / 100.0f; - player_ent->equipped = e->handle; + player_ent->equipped = e->id; } 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) { - 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(); 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_ACTIVE); - camera_ent->camera_follow = player_ent->handle; + camera_ent->camera_follow = player_ent->id; f32 width = (f32)DEFAULT_CAMERA_WIDTH; 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) { 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) { struct phys_collision_data *data = &collision_data_array.a[i]; struct phys_contact_constraint *constraint = data->constraint; - struct sim_ent *e0 = sim_ent_from_handle(world, data->e0); - struct sim_ent *e1 = sim_ent_from_handle(world, data->e1); + struct sim_ent *e0 = sim_ent_from_id(world, data->e0); + 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)) { /* Bullet hit entity */ @@ -267,9 +267,9 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, st normal = v2_neg(normal); 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 * target share same top level parent */ /* 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); /* 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)) { struct xform xf = sim_ent_get_xform(tracer); 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 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 @@ -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_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 (!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 */ continue; } @@ -423,16 +423,16 @@ void sim_step(struct sim_step_ctx *ctx) /* Determine cursor pos from focus */ { - struct sim_ent_handle client_control_ent_handle = client_ent->client_control_ent; - struct sim_ent *client_control_ent = sim_ent_from_handle(world, client_control_ent_handle); - if (client_control_ent->valid || sim_ent_handle_eq(client_control_ent_handle, SIM_ENT_NIL_HANDLE)) { + struct sim_ent_id client_control_ent_id = client_ent->client_control_ent; + struct sim_ent *client_control_ent = sim_ent_from_id(world, client_control_ent_id); + if (client_control_ent->valid || sim_ent_id_eq(client_control_ent_id, SIM_ENT_NIL_ID)) { /* 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); } } /* 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; 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_has_prop(ent, SIM_ENT_PROP_CLIENT)) { /* 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) { control_ent = spawn_test_player(world); sim_ent_enable_prop(control_ent, SIM_ENT_PROP_CONTROLLED); - ent->client_control_ent = control_ent->handle; - control_ent->controlling_client = ent->handle; + ent->client_control_ent = control_ent->id; + 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) { 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_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) { ent->control = client_ent->client_control; /* 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_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_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_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)) { 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->bullet_src = ent->handle; + bullet->bullet_src = ent->id; bullet->bullet_src_pos = rel_pos; bullet->bullet_src_dir = rel_dir; //bullet->bullet_impulse = 0.75f; @@ -768,7 +768,7 @@ void sim_step(struct sim_step_ctx *ctx) tracer->layer = SIM_LAYER_TRACERS; 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_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)) { joint_ent = sim_ent_alloc_local(root); joint_ent->mass_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_ACTIVE); - ent->move_joint = joint_ent->handle; + ent->move_joint = joint_ent->id; struct phys_motor_joint_def def = ZI; - def.e0 = joint_ent->handle; /* Re-using joint entity as e0 */ - def.e1 = ent->handle; + def.e0 = joint_ent->id; /* Re-using joint entity as e0 */ + def.e1 = ent->id; def.correction_rate = 0; def.max_force = ent->control_force; 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) { struct sim_ent *ent = &world->ents[ent_index]; 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)) { struct xform xf = sim_ent_get_xform(ent); struct xform sprite_xf = xform_mul(xf, ent->sprite_local_xform); /* 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)) { joint_ent = sim_ent_alloc_local(root); 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_MOTOR_JOINT); 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; - def.e0 = joint_ent->handle; /* Re-using joint entity as e0 */ - def.e1 = ent->handle; + def.e0 = joint_ent->id; /* Re-using joint entity as e0 */ + def.e1 = ent->id; def.max_force = 0; def.max_torque = ent->control_torque; 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_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; - def.e0 = root->handle; - def.e1 = ent->handle; + def.e0 = root->id; + def.e1 = ent->id; def.correction_rate = 0; def.max_force = ent->linear_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_ACTIVE); 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 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 *target_ent = sim_ent_from_handle(world, joint_ent->mouse_joint_data.target); + 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_id(world, joint_ent->mouse_joint_data.target); if (stop_dragging) { target_ent = sim_ent_nil(); } 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)) { @@ -959,7 +959,7 @@ void sim_step(struct sim_step_ctx *ctx) joint_ent = sim_ent_alloc_local(root); joint_ent->mass_unscaled = F32_INFINITY; joint_ent->inertia_unscaled = F32_INFINITY; - client_ent->client_dbg_drag_joint_ent = joint_ent->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_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)); struct phys_mouse_joint_def def = ZI; - def.target = target_ent->handle; - if (sim_ent_handle_eq(joint_ent->mouse_joint_data.target, target_ent->handle)) { + def.target = target_ent->id; + 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; } else { 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; joint_ent->mouse_joint_data = phys_mouse_joint_from_def(def); } 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 (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 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 */ { /* 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)); } #endif @@ -1051,7 +1051,7 @@ void sim_step(struct sim_step_ctx *ctx) sim_ent_apply_linear_impulse_to_center(ent, impulse); /* 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)) { sim_ent_set_xform(tracer, xf); sim_ent_enable_prop(tracer, SIM_ENT_PROP_PHYSICAL_KINEMATIC); @@ -1087,7 +1087,7 @@ void sim_step(struct sim_step_ctx *ctx) /* 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; { @@ -1163,7 +1163,7 @@ void sim_step(struct sim_step_ctx *ctx) --stack_count; 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)) { child->final_layer = parent_layer + child->layer; *arena_push(temp.arena, struct sim_ent *) = child; diff --git a/src/space.c b/src/space.c index 3aeed8e9..acd8fd18 100644 --- a/src/space.c +++ b/src/space.c @@ -272,7 +272,7 @@ struct space_entry *space_entry_from_handle(struct space *space, struct space_en 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_handle handle = ZI; @@ -289,7 +289,7 @@ struct space_entry *space_entry_alloc(struct space *space, struct sim_ent_handle MEMZERO_STRUCT(entry); entry->valid = true; entry->handle = handle; - entry->ent = entity; + entry->ent = ent; return entry; } diff --git a/src/space.h b/src/space.h index d4918d41..de0b91a5 100644 --- a/src/space.h +++ b/src/space.h @@ -11,7 +11,7 @@ struct space_entry { struct space_cell_node *last_node; struct aabb aabb; - struct sim_ent_handle ent; + struct sim_ent_id ent; 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_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_update_aabb(struct space_entry *entry, struct aabb new_aabb); diff --git a/src/user.c b/src/user.c index 5810a848..70be0ba2 100644 --- a/src/user.c +++ b/src/user.c @@ -86,7 +86,7 @@ GLOBAL struct { /* User -> local sim */ struct sys_mutex user_sim_cmd_mutex; 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 user_sim_cmd_gen; @@ -348,22 +348,19 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e struct string res = ZI; 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]\n"), FMT_UID(ent->uid)).len; + res.len += string_format(arena, LIT("[%F]"), FMT_UID(ent->id.uid)).len; { - res.len += string_copy(arena, LIT("net: ")).len; - b32 transmitting = sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_SRC); b32 receiving = sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_DST); 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) { - res.len += string_copy(arena, LIT(" synced (send)")).len; + res.len += string_copy(arena, LIT(" networked (sending)")).len; } else if (receiving) { - res.len += string_copy(arena, LIT(" synced (recv)")).len; + res.len += string_copy(arena, LIT(" networked (receiving)")).len; } else { - res.len += string_copy(arena, LIT(" local")).len; + res.len += string_copy(arena, LIT(" local")).len; } res.len += string_copy(arena, LIT("\n")).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; } - if (!sim_ent_handle_eq(ent->parent, SIM_ENT_ROOT_HANDLE)) { - res.len += string_format(arena, LIT("parent: <%F>\n"), FMT_HANDLE(ent->parent)).len; + if (!sim_ent_id_eq(ent->parent, SIM_ENT_ROOT_ID)) { + 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)) { - res.len += string_format(arena, LIT("prev: <%F>\n"), FMT_HANDLE(ent->prev)).len; - res.len += string_format(arena, LIT("next: <%F>\n"), FMT_HANDLE(ent->next)).len; + 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_UID(ent->prev.uid)).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)) { - struct sim_ent *child = sim_ent_from_handle(ss, ent->first); - if (!sim_ent_handle_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("last child: <%F>\n"), FMT_HANDLE(ent->last)).len; + 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_id(ss, ent->first); + if (!sim_ent_id_eq(ent->first, ent->last) || !child->valid) { + res.len += string_format(arena, LIT("first child: <%F>\n"), FMT_UID(ent->first.uid)).len; + res.len += string_format(arena, LIT("last child: <%F>\n"), FMT_UID(ent->last.uid)).len; } while (child->valid) { res.len += string_copy(arena, LIT("\nCHILD\n")).len; struct string child_text = get_ent_debug_text(scratch.arena, child); 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 * ========================== */ - struct sim_ent *local_client_ent = sim_ent_from_uid(G.ss_blended, G.ss_blended->local_client_ent_uid); - struct sim_ent *local_player = sim_ent_from_handle(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_client_ent = sim_ent_from_id(G.ss_blended, G.ss_blended->local_client_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_id(G.ss_blended, local_client_ent->client_camera_ent); /* ========================== * * Find hovered entity @@ -739,7 +736,7 @@ INTERNAL void user_update(void) i64 frequency_ns = NS_FROM_SECONDS(0.01f); f32 shake = ent->shake; 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_seed1 = angle_seed0 + 1; 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 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 parent_xf = sim_ent_get_xform(parent); @@ -1113,8 +1110,8 @@ INTERNAL void user_update(void) /* Draw contact constraint */ if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) { 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 *e1 = sim_ent_from_handle(G.ss_blended, data->e1); + struct sim_ent *e0 = sim_ent_from_id(G.ss_blended, data->e0); + struct sim_ent *e1 = sim_ent_from_id(G.ss_blended, data->e1); (UNUSED)e0; (UNUSED)e1; @@ -1187,8 +1184,8 @@ INTERNAL void user_update(void) if (sim_ent_has_prop(ent, SIM_ENT_PROP_COLLISION_DEBUG)) { struct phys_collision_debug *data = &ent->collision_debug_data; 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 *e1 = sim_ent_from_handle(G.ss_blended, data->e1); + struct sim_ent *e0 = sim_ent_from_id(G.ss_blended, data->e0); + struct sim_ent *e1 = sim_ent_from_id(G.ss_blended, data->e1); struct collider_shape e0_collider = e0->local_collider; struct collider_shape e1_collider = e1->local_collider; (UNUSED)e0_collider; @@ -1526,7 +1523,7 @@ INTERNAL void user_update(void) u32 old_flags = G.user_sim_cmd_control.flags; G.user_sim_cmd_control = control; 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); } } @@ -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 */ { 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_ent *user_input_root = sim_ent_from_handle(user_input_ss, SIM_ENT_ROOT_HANDLE); + 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_id(user_input_ss, SIM_ENT_ROOT_ID); /* Find / create local control cmd ent */ struct sim_ent *control_cmd_ent = sim_ent_find_first_match_one(user_input_ss, SIM_ENT_PROP_CMD_CONTROL); if (!control_cmd_ent->valid) { @@ -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); 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; 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 *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) { struct sim_client *client = &store->clients[client_index]; if (client->valid) { /* Create client ent if necessary */ 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) { /* FIXME: Client ent never released upon disconnect */ client_ent = sim_ent_alloc_sync_src(local_root); 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_ACTIVE); - client->ent_uid = client_ent->uid; + client->ent_id = client_ent->id; 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) { sim_snapshot_sync(local_ss, client_ss); 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]; 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_ent *client_ent = sim_ent_from_uid(local_ss, src_client->ent_uid); - ent->cmd_client = client_ent->handle; + struct sim_ent *client_ent = sim_ent_from_id(local_ss, src_client->ent_id); + ent->cmd_client = client_ent->id; } } } else { @@ -2426,7 +2305,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) /* TODO: Double buffer */ struct sys_lock lock = sys_mutex_lock_e(&G.local_to_user_client_mutex); struct sim_snapshot *copy_ss = sim_snapshot_alloc(G.local_to_user_client, local_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(); copy_ss->publish_dt_ns = publish_ns - last_publish_ns; copy_ss->publish_time_ns = publish_ns;