From eee594595424c9705eaaa0a6a522d424dd1671a2 Mon Sep 17 00:00:00 2001 From: jacob Date: Sat, 8 Feb 2025 17:11:04 -0600 Subject: [PATCH] differentiate client entities --- src/app.h | 4 +- src/host.c | 53 +++--- src/host.h | 3 + src/sim.c | 428 +++++++++++++++++++++++++++-------------------- src/sim_client.c | 26 +-- src/sim_client.h | 23 ++- src/sim_ent.h | 13 +- src/sim_msg.c | 42 ++++- src/sim_msg.h | 10 +- src/sock.h | 5 +- src/sock_win32.c | 195 ++++++++++++++------- src/user.c | 32 ++-- src/world.c | 5 + src/world.h | 7 + 14 files changed, 519 insertions(+), 327 deletions(-) diff --git a/src/app.h b/src/app.h index 881e1483..14ab5dbe 100644 --- a/src/app.h +++ b/src/app.h @@ -5,8 +5,8 @@ typedef APP_EXIT_CALLBACK_FUNC_DEF(app_exit_callback_func); struct app_statistics { - struct atomic_u64 host_bytes_sent; - struct atomic_u64 host_bytes_received; + struct atomic_u64 sock_bytes_sent; + struct atomic_u64 sock_bytes_received; struct atomic_u64 memory_committed; struct atomic_u64 memory_reserved; }; diff --git a/src/host.c b/src/host.c index 3a9ad55d..83f3f2c5 100644 --- a/src/host.c +++ b/src/host.c @@ -6,7 +6,6 @@ #include "util.h" #include "log.h" #include "buddy.h" -#include "app.h" #include "atomic.h" //#define HOST_NETWORK_ADDRESS_STRING(str) @@ -196,7 +195,8 @@ struct host *host_alloc(u16 listen_port) void host_release(struct host *host) { - /* FIXME: Signal thread shutdown */ + atomic_i32_eval_exchange(&host->receiver_thread_shutdown_flag, 1); + sock_wake(host->sock); sys_thread_wait_release(&host->receiver_thread); sys_mutex_release(&host->rcv_buffer_write_mutex); @@ -682,10 +682,12 @@ void host_update(struct host *host) /* A foreign host is trying to connect to us */ if (!channel->valid) { logf_info("Received conection attempt from %F", FMT_STR(sock_string_from_address(scratch.arena, address))); - /* TODO: Verify that some per-host uuid isn't - * present in a rolling window to prevent reconnects right after a disconnect? */ + /* 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); } + struct host_cmd *cmd = host_cmd_alloc_and_append(host); + cmd->kind = HOST_CMD_KIND_CONNECT_SUCCESS; + cmd->channel_id = channel->id; } break; case HOST_PACKET_KIND_CONNECT_SUCCESS: @@ -715,7 +717,7 @@ void host_update(struct host *host) case HOST_PACKET_KIND_MSG_CHUNK: { - if (channel->valid) { + if (channel->valid && channel->connected) { /* Packet is chunk out of belonging to message */ u64 msg_id = br_read_var_uint(&br); u64 chunk_id = br_read_var_uint(&br); @@ -771,7 +773,6 @@ void host_update(struct host *host) } } host->bytes_received += packet->data.len; - atomic_u64_eval_add_u64(&app_statistics()->host_bytes_received, packet->data.len); } } /* Reset read buffer */ @@ -816,11 +817,11 @@ void host_update(struct host *host) /* Release timed out unreliable msg buffers */ { /* TODO: Configurable timeout */ - i64 timeout_ns = NS_FROM_SECONDS(0.1); + i64 unreliable_msg_timeout_ns = NS_FROM_SECONDS(0.1); struct host_msg_assembler *ma = channel->least_recent_msg_assembler; while (ma) { struct host_msg_assembler *next = ma->more_recent; - if ((now_ns - ma->touched_ns) > timeout_ns) { + if ((now_ns - ma->touched_ns) > unreliable_msg_timeout_ns) { if (!ma->is_reliable) { host_msg_assembler_release(ma); } @@ -957,7 +958,6 @@ void host_update(struct host *host) channel->num_unreliable_packets = 0; } host->bytes_sent += total_sent; - atomic_u64_eval_add_u64(&app_statistics()->host_bytes_sent, total_sent); } } } @@ -1021,26 +1021,29 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(host_receiver_thread_entry_point, arg) socks.socks = &host->sock; socks.count = 1; - /* FIXME: Shutdown signal */ - volatile b32 run = true; - while (run) { + struct atomic_i32 *shutdown = &host->receiver_thread_shutdown_flag; + while (!atomic_i32_eval(shutdown)) { struct sock *sock = sock_wait_for_available_read(socks, NULL, F32_INFINITY); struct sock_read_result res; - while (sock && (res = sock_read(sock, read_buff)).valid) { - struct sys_lock lock = sys_mutex_lock_e(&host->rcv_buffer_write_mutex); - { - struct host_rcv_buffer *rcv_buffer = host->rcv_buffer_write; - struct host_rcv_packet *packet = arena_push_zero(&rcv_buffer->arena, struct host_rcv_packet); - packet->address = res.address; - packet->data = string_copy(&rcv_buffer->arena, res.data); - if (rcv_buffer->last_packet) { - rcv_buffer->last_packet->next = packet; - } else { - rcv_buffer->first_packet = packet; + while (!atomic_i32_eval(shutdown) && sock && (res = sock_read(sock, read_buff)).valid) { + struct sock_address address = res.address; + struct string data = res.data; + if (data.len > 0) { + struct sys_lock lock = sys_mutex_lock_e(&host->rcv_buffer_write_mutex); + { + struct host_rcv_buffer *rcv_buffer = host->rcv_buffer_write; + struct host_rcv_packet *packet = arena_push_zero(&rcv_buffer->arena, struct host_rcv_packet); + packet->address = address; + packet->data = string_copy(&rcv_buffer->arena, data); + if (rcv_buffer->last_packet) { + rcv_buffer->last_packet->next = packet; + } else { + rcv_buffer->first_packet = packet; + } + rcv_buffer->last_packet = packet; } - rcv_buffer->last_packet = packet; + sys_mutex_unlock(&lock); } - sys_mutex_unlock(&lock); } } diff --git a/src/host.h b/src/host.h index 68daf7a2..8ca41d0e 100644 --- a/src/host.h +++ b/src/host.h @@ -58,6 +58,8 @@ struct host_event_array { struct host { struct arena arena; + + struct sock_signal *sock_signal; struct sock *sock; struct buddy_ctx *buddy; /* For storing msg assembler data */ @@ -94,6 +96,7 @@ struct host { u64 bytes_received; u64 bytes_sent; + struct atomic_i32 receiver_thread_shutdown_flag; struct sys_thread receiver_thread; }; diff --git a/src/sim.c b/src/sim.c index 9b4bee28..acb702fa 100644 --- a/src/sim.c +++ b/src/sim.c @@ -29,9 +29,6 @@ struct sim_ctx { struct host *host; - /* For debugging */ - struct v2 user_cursor; - /* TODO: Remove this (testing) */ b32 extra_spawn; b32 should_reset_level; @@ -44,7 +41,6 @@ struct sim_ctx { struct sim_ent_lookup collision_debug_lookup; #endif struct space *space; - struct sim_client_store *client_store; /* Tick */ struct world tick; @@ -55,7 +51,8 @@ struct sim_ctx { * ========================== */ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg); -INTERNAL void reset_world(struct sim_ctx *ctx); +INTERNAL void test_sim_world_alloc(struct sim_ctx *ctx); +INTERNAL void test_sim_world_release(struct sim_ctx *ctx); struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr, struct phys_startup_receipt *phys_sr, @@ -70,13 +67,11 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr, (UNUSED)phys_sr; (UNUSED)host_sr; - ctx->client_store = sim_client_store_alloc(); - /* Intialize host */ ctx->host = host_alloc(host_port); /* Initialize empty world */ - reset_world(ctx); + test_sim_world_alloc(ctx); ctx->sim_thread = sys_thread_alloc(&sim_thread_entry_point, ctx, LIT("[P2] Sim thread")); @@ -88,25 +83,20 @@ void sim_ctx_release(struct sim_ctx *ctx) __prof; atomic_i32_eval_exchange(&ctx->sim_thread_shutdown, true); sys_thread_wait_release(&ctx->sim_thread); + + test_sim_world_release(ctx); + host_release(ctx->host); + arena_release(&ctx->arena); } /* ========================== * * Reset * ========================== */ -INTERNAL void reset_world(struct sim_ctx *ctx) -{ - if (ctx->tick.ent_store) { - /* Release world */ - world_release(&ctx->tick); - /* Release bookkeeping */ - space_release(ctx->space); -#if COLLIDER_DEBUG - sim_ent_lookup_release(&ctx->collision_debug_lookup); -#endif - sim_ent_lookup_release(&ctx->contact_lookup); - } +/* TODO: Remove this */ +INTERNAL void test_sim_world_alloc(struct sim_ctx *ctx) +{ /* Create bookkeeping */ ctx->contact_lookup = sim_ent_lookup_alloc(4096); #if COLLIDER_DEBUG @@ -119,6 +109,18 @@ INTERNAL void reset_world(struct sim_ctx *ctx) ctx->tick.timescale = SIM_TIMESCALE; } +INTERNAL void test_sim_world_release(struct sim_ctx *ctx) +{ + /* Release world */ + world_release(&ctx->tick); + /* Release bookkeeping */ + space_release(ctx->space); +#if COLLIDER_DEBUG + sim_ent_lookup_release(&ctx->collision_debug_lookup); +#endif + sim_ent_lookup_release(&ctx->contact_lookup); +} + /* ========================== * * Test * ========================== */ @@ -131,70 +133,6 @@ INTERNAL void spawn_test_entities(struct sim_ctx *ctx) root->mass_unscaled = F32_INFINITY; root->inertia_unscaled = F32_INFINITY; - /* Player */ - struct sim_ent *player_ent = sim_ent_nil(); - //if (!ctx->extra_spawn) { - { - - struct sim_ent *e = sim_ent_alloc(root); - - struct v2 pos = V2(1, -1); - - //struct v2 size = V2(0.5, 0.5); - //struct v2 size = V2(0.5, 0.25); - struct v2 size = V2(1.0, 1.0); - - //f32 r = PI / 4; - f32 r = 0; - - if (!ctx->extra_spawn) { - sim_ent_enable_prop(e, SIM_ENT_PROP_PLAYER_CONTROLLED); - sim_ent_enable_prop(e, SIM_ENT_PROP_TEST); - e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase")); - e->mass_unscaled = 10; - e->inertia_unscaled = 5; - } else { - sim_ent_enable_prop(e, SIM_ENT_PROP_TEST); - e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase")); - e->mass_unscaled = 10; - e->inertia_unscaled = 5; -#if 0 - e->sprite = sprite_tag_from_path(LIT("res/graphics/box.ase")); - e->mass_unscaled = 100; - e->inertia_unscaled = 100; -#endif - } - - e->local_collider.points[0] = v2_with_len(V2(0.08f, 0.17f), 0.15f); - e->local_collider.points[1] = v2_with_len(V2(-0.07f, -0.2f), 0.15f); - e->local_collider.count = 2; - e->local_collider.radius = 0.075f; - - //e->sprite = sprite_tag_from_path(LIT("res/graphics/box_rounded.ase")); - //e->sprite_span_name = LIT("idle.unarmed"); - //e->sprite_span_name = LIT("idle.one_handed"); - e->sprite_span_name = LIT("idle.two_handed"); - e->layer = SIM_LAYER_SHOULDERS; - - struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); - //xf.bx.y = -1.f; - - sim_ent_set_xform(e, xf); - - e->linear_ground_friction = 250; - e->angular_ground_friction = 200; - - //e->control_force = 500; - e->control_force = 500; - //e->control_force_max_speed = 4; - e->control_torque = 5000; - e->control_force_max_speed = 4; - - sim_ent_enable_prop(e, SIM_ENT_PROP_PHYSICAL_DYNAMIC); - - player_ent = e; - } - /* Enemy */ { struct sim_ent *e = sim_ent_alloc(root); @@ -262,6 +200,77 @@ INTERNAL void spawn_test_entities(struct sim_ctx *ctx) } #endif + ctx->extra_spawn = true; +} + +INTERNAL struct sim_ent *spawn_test_player(struct sim_ctx *ctx) +{ + struct sim_ent_store *store = ctx->tick.ent_store; + struct sim_ent *root = sim_ent_from_handle(store, store->root); + + /* Player */ + struct sim_ent *player_ent = sim_ent_nil(); + //if (!ctx->extra_spawn) { + { + + struct sim_ent *e = sim_ent_alloc(root); + + struct v2 pos = V2(1, -1); + + //struct v2 size = V2(0.5, 0.5); + //struct v2 size = V2(0.5, 0.25); + struct v2 size = V2(1.0, 1.0); + + //f32 r = PI / 4; + f32 r = 0; + + if (!ctx->extra_spawn) { + sim_ent_enable_prop(e, SIM_ENT_PROP_TEST); + e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase")); + e->mass_unscaled = 10; + e->inertia_unscaled = 5; + } else { + sim_ent_enable_prop(e, SIM_ENT_PROP_TEST); + e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase")); + e->mass_unscaled = 10; + e->inertia_unscaled = 5; +#if 0 + e->sprite = sprite_tag_from_path(LIT("res/graphics/box.ase")); + e->mass_unscaled = 100; + e->inertia_unscaled = 100; +#endif + } + + e->local_collider.points[0] = v2_with_len(V2(0.08f, 0.17f), 0.15f); + e->local_collider.points[1] = v2_with_len(V2(-0.07f, -0.2f), 0.15f); + e->local_collider.count = 2; + e->local_collider.radius = 0.075f; + + //e->sprite = sprite_tag_from_path(LIT("res/graphics/box_rounded.ase")); + //e->sprite_span_name = LIT("idle.unarmed"); + //e->sprite_span_name = LIT("idle.one_handed"); + e->sprite_span_name = LIT("idle.two_handed"); + e->layer = SIM_LAYER_SHOULDERS; + + struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); + //xf.bx.y = -1.f; + + sim_ent_set_xform(e, xf); + + e->linear_ground_friction = 250; + e->angular_ground_friction = 200; + + //e->control_force = 500; + e->control_force = 500; + //e->control_force_max_speed = 4; + e->control_torque = 5000; + e->control_force_max_speed = 4; + + sim_ent_enable_prop(e, SIM_ENT_PROP_PHYSICAL_DYNAMIC); + + player_ent = e; + } + /* Player weapon */ if (player_ent->valid) { struct sim_ent *e = sim_ent_alloc(player_ent); @@ -278,21 +287,29 @@ INTERNAL void spawn_test_entities(struct sim_ctx *ctx) player_ent->equipped = e->handle; } - /* Camera */ - if (!ctx->extra_spawn && player_ent->valid) { - struct sim_ent *e = sim_ent_alloc(root); - sim_ent_set_xform(e, XFORM_IDENT); + return player_ent; +} - sim_ent_enable_prop(e, SIM_ENT_PROP_CAMERA); - sim_ent_enable_prop(e, SIM_ENT_PROP_CAMERA_ACTIVE); - e->camera_follow = player_ent->handle; +INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_ctx *ctx, struct sim_ent *player_ent) +{ + struct sim_ent_store *store = ctx->tick.ent_store; + struct sim_ent *root = sim_ent_from_handle(store, store->root); + + struct sim_ent *camera_ent = sim_ent_nil(); + if (player_ent->valid) { + camera_ent = sim_ent_alloc(root); + sim_ent_set_xform(camera_ent, XFORM_IDENT); + + sim_ent_enable_prop(camera_ent, SIM_ENT_PROP_CAMERA); + sim_ent_enable_prop(camera_ent, SIM_ENT_PROP_CAMERA_ACTIVE); + camera_ent->camera_follow = player_ent->handle; f32 width = (f32)DEFAULT_CAMERA_WIDTH; f32 height = (f32)DEFAULT_CAMERA_HEIGHT; - e->camera_quad_xform = XFORM_TRS(.s = V2(width, height)); + camera_ent->camera_quad_xform = XFORM_TRS(.s = V2(width, height)); } - ctx->extra_spawn = true; + return camera_ent; } /* ========================== * @@ -434,7 +451,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, ud * Update * ========================== */ -INTERNAL void sim_update(struct sim_ctx *ctx) +INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) { __prof; @@ -448,7 +465,8 @@ INTERNAL void sim_update(struct sim_ctx *ctx) logf_info("Clearing level"); ctx->should_reset_level = false; ctx->extra_spawn = false; - reset_world(ctx); + test_sim_world_release(ctx); + test_sim_world_alloc(ctx); } /* ========================== * @@ -457,10 +475,9 @@ INTERNAL void sim_update(struct sim_ctx *ctx) ++ctx->tick.tick_id; - ctx->tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, (1.0 / SIM_FPS) * ctx->tick.timescale)); + ctx->tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, dt * ctx->tick.timescale)); ctx->tick.time_ns += ctx->tick.dt_ns; - f64 dt = SECONDS_FROM_NS(ctx->tick.dt_ns); f64 time = SECONDS_FROM_NS(ctx->tick.time_ns); ctx->sprite_frame_scope = sprite_scope_begin(); ctx->root = sim_ent_from_handle(ctx->tick.ent_store, ctx->tick.ent_store->root); @@ -544,13 +561,50 @@ INTERNAL void sim_update(struct sim_ctx *ctx) enum sim_cmd_kind kind = cmd->kind; struct host_channel_id channel_id = cmd->channel_id; - struct sim_client *client = sim_client_from_channel_id(ctx->client_store, channel_id); - if (client->valid || host_channel_id_is_nil(channel_id)) { + struct sim_client *client = sim_client_from_channel_id(ctx->tick.client_store, channel_id); + if (client->valid) { + struct sim_ent *player_ent = sim_ent_from_handle(ctx->tick.ent_store, client->control_ent); + b32 start = cmd->state == SIM_CMD_STATE_START; + b32 stop = cmd->state == SIM_CMD_STATE_STOP; switch (kind) { + /* TODO: Combine movement from multiple inputs? E.ctx-> a sudden + * start and immediate stop cmd should still move the player a + * tad. */ + case SIM_CMD_KIND_PLAYER_MOVE: + { + if (player_ent->valid) { + struct v2 move = cmd->move_dir; + struct v2 focus = cmd->aim_dir; + if (v2_len_sq(move) > 1) { + /* Cap movement vector magnitude at 1 */ + move = v2_norm(move); + } + player_ent->control.move = move; + player_ent->control.focus = focus; + } + } break; + + case SIM_CMD_KIND_PLAYER_FIRE: + { + if (player_ent->valid) { + b32 firing = sim_ent_has_prop(player_ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); + if (start) { + firing = true; + } else if (stop) { + firing = false; + } + if (firing) { + sim_ent_enable_prop(player_ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); + } else { + sim_ent_disable_prop(player_ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); + } + } + } break; + /* Cursor */ case SIM_CMD_KIND_CURSOR_MOVE: { - ctx->user_cursor = cmd->cursor_pos; + client->cursor_pos = cmd->cursor_pos; } break; /* Clear level */ @@ -569,28 +623,84 @@ INTERNAL void sim_update(struct sim_ctx *ctx) /* Disconnect client */ case SIM_CMD_KIND_SIM_CLIENT_DISCONNECT: { - if (client->valid) { - struct sim_ent *client_ent = sim_ent_from_handle(ent_store, client->ent); - if (client_ent->valid) { - sim_ent_disable_prop(client_ent, SIM_ENT_PROP_PLAYER_CONTROLLED); - sim_ent_enable_prop(client_ent, SIM_ENT_PROP_RELEASE_NEXT_TICK); - host_queue_disconnect(ctx->host, channel_id); - } - sim_client_release(client); + if (player_ent->valid) { + sim_ent_enable_prop(player_ent, SIM_ENT_PROP_RELEASE_NEXT_TICK); + host_queue_disconnect(ctx->host, channel_id); } + sim_client_release(client); } break; default: break; }; } else if (kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id) && !client->valid) { /* Connect client */ - client = sim_client_alloc(ctx->client_store, channel_id); - struct sim_ent *client_ent = sim_ent_alloc(root); - sim_ent_enable_prop(client_ent, SIM_ENT_PROP_PLAYER_CONTROLLED); - client_ent->controlling_client = client->handle; + client = sim_client_alloc(ctx->tick.client_store, channel_id); + struct sim_ent *player_ent = spawn_test_player(ctx); + sim_ent_enable_prop(player_ent, SIM_ENT_PROP_CONTROLLED); + struct sim_ent *camera_ent = spawn_test_player_camera(ctx, player_ent); + client->control_ent = player_ent->handle; + client->camera_ent = camera_ent->handle;; + player_ent->controlling_client = client->handle; } } +#if 0 + /* ========================== * + * Update entity movement from control + * ========================== */ + + for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) { + struct sim_ent *ent = &ent_store->entities[ent_index]; + if (!sim_ent_is_valid_and_active(ent)) continue; + + if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) { + /* Process cmds */ + struct v2 move = ent->control.move; + struct v2 focus = ent->control.focus; + b32 firing = sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); + + for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) { + /* TODO: Combine movement from multiple inputs? E.ctx-> a sudden + * start and immediate stop cmd should still move the player a + * tad. */ + switch (cmd->kind) { + case SIM_CMD_KIND_PLAYER_MOVE: + { + move = cmd->move_dir; + focus = cmd->aim_dir; + } break; + + case SIM_CMD_KIND_PLAYER_FIRE: + { + if (start) { + firing = true; + } else if (stop) { + firing = false; + } + } break; + + default: break; + } + } + + /* Movement */ + if (v2_len_sq(move) > 1) { + /* Cap movement vector magnitude at 1 */ + move = v2_norm(move); + } + ent->control.move = move; + ent->control.focus = focus; + + /* Firing */ + if (firing) { + sim_ent_enable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); + } else { + sim_ent_disable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); + } + } + } +#endif + /* ========================== * * Update entities from sprite * ========================== */ @@ -711,64 +821,6 @@ INTERNAL void sim_update(struct sim_ctx *ctx) sim_ent_set_local_xform(ent, xf); } - /* ========================== * - * Update control from player cmds - * ========================== */ - - for (u64 ent_index = 0; ent_index < ent_store->num_reserved; ++ent_index) { - struct sim_ent *ent = &ent_store->entities[ent_index]; - if (!sim_ent_is_valid_and_active(ent)) continue; - - if (sim_ent_has_prop(ent, SIM_ENT_PROP_PLAYER_CONTROLLED)) { - /* Process cmds */ - struct v2 move = ent->control.move; - struct v2 focus = ent->control.focus; - b32 firing = sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); - - for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) { - b32 start = cmd->state == SIM_CMD_STATE_START; - b32 stop = cmd->state == SIM_CMD_STATE_STOP; - - /* TODO: Combine movement from multiple inputs? E.ctx-> a sudden - * start and immediate stop cmd should still move the player a - * tad. */ - switch (cmd->kind) { - case SIM_CMD_KIND_PLAYER_MOVE: - { - move = cmd->move_dir; - focus = cmd->aim_dir; - } break; - - case SIM_CMD_KIND_PLAYER_FIRE: - { - if (start) { - firing = true; - } else if (stop) { - firing = false; - } - } break; - - default: break; - } - } - - /* Movement */ - if (v2_len_sq(move) > 1) { - /* Cap movement vector magnitude at 1 */ - move = v2_norm(move); - } - ent->control.move = move; - ent->control.focus = focus; - - /* Firing */ - if (firing) { - sim_ent_enable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); - } else { - sim_ent_disable_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED); - } - } - } - /* ========================== * * Test * ========================== */ @@ -919,7 +971,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx) struct sim_ent *ent = &ent_store->entities[ent_index]; if (!sim_ent_is_valid_and_active(ent)) continue; - if (sim_ent_has_prop(ent, SIM_ENT_PROP_PLAYER_CONTROLLED)) { + if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) { struct sim_ent *joint_ent = sim_ent_from_handle(ent_store, ent->move_joint); if (!sim_ent_is_valid_and_active(joint_ent)) { joint_ent = sim_ent_alloc(root); @@ -953,7 +1005,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx) struct sim_ent *ent = &ent_store->entities[ent_index]; if (!sim_ent_is_valid_and_active(ent)) continue; - if (sim_ent_has_prop(ent, SIM_ENT_PROP_PLAYER_CONTROLLED)) { + if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) { struct xform xf = sim_ent_get_xform(ent); struct xform sprite_xf = xform_mul(xf, ent->sprite_local_xform); @@ -1082,6 +1134,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx) phys.debug_lookup = &phys->collision_debug_lookup; #endif +#if 0 /* Mouse drag */ phys.dbg_cursor_pos = ctx->user_cursor; for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) { @@ -1093,6 +1146,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx) } } } +#endif /* Step */ ctx->last_phys_iteration = phys_step(&phys, dt, ctx->last_phys_iteration); @@ -1318,22 +1372,26 @@ INTERNAL void sim_update(struct sim_ctx *ctx) * Publish tick * ========================== */ - { - struct temp_arena temp = arena_temp_begin(scratch.arena); + for (u64 i = 0; i < ctx->tick.client_store->num_reserved; ++i) { + struct sim_client *client = &ctx->tick.client_store->clients[i]; + if (client->valid) { + struct temp_arena temp = arena_temp_begin(scratch.arena); - /* TODO: Not like this */ - struct sim_event snapshot_event = ZI; - snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT_FULL; - snapshot_event.snapshot_data = sim_string_from_tick(temp.arena, &ctx->tick); + /* TODO: Not like this */ + struct sim_event snapshot_event = ZI; + snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT; + snapshot_event.snapshot_data = sim_string_from_tick(temp.arena, client, &ctx->tick); - struct sim_event_list l = ZI; - l.first = &snapshot_event; - l.last = &snapshot_event; - struct string msg = sim_string_from_events(temp.arena, l); + struct sim_event_list l = ZI; + l.first = &snapshot_event; + l.last = &snapshot_event; + struct string msg = sim_string_from_events(temp.arena, l); - host_queue_write(ctx->host, HOST_CHANNEL_ID_ALL, msg, 0); + host_queue_write(ctx->host, client->channel_id, msg, 0); + //host_queue_write(ctx->host, HOST_CHANNEL_ID_ALL, msg, 0); - arena_temp_end(temp); + arena_temp_end(temp); + } } host_update(ctx->host); @@ -1361,6 +1419,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg) __profscope(sim_update_w_sleep); sleep_frame(last_frame_ns, target_dt_ns); last_frame_ns = sys_time_ns(); - sim_update(ctx); + sim_update(ctx, (1.0 / SIM_FPS)); } } diff --git a/src/sim_client.c b/src/sim_client.c index f13cc23f..7850365f 100644 --- a/src/sim_client.c +++ b/src/sim_client.c @@ -8,11 +8,15 @@ /* Offset in bytes from start of store struct to start of clients array (assume adjacently allocated) */ #define STORE_CLIENTS_OFFSET (sizeof(struct sim_client_store) + (sizeof(struct sim_client_store) % alignof(struct sim_client))) - /* Accessed via client_nil() */ READONLY struct sim_client _g_sim_client_nil = { .valid = false }; READONLY struct sim_client_store _g_sim_client_store_nil = { .valid = false }; +struct sim_client_channel_lookup_bucket { + struct sim_client *first; + struct sim_client *last; +}; + /* ========================== * * Store * ========================== */ @@ -21,7 +25,7 @@ struct sim_client_store *sim_client_store_alloc(void) { struct arena arena = arena_alloc(GIGABYTE(64)); u64 num_channel_lookup_buckets = CHANNEL_LOOKUP_BUCKETS; - u64 channel_lookup_buckets = arena_push_array_zero(&arena, struct channel_lookup_bucket, num_channel_lookup_buckets); + u64 channel_lookup_buckets = arena_push_array_zero(&arena, struct sim_client_channel_lookup_bucket, num_channel_lookup_buckets); struct sim_client_store *store = arena_push_zero(&arena, struct sim_client_store); store->clients = arena_dry_push(&arena, struct sim_client); @@ -60,9 +64,9 @@ INTERNAL u64 hash_from_channel_id(struct host_channel_id channel_id) return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&channel_id)); } -struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct client_handle handle) +struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct sim_client_handle handle) { - if (handle.gen != 0 && handle.idx < store->clients_reserved) { + if (handle.gen != 0 && handle.idx < store->num_reserved) { struct sim_client *client = &store->clients[handle.idx]; if (client->handle.gen == handle.gen) { return client; @@ -76,7 +80,7 @@ struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, st struct sim_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[bucket_index]; + struct sim_client_channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; for (struct sim_client *client = bucket->first; client; client = client->next_hash) { if (client->channel_hash == channel_hash) { res = client; @@ -89,7 +93,7 @@ struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, st struct sim_client *sim_client_alloc(struct sim_client_store *store, struct host_channel_id channel_id) { struct sim_client *client = NULL; - struct client_handle handle = ZI; + struct sim_client_handle handle = ZI; if (store->first_free_client) { client = store->first_free_client; store->first_free_client = client->next_free; @@ -98,9 +102,10 @@ struct sim_client *sim_client_alloc(struct sim_client_store *store, struct host_ } else { client = arena_push(&store->arena, struct sim_client); handle.gen = 1; - handle.idx = store->clients_reserved; - ++store->clients_reserved; + handle.idx = store->num_reserved; + ++store->num_reserved; } + ++store->num_allocated; *client = _g_sim_client_nil; client->valid = true; client->handle = handle; @@ -111,7 +116,7 @@ struct sim_client *sim_client_alloc(struct sim_client_store *store, struct host_ /* Insert into channel lookup */ u64 bucket_index = channel_hash % store->num_channel_lookup_buckets; - struct channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; + struct sim_client_channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; if (bucket->last) { bucket->last->next_hash = client; client->prev_hash = bucket->last; @@ -129,10 +134,11 @@ void sim_client_release(struct sim_client *client) ++client->handle.gen; client->next_free = store->first_free_client; store->first_free_client = client; + --store->num_allocated; /* Remove from channel lookup */ u64 bucket_index = client->channel_hash % store->num_channel_lookup_buckets; - struct channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; + struct sim_client_channel_lookup_bucket *bucket = &store->channel_lookup_buckets[bucket_index]; struct sim_client *prev = client->prev_hash; struct sim_client *next = client->next_hash; if (prev) { diff --git a/src/sim_client.h b/src/sim_client.h index c82fde87..75d411ac 100644 --- a/src/sim_client.h +++ b/src/sim_client.h @@ -1,15 +1,16 @@ #ifndef SIM_CLIENT_H #define SIM_CLIENT_H -struct client_handle { - b32 valid; +struct sim_client_channel_lookup_bucket; + +struct sim_client_handle { u32 idx; u32 gen; }; struct sim_client { b32 valid; - struct client_handle handle; + struct sim_client_handle handle; struct host_channel_id channel_id; u64 channel_hash; @@ -18,24 +19,22 @@ struct sim_client { struct sim_client *next_hash; struct sim_client *prev_hash; - struct sim_ent_handle ent; -}; - -struct channel_lookup_bucket { - struct sim_client *first; - struct sim_client *last; + struct v2 cursor_pos; + struct sim_ent_handle camera_ent; + struct sim_ent_handle control_ent; }; struct sim_client_store { b32 valid; struct arena arena; - struct channel_lookup_bucket *channel_lookup_buckets; + struct sim_client_channel_lookup_bucket *channel_lookup_buckets; u64 num_channel_lookup_buckets; struct sim_client *clients; struct sim_client *first_free_client; - u64 clients_reserved; + u64 num_allocated; + u64 num_reserved; }; INLINE struct sim_client *client_nil(void) @@ -53,7 +52,7 @@ INLINE struct sim_client_store *client_store_nil(void) struct sim_client_store *sim_client_store_alloc(void); void sim_client_store_release(struct sim_client_store *store); struct sim_client_store *client_store_from_client(struct sim_client *client); -struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct client_handle handle); +struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct sim_client_handle handle); struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id); struct sim_client *sim_client_alloc(struct sim_client_store *store, struct host_channel_id channel_id); void sim_client_release(struct sim_client *client); diff --git a/src/sim_ent.h b/src/sim_ent.h index 895bd769..a6f9d343 100644 --- a/src/sim_ent.h +++ b/src/sim_ent.h @@ -17,13 +17,14 @@ enum sim_ent_prop { SIM_ENT_PROP_PHYSICAL_DYNAMIC, SIM_ENT_PROP_PHYSICAL_KINEMATIC, + SIM_ENT_PROP_CONTROLLED, + SIM_ENT_PROP_COLLISION_DEBUG, SIM_ENT_PROP_CONTACT_CONSTRAINT, SIM_ENT_PROP_MOTOR_JOINT, SIM_ENT_PROP_MOUSE_JOINT, SIM_ENT_PROP_SENSOR, - SIM_ENT_PROP_PLAYER_CONTROLLED, SIM_ENT_PROP_CAMERA, SIM_ENT_PROP_CAMERA_ACTIVE, @@ -155,15 +156,13 @@ struct sim_ent { /* SIM_ENT_PROP_MOUSE_JOINT */ struct phys_mouse_joint mouse_joint_data; - /* ====================================================================== */ - /* Player */ - - /* SIM_ENT_PROP_PLAYER_CONTROLLED */ - struct client_handle controlling_client; - /* ====================================================================== */ /* Control */ + /* SIM_ENT_PROP_CONTROLLED */ + + struct sim_client_handle controlling_client; + f32 control_force; /* How much force is applied to achieve desired control movement */ f32 control_force_max_speed; /* Maximum linear velocity achieved by force (m/s) */ diff --git a/src/sim_msg.c b/src/sim_msg.c index d93de2b9..e16b0203 100644 --- a/src/sim_msg.c +++ b/src/sim_msg.c @@ -86,6 +86,7 @@ void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host u64 cmd_size = br_read_u64(&br); u64 cmd_pos_end = br_pos(&br) + cmd_size; cmd->kind = br_read_i8(&br); + cmd->channel_id = host_event.channel_id; cmd->state = br_read_i8(&br); #if COLLIDER_DEBUG cmd->collider_gjk_steps = br_read_u32(&br); @@ -137,7 +138,7 @@ struct string sim_string_from_events(struct arena *arena, struct sim_event_list bw_write_i8(&bw, event->kind); switch (event->kind) { - case SIM_EVENT_KIND_SNAPSHOT_FULL: + case SIM_EVENT_KIND_SNAPSHOT: { bw_write_string(&bw, event->snapshot_data); } break; @@ -180,7 +181,7 @@ void sim_events_from_host_events(struct arena *arena, struct host_event_array ho sim_event->kind = br_read_i8(&br); switch (sim_event->kind) { - case SIM_EVENT_KIND_SNAPSHOT_FULL: + case SIM_EVENT_KIND_SNAPSHOT: { sim_event->snapshot_data = br_read_string(arena, &br); } break; @@ -209,7 +210,7 @@ void sim_events_from_host_events(struct arena *arena, struct host_event_array ho * Snapshot * ========================== */ -struct string sim_string_from_tick(struct arena *arena, struct world *tick) +struct string sim_string_from_tick(struct arena *arena, struct sim_client *client, struct world *tick) { __prof; struct byte_writer bw = bw_from_arena(arena); @@ -222,6 +223,19 @@ struct string sim_string_from_tick(struct arena *arena, struct world *tick) bw_write_var_sint(&bw, tick->dt_ns); bw_write_var_sint(&bw, tick->time_ns); + bw_write_var_uint(&bw, client->handle.gen); + bw_write_var_uint(&bw, client->handle.idx); + + /* Client store */ + u64 num_clients = tick->client_store->num_reserved; + bw_write_var_uint(&bw, num_clients); + + struct string clients_src = ZI; + clients_src.text = (u8 *)tick->client_store->clients; + clients_src.len = sizeof(struct sim_client) * num_clients; + br_write_bytes(&bw, clients_src); + + /* Entity store */ u64 num_entities = tick->ent_store->num_reserved; bw_write_var_uint(&bw, num_entities); @@ -246,6 +260,28 @@ void sim_tick_from_string(struct string str, struct world *tick_out) tick_out->dt_ns = br_read_var_sint(&br); tick_out->time_ns = br_read_var_sint(&br); + tick_out->local_client.gen = br_read_var_uint(&br); + tick_out->local_client.idx = br_read_var_uint(&br); + + /* Client store */ + u64 num_clients = br_read_var_uint(&br); + arena_push_array(&tick_out->client_store->arena, struct sim_client, num_clients - tick_out->client_store->num_reserved); + tick_out->client_store->num_reserved = num_clients; + + tick_out->client_store->num_allocated = 0; + struct sim_client *clients_src = br_seek(&br, num_clients * sizeof(struct sim_client)); + if (clients_src) { + for (u64 i = 0; i < num_clients; ++i) { + struct sim_client *src = &clients_src[i]; + struct sim_client *dst = &tick_out->client_store->clients[i]; + if (dst->valid) { + ++tick_out->client_store->num_allocated; + } + *dst = *src; + } + } + + /* Entity store */ u64 num_entities = br_read_var_uint(&br); arena_push_array(&tick_out->ent_store->arena, struct sim_ent, num_entities - tick_out->ent_store->num_reserved); tick_out->ent_store->num_reserved = num_entities; diff --git a/src/sim_msg.h b/src/sim_msg.h index 4a877a69..7ab968b7 100644 --- a/src/sim_msg.h +++ b/src/sim_msg.h @@ -4,6 +4,7 @@ #include "host.h" struct world; +struct sim_client; /* ========================== * * Sim cmd @@ -74,7 +75,7 @@ enum sim_event_kind { SIM_EVENT_KIND_CONNECT, SIM_EVENT_KIND_DISCONNECT, - SIM_EVENT_KIND_SNAPSHOT_FULL, + SIM_EVENT_KIND_SNAPSHOT, //SIM_EVENT_KIND_ENTITY_UPDATE, //SIM_EVENT_KIND_ENTITY_CREATE, @@ -85,11 +86,10 @@ struct sim_event { enum sim_event_kind kind; struct host_channel_id channel_id; - struct string snapshot_data; struct string disconnect_reason; - //struct sim_ent_handle entity; - //struct string update_data; + /* SIM_EVENT_KIND_SNAPSHOT */ + struct string snapshot_data; struct sim_event *next; }; @@ -106,7 +106,7 @@ void sim_events_from_host_events(struct arena *arena, struct host_event_array ho * Snapshot * ========================== */ -struct string sim_string_from_tick(struct arena *arena, struct world *tick); +struct string sim_string_from_tick(struct arena *arena, struct sim_client *client, struct world *tick); void sim_tick_from_string(struct string str, struct world *tick_out); #endif diff --git a/src/sock.h b/src/sock.h index 7a4f7c1f..54642548 100644 --- a/src/sock.h +++ b/src/sock.h @@ -25,7 +25,7 @@ struct sock_address { }; struct sock_read_result { - b32 valid; + b32 valid; /* Since data.len = 0 can be valid */ struct sock_address address; struct string data; }; @@ -44,6 +44,9 @@ INLINE b32 sock_address_eq(struct sock_address a, struct sock_address b) struct sock *sock_alloc(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size); void sock_release(struct sock *sock); +/* Wake anyone blocking on sock read */ +void sock_wake(struct sock *sock); + struct sock *sock_wait_for_available_read(struct sock_array socks, struct sock_signal *signal, f32 timeout); 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); diff --git a/src/sock_win32.c b/src/sock_win32.c index e7254dcd..f1c81b6c 100644 --- a/src/sock_win32.c +++ b/src/sock_win32.c @@ -5,6 +5,8 @@ #include "scratch.h" #include "string.h" #include "log.h" +#include "app.h" +#include "atomic.h" #define WIN32_LEAN_AND_MEAN #define UNICODE @@ -18,7 +20,7 @@ #define MAX_POLL_FDS 64 -struct winsock_address { +struct win32_address { i32 size; i32 family; union { @@ -29,15 +31,32 @@ struct winsock_address { }; }; +struct win32_sock { + SOCKET sock; + struct win32_sock *next_free; +}; + +/* ========================== * + * Global state + * ========================== */ + +GLOBAL struct { + WSADATA wsa_data; + struct arena win32_socks_arena; + struct sys_mutex win32_socks_mutex; + struct win32_sock *first_free_win32_sock; +} G = ZI, DEBUG_ALIAS(G, G_sock_win32); + /* ========================== * * Startup * ========================== */ struct sock_startup_receipt sock_startup(void) { - WSADATA wsa_data; /* Startup winsock */ - WSAStartup(MAKEWORD(2, 2), &wsa_data); + WSAStartup(MAKEWORD(2, 2), &G.wsa_data); + G.win32_socks_arena = arena_alloc(GIGABYTE(64)); + G.win32_socks_mutex = sys_mutex_alloc(); return (struct sock_startup_receipt) { 0 }; } @@ -203,9 +222,9 @@ struct string sock_string_from_address(struct arena *arena, struct sock_address return res; } -INTERNAL struct winsock_address winsock_address_from_sock_address(struct sock_address addr) +INTERNAL struct win32_address win32_address_from_sock_address(struct sock_address addr) { - struct winsock_address res = ZI; + struct win32_address res = ZI; if (addr.family == SOCK_ADDRESS_FAMILY_IPV4) { res.family = AF_INET; res.size = sizeof(struct sockaddr_in); @@ -222,7 +241,39 @@ INTERNAL struct winsock_address winsock_address_from_sock_address(struct sock_ad return res; } -INTERNAL struct sock_address sock_address_from_winsock_address(struct winsock_address ws_addr) +/* If supplied address has ip INADDR_ANY (0), convert ip to localhost */ +INTERNAL struct win32_address win32_address_convert_any_to_localhost(struct win32_address addr) +{ + if (addr.family == AF_INET) { + u8 *bytes = (u8 *)&addr.sin.sin_addr; + b32 is_any = true; + for (u64 i = 0; i < 4; ++i) { + if (bytes[i] != 0) { + is_any = false; + break; + } + } + if (is_any) { + bytes[0] = 127; + bytes[3] = 1; + } + } else if (addr.family == AF_INET6) { + u8 *bytes = (u8 *)&addr.sin.sin_addr; + b32 is_any = true; + for (u64 i = 0; i < 16; ++i) { + if (bytes[i] != 0) { + is_any = false; + break; + } + } + if (is_any) { + bytes[15] = 1; + } + } + return addr; +} + +INTERNAL struct sock_address sock_address_from_win32_address(struct win32_address ws_addr) { struct sock_address res = ZI; if (ws_addr.family == AF_INET) { @@ -240,38 +291,80 @@ INTERNAL struct sock_address sock_address_from_winsock_address(struct winsock_ad } /* ========================== * - * Alloc + * Sock * ========================== */ +INTERNAL struct win32_sock *win32_sock_alloc(void) +{ + struct win32_sock *ws = NULL; + { + struct sys_lock lock = sys_mutex_lock_e(&G.win32_socks_mutex); + if (G.first_free_win32_sock) { + ws = G.first_free_win32_sock; + G.first_free_win32_sock = ws->next_free; + } else { + ws = arena_push(&G.win32_socks_arena, struct win32_sock); + } + sys_mutex_unlock(&lock); + } + MEMZERO_STRUCT(ws); + return ws; +} + +INTERNAL void win32_sock_release(struct win32_sock *ws) +{ + struct sys_lock lock = sys_mutex_lock_e(&G.win32_socks_mutex); + ws->next_free = G.first_free_win32_sock; + G.first_free_win32_sock = ws; + sys_mutex_unlock(&lock); +} + struct sock *sock_alloc(u16 listen_port, u64 sndbuf_size, u64 rcvbuf_size) { + struct win32_sock *ws = win32_sock_alloc(); struct sock_address addr = sock_address_from_port(listen_port); - struct winsock_address ws_addr = winsock_address_from_sock_address(addr); - - SOCKET ws = socket(ws_addr.family, SOCK_DGRAM, IPPROTO_UDP); + struct win32_address bind_address = win32_address_from_sock_address(addr); + ws->sock = socket(bind_address.family, SOCK_DGRAM, IPPROTO_UDP); { i32 sb = sndbuf_size; i32 rb = rcvbuf_size; - setsockopt(ws, SOL_SOCKET, SO_SNDBUF, (char *)&sb, sizeof(sb)); - setsockopt(ws, SOL_SOCKET, SO_RCVBUF, (char *)&rb, sizeof(rb)); + setsockopt(ws->sock, SOL_SOCKET, SO_SNDBUF, (char *)&sb, sizeof(sb)); + setsockopt(ws->sock, SOL_SOCKET, SO_RCVBUF, (char *)&rb, sizeof(rb)); } -#if 0 - if (listen_port != 0) { - bind(ws, &ws_addr.sa, ws_addr.size); - } -#else - bind(ws, &ws_addr.sa, ws_addr.size); -#endif + bind(ws->sock, &bind_address.sa, bind_address.size); return (struct sock *)ws; } void sock_release(struct sock *sock) { - SOCKET ws = (SOCKET)sock; - closesocket(ws); + struct win32_sock *ws = (struct win32_sock *)sock; + closesocket(ws->sock); + win32_sock_release(ws); +} + +/* Send an empty dummy packet to wake anyone blocking on read (dumb hack since + * winsock doesn't have eventfd). + * + * TODO: Use WSAEvent and WSAWaitForMultipleEvents instead */ +void sock_wake(struct sock *sock) +{ + struct win32_sock *ws = (struct win32_sock *)sock; + + /* Get bound address as localhost so we can write to it (if bound to INADDR_ANY) */ + struct win32_address bind_address = ZI; + { + i32 len = sizeof(bind_address.sas); + getsockname(ws->sock, &bind_address.sa, &len); + bind_address.family = bind_address.sin.sin_family; + bind_address.size = len; + bind_address = win32_address_convert_any_to_localhost(bind_address); + } + + /* Have sock send an empty dummy packet to itself to signal read available */ + sendto(ws->sock, "", 0, 0, &bind_address.sa, bind_address.size); } /* ========================== * @@ -280,27 +373,14 @@ void sock_release(struct sock *sock) struct sock *sock_wait_for_available_read(struct sock_array socks, struct sock_signal *signal, f32 timeout) { - struct temp_arena scratch = scratch_begin_no_conflict(); struct sock *res = NULL; u64 num_fds = socks.count + (signal != NULL); WSAPOLLFD fds[MAX_POLL_FDS] = ZI; - { - u32 fd_i = 0; - if (signal != NULL) { - fds[fd_i].fd = (SOCKET)signal; - fds[fd_i].events = POLLRDNORM; - ++fd_i; - } - for (u32 i = 0; i < socks.count; ++i) { - if (fd_i >= ARRAY_COUNT(fds)) { - ASSERT(false); - break; - } - fds[fd_i].fd = (SOCKET)socks.socks[i]; - fds[fd_i].events = POLLRDNORM; - ++fd_i; - } + for (u32 i = 0; i < socks.count; ++i) { + struct win32_sock *ws = (struct win32_sock *)socks.socks[i]; + fds[i].fd = ws->sock; + fds[i].events = POLLRDNORM; } i32 timeout_ms; @@ -311,43 +391,42 @@ struct sock *sock_wait_for_available_read(struct sock_array socks, struct sock_s } WSAPoll(fds, num_fds, timeout_ms); + b32 none = true; for (u64 i = 0; i < num_fds; ++i) { if (fds[i].revents & POLLRDNORM) { - if (i < socks.count) { - res = socks.socks[i]; - break; - } else { - /* FIXME: Return signal */ - ASSERT(false); - break; - } + res = socks.socks[i]; + none = false; + break; } } - scratch_end(scratch); + if (none) { + DEBUGBREAKABLE; + } return res; } struct sock_read_result sock_read(struct sock *sock, struct string read_buff) { - SOCKET ws = (SOCKET)sock; + struct win32_sock *ws = (struct win32_sock *)sock; struct sock_read_result res = ZI; - struct winsock_address ws_addr = ZI; + struct win32_address ws_addr = ZI; ws_addr.size = sizeof(ws_addr.sas); - i32 size = recvfrom(ws, (char *)read_buff.text, read_buff.len, 0, &ws_addr.sa, &ws_addr.size); + i32 size = recvfrom(ws->sock, (char *)read_buff.text, read_buff.len, 0, &ws_addr.sa, &ws_addr.size); ws_addr.family = ws_addr.sin.sin_family; - res.address = sock_address_from_winsock_address(ws_addr); - if (size > 0) { + res.address = sock_address_from_win32_address(ws_addr); + if (size >= 0) { + atomic_u64_eval_add_u64(&app_statistics()->sock_bytes_sent, size); res.data.text = read_buff.text; res.data.len = size; res.valid = true; } else { #if RTC i32 err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK && err != WSAETIMEDOUT) { + if (err != WSAEWOULDBLOCK && err != WSAETIMEDOUT && err != WSAECONNRESET) { ASSERT(false); } #endif @@ -362,10 +441,12 @@ 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) { - SOCKET ws = (SOCKET)sock; - struct winsock_address ws_addr = winsock_address_from_sock_address(address); - i32 size = sendto(ws, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size); - (UNUSED)size; + struct win32_sock *ws = (struct win32_sock *)sock; + struct win32_address ws_addr = win32_address_from_sock_address(address); + i32 size = sendto(ws->sock, (char *)data.text, data.len, 0, &ws_addr.sa, ws_addr.size); + if (size > 0) { + atomic_u64_eval_add_u64(&app_statistics()->sock_bytes_sent, size); + } #if RTC if (size != (i32)data.len) { i32 err = WSAGetLastError(); diff --git a/src/user.c b/src/user.c index 2d46364c..bfc9e8a9 100644 --- a/src/user.c +++ b/src/user.c @@ -660,7 +660,7 @@ INTERNAL void user_update(void) last_try_connect = 0; } break; - case SIM_EVENT_KIND_SNAPSHOT_FULL: + case SIM_EVENT_KIND_SNAPSHOT: { struct string snapshot_data = event->snapshot_data; sim_tick_from_string(snapshot_data, &G.world); @@ -740,20 +740,12 @@ INTERNAL void user_update(void) } /* ========================== * - * Find important entities + * Find local entities * ========================== */ - struct sim_ent *active_camera; - { - enum sim_ent_prop props[] = { SIM_ENT_PROP_CAMERA, SIM_ENT_PROP_CAMERA_ACTIVE }; - active_camera = sim_ent_find_first_match_all(store, (struct sim_ent_prop_array) { .count = ARRAY_COUNT(props), .props = props }); - } - - struct sim_ent *active_player; - { - enum sim_ent_prop props[] = { SIM_ENT_PROP_PLAYER_CONTROLLED, SIM_ENT_PROP_ACTIVE }; - active_player = sim_ent_find_first_match_all(store, (struct sim_ent_prop_array) { .count = ARRAY_COUNT(props), .props = props }); - } + struct sim_client *local_client = sim_client_from_handle(G.world.client_store, G.world.local_client); + struct sim_ent *local_player = sim_ent_from_handle(G.world.ent_store, local_client->control_ent); + struct sim_ent *local_camera = sim_ent_from_handle(G.world.ent_store, local_client->camera_ent); /* ========================== * * Debug commands @@ -862,7 +854,7 @@ INTERNAL void user_update(void) /* Determine ui size by camera & window dimensions */ f32 aspect_ratio = 1.0; { - struct xform quad_xf = xform_mul(sim_ent_get_xform(active_camera), active_camera->camera_quad_xform); + struct xform quad_xf = xform_mul(sim_ent_get_xform(local_camera), local_camera->camera_quad_xform); struct v2 camera_size = xform_get_scale(quad_xf); if (!v2_is_zero(camera_size)) { aspect_ratio = camera_size.x / camera_size.y; @@ -922,7 +914,7 @@ INTERNAL void user_update(void) G.world_to_ui_xf = xform_translated(G.world_to_ui_xf, v2_neg(world_cursor)); } } else { - struct xform xf = sim_ent_get_xform(active_camera); + struct xform xf = sim_ent_get_xform(local_camera); struct v2 center = xf.og; f32 rot = xform_get_rotation(xf); @@ -930,7 +922,7 @@ INTERNAL void user_update(void) /* Scale view into viewport based on camera size */ struct v2 size = G.ui_size; { - struct xform quad_xf = xform_mul(xf, active_camera->camera_quad_xform); + struct xform quad_xf = xform_mul(xf, local_camera->camera_quad_xform); struct v2 camera_size = xform_get_scale(quad_xf); if (!v2_is_zero(camera_size)) { size = v2_div_v2(size, camera_size); @@ -1022,7 +1014,7 @@ INTERNAL void user_update(void) struct xform xf = sim_ent_get_xform(ent); struct xform parent_xf = sim_ent_get_xform(parent); - b32 skip_debug_draw = !G.debug_camera && ent == active_camera; + b32 skip_debug_draw = !G.debug_camera && ent == local_camera; b32 skip_debug_draw_transform = sim_ent_has_prop(ent, SIM_ENT_PROP_CAMERA); skip_debug_draw_transform = true; @@ -1109,7 +1101,7 @@ INTERNAL void user_update(void) } /* Draw focus arrow */ - if (sim_ent_has_prop(ent, SIM_ENT_PROP_PLAYER_CONTROLLED)) { + if (ent == local_player) { struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, ent->sprite); struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, LIT("attach.wep"), ent->animation_frame); struct v2 start = xform_mul_v2(sprite_xform, slice.center); @@ -1476,7 +1468,7 @@ INTERNAL void user_update(void) /* Draw camera rect */ if (sim_ent_has_prop(ent, SIM_ENT_PROP_CAMERA)) { - u32 color = ent == active_camera ? RGBA_32_F(1, 1, 1, 0.5) : RGBA_32_F(0, 0.75, 0, 0.5); + u32 color = ent == local_camera ? RGBA_32_F(1, 1, 1, 0.5) : RGBA_32_F(0, 0.75, 0, 0.5); f32 thickness = 3; struct xform quad_xf = xform_mul(xf, ent->camera_quad_xform); @@ -1562,7 +1554,7 @@ INTERNAL void user_update(void) input_move_dir = xform_basis_invert_mul_v2(G.world_to_ui_xf, input_move_dir); /* Make move dir relative to world view */ input_move_dir = v2_mul(v2_norm(input_move_dir), move_speed); } - struct v2 input_aim_dir = v2_sub(G.world_cursor, sim_ent_get_xform(active_player).og); + struct v2 input_aim_dir = v2_sub(G.world_cursor, sim_ent_get_xform(local_player).og); /* Queue cursor move cmd */ queue_sim_cmd(scratch.arena, &cmd_list, (struct sim_cmd) { diff --git a/src/world.c b/src/world.c index 2921c250..0b9c14e6 100644 --- a/src/world.c +++ b/src/world.c @@ -1,19 +1,23 @@ #include "world.h" #include "sim_ent.h" +#include "sim_client.h" #include "arena.h" #include "scratch.h" void world_alloc(struct world *world) { MEMZERO_STRUCT(world); + world->client_store = sim_client_store_alloc(); world->ent_store = sim_ent_store_alloc(); } void world_release(struct world *world) { sim_ent_store_release(world->ent_store); + sim_client_store_release(world->client_store); } +#if 0 void world_copy_replace(struct world *dest, struct world *src) { __prof; @@ -27,3 +31,4 @@ void world_copy_replace(struct world *dest, struct world *src) scratch_end(scratch); } +#endif diff --git a/src/world.h b/src/world.h index 2fdbc48f..2e2828c4 100644 --- a/src/world.h +++ b/src/world.h @@ -2,6 +2,7 @@ #define WORLD_H #include "sim_ent.h" +#include "sim_client.h" struct world { u64 continuity_gen; /* Starts at 1 */ @@ -13,11 +14,17 @@ struct world { i64 dt_ns; i64 time_ns; + struct sim_client_handle local_client; + + struct sim_client_store *client_store; struct sim_ent_store *ent_store; }; void world_alloc(struct world *world); void world_release(struct world *world); + +#if 0 void world_copy_replace(struct world *dest, struct world *src); +#endif #endif