differentiate client entities
This commit is contained in:
parent
16e8bb0dca
commit
eee5945954
@ -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;
|
||||
};
|
||||
|
||||
53
src/host.c
53
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 <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);
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
428
src/sim.c
428
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) */
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
195
src/sock_win32.c
195
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();
|
||||
|
||||
32
src/user.c
32
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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user