net layer refactor

This commit is contained in:
jacob 2025-07-30 19:59:36 -05:00
parent 08a69f4a31
commit 634c4c6a02
9 changed files with 692 additions and 512 deletions

View File

@ -238,19 +238,18 @@ void P_AppStartup(String args_str)
gp_startup();
/* Subsystems */
N_StartupReceipt host_sr = host_startup();
AC_StartupReceipt asset_cache_sr = AC_Startup();
TTF_StartupReceipt ttf_sr = ttf_startup();
F_StartupReceipt font_sr = F_Startup(&asset_cache_sr, &ttf_sr);
S_StartupReceipt sprite_sr = sprite_startup();
M_StartupReceipt mixer_sr = M_Startup();
SND_StartupReceipt sound_sr = sound_startup(&asset_cache_sr);
D_StartupReceipt draw_sr = D_Startup(&font_sr);
SimStartupReceipt sim_sr = sim_startup();
AC_StartupReceipt asset_cache_sr = AC_Startup();
TTF_StartupReceipt ttf_sr = ttf_startup();
F_StartupReceipt font_sr = F_Startup(&asset_cache_sr, &ttf_sr);
S_StartupReceipt sprite_sr = sprite_startup();
M_StartupReceipt mixer_sr = M_Startup();
SND_StartupReceipt sound_sr = sound_startup(&asset_cache_sr);
D_StartupReceipt draw_sr = D_Startup(&font_sr);
SimStartupReceipt sim_sr = sim_startup();
/* Interface systems */
PB_StartupReceipt playback_sr = playback_startup(&mixer_sr);
struct user_startup_receipt user_sr = user_startup(&font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &host_sr, &sim_sr, connect_address);
PB_StartupReceipt playback_sr = playback_startup(&mixer_sr);
struct user_startup_receipt user_sr = user_startup(&font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &sim_sr, connect_address);
(UNUSED)user_sr;
(UNUSED)playback_sr;

View File

@ -92,7 +92,7 @@ typedef i32 G_TextureFormat; enum
typedef i32 G_TextureFlag; enum
{
GP_TEXTURE_FLAG_NONE = (0),
GP_TEXTURE_FLAG_NONE = 0,
GP_TEXTURE_FLAG_TARGETABLE = (1 << 0)
};

View File

@ -3,8 +3,8 @@
typedef u32 M_TrackFlag; enum
{
M_TrackFlag_None = (0),
M_TrackFlag_Spatialize = (1 << 0)
M_TrackFlag_None = 0,
M_TrackFlag_Spatialize = (1 << 0)
};
Struct(M_Handle)

View File

@ -1,9 +1,9 @@
////////////////////////////////
//~ Mp3 structs
//~ Mp3 types
typedef u32 MP3_DecodeFlag; enum
{
MP3_DecodeFlag_None = (0),
MP3_DecodeFlag_None = 0,
MP3_DecodeFlag_Stereo = (1 << 0),
};

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +1,33 @@
#define HOST_CHANNEL_ID_NIL (N_ChannelId) { .gen = 0, .idx = 0 }
#define HOST_CHANNEL_ID_ALL (N_ChannelId) { .gen = U32Max, .idx = U32Max }
////////////////////////////////
//~ Channel ID
#define N_PacketMagic 0xd9e3b8b6
#define N_MaxPacketChunkLen 1024
#define N_MaxPacketLen 1280 /* Give enough space for msg chunk + header */
#define N_NumChannelLookupBins 512
#define N_NumMsgAssemblerLookupBins 16384
typedef i32 N_CmdKind; enum {
HOST_CMD_KIND_NONE,
HOST_CMD_KIND_TRY_CONNECT,
HOST_CMD_KIND_CONNECT_SUCCESS,
HOST_CMD_KIND_DISCONNECT,
HOST_CMD_KIND_HEARTBEAT,
HOST_CMD_KIND_WRITE
};
typedef i32 N_EventKind; enum {
HOST_EVENT_KIND_NONE,
HOST_EVENT_KIND_CHANNEL_OPENED,
HOST_EVENT_KIND_CHANNEL_CLOSED,
HOST_EVENT_KIND_MSG
};
typedef i32 N_WriteFlag; enum {
HOST_WRITE_FLAG_NONE = 0,
HOST_WRITE_FLAG_RELIABLE = (1 << 0)
};
Struct(N_ChannelId) {
Struct(N_ChannelId)
{
u32 gen;
u32 idx;
};
Struct(N_Cmd) {
////////////////////////////////
//~ Host command types
typedef i32 N_CmdKind; enum
{
N_CmdKind_None,
N_CmdKind_TryConnect,
N_CmdKind_ConnectSuccess,
N_CmdKind_Disconnect,
N_CmdKind_Heartbeat,
N_CmdKind_Write
};
typedef i32 N_WriteFlag; enum
{
N_WriteFlag_None = 0,
N_WriteFlag_Reliable = (1 << 0)
};
Struct(N_Cmd)
{
N_CmdKind kind;
N_ChannelId channel_id;
@ -47,11 +37,22 @@ Struct(N_Cmd) {
b32 write_reliable;
String write_msg;
N_Cmd *next;
};
Struct(N_Event) {
////////////////////////////////
//~ Event types
typedef i32 N_EventKind; enum
{
N_EventKind_None,
N_EventKind_ChannelOpened,
N_EventKind_ChannelClosed,
N_EventKind_Msg
};
Struct(N_Event)
{
N_EventKind kind;
N_ChannelId channel_id;
String msg;
@ -59,23 +60,43 @@ Struct(N_Event) {
N_Event *next;
};
Struct(N_EventList) {
Struct(N_EventList)
{
N_Event *first;
N_Event *last;
};
Struct(N_ChannelLookupBin) {
struct host_channel *first;
struct host_channel *last;
Struct(N_ChannelLookupBin)
{
struct N_Channel *first;
struct N_Channel *last;
};
Struct(N_RcvBuffer) {
Arena *arena;
struct host_rcv_packet *first_packet;
struct host_rcv_packet *last_packet;
////////////////////////////////
//~ Packet types
#define N_PacketMagic 0xd9e3b8b6
#define N_MaxPacketChunkLen 1024
#define N_MaxPacketLen 1280 /* Give enough space for msg chunk + header */
typedef i32 N_PacketKind; enum
{
N_PacketKind_None,
N_PacketKind_TryConnect,
N_PacketKind_ConnectSuccess,
N_PacketKind_Disconnect,
N_PacketKind_Heartbeat,
N_PacketKind_MsgChunk
};
Struct(N_SndPacket) {
typedef i32 N_PacketFlag; enum
{
N_PacketFlag_None = 0,
N_PacketFlag_Reliable = (1 << 0)
};
Struct(N_SndPacket)
{
N_SndPacket *next;
u64 seq;
@ -83,7 +104,122 @@ Struct(N_SndPacket) {
u8 data[N_MaxPacketLen];
};
Struct(N_Host) {
Struct(N_RcvPacket)
{
P_Sock *sock;
P_Address address;
String data;
N_RcvPacket *next;
};
Struct(N_RcvBuffer)
{
Arena *arena;
N_RcvPacket *first_packet;
N_RcvPacket *last_packet;
};
////////////////////////////////
//~ Channel types
Struct(N_Channel)
{
N_ChannelId id;
b32 valid;
b32 connected;
struct N_Host *host;
N_Channel *next_free;
P_Address address;
u64 address_hash;
N_Channel *next_address_hash;
N_Channel *prev_address_hash;
/* NOTE: Packets are allocated in host's `arena` */
N_SndPacket *first_reliable_packet;
N_SndPacket *last_reliable_packet;
N_SndPacket *first_unreliable_packet;
N_SndPacket *last_unreliable_packet;
u64 num_reliable_packets;
u64 num_unreliable_packets;
/* NOTE: Msg assemblers are allocated in host's `arena` */
struct N_MsgAssembler *least_recent_msg_assembler;
struct N_MsgAssembler *most_recent_msg_assembler;
u16 last_heartbeat_received_id;
u16 last_heartbeat_acked_id;
i64 last_heartbeat_acked_ns;
i64 last_heartbeat_rtt_ns;
u64 last_sent_msg_id;
u64 their_acked_seq;
u64 our_acked_seq;
u64 last_sent_seq;
i64 last_packet_received_ns;
};
Struct(N_ChannelNode)
{
N_Channel *channel;
N_ChannelNode *next;
};
Struct(N_ChannelList)
{
N_ChannelNode *first;
N_ChannelNode *last;
};
////////////////////////////////
//~ Message asssembler types
Struct(N_MsgAssembler)
{
N_Channel *channel;
b32 is_reliable;
/* Free list */
N_MsgAssembler *next_free;
/* Bucket list */
N_MsgAssembler *next_hash;
N_MsgAssembler *prev_hash;
/* Channel list */
N_MsgAssembler *less_recent;
N_MsgAssembler *more_recent;
u64 msg_id;
u64 hash;
u64 last_chunk_len;
u64 num_chunks_total;
u64 num_chunks_received;
i64 touched_ns;
BuddyBlock *buddy_block;
u8 *chunk_bitmap;
u8 *chunk_data;
};
Struct(N_MsgAssemblerLookupBin)
{
N_MsgAssembler *first;
N_MsgAssembler *last;
};
////////////////////////////////
//~ Host types
#define N_NumChannelLookupBins 512
#define N_NumMsgAssemblerLookupBins 16384
Struct(N_Host)
{
Arena *arena;
P_Sock *sock;
@ -96,17 +232,17 @@ Struct(N_Host) {
N_Cmd *first_free_cmd;
Arena *channel_arena;
struct host_channel *channels;
struct host_channel *first_free_channel;
N_Channel *channels;
N_Channel *first_free_channel;
u64 num_channels_reserved;
N_SndPacket *first_free_packet; /* Allocated in `arena` */
struct host_msg_assembler *first_free_msg_assembler; /* Allocated in `arena` */
N_SndPacket *first_free_packet; /* Allocated in `arena` */
N_MsgAssembler *first_free_msg_assembler; /* Allocated in `arena` */
N_ChannelLookupBin *channel_lookup_bins; /* Allocated in `arena` */
N_ChannelLookupBin *channel_lookup_bins; /* Allocated in `arena` */
u64 num_channel_lookup_bins;
struct host_msg_assembler_lookup_bin *msg_assembler_lookup_bins; /* Allocated in `arena` */
N_MsgAssemblerLookupBin *msg_assembler_lookup_bins; /* Allocated in `arena` */
u64 num_msg_assembler_lookup_bins;
/* Double buffer for incoming data */
@ -118,42 +254,65 @@ Struct(N_Host) {
u64 bytes_sent;
};
/* ========================== *
* Startup
* ========================== */
////////////////////////////////
//~ Nil constants
Struct(N_StartupReceipt) { i32 _; };
N_StartupReceipt host_startup(void);
Readonly Global N_Channel N_nil_channel = { .valid = 0 };
/* ========================== *
* Host
* ========================== */
////////////////////////////////
//~ Host initialization
N_Host *host_alloc(u16 listen_port);
N_Host *N_AllocHost(u16 listen_port);
void N_ReleaseHost(N_Host *host);
void host_release(N_Host *host);
////////////////////////////////
//~ Channel operations
/* ========================== *
* Queue
* ========================== */
#define N_NilChannelId (N_ChannelId) { .gen = 0, .idx = 0 }
#define N_AllChannelsId (N_ChannelId) { .gen = U32Max, .idx = U32Max }
void host_queue_connect_to_address(N_Host *host, P_Address connect_address);
#define N_EqChannelId(a, b) ((a).gen == (b).gen && (a).idx == (b).idx)
#define N_IsChannelIdNil(v) ((v).gen == 0 && (v).idx == 0)
void host_queue_disconnect(N_Host *host, N_ChannelId channel_id);
u64 N_HashFromAddress(P_Address address);
N_Channel *N_ChannelFromAddress(N_Host *host, P_Address address);
N_Channel *N_ChannelFromId(N_Host *host, N_ChannelId channel_id);
N_ChannelList N_ChannelsFromId(Arena *arena, N_Host *host, N_ChannelId channel_id);
N_Channel *N_AllocChannel(N_Host *host, P_Address address);
void N_ReleaseChannel(N_Channel *channel);
void host_queue_write(N_Host *host, N_ChannelId channel_id, String msg, u32 flags);
////////////////////////////////
//~ Message assembler operations
/* ========================== *
* Info
* ========================== */
u64 N_HashFromMsg(N_ChannelId channel_id, u64 msg_id);
N_MsgAssembler *N_MsgAssemblerFromMsg(N_Host *host, N_ChannelId channel_id, u64 msg_id);
N_MsgAssembler *N_AllocMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_count, u64 now_ns, b32 is_reliable);
void N_ReleaseMessageAssembler(N_MsgAssembler *ma);
void N_TouchMessageAssembler(N_MsgAssembler *ma, i64 now_ns);
b32 N_IsChunkFilled(N_MsgAssembler *ma, u64 chunk_id);
void N_MarkChunkReceived(N_MsgAssembler *ma, u64 chunk_id);
i64 host_get_channel_last_rtt_ns(N_Host *host, N_ChannelId channel_id);
Inline b32 host_channel_id_eq(N_ChannelId a, N_ChannelId b) { return a.idx == b.idx && a.gen == b.gen; }
Inline b32 host_channel_id_is_nil(N_ChannelId id) { return id.gen == 0 && id.idx == 0; }
////////////////////////////////
//~ Packet operations
/* ========================== *
* Update
* ========================== */
N_SndPacket *N_PushSndPacket(N_Channel *channel, b32 is_reliable);
N_EventList host_update_begin(Arena *arena, N_Host *host);
void host_update_end(N_Host *host);
////////////////////////////////
//~ Host command operations
N_Cmd *N_PushCmd(N_Host *host);
void N_Connect(N_Host *host, P_Address connect_address);
void N_Disconnect(N_Host *host, N_ChannelId channel_id);
void N_Write(N_Host *host, N_ChannelId channel_id, String msg, N_WriteFlag flags);
////////////////////////////////
//~ Channel info operations
i64 N_GetChannelLastRttNs(N_Host *host, N_ChannelId channel_id);
////////////////////////////////
//~ Update
N_Event *N_PushEvent(Arena *arena, N_EventList *list);
N_EventList N_BeginUpdate(Arena *arena, N_Host *host);
void N_EndUpdate(N_Host *host);

View File

@ -171,7 +171,7 @@ void sim_client_release(Client *client)
}
/* Remove from channel lookup */
sim_client_set_channel_id(client, HOST_CHANNEL_ID_NIL);
sim_client_set_channel_id(client, N_NilChannelId);
/* Release client */
ClientStore *store = client->store;
@ -198,7 +198,7 @@ void sim_client_set_channel_id(Client *client, N_ChannelId channel_id)
N_ChannelId old_channel_id = client->channel_id;
/* Remove old channel id from channel lookup */
if (!host_channel_id_is_nil(old_channel_id)) {
if (!N_IsChannelIdNil(old_channel_id)) {
u64 bin_index = client->channel_hash % store->num_client_lookup_bins;
ClientLookupBin *bin = &store->client_lookup_bins[bin_index];
Client *prev = sim_client_from_handle(store, client->prev_in_bin);
@ -220,7 +220,7 @@ void sim_client_set_channel_id(Client *client, N_ChannelId channel_id)
u64 channel_hash = hash_from_channel_id(channel_id);
client->channel_id = channel_id;
client->channel_hash = channel_hash;
if (!host_channel_id_is_nil(channel_id)) {
if (!N_IsChannelIdNil(channel_id)) {
u64 bin_index = channel_hash % store->num_client_lookup_bins;
ClientLookupBin *bin = &store->client_lookup_bins[bin_index];
{

View File

@ -184,7 +184,6 @@ struct user_startup_receipt user_startup(F_StartupReceipt *font_sr,
AC_StartupReceipt *asset_cache_sr,
SND_StartupReceipt *sound_sr,
M_StartupReceipt *mixer_sr,
N_StartupReceipt *host_sr,
SimStartupReceipt *sim_sr,
String connect_address_str)
{
@ -195,7 +194,6 @@ struct user_startup_receipt user_startup(F_StartupReceipt *font_sr,
(UNUSED)asset_cache_sr;
(UNUSED)sound_sr;
(UNUSED)mixer_sr;
(UNUSED)host_sr;
(UNUSED)sim_sr;
SetGstat(GSTAT_DEBUG_STEPS, U64Max);
@ -2186,7 +2184,7 @@ internal P_JobDef(local_sim_job, _)
#if 0
struct host_listen_address local_listen_addr = host_listen_address_from_local_name(Lit("LOCAL_SIM"));
struct host_listen_address net_listen_addr = host_listen_address_from_net_port(12345);
//N_Host *host = host_alloc();
//N_Host *host = N_AllocHost();
/* TODO: Host system should allocate & copy string stored in local_listen_addr */
//host_listen(host, local_listen_addr);
//host_listen(host, net_listen_addr);
@ -2195,11 +2193,11 @@ internal P_JobDef(local_sim_job, _)
b32 is_master = 0;
N_Host *host;
if (G.connect_address_str.len > 0) {
host = host_alloc(0);
host = N_AllocHost(0);
P_Address addr = P_AddressFromString(G.connect_address_str);
host_queue_connect_to_address(host, addr);
N_Connect(host, addr);
} else {
host = host_alloc(12345);
host = N_AllocHost(12345);
is_master = 1;
}
@ -2268,7 +2266,7 @@ internal P_JobDef(local_sim_job, _)
real_dt_ns = P_TimeNs() - real_time_ns;
real_time_ns += real_dt_ns;
N_EventList host_events = host_update_begin(scratch.arena, host);
N_EventList host_events = N_BeginUpdate(scratch.arena, host);
/* Read net messages */
struct sim_decode_queue queue = ZI;
@ -2277,7 +2275,7 @@ internal P_JobDef(local_sim_job, _)
N_ChannelId channel_id = event->channel_id;
Client *client = sim_client_from_channel_id(store, channel_id);
switch (event->kind) {
case HOST_EVENT_KIND_CHANNEL_OPENED:
case N_EventKind_ChannelOpened:
{
if (!client->valid) {
if (is_master) {
@ -2299,7 +2297,7 @@ internal P_JobDef(local_sim_job, _)
}
} break;
case HOST_EVENT_KIND_MSG:
case N_EventKind_Msg:
{
if (client->valid) {
BB_Buff msg_bb = BitbuffFromString(event->msg);
@ -2442,7 +2440,7 @@ internal P_JobDef(local_sim_job, _)
for (u64 i = 0; i < store->num_clients_reserved; ++i) {
Client *client = &store->clients[i];
if (client->valid && client != local_client && client != publish_client && client != user_input_client && client != master_client) {
client->last_rtt_ns = host_get_channel_last_rtt_ns(host, client->channel_id);
client->last_rtt_ns = N_GetChannelLastRttNs(host, client->channel_id);
/* Release unneeded received snapshots */
/* TDOO: Cap how many client snapshots we're willing to retain */
if (client->double_ack > 0) {
@ -2741,7 +2739,7 @@ internal P_JobDef(local_sim_job, _)
String encoded = ZI;
encoded.len = BB_GetNumBytesWritten(&msg_bw);
encoded.text = BB_GetWrittenRaw(&msg_bw);
host_queue_write(host, client->channel_id, encoded, 0);
N_Write(host, client->channel_id, encoded, 0);
}
}
@ -2767,7 +2765,7 @@ internal P_JobDef(local_sim_job, _)
skip_step:
/* Send host messages */
host_update_end(host);
N_EndUpdate(host);
__profframe("Local sim");
EndScratch(scratch);
@ -2778,5 +2776,5 @@ skip_step:
sim_accel_release(&accel);
ReleaseBitbuff(&snapshot_writer_bb);
ReleaseBitbuff(&msg_writer_bb);
host_release(host);
N_ReleaseHost(host);
}

View File

@ -54,6 +54,5 @@ struct user_startup_receipt user_startup(F_StartupReceipt *font_sr,
AC_StartupReceipt *asset_cache_sr,
SND_StartupReceipt *sound_sr,
M_StartupReceipt *mixer_sr,
N_StartupReceipt *host_sr,
SimStartupReceipt *sim_sr,
String connect_address_str);