host progress

This commit is contained in:
jacob 2025-02-06 14:32:06 -06:00
parent a80eff9e39
commit 627f736345
13 changed files with 820 additions and 304 deletions

View File

@ -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();

View File

@ -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) {

View File

@ -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

View File

@ -506,6 +506,11 @@ struct space_entry_handle {
u64 gen;
};
struct host_channel_id {
u32 gen;
u32 idx;
};
/* ========================== *
* Tag structs
* ========================== */

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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 <chunk_id> out of <chunk_count> belonging to message <msg_id> */
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 <chunk_id> out of <chunk_count> belonging to message <msg_id> */
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;
}

View File

@ -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

View File

@ -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

View File

@ -1,3 +1,117 @@
#if 1
#include "sock.h"
#include "sys.h"
#include "log.h"
#include "arena.h"
#include "scratch.h"
#include <WinSock2.h>
#include <WS2tcpip.h>
#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

View File

@ -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

View File

@ -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