#define P_MaxFrameSnapshotFragments Kibi(4) //////////////////////////////////////////////////////////// //~ Key types #define P_NilEntKey ((P_EntKey) { 0 }) #define P_NilConstraintKey ((P_EntKey) { 0 }) #define P_WallShapeIDBasis 0x40d501b4cf6d4f0cull #define P_BulletSpreadBasis 0xc3b72fe38ca5a1d6ull #define P_BulletHitBasis 0xbc70fc783c1c507full #define P_BulletTrailBasis 0x27c011f891c571feull #define P_DeathBasis 0x2e3c75a3286d872aull #define P_KillfeedBasis 0xd1f84bd6f7c3cf1eull #define P_EntityColorBasis 0x3d2ddd9778146eccull Struct(P_EntKey) { u64 v; }; Struct(P_ConstraintKey) { u64 v; }; //////////////////////////////////////////////////////////// //~ Shape types Struct(P_ShapeDesc) { f32 radius; f32 mass; i32 count; Vec2 points[8]; }; Struct(P_Shape) { f32 mass; Vec2 centroid; Vec2 center_of_mass; f32 radius; i32 points_count; Vec2 points[8]; }; //////////////////////////////////////////////////////////// //~ Debug visualization types Enum(P_DebugDrawKind) { P_DebugDrawKind_Point, P_DebugDrawKind_Line, P_DebugDrawKind_Rect, P_DebugDrawKind_Shape, }; Struct(P_DebugDrawNode) { P_DebugDrawNode *next; P_DebugDrawKind kind; u32 srgb32; union { struct { Vec2 p; } point; struct { Vec2 p0; Vec2 p1; } line; Rng2 rect; P_Shape shape; }; }; //////////////////////////////////////////////////////////// //~ Ent types // TODO: Move boolean fields into bitwise property flags // TODO: Pack efficiently #define P_MinPlayerNameLen 1 #define P_MaxPlayerNameLen 24 #define P_RollTimeNs NsFromSeconds(0.5) #define P_RollTurnTimeNs (NsFromSeconds(0.1)) #define P_RollTimeoutNs NsFromSeconds(0.5) #define P_ObservationDurationSeconds 1 Enum(P_Button) { P_Button_PrimaryFire, P_Button_AltFire, P_Button_Roll, P_Button_COUNT }; Struct(P_Control) { i64 tick; i64 orig_tick; // Will differ from tick if this control was propagated from the control of another tick // TODO: Move this to client-only code i64 produced_at_ns; Vec2 move; Vec2 look; f32 held[P_Button_COUNT]; f32 downs[P_Button_COUNT]; }; Struct(P_NetworkedEntState) { //- Persistent data P_EntKey key; i64 created_at_ns; i64 created_at_tick; //- Build data u64 continuity_gen; f32 exists; b32 sim; b32 is_guy; b32 is_bot; f32 health; Xform xf; f64 lifetime_seconds; u64 rand_seq; //- Bullet b32 is_bullet; u32 bullet_hits_count; //- Events b32 is_trail; Vec2 trail_p0; Vec2 trail_p1; b32 is_first_trail; b32 is_hit; Vec2 hit_entry; Vec2 hit_entry_normal; Vec2 hit_entry_velocity; P_MaterialKind hit_material; b32 is_death; Vec2 death_pos; Vec2 death_dir; P_EntKey death_victim; P_EntKey death_killer; //- Bomb b32 is_bomb; //- Health b32 is_health; //- Player / guy / weapon / bullet / pickup P_EntKey source; b32 is_pickup; //- Player / Guy P_Control control; //- Guy / Bullet P_EntKey damage_attribution_player; Vec2 damage_attribution_dir; //- Player P_EntKey spawn; b32 is_player; P_EntKey guy; u64 kills; u64 deaths; u8 string_len; u8 string_text[P_MaxPlayerNameLen + 8]; //- Guy P_EntKey weapon; Vec2 last_roll_dir; i64 walk_time_accum_ns; i64 fire_time_accum_ns; i64 last_fire_ns; i64 last_alt_fire_ns; i64 last_roll_ns; f32 last_fire_rate; //- Weapon b32 is_weapon; b32 is_uzi; b32 is_launcher; //- Spawner b32 is_guy_spawn; b32 is_health_spawn; i64 last_spawn_reset_ns; P_EntKey pickup; //- Solver Vec2 v; // Linear velocity f32 w; // Angular velocity //- Smoothed values Vec2 smoothed_move_dir; }; Struct(P_LocalEntState) { //- Observation info i64 initial_observation_time_ns; i64 last_observation_time_ns; b32 is_first_observation; // Vec2 smoothed_v; // Vec2 smoothed_v_dir; // Vec2 smoothed_move_dir; // f32 smoothed_w; }; Struct(P_Ent) { P_Ent *next; P_Ent *prev; P_Ent *next_in_bin; P_Ent *prev_in_bin; Embed(P_NetworkedEntState, net_state); Embed(P_LocalEntState, local_state); }; Struct(P_EntListNode) { P_EntListNode *next; P_Ent ent; }; Struct(P_EntList) { P_EntListNode *first; P_EntListNode *last; i64 count; }; Struct(P_EntBin) { P_Ent *first; P_Ent *last; }; //////////////////////////////////////////////////////////// //~ Animation types Struct(P_Anim) { i64 body_frame_seq; SPR_SpanKey body_span; SPR_SheetKey body_sheet; i64 legs_frame_seq; SPR_SpanKey legs_span; SPR_SheetKey legs_sheet; i64 wep_frame_seq; SPR_SpanKey wep_span; SPR_SheetKey wep_sheet; b32 weapon_over; }; //////////////////////////////////////////////////////////// //~ Constraint types Enum(P_ConstraintFlag) { P_ConstraintFlag_None = 0, P_ConstraintFlag_Solid = (1 << 0), P_ConstraintFlag_Gentle = (1 << 1), P_ConstraintFlag_NoWarmStart = (1 << 2), }; Struct(P_ContactPoint) { Vec2 vcp0; Vec2 vcp1; f32 starting_separation; f32 inv_normal_mass; f32 inv_tangent_mass; u32 id; f32 solved_normal_impulse; f32 solved_tangent_impulse; }; Struct(P_Constraint) { P_Constraint *next; P_Constraint *prev; P_Constraint *next_in_bin; P_Constraint *prev_in_bin; P_ConstraintKey key; P_ConstraintFlag flags; i64 last_touched_tick; P_EntKey ent0; P_EntKey ent1; Vec2 static_center0; Vec2 static_center1; f32 inv_m0; f32 inv_m1; f32 inv_i0; f32 inv_i1; Vec2 normal; f32 friction; i32 points_count; P_ContactPoint points[2]; }; Struct(P_ConstraintBin) { P_Constraint *first; P_Constraint *last; }; //////////////////////////////////////////////////////////// //~ Space types Struct(P_SpaceEntry) { u64 shape_id; P_Shape shape; Vec2 dir; }; Struct(P_SpaceEntryNode) { P_SpaceEntryNode *next; P_SpaceEntry entry; }; Struct(P_SpaceEntryList) { i64 count; P_SpaceEntryNode *first; P_SpaceEntryNode *last; }; Struct(P_SpaceCell) { P_SpaceEntryNode *first; }; Struct(P_Space) { i64 entries_count; i64 unique_entries_count; Vec2I32 dims; P_SpaceCell *cells; }; //////////////////////////////////////////////////////////// //~ World types Struct(P_Frame) { ////////////////////////////// //- Internal world state struct P_World *world; P_Frame *next; P_Frame *prev; P_Frame *next_in_bin; P_Frame *prev_in_bin; ////////////////////////////// //- Frame state i64 src_tick; i64 tick; i64 time_ns; ////////////////////////////// //- Ents i64 ents_count; P_Ent *first_ent; P_Ent *last_ent; i64 ent_bins_count; P_EntBin *ent_bins; ////////////////////////////// //- Constraints i64 constraints_count; P_Constraint *first_constraint; P_Constraint *last_constraint; i64 constraint_bins_count; P_ConstraintBin *constraint_bins; ////////////////////////////// //- Snapshot-assembly state u64 fragments_count; u64 received_fragments_count; u64 received_fragment_bits[(P_MaxFrameSnapshotFragments + 63) / 64]; i64 assembled_at_ns; }; Struct(P_FrameBin) { P_Frame *first; P_Frame *last; }; Struct(P_World) { Arena *arena; Arena *frames_arena; u64 seed; RandState rand; P_Ent *first_free_ent; P_Constraint *first_free_constraint; P_Frame *first_frame; P_Frame *last_frame; P_Frame *first_free_frame; i64 frame_bins_count; P_FrameBin *frame_bins; //- Baked data Arena *bake_arena; P_Space walls_space; u64 baked_hash; u64 tiles_hash; u8 *tiles; }; //////////////////////////////////////////////////////////// //~ Message types Enum(P_MsgKind) { P_MsgKind_None, P_MsgKind_Raw, // Server <-> Client P_MsgKind_Chat, P_MsgKind_Connect, // Client -> Server P_MsgKind_SaveWorld, P_MsgKind_ResetWorld, P_MsgKind_ClearBullets, P_MsgKind_Teleport, P_MsgKind_TileEdit, P_MsgKind_Prefab, P_MsgKind_Delete, // Server -> Client P_MsgKind_Tiles, P_MsgKind_NetVars, P_MsgKind_COUNT }; Struct(P_Msg) { P_MsgKind kind; NET_Key src; NET_Key dst; b32 affect_bots; P_PrefabKind prefab; P_EntKey key; Xform xf; P_TileKind tile_kind; Rng2I32 tile_range; u64 tiles_hash; String data; }; Struct(P_MsgNode) { P_MsgNode *next; P_MsgNode *prev; P_Msg msg; }; Struct(P_MsgList) { P_MsgNode *first; P_MsgNode *last; i64 count; }; //////////////////////////////////////////////////////////// //~ Collision types Struct(P_SupportPoint) { Vec2 p; u32 id; // Index of the originating piont in the shape }; Struct(P_CollisionPoint) { Vec2 p; f32 separation; u32 id; // Based on polygon edge-to-edge }; Struct(P_MenkowskiPoint) { Vec2 p; // Menkowski difference point P_SupportPoint s0; // Support point of first shape in dir P_SupportPoint s1; // Support point of second shape in -dir }; Struct(P_MenkowskiSimplex) { i32 count; P_MenkowskiPoint a, b, c; }; Struct(P_ClippedLine) { Vec2 a0_clipped, b0_clipped; Vec2 a1_clipped, b1_clipped; }; Struct(P_CollisionResult) { // Collision manifold i32 collision_points_count; P_CollisionPoint collision_points[2]; Vec2 collision_normal; // Closest points Vec2 closest_p0; Vec2 closest_p1; }; Struct(P_RaycastResult) { b32 is_intersecting; Vec2 p; Vec2 normal; }; //////////////////////////////////////////////////////////// //~ State types // NOTE: // Network vars are networked reliably to clients whenever any change is detected. // Large or frequently updated data should not go here. // Struct(P_NetVarState) { f32 server_tweak; }; Struct(P_SimStatistics) { NET_PipeStatistics pipe; i64 tick; i64 ents_count; i64 constraints_count; }; Struct(P_Ctx) { // Sim -> Vis state TicketMutex s2v_tm; struct { i64 gen; Arena *arena; i64 debug_draw_nodes_count; P_DebugDrawNode *first_debug_draw_node; P_DebugDrawNode *last_debug_draw_node; P_SimStatistics stats; } s2v; }; Struct(P_ThreadLocalCtx) { b32 is_client; P_EntKey local_player; //- Per-thread debug info Arena *debug_arena; b32 debug_draw_enabled; Vec4 debug_tint; P_DebugDrawNode *first_debug_draw_node; P_DebugDrawNode *last_debug_draw_node; i64 debug_draw_nodes_count; //- Per-thread outbound messages Arena *out_msgs_arena; P_MsgList out_msgs; }; extern P_Ctx P; extern ThreadLocal P_ThreadLocalCtx P_tl; extern Readonly P_Ent P_NilEnt; extern Readonly P_Frame P_NilFrame; //////////////////////////////////////////////////////////// //~ Bootstrap void P_Bootstrap(void); //////////////////////////////////////////////////////////// //~ Nil helpers b32 P_IsEntKeyNil(P_EntKey key); b32 P_IsConstraintKeyNil(P_ConstraintKey key); b32 P_IsEntNil(P_Ent *ent); b32 P_IsConstraintNil(P_Constraint *constraint); b32 P_IsFrameNil(P_Frame *frame); //////////////////////////////////////////////////////////// //~ Key helpers b32 P_MatchEntKey(P_EntKey a, P_EntKey b); b32 P_MatchConstraintKey(P_ConstraintKey a, P_ConstraintKey b); P_ConstraintKey P_ConstraintKeyFromU64s(u64 a, u64 b); P_EntKey P_EntKeyFromU64(u64 v); #define P_FmtKey(key) FmtHandle((key).v) //////////////////////////////////////////////////////////// //~ Rand helpers P_EntKey P_RandEntKey(void); u64 P_RandU64FromEnt(P_Ent *ent); //////////////////////////////////////////////////////////// //~ String helpers String P_StringFromEnt(P_Ent *ent); void P_SetEntString(P_Ent *ent, String str); //////////////////////////////////////////////////////////// //~ Tile helpers String P_NameFromTileKind(P_TileKind kind); //////////////////////////////////////////////////////////// //~ Prefab helpers String P_NameFromPrefabKind(P_PrefabKind kind); //////////////////////////////////////////////////////////// //~ Shape helpers P_Shape P_ShapeFromDescEx(P_ShapeDesc desc); #define P_ShapeFromDesc(...) P_ShapeFromDescEx((P_ShapeDesc) { __VA_ARGS__ }) P_Shape P_MulXformShape(Xform xf, P_Shape shape); Rng2 P_BoundingBoxFromShape(P_Shape shape); P_Shape P_LocalShapeFromEnt(P_Ent *ent); P_Shape P_WorldShapeFromEnt(P_Ent *ent); //////////////////////////////////////////////////////////// //~ Status helpers b32 P_IsEntRolling(P_Frame *frame, P_Ent *ent); P_Anim P_AnimFromEnt(P_Frame *frame, P_Ent *ent); Vec4 P_ColorFromEnt(P_Ent *ent); //////////////////////////////////////////////////////////// //~ Collision P_SupportPoint P_SupportPointFromShapeEx(P_Shape shape, Vec2 dir, i32 ignore_idx); P_SupportPoint P_SupportPointFromShape(P_Shape shape, Vec2 dir); P_MenkowskiPoint P_MenkowskiPointFromShapes(P_Shape shape0, P_Shape shape1, Vec2 dir); P_ClippedLine P_ClipLineToLine(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1, Vec2 normal); Vec2 P_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal); P_CollisionResult P_CollisionResultFromShapes(P_Shape shape0, P_Shape shape1); P_RaycastResult P_RaycastShape(P_Shape shape, Vec2 ray_start, Vec2 ray_dir); Vec2 P_EdgePointFromShape(P_Shape shape, Vec2 dir); //////////////////////////////////////////////////////////// //~ Lookup helpers P_Ent *P_EntFromKey(P_Frame *frame, P_EntKey key); P_Ent *P_SourcePlayerFromEnt(P_Frame *frame, P_Ent *ent); P_Constraint *P_ConstraintFromKey(P_Frame *frame, P_ConstraintKey key); //////////////////////////////////////////////////////////// //~ Iteration helpers P_Ent *P_FirstEnt(P_Frame *frame); P_Ent *P_NextEnt(P_Ent *e); P_Constraint *P_FirstConstraint(P_Frame *frame); P_Constraint *P_NextConstraint(P_Constraint *c); //////////////////////////////////////////////////////////// //~ Space P_Space P_SpaceFromEnts(Arena *arena, P_Frame *frame); P_Space P_SpaceFromWalls(Arena *arena, P_Frame *frame); P_SpaceCell P_SpaceCellFromPos(P_Space *space, Vec2 pos); void P_UniqueSpaceEntriesFromRay(Arena *arena, P_SpaceEntryList *result, i32 spaces_count, P_Space **spaces, Vec2 ray_p0, Vec2 ray_p1); //////////////////////////////////////////////////////////// //~ List helpers P_Ent *P_PushTempEnt(Arena *arena, P_EntList *list); //////////////////////////////////////////////////////////// //~ Debug draw void P_DebugDrawPoint(Vec2 p, Vec4 srgb); void P_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb); void P_DebugDrawRect(Rng2 rect, Vec4 srgb); void P_DebugDrawShape(P_Shape shape, Vec4 srgb); void P_DebugDrawFrame(P_Frame *frame); //////////////////////////////////////////////////////////// //~ Msg P_Msg *P_PushMsg(P_MsgKind kind, String data); //////////////////////////////////////////////////////////// //~ World P_World *P_AcquireWorld(void); void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents); P_Constraint *P_PushConstraint(P_Frame *frame, P_ConstraintKey key); P_Frame *P_FrameFromTick(P_World *world, i64 tick); void P_ClearFrames(P_World *world, i64 tick_min, i64 tick_max); P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick); //////////////////////////////////////////////////////////// //~ Step void P_StepFrame(P_Frame *frame);