prediction progress

This commit is contained in:
jacob 2025-02-23 04:18:14 -06:00
parent 4d419da97b
commit f0834c203f
5 changed files with 727 additions and 740 deletions

View File

@ -488,7 +488,6 @@ struct string32 {
};
#define UID(hi, lo) (struct uid) { .v = U128((hi), (lo)) }
#define UID0 (struct uid) { 0 }
struct uid {
union {
u128 v;
@ -499,6 +498,7 @@ struct uid {
};
};
INLINE b32 uid_eq(struct uid a, struct uid b) { return u128_eq(a.v, b.v); }
INLINE b32 uid_is_zero(struct uid uid) { return u128_eq(uid.v, U128(0, 0)); }
struct image_rgba {
u32 width;

View File

@ -332,6 +332,8 @@ struct sim_snapshot *sim_snapshot_alloc(struct sim_client *client, struct sim_sn
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;
} else {

View File

@ -99,7 +99,7 @@ void sim_ent_release_raw(struct sim_ent *ent)
}
/* Release uid */
sim_ent_set_uid(ent, UID0);
sim_ent_set_uid(ent, UID(0, 0));
/* Release */
++ent->handle.gen;
@ -174,7 +174,7 @@ void sim_ent_set_uid(struct sim_ent *ent, struct uid uid)
struct uid old_uid = ent->uid;
/* Release old from lookup */
if (!uid_eq(old_uid, UID0)) {
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();
@ -203,7 +203,7 @@ void sim_ent_set_uid(struct sim_ent *ent, struct uid uid)
}
/* Insert new uid into lookup */
if (!uid_eq(uid, UID0)) {
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);
@ -223,7 +223,7 @@ struct sim_ent *sim_ent_from_uid(struct sim_snapshot *ss, struct uid uid)
{
struct sim_ent *res = sim_ent_nil();
u64 num_buckets = ss->num_uid_buckets;
if (num_buckets > 0 && !uid_eq(uid, UID0)) {
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)) {

View File

@ -387,6 +387,11 @@ INLINE b32 sim_ent_is_valid_and_active(struct sim_ent *ent)
return ent->valid && sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE);
}
INLINE b32 sim_ent_should_simulate(struct sim_ent *ent)
{
return !sim_ent_has_prop(ent, SIM_ENT_PROP_SYNC_DST);
}
/* ========================== *
* Ent functions
* ========================== */

View File

@ -358,7 +358,6 @@ void sim_step(struct sim_step_ctx *ctx)
sim_ent_release_all_with_prop(world, SIM_ENT_PROP_RELEASE);
sim_accel_reset(world, ctx->accel);
if (ctx->is_master) {
/* ========================== *
* Activate entities
* ========================== */
@ -366,6 +365,7 @@ 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 (!ent->valid) continue;
if (!sim_ent_should_simulate(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE)) {
u64 atick = ent->activation_tick;
@ -375,20 +375,6 @@ void sim_step(struct sim_step_ctx *ctx)
}
}
/* ========================== *
* Spawn test entities
* ========================== */
/* TODO: remove this (testing) */
/* Initialize entities */
{
static b32 run = 0;
if (!run) {
run = 1;
spawn_test_entities(world, V2(0, 0));
}
}
/* ========================== *
* Reset triggered entities
* ========================== */
@ -396,6 +382,7 @@ 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_has_prop(ent, SIM_ENT_PROP_TRIGGER_NEXT_TICK)) {
sim_ent_disable_prop(ent, SIM_ENT_PROP_TRIGGER_NEXT_TICK);
@ -416,6 +403,11 @@ void sim_step(struct sim_step_ctx *ctx)
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);
if (sim_ent_is_valid_and_active(client_ent)) {
if (!ctx->is_master && !uid_eq(client_ent->uid, world->local_client_ent_uid)) {
/* We are not the master and the command is not our own, skip processing */
continue;
}
/* Process control cmd for client */
struct sim_control old_control = client_ent->client_control;
struct sim_control *control = &client_ent->client_control;
@ -476,6 +468,7 @@ void sim_step(struct sim_step_ctx *ctx)
* Create client player ents
* ========================== */
if (ctx->is_master) {
for (u64 i = 0; i < world->num_ents_reserved; ++i) {
struct sim_ent *ent = &world->ents[i];
if (!sim_ent_is_valid_and_active(ent)) continue;
@ -495,6 +488,7 @@ void sim_step(struct sim_step_ctx *ctx)
}
}
}
}
/* ========================== *
* Update entity control from client control
@ -503,6 +497,7 @@ 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_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
struct sim_ent *client_ent = sim_ent_from_handle(world, ent->controlling_client);
@ -525,6 +520,7 @@ 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 (sprite_tag_is_nil(ent->sprite)) continue;
struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite);
@ -583,39 +579,39 @@ void sim_step(struct sim_step_ctx *ctx)
}
/* Test collider */
#if 0
#if 0
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TEST)) {
//if ((true)) {
#if 0
#if 0
ent->local_collider.points[0] = V2(0, 0);
ent->local_collider.count = 1;
ent->local_collider.radius = 0.5;
#elif 0
#elif 0
ent->local_collider.points[0] = v2_with_len(V2(0.08f, 0.17f), 0.15f);
ent->local_collider.points[1] = v2_with_len(V2(-0.07f, -0.2f), 0.15f);
ent->local_collider.count = 2;
ent->local_collider.radius = 0.075f;
#elif 1
#if 0
#elif 1
#if 0
/* "Bad" winding order */
ent->local_collider.points[0] = V2(-0.15, 0.15);
ent->local_collider.points[1] = V2(0.15, 0.15);
ent->local_collider.points[2] = V2(0, -0.15);
#else
#else
ent->local_collider.points[0] = V2(0, -0.15);
ent->local_collider.points[1] = V2(0.15, 0.15);
ent->local_collider.points[2] = V2(-0.15, 0.15);
#endif
#endif
ent->local_collider.count = 3;
ent->local_collider.radius = 0.25;
//ent->local_collider.radius = math_fabs(math_sin(ctx->tick.time) / 3);
#else
#else
//ent->local_collider.radius = 0.5;
ent->local_collider.radius = 0.25;
//ent->local_collider.radius = 0.;
#endif
#endif
}
#endif
#endif
}
/* ========================== *
@ -625,6 +621,7 @@ 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_has_prop(ent, SIM_ENT_PROP_ATTACHED)) continue;
struct sim_ent *parent = sim_ent_from_handle(world, ent->parent);
@ -647,13 +644,13 @@ void sim_step(struct sim_step_ctx *ctx)
* Test
* ========================== */
#if 0
#if 0
for (u64 ent_index = 0; ent_index < ss_blended->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ss_blended->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TEST)) continue;
#if 0
#if 0
if (!ent->test_initialized) {
ent->test_initialized = true;
ent->test_start_local_xform = sim_ent_get_local_xform(ent);
@ -677,7 +674,7 @@ void sim_step(struct sim_step_ctx *ctx)
xf = xform_rotated_to(xf, r);
xf = xform_scaled_to(xf, s);
sim_ent_set_local_xform(ent, xf);
#else
#else
f32 t = (f32)time;
struct v2 og = v2_mul(V2(math_cos(t), math_sin(t)), 3);
f32 rot = t * PI / 3;
@ -690,9 +687,9 @@ void sim_step(struct sim_step_ctx *ctx)
xf = xform_rotated_to(xf, rot);
xf = xform_scaled_to(xf, scale);
sim_ent_set_local_xform(ent, xf);
#endif
#endif
}
#endif
#endif
/* ========================== *
* Trigger equipped
@ -701,6 +698,7 @@ 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_has_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED)) {
struct sim_ent *eq = sim_ent_from_handle(world, ent->equipped);
@ -717,6 +715,7 @@ 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_has_prop(ent, SIM_ENT_PROP_TRIGGERED_THIS_TICK)) continue;
if ((world->sim_time_ns - ent->last_triggered_ns < NS_FROM_SECONDS(ent->trigger_delay)) && ent->last_triggered_ns != 0) continue;
@ -749,14 +748,14 @@ void sim_step(struct sim_step_ctx *ctx)
bullet->inertia_unscaled = 0.00001f;
bullet->layer = SIM_LAYER_BULLETS;
#if 1
#if 1
/* Point collider */
bullet->local_collider.points[0] = V2(0, 0);
bullet->local_collider.count = 1;
#else
#else
bullet->sprite = sprite_tag_from_path(LIT("res/graphics/bullet.ase"));
bullet->sprite_collider_slice = LIT("shape");
#endif
#endif
sim_ent_enable_prop(bullet, SIM_ENT_PROP_BULLET);
sim_ent_enable_prop(bullet, SIM_ENT_PROP_SENSOR);
@ -781,11 +780,12 @@ 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_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
struct sim_ent *joint_ent = sim_ent_from_handle(world, ent->move_joint);
if (!sim_ent_is_valid_and_active(joint_ent)) {
joint_ent = sim_ent_alloc_sync_src(root);
joint_ent = sim_ent_alloc_local(root);
joint_ent->mass_unscaled = F32_INFINITY;
joint_ent->inertia_unscaled = F32_INFINITY;
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_MOTOR_JOINT);
@ -810,10 +810,11 @@ void sim_step(struct sim_step_ctx *ctx)
* Create motor joints from control focus (aim)
* ========================== */
#if SIM_PLAYER_AIM
#if SIM_PLAYER_AIM
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_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
struct xform xf = sim_ent_get_xform(ent);
@ -822,7 +823,7 @@ void sim_step(struct sim_step_ctx *ctx)
/* Retrieve / create aim joint */
struct sim_ent *joint_ent = sim_ent_from_handle(world, ent->aim_joint);
if (!sim_ent_is_valid_and_active(joint_ent)) {
joint_ent = sim_ent_alloc_sync_src(root);
joint_ent = sim_ent_alloc_local(root);
joint_ent->mass_unscaled = F32_INFINITY;
joint_ent->inertia_unscaled = F32_INFINITY;
sim_ent_enable_prop(joint_ent, SIM_ENT_PROP_PHYSICAL_KINEMATIC); /* Since we'll be setting velocity manually */
@ -898,7 +899,7 @@ void sim_step(struct sim_step_ctx *ctx)
sim_ent_set_angular_velocity(joint_ent, new_vel);
}
}
#endif
#endif
/* ========================== *
* Create motor joints from ground friction (gravity)
@ -907,6 +908,7 @@ 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_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
struct sim_ent *joint_ent = sim_ent_from_handle(world, ent->ground_friction_joint);
@ -919,7 +921,7 @@ void sim_step(struct sim_step_ctx *ctx)
def.max_torque = ent->angular_ground_friction;
if (joint_ent->motor_joint_data.max_force != def.max_force || joint_ent->motor_joint_data.max_torque != def.max_torque) {
if (!sim_ent_is_valid_and_active(joint_ent)) {
joint_ent = sim_ent_alloc_sync_src(root);
joint_ent = sim_ent_alloc_local(root);
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);
@ -935,6 +937,7 @@ void sim_step(struct sim_step_ctx *ctx)
for (u64 i = 0; i < world->num_ents_reserved; ++i) {
struct sim_ent *client_ent = &world->ents[i];
if (!sim_ent_is_valid_and_active(client_ent)) continue;
if (!sim_ent_should_simulate(client_ent)) continue;
if (!sim_ent_has_prop(client_ent, SIM_ENT_PROP_CLIENT)) continue;
struct v2 cursor = client_ent->client_cursor_pos;
@ -944,42 +947,16 @@ void sim_step(struct sim_step_ctx *ctx)
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);
if (start_dragging) {
#if 0
struct xform mouse_xf = xform_from_pos(cursor);
struct collider_shape mouse_shape = ZI;
mouse_shape.points[0] = V2(0, 0);
mouse_shape.count = 1;
for (u64 sim_ent_index = 0; sim_ent_index < world->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *ent = &world->ents[sim_ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
struct collider_shape ent_collider = ent->local_collider;
if (ent_collider.count > 0) {
struct xform ent_xf = sim_ent_get_xform(ent);
/* TODO: Can just use boolean GJK */
struct collider_collision_points_result res = collider_collision_points(&ent_collider, &mouse_shape, ent_xf, mouse_xf);
if (res.num_points > 0) {
target_ent = ent;
break;
}
}
}
#else
target_ent = sim_ent_from_handle(world, client_ent->client_hovered_ent);
#endif
}
if (stop_dragging) {
target_ent = sim_ent_nil();
} else if (start_dragging) {
target_ent = sim_ent_from_handle(world, client_ent->client_hovered_ent);
}
if (sim_ent_is_valid_and_active(target_ent)) {
if (!sim_ent_is_valid_and_active(joint_ent)) {
/* FIXME: Joint ent may never release */
joint_ent = sim_ent_alloc_sync_src(root);
joint_ent = sim_ent_alloc_local(root);
joint_ent->mass_unscaled = F32_INFINITY;
joint_ent->inertia_unscaled = F32_INFINITY;
client_ent->client_dbg_drag_joint_ent = joint_ent->handle;
@ -1008,7 +985,7 @@ void sim_step(struct sim_step_ctx *ctx)
* Physics step
* ========================== */
{
if (ctx->is_master) {
struct phys_step_ctx phys = ZI;
phys.sim_step_ctx = ctx;
phys.pre_solve_callback = on_collision;
@ -1022,6 +999,7 @@ 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_has_prop(ent, SIM_ENT_PROP_TRACER)) continue;
struct v2 end = sim_ent_get_xform(ent).og;
@ -1046,6 +1024,7 @@ 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_has_prop(ent, SIM_ENT_PROP_BULLET)) continue;
if (ent->activation_tick == world->tick) {
@ -1056,14 +1035,14 @@ void sim_step(struct sim_step_ctx *ctx)
struct v2 impulse = xform_basis_mul_v2(src_xf, ent->bullet_src_dir);
impulse = v2_with_len(impulse, ent->bullet_impulse);
#if 0
#if 0
/* Add shooter velocity to bullet */
{
/* TODO: Add angular velocity as well? */
struct sim_ent *top = sim_ent_from_handle(ss_blended, src->top);
impulse = v2_add(impulse, v2_mul(top->linear_velocity, dt));
}
#endif
#endif
struct xform xf = XFORM_TRS(.t = pos, .r = v2_angle(impulse) + PI / 2);
sim_ent_set_xform(ent, xf);
@ -1101,6 +1080,7 @@ 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_has_prop(ent, SIM_ENT_PROP_CAMERA)) continue;
struct xform xf = sim_ent_get_xform(ent);
@ -1157,6 +1137,7 @@ 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_has_prop(ent, SIM_ENT_PROP_QUAKE)) continue;
ent->quake_intensity = max_f32(0, ent->quake_intensity - (ent->quake_fade * sim_dt));
@ -1183,7 +1164,7 @@ void sim_step(struct sim_step_ctx *ctx)
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)) {
if (sim_ent_is_valid_and_active(child)) {
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;
++stack_count;
@ -1193,7 +1174,6 @@ void sim_step(struct sim_step_ctx *ctx)
arena_temp_end(temp);
}
}
/* ========================== *
* Release entities at end of frame