power_play/src/pp/pp.h
2026-04-06 01:41:54 -05:00

796 lines
15 KiB
C

#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);