#ifndef SIM_H #define SIM_H #define SIM_CLIENT_NIL_HANDLE ((struct sim_client_handle) { .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) /* ========================== * * Startup * ========================== */ struct sim_startup_receipt { i32 _; }; struct sim_startup_receipt sim_startup(void); /* ========================== * * Client store * ========================== */ struct sim_client_lookup_bin { struct sim_client_handle first; struct sim_client_handle last; }; struct sim_client_store { b32 valid; struct arena arena; /* Client lookup */ struct sim_client_lookup_bin *client_lookup_bins; u64 num_client_lookup_bins; /* Clients */ struct arena clients_arena; struct sim_client *clients; struct sim_client_handle first_free_client; u64 num_clients_allocated; u64 num_clients_reserved; }; INLINE struct sim_client_store *sim_client_store_nil(void) { extern READONLY struct sim_client_store **_g_sim_client_store_nil; return *_g_sim_client_store_nil; } struct sim_client_store *sim_client_store_alloc(void); void sim_client_store_release(struct sim_client_store *store); /* ========================== * * Client * ========================== */ struct sim_snapshot; struct sim_snapshot_lookup_bin { struct sim_snapshot *first; struct sim_snapshot *last; }; struct sim_client { b32 valid; struct sim_client_handle handle; struct sim_client_store *store; struct arena snapshots_arena; /* Round trip time of the client (if networked) */ i64 last_rtt_ns; struct host_channel_id channel_id; u64 channel_hash; struct sim_client_handle next_free; struct sim_client_handle next_in_bin; struct sim_client_handle prev_in_bin; /* The client's player entity id in the master sim (if relevant) */ struct sim_ent_id 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 sim_snapshot *first_free_snapshot; /* Tick -> snapshot lookup */ u64 num_snapshot_lookup_bins; struct sim_snapshot_lookup_bin *snapshot_lookup_bins; }; INLINE struct sim_client *sim_client_nil(void) { extern READONLY struct sim_client **_g_sim_client_nil; return *_g_sim_client_nil; } INLINE b32 sim_client_handle_eq(struct sim_client_handle a, struct sim_client_handle b) { return a.gen == b.gen && a.idx == b.idx; } struct sim_client *sim_client_alloc(struct sim_client_store *store); void sim_client_release(struct sim_client *client); struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id); void sim_client_set_channel_id(struct sim_client *client, struct host_channel_id channel_id); struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct sim_client_handle handle); /* ========================== * * Snapshot * ========================== */ enum sim_sync_flag { SIM_SYNC_FLAG_NOSYNC_PREDICTABLES = 1 << 0 }; enum sim_control_flag { 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_WALLS_TEST = 1 << 8, SIM_CONTROL_FLAG_TILE_TEST = 1 << 9, SIM_CONTROL_FLAG_EXPLODE_TEST = 1 << 10, SIM_CONTROL_FLAG_TELEPORT_TEST = 1 << 11, }; struct sim_control { struct v2 move; /* Movement direction vector (speed of 0 -> 1) */ struct v2 focus; /* Focus direction vector (where does the controller want to look) */ struct v2 dbg_cursor; /* Where is the user's cursor in the world (used for things like editing the world) */ u32 flags; }; enum sim_cmd_kind { SIM_CMD_KIND_INVALID, SIM_CMD_KIND_CONTROL, SIM_CMD_KIND_CHAT }; enum sim_tile_kind { SIM_TILE_KIND_NONE, SIM_TILE_KIND_WALL, NUM_SIM_TILE_KINDS }; CT_ASSERT(NUM_SIM_TILE_KINDS < 256); /* Tile kind must fit in 8 bits */ struct sim_ent_bin; struct sim_snapshot { b32 valid; u64 tick; struct sim_client *client; struct sim_snapshot *next_free; struct sim_snapshot *next_in_bin; struct sim_snapshot *prev_in_bin; u64 prev_tick; u64 next_tick; struct 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 */ struct sim_ent_id local_player; /* Id lookup */ struct sim_ent_bin *id_bins; u64 num_id_bins; /* Entities */ struct arena ents_arena; struct sim_ent *ents; u32 first_free_ent; u32 num_ents_allocated; u32 num_ents_reserved; }; INLINE struct sim_snapshot *sim_snapshot_nil(void) { extern READONLY struct sim_snapshot **_g_sim_snapshot_nil; return *_g_sim_snapshot_nil; } struct bitbuff_writer; struct bitbuff_reader; /* Alloc */ struct sim_snapshot *sim_snapshot_alloc(struct sim_client *client, struct sim_snapshot *src, u64 tick); void sim_snapshot_release(struct sim_snapshot *sim_snapshot); void sim_snapshot_release_ticks_in_range(struct sim_client *client, u64 start, u64 end); /* Lookup */ struct sim_snapshot *sim_snapshot_from_tick(struct sim_client *client, u64 tick); struct sim_snapshot *sim_snapshot_from_closest_tick_lte(struct sim_client *client, u64 tick); struct sim_snapshot *sim_snapshot_from_closest_tick_gte(struct sim_client *client, u64 tick); /* Tile */ struct v2i32 sim_world_tile_index_from_pos(struct v2 pos); struct v2 sim_pos_from_world_tile_index(struct v2i32 world_tile_index); struct v2i32 sim_local_tile_index_from_world_tile_index(struct v2i32 world_tile_index); struct v2i32 sim_world_tile_index_from_local_tile_index(struct v2i32 tile_chunk_index, struct v2i32 local_tile_index); struct v2i32 sim_tile_chunk_index_from_world_tile_index(struct v2i32 world_tile_index); void sim_snapshot_set_tile(struct sim_snapshot *ss, struct v2i32 world_tile_index, enum sim_tile_kind tile_kind); /* Lerp */ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_client *client, struct sim_snapshot *ss0, struct sim_snapshot *ss1, f64 blend); /* Sync */ void sim_snapshot_sync_ents(struct sim_snapshot *local_ss, struct sim_snapshot *remote_ss, struct sim_ent_id remote_player, u32 sync_flags); /* Encode / decode */ void sim_snapshot_encode(struct bitbuff_writer *bw, struct sim_client *receiver, struct sim_snapshot *ss0, struct sim_snapshot *ss1); void sim_snapshot_decode(struct bitbuff_reader *br, struct sim_snapshot *ss); #endif