power_play/src/pp/pp_sim.h
2025-10-22 03:22:23 -05:00

325 lines
8.2 KiB
C

////////////////////////////////////////////////////////////
//~ Id types
Struct(EntityId)
{
Uid uid;
};
Struct(ClientHandle)
{
u32 idx;
u32 gen;
};
#define NilClientHandle ((ClientHandle) { .gen = 0, .idx = 0 })
////////////////////////////////////////////////////////////
//~ Client store types
Struct(ClientLookupBin)
{
struct ClientHandle first;
struct ClientHandle last;
};
Struct(ClientStore)
{
b32 valid;
Arena *arena;
/* Client lookup */
ClientLookupBin *client_lookup_bins;
u64 num_client_lookup_bins;
/* Clients */
Arena *clients_arena;
struct Client *clients;
ClientHandle first_free_client;
u64 num_clients_allocated;
u64 num_clients_reserved;
};
Inline ClientStore *sim_client_store_nil(void)
{
extern Readonly ClientStore **_g_sim_client_store_nil;
return *_g_sim_client_store_nil;
}
////////////////////////////////////////////////////////////
//~ Client types
Struct(SnapshotLookupBin)
{
struct Snapshot *first;
struct Snapshot *last;
};
Struct(Client)
{
b32 valid;
ClientHandle handle;
ClientStore *store;
Arena *snapshots_arena;
/* Round trip time of the client (if networked) */
i64 last_rtt_ns;
N_ChannelId channel_id;
u64 channel_hash;
ClientHandle next_free;
ClientHandle next_in_bin;
ClientHandle prev_in_bin;
/* The client's player entity id in the master sim (if relevant) */
EntityId player_id;
/* This is the highest confirmed tick of ours that we know this client has received */
u64 ack;
/* This is the highest confirmed ack of ours that we know this client has received (this
* can be used to determine which client ticks will no longer be delta encoded from and
* therefore can be released) */
u64 double_ack;
/* This is the highest tick of their's that we have received */
u64 highest_received_tick;
/* Snapshots sorted by tick (low to high) */
u64 first_tick;
u64 last_tick;
u64 num_ticks;
struct Snapshot *first_free_snapshot;
/* Tick -> snapshot lookup */
u64 num_snapshot_lookup_bins;
SnapshotLookupBin *snapshot_lookup_bins;
};
Inline Client *NilClient(void)
{
extern Readonly Client **_g_sim_client_nil;
return *_g_sim_client_nil;
}
Inline b32 EqClientHandle(ClientHandle a, ClientHandle b)
{
return a.gen == b.gen && a.idx == b.idx;
}
////////////////////////////////////////////////////////////
//~ Layer types
/* Absolute layers */
#define Layer_FloorDecals (-300)
#define Layer_Bullets (-200)
#define Layer_Tracers (-100)
#define Layer_Shoulders (0)
#define Layer_Walls (100)
/* Relative layers */
#define Layer_DefaultRelative (0)
#define Layer_RelativeWeapon (1)
////////////////////////////////////////////////////////////
//~ Control types
Enum(ControlFlag)
{
ControlFlag_Fire = 1 << 0,
ControlFlag_AltFire = 1 << 1,
/* Testing */
ControlFlag_Drag = 1 << 2,
ControlFlag_Delete = 1 << 3,
ControlFlag_ClearAll = 1 << 4,
ControlFlag_SpawnTest1 = 1 << 5,
ControlFlag_SpawnTest2 = 1 << 6,
ControlFlag_SpawnTest3 = 1 << 7,
ControlFlag_SpawnTest4 = 1 << 8,
ControlFlag_TestWalls = 1 << 9,
ControlFlag_TestTiles = 1 << 10,
ControlFlag_TestExplode = 1 << 11,
ControlFlag_TestTeleport = 1 << 12,
};
Struct(ControlData)
{
Vec2 move; /* Movement direction vector (speed of 0 -> 1) */
Vec2 focus; /* Focus direction vector (where does the controller want to look) */
Vec2 dbg_cursor; /* Where is the user's cursor in the world (used for things like editing the world) */
ControlFlag flags;
};
Enum(CmdKind)
{
CmdKind_Invalid,
CmdKind_Control,
CmdKind_Chat
};
////////////////////////////////////////////////////////////
//~ Tile types
Enum(TileKind)
{
TileKind_None,
TileKind_Wall,
TileKind_Count
};
StaticAssert(TileKind_Count < 256); /* Tile kind must fit in 8 bits */
////////////////////////////////////////////////////////////
//~ Snapshot types
Enum(SyncFlag)
{
SyncFlag_NoSyncPredictables = 1 << 0
};
Struct(Snapshot)
{
b32 valid;
u64 tick;
Client *client;
Snapshot *next_free;
Snapshot *next_in_bin;
Snapshot *prev_in_bin;
u64 prev_tick;
u64 next_tick;
Arena *arena;
/* Sim time (guaranteed to increase by sim_dt_ns each step) */
i64 sim_dt_ns;
i64 sim_time_ns;
/* If != previous tick's continuity then don't lerp */
u64 continuity_gen;
/* The last physics iteration (used for tracking contact lifetime) */
u64 phys_iteration;
/* The id of the receiver's player in the snapshot */
EntityId local_player;
/* Id lookup */
struct EntBin *id_bins;
u64 num_id_bins;
/* Entities */
Arena *ents_arena;
struct Entity *ents;
u32 first_free_ent;
u32 num_ents_allocated;
u32 num_ents_reserved;
};
Inline Snapshot *NilSnapshot(void)
{
extern Readonly Snapshot **_g_sim_snapshot_nil;
return *_g_sim_snapshot_nil;
}
////////////////////////////////////////////////////////////
//~ State types
#define ClientLookupBinsCount 127
#define TickLookupBinsCount 127
#define IdLookupBinsCount 4096
Struct(SharedSimCtx)
{
Arena *nil_arena;
ClientStore *nil_client_store;
Client *nil_client;
Snapshot *nil_snapshot;
struct Entity *nil_ent;
};
extern SharedSimCtx shared_sim_ctx;
/* Accessed via `sim_client_store_nil()` */
extern Readonly ClientStore **_g_sim_client_store_nil;
/* Accessed via `NilClient()` */
extern Readonly Client **_g_sim_client_nil;
/* Accessed via `NilSnapshot()` */
extern Readonly Snapshot **_g_sim_snapshot_nil;
extern Readonly struct Entity **_g_sim_ent_nil;
////////////////////////////////////////////////////////////
//~ Startup
void StartupSim(void);
////////////////////////////////////////////////////////////
//~ Client store acquire operations
ClientStore *AcquireClientStore(void);
void ReleaseClientStore(ClientStore *store);
////////////////////////////////////////////////////////////
//~ Client acquire operations
Client *AcquireClient(ClientStore *store);
void ReleaseClient(Client *client);
////////////////////////////////////////////////////////////
//~ Client lookup operations
u64 ClientChannelHashFromChannelId(N_ChannelId channel_id);
void SetClientChannelId(Client *client, N_ChannelId channel_id);
Client *ClientFromChannelId(ClientStore *store, N_ChannelId channel_id);
Client *ClientFromHandle(ClientStore *store, ClientHandle handle);
////////////////////////////////////////////////////////////
//~ Snapshot acquire operations
Snapshot *AcquireSnapshot(Client *client, Snapshot *src, u64 tick);
void ReleaseSnapshot(Snapshot *ss);
void ReleaseSnapshotsInRange(Client *client, u64 start, u64 end);
////////////////////////////////////////////////////////////
//~ Snapshot lookup operations
Snapshot *SnapshotFromTick(Client *client, u64 tick);
Snapshot *SnapshotFromClosestTickLte(Client *client, u64 tick);
Snapshot *SnapshotFromClosestTickGte(Client *client, u64 tick);
////////////////////////////////////////////////////////////
//~ Tile operations
Vec2I32 WorldTileIndexFromPos(Vec2 pos);
Vec2 PosFromWorldTileIndex(Vec2I32 world_tile_index);
Vec2I32 LocalTileIndexFromWorldTileIndex(Vec2I32 world_tile_index);
Vec2I32 WorldTileIndexFromLocalTileIndex(Vec2I32 tile_chunk_index, Vec2I32 local_tile_index);
Vec2I32 TileChunkIndexFromWorldTileIndex(Vec2I32 world_tile_index);
void SetSnapshotTile(Snapshot *ss, Vec2I32 world_tile_index, TileKind tile_kind);
////////////////////////////////////////////////////////////
//~ Snapshot lerp operations
Snapshot *AcquireSnapshotFromLerp(Client *client, Snapshot *ss0, Snapshot *ss1, f64 blend);
////////////////////////////////////////////////////////////
//~ Snapshot sync operations
void SyncSnapshotEntities(Snapshot *local_ss, Snapshot *remote_ss, EntityId remote_player, u32 sync_flags);
////////////////////////////////////////////////////////////
//~ Snapshot encode operations
void EncodeSnapshot(BB_Writer *bw, Client *receiver, Snapshot *ss0, Snapshot *ss1);
////////////////////////////////////////////////////////////
//~ Snapshot decode operations
void DecodeSnapshot(BB_Reader *br, Snapshot *ss);