diff --git a/src/app.c b/src/app.c index 50dcdd21..d6615dd0 100644 --- a/src/app.c +++ b/src/app.c @@ -23,6 +23,7 @@ #include "phys.h" #include "rng.h" #include "sock.h" +#include "host.h" struct exit_callback { app_exit_callback_func *func; @@ -123,45 +124,6 @@ void app_register_exit_callback(app_exit_callback_func *func) * Entry point * ========================== */ - - - - - - - - -INTERNAL SOCK_RECEIVE_CALLBACK_FUNC_DEF(server_recv, address, msg) -{ - (UNUSED)address; - (UNUSED)msg; - DEBUGBREAKABLE; -} - -INTERNAL SOCK_RECEIVE_CALLBACK_FUNC_DEF(client_recv, address, msg) -{ - (UNUSED)address; - (UNUSED)msg; - DEBUGBREAKABLE; -} - - - - - - - - - - - - - - - - - - void app_entry_point(void) { struct temp_arena scratch = scratch_begin_no_conflict(); diff --git a/src/client.c b/src/client.c index a1e9daf7..026c30d6 100644 --- a/src/client.c +++ b/src/client.c @@ -1,5 +1,7 @@ #include "client.h" #include "host.h" +#include "arena.h" +#include "util.h" #define CHANNEL_LOOKUP_BUCKETS 4096 @@ -19,12 +21,12 @@ READONLY struct client_store _g_client_store_nil = { .valid = false }; struct client_store *client_store_alloc(void) { - struct arena arena = ARENA_ALLOC(GIGABYTE(64)); + struct arena arena = arena_alloc(GIGABYTE(64)); struct client_store *store = arena_push_zero(&arena, struct client_store); store->arena = arena; store->num_channel_lookup_buckets = CHANNEL_LOOKUP_BUCKETS; store->channel_lookup_buckets = arena_push_array_zero(&arena, struct channel_lookup_bucket, store->num_channel_lookup_buckets); - store->clients = arena_dry_push(store, struct client); + store->clients = arena_dry_push(&arena, struct client); return store; } @@ -49,6 +51,11 @@ struct client_store *client_store_from_client(struct client *client) * Client * ========================== */ +INTERNAL u64 hash_from_channel_id(struct host_channel_id channel_id) +{ + return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&channel_id)); +} + struct client *client_from_handle(struct client_store *store, struct client_handle handle) { if (handle.gen != 0 && handle.idx < store->clients_reserved) { @@ -65,7 +72,7 @@ struct client *client_from_channel_id(struct client_store *store, struct host_ch struct client *res = client_nil(); u64 channel_hash = hash_from_channel_id(channel_id); u64 bucket_index = channel_hash % store->num_channel_lookup_buckets; - struct channel_lookup_bucket *bucket = &store->channel_lookup_buckets[index]; + struct channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; for (struct client *client = bucket->first; client; client = client->next_hash) { if (client->channel_hash == channel_hash) { res = client; @@ -75,7 +82,7 @@ struct client *client_from_channel_id(struct client_store *store, struct host_ch return res; } -struct client client_alloc(struct client_store *store, struct host_channel_id channel_id) +struct client *client_alloc(struct client_store *store, struct host_channel_id channel_id) { struct client *client = NULL; struct client_handle handle = ZI; @@ -90,7 +97,7 @@ struct client client_alloc(struct client_store *store, struct host_channel_id ch handle.idx = store->clients_reserved; ++store->clients_reserved; } - client = _g_client_nil; + *client = _g_client_nil; client->valid = true; client->handle = handle; @@ -100,7 +107,7 @@ struct client client_alloc(struct client_store *store, struct host_channel_id ch /* Insert into channel lookup */ u64 bucket_index = channel_hash % store->num_channel_lookup_buckets; - struct channel_lookup_bucket *bucket = &store->channel_lookup_buckets[index]; + struct channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; if (bucket->last) { bucket->last->next_hash = client; client->prev_hash = bucket->last; @@ -108,6 +115,7 @@ struct client client_alloc(struct client_store *store, struct host_channel_id ch bucket->first = client; } bucket->last = client; + return client; } void client_release(struct client *client) @@ -119,9 +127,8 @@ void client_release(struct client *client) store->first_free_client = client; /* Remove from channel lookup */ - u64 channel_hash = hash_from_channel_id(channel_id); - u64 bucket_index = channel_hash % store->num_channel_lookup_buckets; - struct channel_lookup_bucket *bucket = &store->channel_lookup_buckets[index]; + u64 bucket_index = client->channel_hash % store->num_channel_lookup_buckets; + struct channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; struct client *prev = client->prev_hash; struct client *next = client->next_hash; if (prev) { diff --git a/src/client.h b/src/client.h index 1a54aa71..a38cb952 100644 --- a/src/client.h +++ b/src/client.h @@ -9,7 +9,11 @@ struct client_handle { struct client { b32 valid; + struct client_handle handle; + struct host_channel_id channel_id; + u64 channel_hash; + struct client *next_free; struct client *next_hash; struct client *prev_hash; @@ -23,12 +27,14 @@ struct channel_lookup_bucket { }; struct client_store { + b32 valid; struct arena arena; - struct channel_lookup_bucket channel_lookup_buckets; + struct channel_lookup_bucket *channel_lookup_buckets; u64 num_channel_lookup_buckets; struct client *clients; + struct client *first_free_client; u64 clients_reserved; }; @@ -38,7 +44,7 @@ INLINE struct client *client_nil(void) return &_g_client_nil; } -INLINE struct client *client_store_nil(void) +INLINE struct client_store *client_store_nil(void) { extern READONLY struct client_store _g_client_store_nil; return &_g_client_store_nil; @@ -49,7 +55,7 @@ void client_store_release(struct client_store *store); struct client_store *client_store_from_client(struct client *client); struct client *client_from_handle(struct client_store *store, struct client_handle handle); struct client *client_from_channel_id(struct client_store *store, struct host_channel_id channel_id); -struct client client_alloc(struct client_store *store, struct host_channel_id channel_id); +struct client *client_alloc(struct client_store *store, struct host_channel_id channel_id); void client_release(struct client *client); #endif diff --git a/src/common.h b/src/common.h index 66f6570e..11edc3a3 100644 --- a/src/common.h +++ b/src/common.h @@ -506,6 +506,11 @@ struct space_entry_handle { u64 gen; }; +struct host_channel_id { + u32 gen; + u32 idx; +}; + /* ========================== * * Tag structs * ========================== */ diff --git a/src/entity.h b/src/entity.h index 623ebfca..51d5f2a0 100644 --- a/src/entity.h +++ b/src/entity.h @@ -4,6 +4,7 @@ #include "sprite.h" #include "mixer.h" #include "phys.h" +#include "client.h" enum entity_prop { ENTITY_PROP_NONE, @@ -154,6 +155,12 @@ struct entity { /* ENTITY_PROP_MOUSE_JOINT */ struct phys_mouse_joint mouse_joint_data; + /* ====================================================================== */ + /* Player */ + + /* ENTITY_PROP_PLAYER_CONTROLLED */ + struct client_handle controlling_client; + /* ====================================================================== */ /* Control */ diff --git a/src/game.c b/src/game.c index f9bdf78e..e0b096f4 100644 --- a/src/game.c +++ b/src/game.c @@ -16,6 +16,7 @@ #include "space.h" #include "byteio.h" #include "client.h" +#include "host.h" GLOBAL struct { struct atomic_i32 game_thread_shutdown; @@ -68,14 +69,10 @@ struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr, (UNUSED)phys_sr; (UNUSED)host_sr; - /* Initialize game input storage */ - G.game_input_mutex = sys_mutex_alloc(); - G.game_input_arena = arena_alloc(GIGABYTE(64)); - G.client_store = client_store_alloc(); /* Intialize host */ - struct host_address_desc bind_address = HOST_ADDRESS_ALL_LOCAL_INTERFACES(12345); + struct sock_address bind_address = sock_address_from_any_local_interface_with_port(12345); G.host = host_alloc(bind_address); /* Initialize empty world */ @@ -119,7 +116,6 @@ INTERNAL void reset_world(void) /* Re-create world */ world_alloc(&G.tick); - G.tick.continuity_gen = atomic_u64_eval(&G.prev_tick_continuity_gen) + 1; G.tick.timescale = GAME_TIMESCALE; } @@ -437,7 +433,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array) * Update * ========================== */ -INTERNAL void game_update() +INTERNAL void game_update(void) { __prof; @@ -535,7 +531,7 @@ INTERNAL void game_update() struct game_cmd_list game_cmds = ZI; { - struct host_event_array host_events = host_events_pop(scratch.arena, G.host); + struct host_event_array host_events = host_pop_events(scratch.arena, &G.host); game_cmds_from_host_events(scratch.arena, host_events, &game_cmds); } @@ -545,10 +541,10 @@ INTERNAL void game_update() for (struct game_cmd *cmd = game_cmds.first; cmd; cmd = cmd->next) { enum game_cmd_kind kind = cmd->kind; - struct host_channel_id channel_id = cmd->client_channel_id; + struct host_channel_id channel_id = cmd->channel_id; - struct client *client = client_from_channel_id(channel_id); - if (client->valid || channel_id == HOST_CHANNEL_ID_NIL) { + struct client *client = client_from_channel_id(G.client_store, channel_id); + if (client->valid || host_channel_id_is_nil(channel_id)) { switch (kind) { /* Cursor */ case GAME_CMD_KIND_CURSOR_MOVE: @@ -573,9 +569,9 @@ INTERNAL void game_update() case GAME_CMD_KIND_CLIENT_DISCONNECT: { if (client->valid) { - struct entity *client_ent = entity_from_handle(client->ent); + struct entity *client_ent = entity_from_handle(entity_store, client->ent); if (client_ent->valid) { - entity_disable_prop(client_ent, ENTITY_PROP_CLIENT_CONTROLLED); + entity_disable_prop(client_ent, ENTITY_PROP_PLAYER_CONTROLLED); entity_enable_prop(client_ent, ENTITY_PROP_RELEASE_NEXT_TICK); host_queue_disconnect(&G.host, channel_id); } @@ -585,12 +581,12 @@ INTERNAL void game_update() default: break; }; - } else if (kind == GAME_CMD_KIND_CLIENT_CONNECT && channel_id != HOST_CHANNEL_ID_NIL && !client->valid) { + } else if (kind == GAME_CMD_KIND_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id) && !client->valid) { /* Connect client */ - struct client *client = client_alloc(G.client_store, channel_id); - struct client_ent *client_ent = entity_alloc(root); - entity_enable_prop(client_ent, ENTITY_PROP_CLIENT_CONTROLLED); - client_ent->client_handle = client->handle; + client = client_alloc(G.client_store, channel_id); + struct entity *client_ent = entity_alloc(root); + entity_enable_prop(client_ent, ENTITY_PROP_PLAYER_CONTROLLED); + client_ent->controlling_client = client->handle; } } @@ -1322,19 +1318,21 @@ INTERNAL void game_update() struct temp_arena temp = arena_temp_begin(scratch.arena); /* TODO: Not like this */ - struct game_event_desc snapshot_ed = ZI; - snapshot_ed.kind = GAME_EVENT_KIND_SNAPSHOT_FULL; - snapshot_ed.data = game_string_from_tick(&G.tick); + struct game_event snapshot_event = ZI; + snapshot_event.kind = GAME_EVENT_KIND_SNAPSHOT_FULL; + snapshot_event.snapshot_data = game_string_from_tick(temp.arena, &G.tick); - struct host_msg_desc msg = ZI; - msg.channel = HOST_CHANNEL_ALL; - msg.data = snapshot; - host_queue_write(G.host, msg); + struct game_event_list l = ZI; + l.first = &snapshot_event; + l.last = &snapshot_event; + struct string msg = game_string_from_events(temp.arena, l); - temp_arena_end(temp); + host_queue_write(&G.host, HOST_CHANNEL_ID_ALL, msg); + + arena_temp_end(temp); } - host_update(G.host); + host_update(&G.host); __profframe("Game"); /* ========================== * @@ -1354,7 +1352,7 @@ struct string game_string_from_cmds(struct arena *arena, struct game_cmd_list cm { struct byte_writer bw = bw_from_arena(arena); - for (struct game_cmd *cmd = cmds->first; cmd; cmd = cmd->next) { + for (struct game_cmd *cmd = cmds.first; cmd; cmd = cmd->next) { struct byte_writer bw_size = bw_branch(&bw, sizeof(u64)); u64 start = bw_pos(&bw); @@ -1387,11 +1385,11 @@ struct string game_string_from_cmds(struct arena *arena, struct game_cmd_list cm return bw_get_written(&bw); } -void game_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_cmd *cmds_out) +void game_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_cmd_list *cmds_out) { for (u64 i = 0; i < host_events.count; ++i) { struct game_cmd *cmd = arena_push_zero(arena, struct game_cmd); - struct host_channel_event host_event = host_events.events[i]; + struct host_event host_event = host_events.events[i]; enum host_event_kind host_event_kind = host_event.kind; cmd->channel_id = host_event.channel_id; switch (host_event_kind) { @@ -1408,7 +1406,7 @@ void game_cmds_from_host_events(struct arena *arena, struct host_event_array hos case HOST_EVENT_KIND_MSG: { - struct byte_reader br = br_from_buffer(event.msg); + struct byte_reader br = br_from_buffer(host_event.msg); while (br_bytes_left(&br) > 0) { u64 cmd_size = br_read_u64(&br); u64 cmd_pos_end = br_pos(&br) + cmd_size; @@ -1459,11 +1457,11 @@ void game_cmds_from_host_events(struct arena *arena, struct host_event_array hos struct string game_string_from_events(struct arena *arena, struct game_event_list events) { struct byte_writer bw = bw_from_arena(arena); - for (struct game_cmd *cmd = cmds->first; cmd; cmd = cmd->next) { + for (struct game_event *event = events.first; event; event = event->next) { struct byte_writer bw_size = bw_branch(&bw, sizeof(u64)); u64 start = bw_pos(&bw); - switch (cmd->kind) { + switch (event->kind) { case GAME_EVENT_KIND_SNAPSHOT_FULL: { } break; @@ -1477,34 +1475,34 @@ struct string game_string_from_events(struct arena *arena, struct game_event_lis return bw_get_written(&bw); } -void game_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_event *events_out) +void game_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_event_list *events_out) { for (u64 i = 0; i < host_events.count; ++i) { - struct game_event *event = arena_push_zero(arena, struct game_event); - struct host_channel_event host_event = host_events.events[i]; + struct game_event *game_event = arena_push_zero(arena, struct game_event); + struct host_event host_event = host_events.events[i]; enum host_event_kind host_event_kind = host_event.kind; - event->channel_id = host_event.channel_id; + game_event->channel_id = host_event.channel_id; switch (host_event_kind) { case HOST_EVENT_KIND_CHANNEL_OPENED: { - event->kind = GAME_EVENT_KIND_CONNECT; + game_event->kind = GAME_EVENT_KIND_CONNECT; } break; case HOST_EVENT_KIND_CHANNEL_CLOSED: { - event->kind = GAME_EVENT_KIND_DISCONNECT; - event->disconnect_reason = LIT("Connection lost"); + game_event->kind = GAME_EVENT_KIND_DISCONNECT; + game_event->disconnect_reason = LIT("Connection lost"); } break; case HOST_EVENT_KIND_MSG: { - struct byte_reader br = br_from_buffer(event.msg); + struct byte_reader br = br_from_buffer(host_event.msg); while (br_bytes_left(&br) > 0) { u64 event_size = br_read_u64(&br); u64 event_pos_end = br_pos(&br) + event_size; - event->kind = br_read_i8(&br); - switch (event->kind) { + game_event->kind = br_read_i8(&br); + switch (game_event->kind) { case GAME_EVENT_KIND_SNAPSHOT_FULL: { } break; @@ -1521,14 +1519,33 @@ void game_events_from_host_events(struct arena *arena, struct host_event_array h } if (events_out->last) { - events_out->last->next = cmd; + events_out->last->next = game_event; } else { - events_out->first = cmd; + events_out->first = game_event; } - events_out->last = cmd; + events_out->last = game_event; } } +/* ========================== * + * Snapshot + * ========================== */ + +struct string game_string_from_tick(struct arena *arena, struct world *tick) +{ + (UNUSED)arena; + (UNUSED)tick; + + struct string res = ZI; + return res; +} + +void game_tick_from_string(struct string str, struct world *tick_out) +{ + (UNUSED)str; + (UNUSED)tick_out; +} + /* ========================== * * Game thread * ========================== */ @@ -1536,8 +1553,6 @@ void game_events_from_host_events(struct arena *arena, struct host_event_array h INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg) { - struct temp_arena scratch = scratch_begin_no_conflict(); - (UNUSED)arg; i64 last_frame_ns = 0; i64 target_dt_ns = NS_FROM_SECONDS(GAME_FPS > (0) ? (1.0 / GAME_FPS) : 0); diff --git a/src/game.h b/src/game.h index 4eaf36b4..1099d5a7 100644 --- a/src/game.h +++ b/src/game.h @@ -1,6 +1,8 @@ #ifndef GAME_H #define GAME_H +#include "host.h" + struct world; struct mixer_startup_receipt; struct sprite_startup_receipt; @@ -84,7 +86,7 @@ struct game_cmd_list { }; struct string game_string_from_cmds(struct arena *arena, struct game_cmd_list cmds); -void game_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_cmd *cmds_out); +void game_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_cmd_list *cmds_out); /* ========================== * * Game event @@ -104,9 +106,13 @@ enum game_event_kind { struct game_event { enum game_event_kind kind; + struct host_channel_id channel_id; - struct entity_handle entity; - struct string update_data; + struct string snapshot_data; + struct string disconnect_reason; + + //struct entity_handle entity; + //struct string update_data; struct game_event *next; }; @@ -117,6 +123,13 @@ struct game_event_list { }; struct string game_string_from_events(struct arena *arena, struct game_event_list events); -void game_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_event *events_out); +void game_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct game_event_list *events_out); + +/* ========================== * + * Snapshot + * ========================== */ + +struct string game_string_from_tick(struct arena *arena, struct world *tick); +void game_tick_from_string(struct string str, struct world *tick_out); #endif diff --git a/src/host.c b/src/host.c index a4c684ed..3d42e7f5 100644 --- a/src/host.c +++ b/src/host.c @@ -2,6 +2,7 @@ #include "arena.h" #include "scratch.h" #include "byteio.h" +#include "sys.h" //#define HOST_NETWORK_ADDRESS_STRING(str) //#define HOST_NETWORK_ADDRESS_ALL_LOCAL_INTERFACES(port) @@ -10,69 +11,81 @@ #define PACKET_MAGIC 0xd9e3b8b6 #define PACKET_CHUNK_MAX_LEN 256 -GLOBAL struct { - i32 _; -} G = ZI, DEBUG_ALIAS(G, G_host); +/* Give enough space for msg chunk + header */ +#define PACKET_DATA_MAX_LEN (PACKET_CHUNK_MAX_LEN * 2) - -struct host_address_desc { - i32 _; +enum packet_kind { + PACKET_KIND_NONE, + PACKET_KIND_TRY_CONNECT, + PACKET_KIND_CONNECT_SUCCESS, + PACKET_KIND_DISCONNECT, + PACKET_KIND_MSG_CHUNK }; -struct host_channel_id { - u32 idx; - u32 gen; +enum packet_flag { + PACKET_FLAG_NONE = 0, + PACKET_FLAG_RELIABLE = (1 << 0) +}; + +struct packet { + u64 seq; + u8 flags; + u64 data_len; + u8 data[PACKET_DATA_MAX_LEN]; + + struct packet *next; }; struct host_channel { b32 valid; + b32 connected; + struct host *host; + struct host_channel_id id; + struct sock_address address; + + struct packet *first_reliable_packet; + struct packet *last_reliable_packet; + struct packet *first_unreliable_packet; + struct packet *last_unreliable_packet; + + u64 their_acked_seq; + u64 our_acked_seq; }; -enum host_cmd_kind { - HOST_CMD_KIND_NONE, - - HOST_CMD_KIND_CONNECT, - HOST_CMD_KIND_DISCONNECT, - HOST_CMD_KIND_WRITE +struct host_channel_node { + struct host_channel *channel; + struct host_channel_node *next; }; -enum host_event_kind { - HOST_EVENT_KIND_NONE, - - HOST_EVENT_KIND_CHANNEL_OPENED, - HOST_EVENT_KIND_CHANNEL_CLOSED, - HOST_EVENT_KIND_MSG +struct host_channel_list { + struct host_channel_node *first; + struct host_channel_node *last; }; -struct host_cmd { - enum host_cmd_kind kind; - struct host_cmd *next; +struct host_queued_event { + struct host_event event; + struct host_queued_event *next; }; -struct host_event { - enum host_event_kind kind; +struct recv_buffer { + u64 msg_id; + + u64 last_chunk_len; + u64 num_chunks_total; + u64 num_chunks_received; + + i64 touched_ns; + + u8 *chunks_received_bitmap; + u8 *data; }; -struct host { - struct arena cmd_arena; - struct host_cmd *first_cmd; - struct host_cmd *last_cmd; - struct host_cmd *first_free_cmd; - - struct arena channels_arena; - struct host_channel *channels; - u64 channels_reserved; -}; - - - - - - - - +READONLY GLOBAL struct host_channel _g_host_channel_nil = { .valid = false }; +GLOBAL struct { + i32 _; +} G = ZI, DEBUG_ALIAS(G, G_host); /* ========================== * * Startup @@ -86,37 +99,144 @@ struct host_startup_receipt host_startup(struct sock_startup_receipt *sock_sr) } /* ========================== * - * Allocation + * Host * ========================== */ -struct host host_alloc(struct host_address_desc bind_address) +struct host host_alloc(struct sock_address bind_address) { struct host host = ZI; host.cmd_arena = arena_alloc(GIGABYTE(64)); + host.queued_event_arena = arena_alloc(GIGABYTE(64)); + host.packet_arena = arena_alloc(GIGABYTE(64)); host.channels_arena = arena_alloc(GIGABYTE(64)); + host.sock = sock_alloc(bind_address, SOCK_FLAG_NON_BLOCKING); return host; } void host_release(struct host *host) { + sock_release(&host->sock); arena_release(&host->channels_arena); + arena_release(&host->packet_arena); + arena_release(&host->queued_event_arena); arena_release(&host->cmd_arena); } +/* ========================== * + * Channel + * ========================== */ + +INTERNAL struct host_channel *host_channel_from_address(struct host *host, struct sock_address address) +{ + (UNUSED)host; + (UNUSED)address; + + struct host_channel *res = &_g_host_channel_nil; + return res; +} + +INTERNAL struct host_channel_list host_channels_from_id(struct arena *arena, struct host *host, struct host_channel_id channel_id) +{ + (UNUSED)arena; + (UNUSED)host; + (UNUSED)channel_id; + + struct host_channel_list res = ZI; + return res; +} + +INTERNAL struct host_channel *host_channel_alloc(struct host *host, struct sock_address address) +{ + (UNUSED)host; + (UNUSED)address; + + struct host_channel *res = NULL; + return res; +} + +INTERNAL void host_channel_release(struct host_channel *channel) +{ + (UNUSED)channel; +} + +INTERNAL struct recv_buffer *host_channel_get_recv_buffer(struct host_channel *channel, u64 msg_id) +{ + (UNUSED)channel; + (UNUSED)msg_id; + + struct recv_buffer *res = NULL; + return res; +} + +/* ========================== * + * Packet + * ========================== */ + +INTERNAL struct packet *host_channel_packet_alloc(struct host_channel *channel, b32 is_reliable) +{ + struct host *host = channel->host; + struct packet *packet = NULL; + if (host->first_free_packet) { + packet = host->first_free_packet; + host->first_free_packet = packet->next; + } else { + packet = arena_push(&host->packet_arena, struct packet); + } + MEMZERO_STRUCT(packet); + + if (is_reliable) { + if (channel->last_reliable_packet) { + channel->last_reliable_packet->next = packet; + } else { + channel->first_reliable_packet = packet; + } + channel->last_reliable_packet = packet; + } else { + if (channel->last_unreliable_packet) { + channel->last_unreliable_packet->next = packet; + } else { + channel->first_unreliable_packet = packet; + } + channel->last_unreliable_packet = packet; + } + return packet; +} + +/* ========================== * + * Recv buffer + * ========================== */ + +INTERNAL struct recv_buffer *recv_buffer_alloc(struct host_channel *channel, u64 msg_id, u64 chunk_count) +{ + (UNUSED)channel; + (UNUSED)msg_id; + (UNUSED)chunk_count; + + struct recv_buffer *res = NULL; + return res; +} + +INTERNAL b32 recv_buffer_is_chunk_filled(struct recv_buffer *rb, u64 chunk_id) +{ + (UNUSED)rb; + (UNUSED)chunk_id; + + return false; +} + +INTERNAL void recv_buffer_set_chunk_received(struct recv_buffer *rb, u64 chunk_id) +{ + (UNUSED)rb; + (UNUSED)chunk_id; +} + /* ========================== * * Queue * ========================== */ INTERNAL struct host_cmd *host_cmd_alloc_and_append(struct host *host) { - struct host_cmd *cmd = NULL; - if (host->first_free_cmd) { - cmd = host->first_free_cmd; - host->first_free_cmd = cmd->next_free; - } else { - cmd = arena_push(&host->arena, struct host_cmd); - } - MEMZERO_STRUCT(cmd); + struct host_cmd *cmd = arena_push_zero(&host->cmd_arena, struct host_cmd); if (host->last_cmd) { host->last_cmd->next = cmd; } else { @@ -126,24 +246,29 @@ INTERNAL struct host_cmd *host_cmd_alloc_and_append(struct host *host) return cmd; } -void host_queue_connect_to_address(struct host *host, struct host_address_desc host_address_desc) +void host_queue_connect_to_address(struct host *host, struct sock_address connect_address) { - struct sock_address_desc sock_address_desc = sock_address_desc_from_host_address_desc(host_address_desc); - struct sock_address address = sock_address_from_desc(sock_address_desc); - struct channel *channel = channel_from_address(host, address); + struct host_channel *channel = host_channel_from_address(host, connect_address); if (!channel->valid) { - channel = channel_alloc(host, address); + channel = host_channel_alloc(host, connect_address); } } void host_queue_disconnect(struct host *host, struct host_channel_id channel_id) { + (UNUSED)host; + (UNUSED)channel_id; + struct host_cmd *cmd = host_cmd_alloc_and_append(host); cmd->kind = HOST_CMD_KIND_DISCONNECT; } void host_queue_write(struct host *host, struct host_channel_id channel_id, struct string msg) { + (UNUSED)host; + (UNUSED)channel_id; + (UNUSED)msg; + struct host_cmd *cmd = host_cmd_alloc_and_append(host); cmd->kind = HOST_CMD_KIND_WRITE; } @@ -152,111 +277,143 @@ void host_queue_write(struct host *host, struct host_channel_id channel_id, stru * Update * ========================== */ +INTERNAL struct host_queued_event *host_queued_event_alloc_and_append(struct host *host) +{ + struct host_queued_event *qe = arena_push_zero(&host->queued_event_arena, struct host_queued_event); + if (host->last_queued_event) { + host->last_queued_event->next = qe; + } else { + host->first_queued_event = qe; + } + host->last_queued_event = qe; + ++host->num_queued_events; + return qe; +} + void host_update(struct host *host) { struct temp_arena scratch = scratch_begin_no_conflict(); - struct socket *sock = &host->sock; + i64 now_ns = sys_time_ns(); + + struct sock *sock = &host->sock; struct string read_buff = ZI; - read_buff.len = KILOBYTE(64); + read_buff.len = PACKET_DATA_MAX_LEN; read_buff.text = arena_push_array(scratch.arena, u8, read_buff.len); /* Read socket */ while (true) { struct sock_read_result res = sock_read(sock, read_buff); if (res.valid) { - struct string data = res.data; + struct string sock_data = res.data; struct sock_address address = res.address; - struct byte_reader br = br_from_buffer(data); + struct byte_reader br = br_from_buffer(sock_data); u32 magic = br_read_u32(&br); if (magic == PACKET_MAGIC) { /* TODO: Combine kind byte with flags byte */ - struct host_channel *channel = host_channel_from_sock_address(host, address); + struct host_channel *channel = host_channel_from_address(host, address); enum packet_kind packet_kind = br_read_i8(&br); u8 packet_flags = br_read_u8(&br); - u64 packet_id = br_read_var_uint(&br); - u64 packet_reliable_id = 0; - if (packet_flags & PACKET_FLAG_RELIABLE) { - packet_reliable_id = br_read_var_uint(&br); + + u64 their_acked_seq = br_read_var_uint(&br); + if (their_acked_seq > channel->their_acked_seq) { + channel->their_acked_seq = their_acked_seq; } - switch (packet_kind) { - case PACKET_KIND_TRY_CONNECT: - { - /* A foreign host is trying to connect to us */ - if (!channel->valid) { - channel = channel_alloc(host, address); - } - } break; - case PACKET_KIND_CONNECT_SUCCESS: - { - /* We successfully connected to a foreign host and they are ready to receive messages */ - if (channel->valid && !channel->connected) { - struct host_queued_event *queued_event = queued_event_alloc_and_append(host); - queued_event->kind = HOST_EVENT_KIND_CHANNEL_OPENED; - queued_event->channel_id = channel->id; - channel->connected = true; - } - } break; + b32 should_process_packet = false; + if (packet_flags & PACKET_FLAG_RELIABLE) { + u64 packet_seq = br_read_var_uint(&br); + if (packet_seq == channel->our_acked_seq + 1) { + channel->our_acked_seq = packet_seq; + should_process_packet = true; + } + } else { + should_process_packet = true; + } - case PACKET_KIND_DISCONNECT: - { - /* A foreign host disconnected from us */ - if (channel->valid) { - struct host_queued_event *queued_event = queued_event_alloc_and_append(host); - queued_event->kind = HOST_EVENT_KIND_CHANNEL_CLOSED; - queued_event->channel_id = channel->id; - channel_release(channel); - } + if (should_process_packet) { + switch (packet_kind) { + case PACKET_KIND_TRY_CONNECT: + { + /* A foreign host is trying to connect to us */ + if (!channel->valid) { + /* TODO: Verify that some per-host uuid isn't + * present in a rolling window to prevent reconnects right after a disconnect? */ + channel = host_channel_alloc(host, address); + } + } break; - } break; + case PACKET_KIND_CONNECT_SUCCESS: + { + /* We successfully connected to a foreign host and they are ready to receive messages */ + if (channel->valid && !channel->connected) { + struct host_queued_event *queued_event = host_queued_event_alloc_and_append(host); + queued_event->event.kind = HOST_EVENT_KIND_CHANNEL_OPENED; + queued_event->event.channel_id = channel->id; + channel->connected = true; + } + } break; - case PACKET_KIND_MSG_CHUNK: - { - /* Packet is chunk out of belonging to message */ - u64 msg_id = br_read_var_uint(&br); - u64 chunk_id = br_read_var_uint(&br); - u64 chunk_count = br_read_var_uint(&br); - u64 data_len = ((chunk_id + 1) == chunk_count) ? br_read_u8(&br) : PACKET_CHUNK_MAX_LEN; + case PACKET_KIND_DISCONNECT: + { + /* A foreign host disconnected from us */ + if (channel->valid) { + struct host_queued_event *queued_event = host_queued_event_alloc_and_append(host); + queued_event->event.kind = HOST_EVENT_KIND_CHANNEL_CLOSED; + queued_event->event.channel_id = channel->id; + host_channel_release(channel); + } - struct msg_buffer *msg_buff = channel_get_msg_buffer(channel, msg_id); - if (!msg_buff) { - msg_buff = channel_msg_buffer_alloc(channel, chunk_count); - } + } break; - if (chunk_count == msg_buff->chunk_count && chunk_id < chunk_count) { - struct msg_chunk *chunk = &msg_buff->chunks[chunk_id]; - if (!chunk->filled) { - u8 *data = br_seek(&br, data_len); - if (data) { - MEMCPY(chunk->data, data, data_len); - chunk->data_len = data_len; - chunk->filled = true; - ++msg_buff->filled_chunks; - msg_buff->last_touch = now; - if (msg_buff->filled_chunks == chunk_count) { - /* All chunks filled, message has finished assembling */ - /* TODO: Message ordering */ - struct host_queued_event *queued_event = queued_event_alloc_and_append(host); - struct string data = ZI; - data.text = arena_push_array(&host->queued_event_arena, u8, chunk_count * PACKET_CHUNK_MAX_LEN); - for (u64 i = 0; i < chunk_count; ++i) { - struct msg_chunk *filled_chunk = &msg_buff->chunks[i]; - u64 len = filled_chunk->data_len; - MEMCPY(data.text + data.len, filled_chunk->data, len); - data.len += len; + case PACKET_KIND_MSG_CHUNK: + { + /* Packet is chunk out of belonging to message */ + u64 msg_id = br_read_var_uint(&br); + u64 chunk_id = br_read_var_uint(&br); + u64 chunk_count = br_read_var_uint(&br); + + b32 is_last_chunk = (chunk_id + 1) == chunk_count; + u64 data_len = is_last_chunk ? (br_read_u8(&br) + 1) : PACKET_CHUNK_MAX_LEN; + + struct recv_buffer *recv_buff = host_channel_get_recv_buffer(channel, msg_id); + if (!recv_buff) { + recv_buff = recv_buffer_alloc(channel, msg_id, chunk_count); + } + + if (chunk_count == recv_buff->num_chunks_total && chunk_id < chunk_count) { + if (!recv_buffer_is_chunk_filled(recv_buff, chunk_id)) { + u8 *src = br_seek(&br, data_len); + if (src) { + u8 *dst = &recv_buff->data[chunk_id * PACKET_CHUNK_MAX_LEN]; + MEMCPY(dst, src, data_len); + if (is_last_chunk) { + recv_buff->last_chunk_len = data_len; + } + recv_buffer_set_chunk_received(recv_buff, chunk_id); + ++recv_buff->num_chunks_received; + recv_buff->touched_ns = now_ns; + if (recv_buff->num_chunks_received == chunk_count) { + /* All chunks filled, message has finished assembling */ + /* TODO: Message ordering */ + struct host_queued_event *queued_event = host_queued_event_alloc_and_append(host); + struct string data = ZI; + data.len = ((chunk_count - 1) * PACKET_CHUNK_MAX_LEN) + recv_buff->last_chunk_len; + data.text = arena_push_array(&host->queued_event_arena, u8, data.len); + MEMCPY(data.text, recv_buff->data, data.len); + queued_event->event.kind = HOST_EVENT_KIND_MSG; + queued_event->event.msg = data; + queued_event->event.channel_id = channel->id; } - queued_event->kind = HOST_EVENT_KIND_MSG; - queued_event->msg_data = data; - queued_event->channel_id = channel->id; } } } - } - } break; + } break; - default: break; + default: break; + } } + } } else { break; @@ -265,66 +422,93 @@ void host_update(struct host *host) /* Release expired msg buffers */ - /* Try connecting to unconnected hosts */ - for (u64 i = 0; i < host->channels; ++i) { - struct channel *channel = &host->channels[i]; - if (channel->valid && !channel->connected) { - struct host_cmd *cmd = host_cmd_alloc_and_append(host); - cmd->kind = HOST_CMD_KIND_TRY_CONNECT; - cmd->channel_id = channel->id; + /* Update channels */ + for (u64 i = 0; i < host->channels_reserved; ++i) { + struct host_channel *channel = &host->channels[i]; + if (channel->valid) { + /* Send / resend handshake if not connected */ + if (!channel->connected) { + struct host_cmd *cmd = host_cmd_alloc_and_append(host); + cmd->kind = HOST_CMD_KIND_TRY_CONNECT; + cmd->channel_id = channel->id; + } + /* Release acked reliable packets */ + { + u64 acked_seq = channel->their_acked_seq; + struct packet *packet = channel->first_reliable_packet; + while (packet) { + struct packet *next = packet->next; + u64 seq = packet->seq; + if (seq < acked_seq) { + packet->next = host->first_free_packet; + host->first_free_packet = packet; + channel->first_reliable_packet = next; + } else { + break; + } + packet = next; + } + if (channel->first_reliable_packet == NULL) { + channel->last_reliable_packet = NULL; + } + } } } - /* Release un - /* Process cmds */ + /* TODO: Unreliable packets don't need to be allocated into unreliable packet queue, should just send them and forget */ for (struct host_cmd *cmd = host->first_cmd; cmd; cmd = cmd->next) { - struct host_channel *channel = host_channel_from_id(host, cmd->channel_id); - if (channel->valid) { - enum host_cmd_kind kind = cmd->kind; - struct sock_address address = channel->sock_address; - + struct temp_arena temp = arena_temp_begin(scratch.arena); + enum host_cmd_kind kind = cmd->kind; + struct host_channel_id channel_id = cmd->channel_id; + struct host_channel_list channels = host_channels_from_id(temp.arena, host, channel_id); + for (struct host_channel_node *node = channels.first; node; node = node->next) { + struct host_channel *channel = node->channel; switch (kind) { case HOST_CMD_KIND_TRY_CONNECT: { - struct packet *packet = host_packet_alloc(host, address, false); + u8 packet_flags = 0; + struct packet *packet = host_channel_packet_alloc(channel, false); struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(packet->data)); bw_write_i8(&bw, PACKET_KIND_TRY_CONNECT); bw_write_u8(&bw, packet_flags); - bw_write_var_uint(&bw, packet->id); - bw_write_var_uint(&bw, packet->reliable_id); + bw_write_var_uint(&bw, channel->our_acked_seq); packet->data_len = bw_pos(&bw); } break; case HOST_CMD_KIND_CONNECT_SUCCESS: { - struct packet *packet = host_packet_alloc(host, address, false); + u8 packet_flags = 0; + struct packet *packet = host_channel_packet_alloc(channel, false); struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(packet->data)); bw_write_i8(&bw, PACKET_KIND_CONNECT_SUCCESS); bw_write_u8(&bw, packet_flags); - bw_write_var_uint(&bw, packet->id); - bw_write_var_uint(&bw, packet->reliable_id); + bw_write_var_uint(&bw, channel->our_acked_seq); packet->data_len = bw_pos(&bw); } break; case HOST_CMD_KIND_DISCONNECT: { - struct packet *packet = host_packet_alloc(host, address, false); + u8 packet_flags = 0; + struct packet *packet = host_channel_packet_alloc(channel, false); struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(packet->data)); bw_write_i8(&bw, PACKET_KIND_DISCONNECT); bw_write_u8(&bw, packet_flags); - bw_write_var_uint(&bw, packet->id); + bw_write_var_uint(&bw, channel->our_acked_seq); packet->data_len = bw_pos(&bw); } break; case HOST_CMD_KIND_WRITE: { - b32 is_reliable = packet_flags & HOST_WRITE_FLAG_RELIABLE; - struct string msg = cmd->msg; + b32 is_reliable = cmd->write_reliable; + u8 packet_flags = (is_reliable * PACKET_FLAG_RELIABLE); + struct string msg = cmd->write_msg; + u64 chunk_count = 0; if (msg.len > 0) { - chunk_count = ((msg.len - 1) / PACKET_CHUNK_MAX_LEN) + 1 + chunk_count = (msg.len - 1) / PACKET_CHUNK_MAX_LEN; } + chunk_count += 1; for (u64 i = 0; i < chunk_count; ++i) { u64 data_len = PACKET_CHUNK_MAX_LEN; @@ -333,16 +517,17 @@ void host_update(struct host *host) data_len = msg.len % PACKET_CHUNK_MAX_LEN; } u8 *data = msg.text + (i * PACKET_CHUNK_MAX_LEN); - struct packet *packet = host_packet_alloc(host, address, is_reliable); + struct packet *packet = host_channel_packet_alloc(channel, is_reliable); struct byte_writer bw = bw_from_buffer(STRING_FROM_ARRAY(packet->data)); bw_write_i8(&bw, PACKET_KIND_MSG_CHUNK); bw_write_u8(&bw, packet_flags); - bw_write_var_uint(&bw, packet->id); + bw_write_var_uint(&bw, channel->our_acked_seq); if (is_reliable) { - bw_write_var_uint(&bw, packet->reliable_id); + bw_write_var_uint(&bw, packet->seq); } if (is_last_chunk) { - bw_write_u8(&bw, data_len); + /* FIXME: Ensure data_len can never be 0 */ + bw_write_u8(&bw, data_len - 1); } bw_write_buffer(&bw, STRING(data_len, data)); packet->data_len = bw_pos(&bw); @@ -352,24 +537,35 @@ void host_update(struct host *host) default: break; } } + arena_temp_end(temp); } - /* Send packets */ - for (struct packet *packet = host->first_packet; packet; packet = packet->next) { - struct sock_address address = packet->address; - sock_write(sock, address, STRING(packet->data_len, packet->data)); + /* Process packets */ + /* TODO: Aggregate small packets */ + for (u64 i = 0; i < host->channels_reserved; ++i) { + struct host_channel *channel = &host->channels[i]; + struct sock_address address = channel->address; + /* Send unreliable packets to channel */ + for (struct packet *packet = channel->first_unreliable_packet; packet; packet = packet->next) { + sock_write(sock, address, STRING(packet->data_len, packet->data)); + } + /* Send un-acked reliable packets to channel */ + for (struct packet *packet = channel->first_reliable_packet; packet; packet = packet->next) { + sock_write(sock, address, STRING(packet->data_len, packet->data)); + } + /* Release unreliable packets */ + if (channel->first_unreliable_packet) { + host->first_free_packet = channel->first_unreliable_packet; + channel->last_unreliable_packet->next = host->first_free_packet; + channel->first_unreliable_packet = NULL; + channel->last_unreliable_packet = NULL; + } } - /* Reset packets */ - host->first_packet = NULL; - host->last_packet = NULL; - host->first_free_packet = NULL; - arena_reset(&host->packet_arena); /* Reset cmds */ host->first_cmd = NULL; host->last_cmd = NULL; - host->first_free_cmd = NULL; arena_reset(&host->cmd_arena); scratch_end(scratch); @@ -388,17 +584,20 @@ struct host_event_array host_pop_events(struct arena *arena, struct host *host) u64 i = 0; for (struct host_queued_event *qe = host->first_queued_event; qe; qe = qe->next) { struct host_event *dest = &res.events[i]; - *dest = (struct host_event) { - .kind = qe->kind, - .msg = qe->msg - }; + *dest = qe->event; + struct string src_msg = qe->event.msg; + if (src_msg.len > 0) { + dest->msg.text = arena_push_array(arena, u8, src_msg.len); + MEMCPY(dest->msg.text, src_msg.text, src_msg.len); + } ++i; } /* Reset queued events */ - hust->num_queued_events = 0; + host->num_queued_events = 0; host->first_queued_event = NULL; host->last_queued_event = NULL; - host->first_free_queued_event = NULL; arena_reset(&host->queued_event_arena); + + return res; } diff --git a/src/host.h b/src/host.h index 68d4667c..e0231e67 100644 --- a/src/host.h +++ b/src/host.h @@ -1,4 +1,124 @@ #ifndef HOST_H #define HOST_H +#include "sock.h" + +#define HOST_CHANNEL_ID_NIL (struct host_channel_id) { .gen = 0, .idx = 0 } +#define HOST_CHANNEL_ID_ALL (struct host_channel_id) { .gen = U32_MAX, .idx = U32_MAX } + +struct packet; + +enum host_cmd_kind { + HOST_CMD_KIND_NONE, + + HOST_CMD_KIND_TRY_CONNECT, + HOST_CMD_KIND_CONNECT_SUCCESS, + HOST_CMD_KIND_DISCONNECT, + HOST_CMD_KIND_WRITE +}; + +enum host_event_kind { + HOST_EVENT_KIND_NONE, + + HOST_EVENT_KIND_CHANNEL_OPENED, + HOST_EVENT_KIND_CHANNEL_CLOSED, + HOST_EVENT_KIND_MSG +}; + +struct host_cmd { + enum host_cmd_kind kind; + struct host_channel_id channel_id; + + b32 write_reliable; + struct string write_msg; + + struct host_cmd *next; +}; + +struct host_event { + enum host_event_kind kind; + struct host_channel_id channel_id; + struct string msg; +}; + +struct host_event_array { + struct host_event *events; + u64 count; +}; + +struct host { + struct sock sock; + + struct arena cmd_arena; + struct host_cmd *first_cmd; + struct host_cmd *last_cmd; + struct host_cmd *first_free_cmd; + + struct arena queued_event_arena; + struct host_queued_event *first_queued_event; + struct host_queued_event *last_queued_event; + u64 num_queued_events; + + struct arena packet_arena; + struct packet *first_free_packet; + + struct arena channels_arena; + struct host_channel *channels; + u64 channels_reserved; +}; + +/* ========================== * + * Startup + * ========================== */ + +struct host_startup_receipt { i32 _; }; +struct host_startup_receipt host_startup(struct sock_startup_receipt *sock_sr); + +/* ========================== * + * Host + * ========================== */ + +struct host host_alloc(struct sock_address bind_address); + +void host_release(struct host *host); + +/* ========================== * + * Queue + * ========================== */ + +void host_queue_connect_to_address(struct host *host, struct sock_address connect_address); + +void host_queue_disconnect(struct host *host, struct host_channel_id channel_id); + +void host_queue_write(struct host *host, struct host_channel_id channel_id, struct string msg); + +/* ========================== * + * Update + * ========================== */ + +void host_update(struct host *host); + +/* ========================== * + * Events + * ========================== */ + +struct host_event_array host_pop_events(struct arena *arena, struct host *host); + + + + + + + + + + + +INLINE b32 host_channel_id_is_nil(struct host_channel_id id) +{ + return id.gen == 0 && id.idx == 0; +} + + + #endif diff --git a/src/sock.h b/src/sock.h index 538960e4..219e5876 100644 --- a/src/sock.h +++ b/src/sock.h @@ -1,6 +1,60 @@ #ifndef SOCK_H #define SOCK_H + + + +#if 1 + + + +enum sock_flag { + SOCK_FLAG_NONE = 0, + SOCK_FLAG_NON_BLOCKING = (1 << 0) +}; + +struct sock { + i32 _; +}; + +enum sock_address_kind { + SOCK_ADDRESS_KIND_NONE, + SOCK_ADDRESS_KIND_UNBINDABLE, + + /* Network addresses */ + SOCK_ADDRESS_KIND_ANY_LOCAL_INTERFACE, + SOCK_ADDRESS_KIND_RAW +}; + +struct sock_address { + enum sock_address_kind kind; + u8 ip[16]; + u16 port; +}; + +struct sock_read_result { + b32 valid; + struct sock_address address; + struct string data; +}; + +struct sock_startup_receipt { i32 _; }; +struct sock_startup_receipt sock_startup(void); + +struct sock_address sock_address_from_string(struct string str); +struct sock_address sock_address_from_any_local_interface_with_port(u16 port); +struct sock_address sock_address_from_any_local_interface_with_dynamic_port(void); +struct sock_address sock_address_unbindable(void); + +struct sock sock_alloc(struct sock_address bind_address, u32 sock_flags); +void sock_release(struct sock *sock); +struct sock_read_result sock_read(struct sock *sock, struct string read_buff); +void sock_write(struct sock *sock, struct sock_address address, struct string data); + + + +#else + #define SOCK_IP_ANY_INTERFACE CPPCOMPAT_INITLIST_TYPE(struct sock_ip) { 0 } #define SOCK_PORT_DYNAMIC (0) @@ -58,5 +112,6 @@ void sock_write(struct sock *sock, struct sock_address address, struct string ms void sock_testsend(void); void sock_testrecv(void); +#endif #endif diff --git a/src/sock_win32.c b/src/sock_win32.c index bc0a0474..5b7591b0 100644 --- a/src/sock_win32.c +++ b/src/sock_win32.c @@ -1,3 +1,117 @@ +#if 1 + + +#include "sock.h" +#include "sys.h" +#include "log.h" +#include "arena.h" +#include "scratch.h" + +#include +#include + +#pragma comment(lib, "ws2_32.lib") + +//#define MAX_IP_STR_LEN 46 + +struct sock_startup_receipt sock_startup(void) +{ + WSADATA wsa_data; + /* Startup winsock */ + WSAStartup(MAKEWORD(2, 2), &wsa_data); + return (struct sock_startup_receipt) { 0 }; +} + +struct sock_address sock_address_from_string(struct string str) +{ + (UNUSED)str; + + struct sock_address res = ZI; + +#if 0 + struct addrinfo *servinfo; + + struct addrinfo hints = ZI; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + + status = getaddrinfo(NULL, "3490", &hints, &servinfo) +#endif + + return res; +} + +struct sock_address sock_address_from_any_local_interface_with_port(u16 port) +{ + (UNUSED)port; + + struct sock_address res = ZI; + return res; +} + +struct sock_address sock_address_from_any_local_interface_with_dynamic_port(void) +{ + struct sock_address res = ZI; + return res; +} + +struct sock_address sock_address_unbindable(void) +{ + struct sock_address res = ZI; + return res; +} + +struct sock sock_alloc(struct sock_address bind_address, u32 sock_flags) +{ + (UNUSED)bind_address; + (UNUSED)sock_flags; + + struct sock sock = ZI; + + + + return sock; +} + +void sock_release(struct sock *sock) +{ + (UNUSED)sock; +} + +struct sock_read_result sock_read(struct sock *sock, struct string read_buff) +{ + (UNUSED)sock; + (UNUSED)read_buff; + + struct sock_read_result res = ZI; + return res; +} + +void sock_write(struct sock *sock, struct sock_address address, struct string data) +{ + (UNUSED)sock; + (UNUSED)address; + (UNUSED)data; +} + + + + + + + + + + + + + +#else + + + + #include "sock.h" #include "sys.h" #include "log.h" @@ -492,3 +606,6 @@ void sock_testrecv(void) closesocket(sock); WSACleanup(); } + + +#endif diff --git a/src/user.c b/src/user.c index a7880acf..a63cff2e 100644 --- a/src/user.c +++ b/src/user.c @@ -20,6 +20,7 @@ #include "rng.h" #include "log.h" #include "sock.h" +#include "host.h" struct bind_state { b32 is_held; /* Is this bind held down this frame */ @@ -42,6 +43,8 @@ GLOBAL struct { struct sys_window *window; + struct host host; + /* Render targets */ struct renderer_texture final_texture; struct renderer_texture world_texture; @@ -137,7 +140,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, struct game_startup_receipt *game_sr, struct asset_cache_startup_receipt *asset_cache_sr, struct mixer_startup_receipt *mixer_sr, - struct sock_startup_receipt *sock_sr, + struct host_startup_receipt *host_sr, struct sys_window *window) { (UNUSED)work_sr; @@ -148,14 +151,14 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, (UNUSED)game_sr; (UNUSED)asset_cache_sr; (UNUSED)mixer_sr; - (UNUSED)sock_sr; + (UNUSED)host_sr; G.arena = arena_alloc(GIGABYTE(64)); G.sys_events_mutex = sys_mutex_alloc(); G.sys_events_arena = arena_alloc(GIGABYTE(64)); world_alloc(&G.world); - struct net_address_desc bind_addr = NET_ADDRESS_DESC_ALL_LOCAL_INTERFACES(NET_PORT_DYNAMIC); + struct sock_address bind_addr = sock_address_from_any_local_interface_with_dynamic_port(); G.host = host_alloc(bind_addr); G.world_to_ui_xf = XFORM_IDENT; @@ -215,6 +218,7 @@ INTERNAL SYS_WINDOW_EVENT_CALLBACK_FUNC_DEF(window_event_callback, event) * Game -> user communication * ========================== */ +#if 0 INTERNAL struct blend_tick *blend_tick_alloc(void) { struct blend_tick *bt = NULL; @@ -361,6 +365,7 @@ INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns) .to_tick = to_tick }; } +#endif /* ========================== * * Debug draw @@ -455,7 +460,17 @@ INTERNAL SORT_COMPARE_FUNC_DEF(entity_draw_order_cmp, arg_a, arg_b, udata) - +INTERNAL void queue_game_cmd(struct arena *arena, struct game_cmd_list *list, struct game_cmd src) +{ + struct game_cmd *cmd = arena_push(arena, struct game_cmd); + *cmd = src; + if (list->last) { + list->last->next = cmd; + } else { + list->first = cmd; + } + list->last = cmd; +} @@ -588,7 +603,7 @@ INTERNAL void user_update(void) struct game_event_list game_events = ZI; { - struct host_events_array = host_pop_events(scratch.arena, G.host); + struct host_event_array host_events = host_pop_events(scratch.arena, &G.host); game_events_from_host_events(scratch.arena, host_events, &game_events); } @@ -603,14 +618,13 @@ INTERNAL void user_update(void) static f64 last_try_connect = 0; f64 now = SECONDS_FROM_NS(sys_time_ns()); if (last_try_connect == 0 || (now - last_try_connect) > 5) { - struct host_address_desc connect_addr = host_address_desc_from_string(LIT("127.0.0.1:12345")); - host_connect_to_address(G.host, connect_addr); + struct sock_address connect_addr = sock_address_from_string(LIT("127.0.0.1:12345")); + host_queue_connect_to_address(&G.host, connect_addr); last_try_connect = now; } - for (u64 i = 0; i < game_events.count; ++i) { - struct game_event event = game_events.events[i]; - enum game_event_kind kind = event.kind; + for (struct game_event *event = game_events.first; event; event = event->next) { + enum game_event_kind kind = event->kind; switch (kind) { case GAME_EVENT_KIND_CONNECT: @@ -623,10 +637,10 @@ INTERNAL void user_update(void) last_try_connect = 0; } break; - case GAME_EVENT_KIND_SNAPSHOT: + case GAME_EVENT_KIND_SNAPSHOT_FULL: { - struct string data = event.data; - game_tick_from_string(&G.world, data); + struct string snapshot_data = event->snapshot_data; + game_tick_from_string(snapshot_data, &G.world); } break; default: break; @@ -1656,17 +1670,13 @@ INTERNAL void user_update(void) { struct temp_arena temp = arena_temp_begin(scratch.arena); - struct string cmds_str = game_string_from_cmds(temp.arena, game_cmds_list); - - struct host_msg_desc msg = ZI; - msg.channel = CHANNEL_ID_ALL; - msg.data = cmds_str; - host_queue_write(G.host, msg); + struct string cmds_str = game_string_from_cmds(temp.arena, cmd_list); + host_queue_write(&G.host, HOST_CHANNEL_ID_ALL, cmds_str); arena_temp_end(temp); } - host_update(G.host); + host_update(&G.host); /* ========================== * * Render diff --git a/src/user.h b/src/user.h index 08aa9ead..534c4ec8 100644 --- a/src/user.h +++ b/src/user.h @@ -10,7 +10,7 @@ struct draw_startup_receipt; struct game_startup_receipt; struct asset_cache_startup_receipt; struct mixer_startup_receipt; -struct sock_startup_receipt; +struct host_startup_receipt; enum user_bind_kind { USER_BIND_KIND_NONE, @@ -57,7 +57,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, struct game_startup_receipt *game_sr, struct asset_cache_startup_receipt *asset_cache_sr, struct mixer_startup_receipt *mixer_sr, - struct sock_startup_receipt *sock_sr, + struct host_startup_receipt *host_sr, struct sys_window *window); #endif