power_play/src/sim/sim_core.h
2025-07-29 20:56:33 -05:00

252 lines
6.8 KiB
C

#define SIM_CLIENT_NIL_HANDLE ((ClientHandle) { .gen = 0, .idx = 0 })
/* Absolute layers */
#define SIM_LAYER_FLOOR_DECALS (-300)
#define SIM_LAYER_BULLETS (-200)
#define SIM_LAYER_TRACERS (-100)
#define SIM_LAYER_SHOULDERS (0)
#define SIM_LAYER_WALLS (100)
/* Relative layers */
#define SIM_LAYER_RELATIVE_DEFAULT (0)
#define SIM_LAYER_RELATIVE_WEAPON (1)
Struct(EntId) {
UID uid;
};
Struct(ClientHandle) {
u32 idx;
u32 gen;
};
/* ========================== *
* Startup
* ========================== */
Struct(SimStartupReceipt) { i32 _; };
SimStartupReceipt sim_startup(void);
/* ========================== *
* Client store
* ========================== */
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;
}
ClientStore *sim_client_store_alloc(void);
void sim_client_store_release(ClientStore *store);
/* ========================== *
* Client
* ========================== */
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) */
EntId 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 *sim_client_nil(void)
{
extern Readonly Client **_g_sim_client_nil;
return *_g_sim_client_nil;
}
Inline b32 sim_client_handle_eq(ClientHandle a, ClientHandle b)
{
return a.gen == b.gen && a.idx == b.idx;
}
Client *sim_client_alloc(ClientStore *store);
void sim_client_release(Client *client);
Client *sim_client_from_channel_id(ClientStore *store, N_ChannelId channel_id);
void sim_client_set_channel_id(Client *client, N_ChannelId channel_id);
Client *sim_client_from_handle(ClientStore *store, ClientHandle handle);
/* ========================== *
* Snapshot
* ========================== */
typedef i32 SyncFlag; enum {
SIM_SYNC_FLAG_NOSYNC_PREDICTABLES = 1 << 0
};
typedef i32 ControlFlag; enum {
SIM_CONTROL_FLAG_FIRE = 1 << 0,
SIM_CONTROL_FLAG_FIRE_ALT = 1 << 1,
/* Testing */
SIM_CONTROL_FLAG_DRAG = 1 << 2,
SIM_CONTROL_FLAG_DELETE = 1 << 3,
SIM_CONTROL_FLAG_CLEAR_ALL = 1 << 4,
SIM_CONTROL_FLAG_SPAWN1_TEST = 1 << 5,
SIM_CONTROL_FLAG_SPAWN2_TEST = 1 << 6,
SIM_CONTROL_FLAG_SPAWN3_TEST = 1 << 7,
SIM_CONTROL_FLAG_SPAWN4_TEST = 1 << 8,
SIM_CONTROL_FLAG_WALLS_TEST = 1 << 9,
SIM_CONTROL_FLAG_TILE_TEST = 1 << 10,
SIM_CONTROL_FLAG_EXPLODE_TEST = 1 << 11,
SIM_CONTROL_FLAG_TELEPORT_TEST = 1 << 12,
};
Struct(ControlData) {
V2 move; /* Movement direction vector (speed of 0 -> 1) */
V2 focus; /* Focus direction vector (where does the controller want to look) */
V2 dbg_cursor; /* Where is the user's cursor in the world (used for things like editing the world) */
u32 flags;
};
typedef i32 CmdKind; enum {
SIM_CMD_KIND_INVALID,
SIM_CMD_KIND_CONTROL,
SIM_CMD_KIND_CHAT
};
typedef i32 TileKind; enum {
SIM_TILE_KIND_NONE,
SIM_TILE_KIND_WALL,
NUM_SIM_TILE_KINDS
};
StaticAssert(NUM_SIM_TILE_KINDS < 256); /* Tile kind must fit in 8 bits */
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 */
EntId local_player;
/* Id lookup */
struct EntBin *id_bins;
u64 num_id_bins;
/* Entities */
Arena *ents_arena;
struct Ent *ents;
u32 first_free_ent;
u32 num_ents_allocated;
u32 num_ents_reserved;
};
Inline Snapshot *sim_snapshot_nil(void)
{
extern Readonly Snapshot **_g_sim_snapshot_nil;
return *_g_sim_snapshot_nil;
}
/* Alloc */
Snapshot *sim_snapshot_alloc(Client *client, Snapshot *src, u64 tick);
void sim_snapshot_release(Snapshot *sim_snapshot);
void sim_snapshot_release_ticks_in_range(Client *client, u64 start, u64 end);
/* Lookup */
Snapshot *sim_snapshot_from_tick(Client *client, u64 tick);
Snapshot *sim_snapshot_from_closest_tick_lte(Client *client, u64 tick);
Snapshot *sim_snapshot_from_closest_tick_gte(Client *client, u64 tick);
/* Tile */
V2i32 sim_world_tile_index_from_pos(V2 pos);
V2 sim_pos_from_world_tile_index(V2i32 world_tile_index);
V2i32 sim_local_tile_index_from_world_tile_index(V2i32 world_tile_index);
V2i32 sim_world_tile_index_from_local_tile_index(V2i32 tile_chunk_index, V2i32 local_tile_index);
V2i32 sim_tile_chunk_index_from_world_tile_index(V2i32 world_tile_index);
void sim_snapshot_set_tile(Snapshot *ss, V2i32 world_tile_index, TileKind tile_kind);
/* Lerp */
Snapshot *sim_snapshot_alloc_from_lerp(Client *client, Snapshot *ss0, Snapshot *ss1, f64 blend);
/* Sync */
void sim_snapshot_sync_ents(Snapshot *local_ss, Snapshot *remote_ss, EntId remote_player, u32 sync_flags);
/* Encode / decode */
void sim_snapshot_encode(BB_Writer *bw, Client *receiver, Snapshot *ss0, Snapshot *ss1);
void sim_snapshot_decode(BB_Reader *br, Snapshot *ss);