power_play/src/pp/pp_ent.h
2025-08-01 04:36:37 -05:00

551 lines
15 KiB
C

#define SIM_ENT_NIL_ID ((EntityId) { UID(0, 0) })
#define SIM_ENT_ROOT_ID ((EntityId) { UID(0xaaaaaaaaaaaaaaaa, 0xaaaaaaaaaaaaaaaa) })
typedef i32 EntProp; enum {
SEPROP_ACTIVE,
SEPROP_RELEASE,
SEPROP_SYNC_SRC, /* This entity is networked to other clients */
SEPROP_SYNC_DST, /* This entity is not locally created, and will sync with incoming net src ents */
SEPROP_PLAYER,
SEPROP_PLAYER_IS_MASTER,
SEPROP_CMD,
SEPROP_TILE_CHUNK,
SEPROP_WALL,
/* Physics collision */
SEPROP_SENSOR, /* This entity's collisions generate contacts */
SEPROP_SOLID, /* This entity's collisions generate contacts to be solved by the physics system (overrides SEPROP_SENSOR) */
SEPROP_TOI, /* This entity's collisions are processed using TOI (time of impact) for precise collisions */
/* Physics movement */
SEPROP_KINEMATIC, /* This entity reacts to velocity */
SEPROP_DYNAMIC, /* This entity reacts to velocity and forces (overrides SEPROP_KINEMATIC) */
SEPROP_CONTROLLED,
SEPROP_COLLISION_DEBUG,
SEPROP_CONTACT_CONSTRAINT,
SEPROP_MOTOR_JOINT,
SEPROP_MOUSE_JOINT,
SEPROP_WELD_JOINT,
SEPROP_CAMERA,
SEPROP_CAMERA_ACTIVE,
SEPROP_BULLET,
SEPROP_WEAPON_SMG,
SEPROP_WEAPON_LAUNCHER,
SEPROP_WEAPON_CHUCKER,
SEPROP_CHUCKER_ZONE,
SEPROP_EXPLOSION,
SEPROP_TRACER,
SEPROP_QUAKE,
SEPROP_ATTACHED,
/* Test props */
SEPROP_TEST,
SEPROP_TEST_SOUND_EMITTER,
SEPROP_LIGHT_TEST,
SEPROP_COUNT
};
Struct(Entity) {
Snapshot *ss;
/* ====================================================================== */
/* Metadata */
b32 valid; /* Is this ent allocated in memory that can be written to (can always be read) */
EntityId id;
u64 props[(SEPROP_COUNT + 63) / 64];
u64 continuity_gen;
/* Is this the root ent */
b32 is_root;
/* Is ent a child of the root ent */
b32 is_top;
/* The id of the top level parent of the ent tree (if ent is top then this point to itself) */
EntityId top;
/* Tree */
EntityId parent;
EntityId next;
EntityId prev;
EntityId first;
EntityId last;
/* Lists keyed by index in snapshot ent array */
u32 next_in_id_bin;
u32 prev_in_id_bin;
u32 next_free;
/* ====================================================================== */
/* Sync */
/* SEPROP_SYNC_SRC */
/* SEPROP_SYNC_DST */
/* Id of the player that owns simulation for this entity */
EntityId owner;
/* Id of the player that should predict simulation of this this entity locally */
EntityId predictor;
/* ====================================================================== */
/* Position */
/* Use xform getters & setters to access. */
Xform _local_xform; /* Transform in relation to parent ent (or the world if ent has no parent) */
Xform _xform; /* Calculated from ent tree */
b32 _is_xform_dirty;
/* ====================================================================== */
/* Activation */
/* If 0, the ent will auto activate at start of next tick if not already active. */
u64 activation_tick;
/* ====================================================================== */
/* Layer */
i32 layer;
i32 final_layer; /* Calculated each tick from ent tree */
/* ====================================================================== */
/* Cmd */
/* SEPROP_CMD */
CmdKind cmd_kind;
EntityId cmd_player;
/* FIXME: Lerp */
/* Control cmd */
ControlData cmd_control;
EntityId cmd_control_hovered_ent;
/* Chat cmd */
//String cmd_chat_msg;
/* ====================================================================== */
/* Chat */
/* SEPROP_CHAT */
EntityId chat_player;
//String chat_msg;
/* ====================================================================== */
/* Tile */
/* SEPROP_TILE_CHUNK */
/* FIXME: Move out of here */
u8 tile_chunk_tiles[SIM_TILES_PER_CHUNK_SQRT * SIM_TILES_PER_CHUNK_SQRT];
Vec2I32 tile_chunk_index;
/* ====================================================================== */
/* Client */
/* SEPROP_PLAYER */
/* FIXME: Lerp */
ClientHandle player_client_handle; /* The client handle on the master sim's machine */
ControlData player_control;
Vec2 player_cursor_pos;
EntityId player_hovered_ent;
EntityId player_control_ent;
EntityId player_camera_ent;
EntityId player_dbg_drag_joint_ent;
b32 player_dbg_drag_start;
b32 player_dbg_drag_stop;
/* Client round-trip-time to server */
i64 player_last_rtt_ns;
f64 player_average_rtt_seconds;
/* ====================================================================== */
/* Collider */
Vec2 collision_dir; /* If set, then only collisions coming from this direction will generate contacts (used for walls to prevent ghost collisions) */
CLD_Shape local_collider;
#if COLLIDER_DEBUG
CollisionDebugData collision_debug_data;
#endif
SpaceEntryHandle space_handle;
/* ====================================================================== */
/* Constraints / joints */
/* SEPROP_CONSTRAINT_CONTACT */
ContactConstraint contact_constraint_data;
/* SEPROP_MOTOR_JOINT */
MotorJoint motor_joint_data;
/* SEPROP_MOUSE_JOINT */
MouseJoint mouse_joint_data;
/* SEPROP_WELD_JOINT */
WeldJoint weld_joint_data;
/* ====================================================================== */
/* Control */
/* SEPROP_CONTROLLED */
EntityId controlling_player;
f32 control_force; /* How much force is applied to achieve desired control movement */
f32 control_force_max_speed; /* Maximum linear velocity achieved by force (m/s) */
f32 control_torque; /* How much torque is applied when turning towards desired focus */
ControlData control;
EntityId move_joint;
EntityId aim_joint;
/* ====================================================================== */
/* Physics */
/* SEPROP_DYNAMIC */
//f32 density; /* Density in kg/m^2 */
f32 friction;
f32 mass_unscaled; /* Mass of ent in kg before any transformations */
f32 inertia_unscaled; /* Inertia of ent in kg*m^2 before any transformations */
EntityId ground_friction_joint;
f32 linear_ground_friction;
f32 angular_ground_friction;
/* Use sim_ent_set_linear_velocity & sim_ent_set_angular_velocity to set */
Vec2 linear_velocity; /* m/s */
f32 angular_velocity; /* rad/s */
Vec2 force;
f32 torque;
f32 linear_damping;
f32 angular_damping;
/* ====================================================================== */
/* Sprite */
S_Tag sprite;
String sprite_span_name;
u32 sprite_tint;
Vec3 sprite_emittance;
String sprite_collider_slice; /* Collider will sync to bounds of this slice if set */
Xform sprite_local_xform; /* Sprite transform in relation to ent */
/* ====================================================================== */
/* Animation */
/* SEPROP_ANIMATING */
i64 animation_last_frame_change_time_ns;
u32 animation_frame;
/* ====================================================================== */
/* Attachment */
/* SEPROP_ATTACHED */
/* Slice name on the parent ent's sprite to attach to */
String attach_slice;
/* ====================================================================== */
/* Equip */
EntityId equipped;
/* ====================================================================== */
/* Chucker */
/* SEPROP_WEAPON_CHUCKER */
EntityId chucker_zone;
EntityId chucker_joint;
/* ====================================================================== */
/* Chucker zone */
/* SEPROP_CHUCKER_ZONE */
EntityId chucker_zone_ent;
u64 chucker_zone_ent_tick;
/* ====================================================================== */
/* Triggerable */
i32 num_primary_triggers;
i32 num_secondary_triggers;
f32 primary_fire_delay;
f32 secondary_fire_delay;
i64 last_primary_fire_ns;
i64 last_secondary_fire_ns;
/* ====================================================================== */
/* Trigger */
/* How many times has this trigger been triggered this tick */
i64 triggered_count;
/* Other triggers to activate when this entity has been triggered */
//EntityId trigger_out_left;
//EntityId trigger_out_right;
/* ====================================================================== */
/* Bullet */
EntityId bullet_src;
EntityId bullet_tracer;
Vec2 bullet_src_pos;
Vec2 bullet_src_dir;
f32 bullet_launch_velocity;
f32 bullet_knockback;
f32 bullet_explosion_strength;
f32 bullet_explosion_radius;
b32 bullet_has_hit;
/* ====================================================================== */
/* Explosion */
f32 explosion_strength;
f32 explosion_radius;
/* ====================================================================== */
/* Tracer */
/* SEPROP_TRACER */
Vec2 tracer_start;
Vec2 tracer_start_velocity;
f32 tracer_fade_duration; /* Time for tracer to fade from opacity of 1 to 0 */
/* calculated each frame */
Vec2 tracer_gradient_start;
Vec2 tracer_gradient_end;
/* ====================================================================== */
/* Quake */
/* SEPROP_QUAKE */
f32 quake_intensity;
f32 quake_frequency;
f32 quake_fade; /* How much intensity to lose per second */
/* ====================================================================== */
/* Testing */
/* SEPROP_TEST */
b32 test_initialized;
Xform test_start_local_xform;
Xform test_start_sprite_xform;
/* SEPROP_TEST_SOUND_EMITTER */
String sound_name;
MIX_TrackDesc sound_desc;
MIX_Handle sound_handle;
/* ====================================================================== */
/* Camera */
/* SEPROP_CAMERA */
EntityId camera_follow;
Xform camera_quad_xform;
f32 camera_lerp; /* Rate at which camera xform approaches target xform */
u32 camera_lerp_continuity_gen;
Xform camera_xform_target; /* Calculated from camera_follow */
u32 camera_applied_lerp_continuity_gen_plus_one; /* Calculated */
f32 shake;
};
Struct(EntArray) {
Entity *ents;
u64 count;
};
Struct(EntPropArray) {
EntProp *props;
u64 count;
};
Struct(EntBin) {
u32 first;
u32 last;
};
/* ========================== *
* Nil
* ========================== */
Inline Entity *sim_ent_nil(void)
{
extern Readonly Entity **_g_sim_ent_nil;
return *_g_sim_ent_nil;
}
/* ========================== *
* Id helpers
* ========================== */
Inline b32 sim_ent_id_eq(EntityId a, EntityId b)
{
return EqUid(a.uid, b.uid);
}
Inline b32 sim_ent_id_is_nil(EntityId id)
{
return EqUid(id.uid, SIM_ENT_NIL_ID.uid);
}
/* ========================== *
* Property helpers
* ========================== */
Inline void sim_ent_enable_prop(Entity *ent, EntProp prop)
{
u64 index = prop / 64;
u64 bit = prop % 64;
ent->props[index] |= ((u64)1 << bit);
}
Inline void sim_ent_disable_prop(Entity *ent, EntProp prop)
{
u64 index = prop / 64;
u64 bit = prop % 64;
ent->props[index] &= ~((u64)1 << bit);
}
Inline b32 sim_ent_has_prop(Entity *ent, EntProp prop)
{
u64 index = prop / 64;
u64 bit = prop % 64;
return !!(ent->props[index] & ((u64)1 << bit));
}
Inline b32 sim_ent_is_valid_and_active(Entity *ent)
{
return ent->valid && sim_ent_has_prop(ent, SEPROP_ACTIVE);
}
Inline b32 sim_ent_should_predict(Entity *ent)
{
return sim_ent_id_eq(ent->predictor, ent->ss->local_player);
}
Inline b32 sim_ent_is_owner(Entity *ent)
{
return sim_ent_id_eq(ent->owner, ent->ss->local_player);
}
Inline b32 sim_ent_should_simulate(Entity *ent)
{
b32 result = 0;
if (sim_ent_is_valid_and_active(ent)) {
result = 1;
if (sim_ent_has_prop(ent, SEPROP_SYNC_DST)) {
EntityId local_player = ent->ss->local_player;
result = sim_ent_id_eq(local_player, ent->owner) || sim_ent_id_eq(local_player, ent->predictor);
}
}
return result;
}
/* ========================== *
* Entity functions
* ========================== */
/* Alloc */
Entity *sim_ent_alloc_raw(Snapshot *ss, Entity *parent, EntityId id);
Entity *sim_ent_alloc_local(Entity *parent);
Entity *sim_ent_alloc_local_with_id(Entity *parent, EntityId id);
Entity *sim_ent_alloc_sync_src(Entity *parent);
Entity *sim_ent_alloc_sync_src_with_id(Entity *parent, EntityId id);
Entity *sim_ent_alloc_sync_dst(Entity *parent, EntityId ent_id, EntityId owner_id);
void sim_ent_release_raw(Entity *ent);
void sim_ent_release(Entity *ent);
void sim_ent_release_all_with_prop(Snapshot *ss, EntProp prop);
/* Activate */
void sim_ent_activate(Entity *ent, u64 current_tick);
/* Id */
void sim_ent_set_id(Entity *ent, EntityId id);
Entity *sim_ent_from_id(Snapshot *ss, EntityId id);
EntityId sim_ent_random_id(void);
EntityId sim_ent_contact_constraint_id_from_contacting_ids(EntityId player_id, EntityId id0, EntityId id1);
EntityId sim_ent_collision_debug_id_from_ids(EntityId player_id, EntityId id0, EntityId id1);
EntityId sim_ent_tile_chunk_id_from_tile_chunk_index(Vec2I32 chunk_start);
/* Query */
Entity *sim_ent_find_first_match_one(Snapshot *ss, EntProp prop);
Entity *sim_ent_find_first_match_all(Snapshot *ss, EntPropArray props);
/* Tree */
void sim_ent_link_parent(Entity *parent, Entity *child);
void sim_ent_unlink_from_parent(Entity *ent);
/* Xform */
Xform sim_ent_get_xform(Entity *ent);
Xform sim_ent_get_local_xform(Entity *ent);
void sim_ent_set_xform(Entity *ent, Xform xf);
void sim_ent_set_local_xform(Entity *ent, Xform xf);
/* Movement */
void sim_ent_set_linear_velocity(Entity *ent, Vec2 velocity);
void sim_ent_set_angular_velocity(Entity *ent, f32 velocity);
void sim_ent_apply_linear_impulse(Entity *ent, Vec2 impulse, Vec2 world_point);
void sim_ent_apply_linear_impulse_to_center(Entity *ent, Vec2 impulse);
void sim_ent_apply_force_to_center(Entity *ent, Vec2 force);
void sim_ent_apply_angular_impulse(Entity *ent, f32 impulse);
void sim_ent_apply_torque(Entity *ent, f32 torque);
/* Tile */
Entity *sim_tile_chunk_from_chunk_index(Snapshot *ss, Vec2I32 chunk_index);
Entity *sim_tile_chunk_from_world_tile_index(Snapshot *ss, Vec2I32 world_tile_index);
TileKind sim_get_chunk_tile(Entity *chunk_ent, Vec2I32 local_tile_index);
/* Lerp */
void sim_ent_lerp(Entity *e, Entity *e0, Entity *e1, f64 blend);
/* Sync */
void sim_ent_sync_alloc_tree(Entity *local_parent, Entity *remote, EntityId remote_player);
void sim_ent_sync(Entity *local, Entity *remote);
/* Encode / decode */
void sim_ent_encode(BB_Writer *bw, Entity *e0, Entity *e1);
void sim_ent_decode(BB_Reader *br, Entity *e);