#ifndef SIM_ENT_H #define SIM_ENT_H #include "sim.h" #include "sprite.h" #include "mixer.h" #include "phys.h" #define SIM_ENT_NIL_ID ((struct sim_ent_id) { UID(0, 0) }) #define SIM_ENT_ROOT_ID ((struct sim_ent_id) { UID(0xaaaaaaaaaaaaaaaa, 0xaaaaaaaaaaaaaaaa) }) struct bitbuff_writer; struct bitbuff_reader; enum sim_ent_prop { 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 sim_ent { struct sim_snapshot *ss; /* ====================================================================== */ /* Metadata */ b32 valid; /* Is this ent allocated in memory that can be written to (can always be read) */ struct sim_ent_id 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) */ struct sim_ent_id top; /* Tree */ 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; /* 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 */ struct sim_ent_id owner; /* Id of the player that should predict simulation of this this entity locally */ struct sim_ent_id predictor; /* ====================================================================== */ /* Position */ /* Use xform getters & setters to access. */ struct xform _local_xform; /* Transform in relation to parent ent (or the world if ent has no parent) */ struct 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 */ enum sim_cmd_kind cmd_kind; struct sim_ent_id cmd_player; /* FIXME: Lerp */ /* Control cmd */ struct sim_control cmd_control; struct sim_ent_id cmd_control_hovered_ent; /* Chat cmd */ //struct string cmd_chat_msg; /* ====================================================================== */ /* Chat */ /* SEPROP_CHAT */ struct sim_ent_id chat_player; //struct 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]; struct v2i32 tile_chunk_index; /* ====================================================================== */ /* Client */ /* SEPROP_PLAYER */ /* FIXME: Lerp */ struct sim_client_handle player_client_handle; /* The client handle on the master sim's machine */ struct sim_control player_control; struct v2 player_cursor_pos; struct sim_ent_id player_hovered_ent; struct sim_ent_id player_control_ent; struct sim_ent_id player_camera_ent; struct sim_ent_id 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 */ struct v2 collision_dir; /* If set, then only collisions coming from this direction will generate contacts (used for walls to prevent ghost collisions) */ struct collider_shape local_collider; #if COLLIDER_DEBUG struct phys_collision_debug collision_debug_data; #endif struct space_entry_handle space_handle; /* ====================================================================== */ /* Constraints / joints */ /* SEPROP_CONSTRAINT_CONTACT */ struct phys_contact_constraint contact_constraint_data; /* SEPROP_MOTOR_JOINT */ struct phys_motor_joint motor_joint_data; /* SEPROP_MOUSE_JOINT */ struct phys_mouse_joint mouse_joint_data; /* SEPROP_WELD_JOINT */ struct phys_weld_joint weld_joint_data; /* ====================================================================== */ /* Control */ /* SEPROP_CONTROLLED */ struct sim_ent_id 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 */ struct sim_control control; struct sim_ent_id move_joint; struct sim_ent_id 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 */ struct sim_ent_id ground_friction_joint; f32 linear_ground_friction; f32 angular_ground_friction; /* Use sim_ent_set_linear_velocity & sim_ent_set_angular_velocity to set */ struct v2 linear_velocity; /* m/s */ f32 angular_velocity; /* rad/s */ struct v2 force; f32 torque; f32 linear_damping; f32 angular_damping; /* ====================================================================== */ /* Sprite */ struct sprite_tag sprite; struct string sprite_span_name; u32 sprite_tint; struct v3 sprite_emittance; struct string sprite_collider_slice; /* Collider will sync to bounds of this slice if set */ struct 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 */ struct string attach_slice; /* ====================================================================== */ /* Equip */ struct sim_ent_id equipped; /* ====================================================================== */ /* Chucker */ /* SEPROP_WEAPON_CHUCKER */ struct sim_ent_id chucker_zone; struct sim_ent_id chucker_joint; /* ====================================================================== */ /* Chucker zone */ /* SEPROP_CHUCKER_ZONE */ struct sim_ent_id 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 */ //struct sim_ent_id trigger_out_left; //struct sim_ent_id trigger_out_right; /* ====================================================================== */ /* Bullet */ struct sim_ent_id bullet_src; struct sim_ent_id bullet_tracer; struct v2 bullet_src_pos; struct v2 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 */ struct v2 tracer_start; struct v2 tracer_start_velocity; f32 tracer_fade_duration; /* Time for tracer to fade from opacity of 1 to 0 */ /* calculated each frame */ struct v2 tracer_gradient_start; struct v2 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; struct xform test_start_local_xform; struct xform test_start_sprite_xform; /* SEPROP_TEST_SOUND_EMITTER */ struct string sound_name; struct mixer_desc sound_desc; struct mixer_track_handle sound_handle; /* ====================================================================== */ /* Camera */ /* SEPROP_CAMERA */ struct sim_ent_id camera_follow; struct xform camera_quad_xform; f32 camera_lerp; /* Rate at which camera xform approaches target xform */ u32 camera_lerp_continuity_gen; struct xform camera_xform_target; /* Calculated from camera_follow */ u32 camera_applied_lerp_continuity_gen_plus_one; /* Calculated */ f32 shake; }; struct sim_ent_array { struct sim_ent *ents; u64 count; }; struct sim_ent_prop_array { enum sim_ent_prop *props; u64 count; }; struct sim_ent_bin { u32 first; u32 last; }; /* ========================== * * Nil * ========================== */ INLINE struct sim_ent *sim_ent_nil(void) { extern READONLY struct sim_ent **_g_sim_ent_nil; return *_g_sim_ent_nil; } /* ========================== * * Id helpers * ========================== */ INLINE b32 sim_ent_id_eq(struct sim_ent_id a, struct sim_ent_id b) { return uid_eq(a.uid, b.uid); } INLINE b32 sim_ent_id_is_nil(struct sim_ent_id id) { return uid_eq(id.uid, SIM_ENT_NIL_ID.uid); } /* ========================== * * Property helpers * ========================== */ INLINE void sim_ent_enable_prop(struct sim_ent *ent, enum sim_ent_prop prop) { u64 index = prop / 64; u64 bit = prop % 64; ent->props[index] |= ((u64)1 << bit); } INLINE void sim_ent_disable_prop(struct sim_ent *ent, enum sim_ent_prop prop) { u64 index = prop / 64; u64 bit = prop % 64; ent->props[index] &= ~((u64)1 << bit); } INLINE b32 sim_ent_has_prop(struct sim_ent *ent, enum sim_ent_prop prop) { u64 index = prop / 64; u64 bit = prop % 64; return !!(ent->props[index] & ((u64)1 << bit)); } INLINE b32 sim_ent_is_valid_and_active(struct sim_ent *ent) { return ent->valid && sim_ent_has_prop(ent, SEPROP_ACTIVE); } INLINE b32 sim_ent_should_predict(struct sim_ent *ent) { return sim_ent_id_eq(ent->predictor, ent->ss->local_player); } INLINE b32 sim_ent_is_owner(struct sim_ent *ent) { return sim_ent_id_eq(ent->owner, ent->ss->local_player); } INLINE b32 sim_ent_should_simulate(struct sim_ent *ent) { b32 res = 0; if (sim_ent_is_valid_and_active(ent)) { res = 1; if (sim_ent_has_prop(ent, SEPROP_SYNC_DST)) { struct sim_ent_id local_player = ent->ss->local_player; res = sim_ent_id_eq(local_player, ent->owner) || sim_ent_id_eq(local_player, ent->predictor); } } return res; } /* ========================== * * Ent functions * ========================== */ /* Alloc */ struct sim_ent *sim_ent_alloc_raw(struct sim_snapshot *ss, struct sim_ent *parent, struct sim_ent_id id); struct sim_ent *sim_ent_alloc_local(struct sim_ent *parent); struct sim_ent *sim_ent_alloc_local_with_id(struct sim_ent *parent, struct sim_ent_id id); struct sim_ent *sim_ent_alloc_sync_src(struct sim_ent *parent); struct sim_ent *sim_ent_alloc_sync_src_with_id(struct sim_ent *parent, struct sim_ent_id id); struct sim_ent *sim_ent_alloc_sync_dst(struct sim_ent *parent, struct sim_ent_id ent_id, struct sim_ent_id owner_id); void sim_ent_release_raw(struct sim_ent *ent); void sim_ent_release(struct sim_ent *ent); void sim_ent_release_all_with_prop(struct sim_snapshot *ss, enum sim_ent_prop prop); /* Activate */ void sim_ent_activate(struct sim_ent *ent, u64 current_tick); /* Id */ 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 player_id, struct sim_ent_id id0, struct sim_ent_id id1); struct sim_ent_id sim_ent_collision_debug_id_from_ids(struct sim_ent_id player_id, struct sim_ent_id id0, struct sim_ent_id id1); struct sim_ent_id sim_ent_tile_chunk_id_from_tile_chunk_index(struct v2i32 chunk_start); /* Query */ 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); /* Tree */ void sim_ent_link_parent(struct sim_ent *parent, struct sim_ent *child); void sim_ent_unlink_from_parent(struct sim_ent *ent); /* Xform */ struct xform sim_ent_get_xform(struct sim_ent *ent); struct xform sim_ent_get_local_xform(struct sim_ent *ent); void sim_ent_set_xform(struct sim_ent *ent, struct xform xf); void sim_ent_set_local_xform(struct sim_ent *ent, struct xform xf); /* Movement */ void sim_ent_set_linear_velocity(struct sim_ent *ent, struct v2 velocity); void sim_ent_set_angular_velocity(struct sim_ent *ent, f32 velocity); void sim_ent_apply_linear_impulse(struct sim_ent *ent, struct v2 impulse, struct v2 world_point); void sim_ent_apply_linear_impulse_to_center(struct sim_ent *ent, struct v2 impulse); void sim_ent_apply_force_to_center(struct sim_ent *ent, struct v2 force); void sim_ent_apply_angular_impulse(struct sim_ent *ent, f32 impulse); void sim_ent_apply_torque(struct sim_ent *ent, f32 torque); /* Tile */ struct sim_ent *sim_tile_chunk_from_chunk_index(struct sim_snapshot *ss, struct v2i32 chunk_index); struct sim_ent *sim_tile_chunk_from_world_tile_index(struct sim_snapshot *ss, struct v2i32 world_tile_index); enum sim_tile_kind sim_get_chunk_tile(struct sim_ent *chunk_ent, struct v2i32 local_tile_index); /* 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, struct sim_ent_id remote_player); 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); #endif