migrate sim global state to ctx structure

This commit is contained in:
jacob 2025-02-08 12:00:27 -06:00
parent 5f75b765c3
commit ed66382fd6
13 changed files with 525 additions and 510 deletions

View File

@ -223,8 +223,7 @@ void app_entry_point(void)
struct sound_startup_receipt sound_sr = sound_startup(&work_sr, &asset_cache_sr, &resource_sr); struct sound_startup_receipt sound_sr = sound_startup(&work_sr, &asset_cache_sr, &resource_sr);
struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr); struct draw_startup_receipt draw_sr = draw_startup(&renderer_sr, &font_sr);
struct phys_startup_receipt phys_sr = phys_startup(); struct phys_startup_receipt phys_sr = phys_startup();
struct sim_startup_receipt sim_sr = sim_startup(&mixer_sr, &sprite_sr, &sound_sr, &phys_sr, &host_sr); struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &phys_sr, &host_sr, &window);
struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &sprite_sr, &draw_sr, &sim_sr, &asset_cache_sr, &mixer_sr, &host_sr, &window);
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr); struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
(UNUSED)user_sr; (UNUSED)user_sr;

View File

@ -33,7 +33,6 @@
#define SPACE_CELL_BUCKETS_SQRT (256) #define SPACE_CELL_BUCKETS_SQRT (256)
#define SPACE_CELL_SIZE 1.0f #define SPACE_CELL_SIZE 1.0f
#define SIM_FPS 50.0 #define SIM_FPS 50.0
#define SIM_TIMESCALE 1 #define SIM_TIMESCALE 1

View File

@ -1172,7 +1172,7 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_phys_iteration)
if (ctx->pre_solve_callback) { if (ctx->pre_solve_callback) {
__profscope(pre_solve_callback); __profscope(pre_solve_callback);
ctx->pre_solve_callback(collision_data); ctx->pre_solve_callback(collision_data, ctx->pre_solve_callback_udata);
} }
f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS; f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS;
@ -1204,7 +1204,7 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_phys_iteration)
if (ctx->post_solve_callback) { if (ctx->post_solve_callback) {
__profscope(post_solve_callback); __profscope(post_solve_callback);
ctx->post_solve_callback(collision_data); ctx->post_solve_callback(collision_data, ctx->post_solve_callback_udata);
} }
scratch_end(scratch); scratch_end(scratch);

View File

@ -25,8 +25,8 @@ struct phys_collision_data_array {
}; };
struct phys_collision_data; struct phys_collision_data;
#define PHYS_COLLISION_CALLBACK_FUNC_DEF(name, arg) void name(struct phys_collision_data_array arg) #define PHYS_COLLISION_CALLBACK_FUNC_DEF(name, arg_collision_data, arg_udata) void name(struct phys_collision_data_array arg_collision_data, void *arg_udata)
typedef PHYS_COLLISION_CALLBACK_FUNC_DEF(phys_collision_callback_func, data); typedef PHYS_COLLISION_CALLBACK_FUNC_DEF(phys_collision_callback_func, collision_data, udata);
/* Structure containing data used for a single physics step */ /* Structure containing data used for a single physics step */
struct phys_ctx { struct phys_ctx {
@ -37,6 +37,8 @@ struct phys_ctx {
phys_collision_callback_func *pre_solve_callback; phys_collision_callback_func *pre_solve_callback;
phys_collision_callback_func *post_solve_callback; phys_collision_callback_func *post_solve_callback;
void *pre_solve_callback_udata;
void *post_solve_callback_udata;
struct sim_ent_lookup *debug_lookup; struct sim_ent_lookup *debug_lookup;
struct v2 dbg_cursor_pos; struct v2 dbg_cursor_pos;

461
src/sim.c
View File

@ -1,12 +1,11 @@
#include "sim.h" #include "sim.h"
#include "sim_ent.h" #include "sim_ent.h"
#include "sim_client.h" #include "sim_client.h"
#include "sim_msg.h"
#include "sys.h" #include "sys.h"
#include "util.h" #include "util.h"
#include "world.h" #include "world.h"
#include "sprite.h" #include "sprite.h"
#include "sound.h"
#include "mixer.h"
#include "math.h" #include "math.h"
#include "scratch.h" #include "scratch.h"
#include "atomic.h" #include "atomic.h"
@ -19,7 +18,8 @@
#include "byteio.h" #include "byteio.h"
#include "host.h" #include "host.h"
GLOBAL struct { struct sim_ctx {
struct arena arena;
struct atomic_i32 sim_thread_shutdown; struct atomic_i32 sim_thread_shutdown;
struct sys_thread sim_thread; struct sys_thread sim_thread;
@ -48,76 +48,75 @@ GLOBAL struct {
/* Tick */ /* Tick */
struct world tick; struct world tick;
} G = ZI, DEBUG_ALIAS(G, G_sim); };
/* ========================== * /* ========================== *
* Startup * Ctx
* ========================== */ * ========================== */
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sim_shutdown);
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg); INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg);
INTERNAL void reset_world(void); INTERNAL void reset_world(struct sim_ctx *ctx);
struct sim_startup_receipt sim_startup(struct mixer_startup_receipt *mixer_sr, struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
struct sprite_startup_receipt *sheet_sr, struct phys_startup_receipt *phys_sr,
struct sound_startup_receipt *sound_sr, struct host_startup_receipt *host_sr,
struct phys_startup_receipt *phys_sr, u16 host_port)
struct host_startup_receipt *host_sr)
{ {
(UNUSED)mixer_sr; struct arena arena = arena_alloc(GIGABYTE(64));
(UNUSED)sheet_sr; struct sim_ctx *ctx = arena_push_zero(&arena, struct sim_ctx);
(UNUSED)sound_sr; ctx->arena = arena;
(UNUSED)sprite_sr;
(UNUSED)phys_sr; (UNUSED)phys_sr;
(UNUSED)host_sr; (UNUSED)host_sr;
G.client_store = client_store_alloc(); ctx->client_store = sim_client_store_alloc();
/* Intialize host */ /* Intialize host */
G.host = host_alloc(12345); ctx->host = host_alloc(host_port);
/* Initialize empty world */ /* Initialize empty world */
reset_world(); reset_world(ctx);
G.sim_thread = sys_thread_alloc(&sim_thread_entry_point, NULL, LIT("[P2] Sim thread")); ctx->sim_thread = sys_thread_alloc(&sim_thread_entry_point, ctx, LIT("[P2] Sim thread"));
app_register_exit_callback(&sim_shutdown);
return (struct sim_startup_receipt) { 0 }; return ctx;
} }
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(sim_shutdown) void sim_ctx_release(struct sim_ctx *ctx)
{ {
__prof; __prof;
atomic_i32_eval_exchange(&G.sim_thread_shutdown, true); atomic_i32_eval_exchange(&ctx->sim_thread_shutdown, true);
sys_thread_wait_release(&G.sim_thread); sys_thread_wait_release(&ctx->sim_thread);
} }
/* ========================== * /* ========================== *
* Reset * Reset
* ========================== */ * ========================== */
INTERNAL void reset_world(void) INTERNAL void reset_world(struct sim_ctx *ctx)
{ {
if (G.tick.ent_store) { if (ctx->tick.ent_store) {
/* Release world */ /* Release world */
world_release(&G.tick); world_release(&ctx->tick);
/* Release bookkeeping */ /* Release bookkeeping */
space_release(G.space); space_release(ctx->space);
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
sim_ent_lookup_release(&G.collision_debug_lookup); sim_ent_lookup_release(&ctx->collision_debug_lookup);
#endif #endif
sim_ent_lookup_release(&G.contact_lookup); sim_ent_lookup_release(&ctx->contact_lookup);
} }
/* Create bookkeeping */ /* Create bookkeeping */
G.contact_lookup = sim_ent_lookup_alloc(4096); ctx->contact_lookup = sim_ent_lookup_alloc(4096);
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
G.collision_debug_lookup = sim_ent_lookup_alloc(4096); ctx->collision_debug_lookup = sim_ent_lookup_alloc(4096);
#endif #endif
G.space = space_alloc(SPACE_CELL_SIZE, SPACE_CELL_BUCKETS_SQRT); ctx->space = space_alloc(SPACE_CELL_SIZE, SPACE_CELL_BUCKETS_SQRT);
/* Re-create world */ /* Re-create world */
world_alloc(&G.tick); world_alloc(&ctx->tick);
G.tick.timescale = SIM_TIMESCALE; ctx->tick.timescale = SIM_TIMESCALE;
} }
/* ========================== * /* ========================== *
@ -126,15 +125,15 @@ INTERNAL void reset_world(void)
/* TODO: Remove this */ /* TODO: Remove this */
INTERNAL void spawn_test_entities(void) INTERNAL void spawn_test_entities(struct sim_ctx *ctx)
{ {
struct sim_ent *root = sim_ent_from_handle(G.tick.ent_store, G.tick.ent_store->root); struct sim_ent *root = sim_ent_from_handle(ctx->tick.ent_store, ctx->tick.ent_store->root);
root->mass_unscaled = F32_INFINITY; root->mass_unscaled = F32_INFINITY;
root->inertia_unscaled = F32_INFINITY; root->inertia_unscaled = F32_INFINITY;
/* Player */ /* Player */
struct sim_ent *player_ent = sim_ent_nil(); struct sim_ent *player_ent = sim_ent_nil();
//if (!G.extra_spawn) { //if (!ctx->extra_spawn) {
{ {
struct sim_ent *e = sim_ent_alloc(root); struct sim_ent *e = sim_ent_alloc(root);
@ -148,7 +147,7 @@ INTERNAL void spawn_test_entities(void)
//f32 r = PI / 4; //f32 r = PI / 4;
f32 r = 0; f32 r = 0;
if (!G.extra_spawn) { if (!ctx->extra_spawn) {
sim_ent_enable_prop(e, SIM_ENT_PROP_PLAYER_CONTROLLED); sim_ent_enable_prop(e, SIM_ENT_PROP_PLAYER_CONTROLLED);
sim_ent_enable_prop(e, SIM_ENT_PROP_TEST); sim_ent_enable_prop(e, SIM_ENT_PROP_TEST);
e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase")); e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase"));
@ -280,7 +279,7 @@ INTERNAL void spawn_test_entities(void)
} }
/* Camera */ /* Camera */
if (!G.extra_spawn && player_ent->valid) { if (!ctx->extra_spawn && player_ent->valid) {
struct sim_ent *e = sim_ent_alloc(root); struct sim_ent *e = sim_ent_alloc(root);
sim_ent_set_xform(e, XFORM_IDENT); sim_ent_set_xform(e, XFORM_IDENT);
@ -293,18 +292,18 @@ INTERNAL void spawn_test_entities(void)
e->camera_quad_xform = XFORM_TRS(.s = V2(width, height)); e->camera_quad_xform = XFORM_TRS(.s = V2(width, height));
} }
G.extra_spawn = true; ctx->extra_spawn = true;
} }
/* ========================== * /* ========================== *
* Release entities * Release entities
* ========================== */ * ========================== */
INTERNAL void release_entities_with_prop(enum sim_ent_prop prop) INTERNAL void release_entities_with_prop(struct sim_ctx *ctx, enum sim_ent_prop prop)
{ {
struct temp_arena scratch = scratch_begin_no_conflict(); struct temp_arena scratch = scratch_begin_no_conflict();
struct sim_ent_store *store = G.tick.ent_store; struct sim_ent_store *store = ctx->tick.ent_store;
struct space *space = G.space; struct space *space = ctx->space;
struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *); struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *);
u64 ents_to_release_count = 0; u64 ents_to_release_count = 0;
@ -347,13 +346,14 @@ INTERNAL void release_entities_with_prop(enum sim_ent_prop prop)
* Respond to physics collisions * Respond to physics collisions
* ========================== */ * ========================== */
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array) INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, udata)
{ {
struct sim_ent_store *store = G.tick.ent_store; struct sim_ctx *ctx = (struct sim_ctx *)udata;
struct sim_ent_store *store = ctx->tick.ent_store;
struct sim_ent *root = sim_ent_from_handle(store, store->root); struct sim_ent *root = sim_ent_from_handle(store, store->root);
for (u64 i = 0; i < array.count; ++i) { for (u64 i = 0; i < collision_data_array.count; ++i) {
struct phys_collision_data *data = &array.a[i]; struct phys_collision_data *data = &collision_data_array.a[i];
struct phys_contact_constraint *constraint = data->constraint; struct phys_contact_constraint *constraint = data->constraint;
struct sim_ent *e0 = sim_ent_from_handle(store, data->e0); struct sim_ent *e0 = sim_ent_from_handle(store, data->e0);
@ -434,7 +434,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, array)
* Update * Update
* ========================== */ * ========================== */
INTERNAL void sim_update(void) INTERNAL void sim_update(struct sim_ctx *ctx)
{ {
__prof; __prof;
@ -444,31 +444,31 @@ INTERNAL void sim_update(void)
* Reset level if necessary * Reset level if necessary
* ========================== */ * ========================== */
if (G.should_reset_level) { if (ctx->should_reset_level) {
logf_info("Clearing level"); logf_info("Clearing level");
G.should_reset_level = false; ctx->should_reset_level = false;
G.extra_spawn = false; ctx->extra_spawn = false;
reset_world(); reset_world(ctx);
} }
/* ========================== * /* ========================== *
* Begin frame * Begin frame
* ========================== */ * ========================== */
++G.tick.tick_id; ++ctx->tick.tick_id;
G.tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, (1.0 / SIM_FPS) * G.tick.timescale)); ctx->tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, (1.0 / SIM_FPS) * ctx->tick.timescale));
G.tick.time_ns += G.tick.dt_ns; ctx->tick.time_ns += ctx->tick.dt_ns;
f64 dt = SECONDS_FROM_NS(G.tick.dt_ns); f64 dt = SECONDS_FROM_NS(ctx->tick.dt_ns);
f64 time = SECONDS_FROM_NS(G.tick.time_ns); f64 time = SECONDS_FROM_NS(ctx->tick.time_ns);
G.sprite_frame_scope = sprite_scope_begin(); ctx->sprite_frame_scope = sprite_scope_begin();
G.root = sim_ent_from_handle(G.tick.ent_store, G.tick.ent_store->root); ctx->root = sim_ent_from_handle(ctx->tick.ent_store, ctx->tick.ent_store->root);
struct sim_ent *root = G.root; struct sim_ent *root = ctx->root;
struct sim_ent_store *ent_store = G.tick.ent_store; struct sim_ent_store *ent_store = ctx->tick.ent_store;
struct space *space = G.space; struct space *space = ctx->space;
struct sprite_scope *sprite_frame_scope = G.sprite_frame_scope; struct sprite_scope *sprite_frame_scope = ctx->sprite_frame_scope;
(UNUSED)dt; (UNUSED)dt;
(UNUSED)time; (UNUSED)time;
@ -483,7 +483,7 @@ INTERNAL void sim_update(void)
static b32 run = 0; static b32 run = 0;
if (!run) { if (!run) {
run = 1; run = 1;
spawn_test_entities(); spawn_test_entities(ctx);
} }
} }
@ -491,7 +491,7 @@ INTERNAL void sim_update(void)
* Release entities * Release entities
* ========================== */ * ========================== */
release_entities_with_prop(SIM_ENT_PROP_RELEASE_NEXT_TICK); release_entities_with_prop(ctx, SIM_ENT_PROP_RELEASE_NEXT_TICK);
/* ========================== * /* ========================== *
* Activate entities * Activate entities
@ -503,8 +503,8 @@ INTERNAL void sim_update(void)
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE)) { if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE)) {
u64 atick = ent->activation_tick; u64 atick = ent->activation_tick;
if (atick != 0 || G.tick.tick_id >= atick) { if (atick != 0 || ctx->tick.tick_id >= atick) {
sim_ent_activate(ent, G.tick.tick_id); sim_ent_activate(ent, ctx->tick.tick_id);
} }
} }
} }
@ -532,7 +532,7 @@ INTERNAL void sim_update(void)
struct sim_cmd_list sim_cmds = ZI; struct sim_cmd_list sim_cmds = ZI;
{ {
struct host_event_array host_events = host_pop_events(scratch.arena, G.host); struct host_event_array host_events = host_pop_events(scratch.arena, ctx->host);
sim_cmds_from_host_events(scratch.arena, host_events, &sim_cmds); sim_cmds_from_host_events(scratch.arena, host_events, &sim_cmds);
} }
@ -544,26 +544,26 @@ INTERNAL void sim_update(void)
enum sim_cmd_kind kind = cmd->kind; enum sim_cmd_kind kind = cmd->kind;
struct host_channel_id channel_id = cmd->channel_id; struct host_channel_id channel_id = cmd->channel_id;
struct sim_client *client = client_from_channel_id(G.client_store, 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)) { if (client->valid || host_channel_id_is_nil(channel_id)) {
switch (kind) { switch (kind) {
/* Cursor */ /* Cursor */
case SIM_CMD_KIND_CURSOR_MOVE: case SIM_CMD_KIND_CURSOR_MOVE:
{ {
G.user_cursor = cmd->cursor_pos; ctx->user_cursor = cmd->cursor_pos;
} break; } break;
/* Clear level */ /* Clear level */
case SIM_CMD_KIND_CLEAR_ALL: case SIM_CMD_KIND_CLEAR_ALL:
{ {
G.should_reset_level = true; ctx->should_reset_level = true;
} break; } break;
/* Spawn test */ /* Spawn test */
case SIM_CMD_KIND_SPAWN_TEST: case SIM_CMD_KIND_SPAWN_TEST:
{ {
logf_info("Spawning (test)"); logf_info("Spawning (test)");
spawn_test_entities(); spawn_test_entities(ctx);
} break; } break;
/* Disconnect client */ /* Disconnect client */
@ -574,9 +574,9 @@ INTERNAL void sim_update(void)
if (client_ent->valid) { if (client_ent->valid) {
sim_ent_disable_prop(client_ent, SIM_ENT_PROP_PLAYER_CONTROLLED); sim_ent_disable_prop(client_ent, SIM_ENT_PROP_PLAYER_CONTROLLED);
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_RELEASE_NEXT_TICK); sim_ent_enable_prop(client_ent, SIM_ENT_PROP_RELEASE_NEXT_TICK);
host_queue_disconnect(G.host, channel_id); host_queue_disconnect(ctx->host, channel_id);
} }
client_release(client); sim_client_release(client);
} }
} break; } break;
@ -584,7 +584,7 @@ INTERNAL void sim_update(void)
}; };
} else if (kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id) && !client->valid) { } else if (kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id) && !client->valid) {
/* Connect client */ /* Connect client */
client = client_alloc(G.client_store, channel_id); client = sim_client_alloc(ctx->client_store, channel_id);
struct sim_ent *client_ent = sim_ent_alloc(root); struct sim_ent *client_ent = sim_ent_alloc(root);
sim_ent_enable_prop(client_ent, SIM_ENT_PROP_PLAYER_CONTROLLED); sim_ent_enable_prop(client_ent, SIM_ENT_PROP_PLAYER_CONTROLLED);
client_ent->controlling_client = client->handle; client_ent->controlling_client = client->handle;
@ -676,7 +676,7 @@ INTERNAL void sim_update(void)
#endif #endif
ent->local_collider.count = 3; ent->local_collider.count = 3;
ent->local_collider.radius = 0.25; ent->local_collider.radius = 0.25;
//ent->local_collider.radius = math_fabs(math_sin(G.tick.time) / 3); //ent->local_collider.radius = math_fabs(math_sin(ctx->tick.time) / 3);
#else #else
//ent->local_collider.radius = 0.5; //ent->local_collider.radius = 0.5;
ent->local_collider.radius = 0.25; ent->local_collider.radius = 0.25;
@ -729,7 +729,7 @@ INTERNAL void sim_update(void)
b32 start = cmd->state == SIM_CMD_STATE_START; b32 start = cmd->state == SIM_CMD_STATE_START;
b32 stop = cmd->state == SIM_CMD_STATE_STOP; b32 stop = cmd->state == SIM_CMD_STATE_STOP;
/* TODO: Combine movement from multiple inputs? E.G. a sudden /* TODO: Combine movement from multiple inputs? E.ctx-> a sudden
* start and immediate stop cmd should still move the player a * start and immediate stop cmd should still move the player a
* tad. */ * tad. */
switch (cmd->kind) { switch (cmd->kind) {
@ -1071,30 +1071,31 @@ INTERNAL void sim_update(void)
* ========================== */ * ========================== */
{ {
struct phys_ctx ctx = ZI; struct phys_ctx phys = ZI;
ctx.tick_id = G.tick.tick_id; phys.tick_id = ctx->tick.tick_id;
ctx.store = ent_store; phys.store = ent_store;
ctx.space = space; phys.space = space;
ctx.contact_lookup = &G.contact_lookup; phys.contact_lookup = &ctx->contact_lookup;
ctx.pre_solve_callback = on_collision; phys.pre_solve_callback = on_collision;
phys.pre_solve_callback_udata = ctx;
#if COLLIDER_DEBUG #if COLLIDER_DEBUG
ctx.debug_lookup = &G.collision_debug_lookup; phys.debug_lookup = &phys->collision_debug_lookup;
#endif #endif
/* Mouse drag */ /* Mouse drag */
ctx.dbg_cursor_pos = G.user_cursor; phys.dbg_cursor_pos = ctx->user_cursor;
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) { for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
if (cmd->kind == SIM_CMD_KIND_DRAG_OBJECT) { if (cmd->kind == SIM_CMD_KIND_DRAG_OBJECT) {
if (cmd->state == SIM_CMD_STATE_START) { if (cmd->state == SIM_CMD_STATE_START) {
ctx.dbg_start_dragging = true; phys.dbg_start_dragging = true;
} else if (cmd->state == SIM_CMD_STATE_STOP) { } else if (cmd->state == SIM_CMD_STATE_STOP) {
ctx.dbg_stop_dragging = true; phys.dbg_stop_dragging = true;
} }
} }
} }
/* Step */ /* Step */
G.last_phys_iteration = phys_step(&ctx, dt, G.last_phys_iteration); ctx->last_phys_iteration = phys_step(&phys, dt, ctx->last_phys_iteration);
} }
/* ========================== * /* ========================== *
@ -1130,7 +1131,7 @@ INTERNAL void sim_update(void)
if (!sim_ent_is_valid_and_active(ent)) continue; if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_BULLET)) continue; if (!sim_ent_has_prop(ent, SIM_ENT_PROP_BULLET)) continue;
if (ent->activation_tick == G.tick.tick_id) { if (ent->activation_tick == ctx->tick.tick_id) {
struct sim_ent *src = sim_ent_from_handle(ent_store, ent->bullet_src); struct sim_ent *src = sim_ent_from_handle(ent_store, ent->bullet_src);
struct xform src_xf = sim_ent_get_xform(src); struct xform src_xf = sim_ent_get_xform(src);
@ -1276,6 +1277,7 @@ INTERNAL void sim_update(void)
arena_temp_end(temp); arena_temp_end(temp);
} }
#if 0
/* ========================== * /* ========================== *
* Update sound emitters * Update sound emitters
* ========================== */ * ========================== */
@ -1290,7 +1292,7 @@ INTERNAL void sim_update(void)
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TEST_SOUND_EMITTER)) { if (sim_ent_has_prop(ent, SIM_ENT_PROP_TEST_SOUND_EMITTER)) {
struct mixer_desc desc = ent->sound_desc; struct mixer_desc desc = ent->sound_desc;
desc.speed = G.tick.timescale; desc.speed = ctx->tick.timescale;
desc.pos = sim_ent_get_xform(ent).og; desc.pos = sim_ent_get_xform(ent).og;
struct sound *sound = sound_load_async(ent->sound_name, 0); struct sound *sound = sound_load_async(ent->sound_name, 0);
@ -1304,12 +1306,13 @@ INTERNAL void sim_update(void)
} }
} }
} }
#endif
/* ========================== * /* ========================== *
* Release entities * Release entities
* ========================== */ * ========================== */
release_entities_with_prop(SIM_ENT_PROP_RELEASE_THIS_TICK); release_entities_with_prop(ctx, SIM_ENT_PROP_RELEASE_THIS_TICK);
/* ========================== * /* ========================== *
* Publish tick * Publish tick
@ -1321,19 +1324,19 @@ INTERNAL void sim_update(void)
/* TODO: Not like this */ /* TODO: Not like this */
struct sim_event snapshot_event = ZI; struct sim_event snapshot_event = ZI;
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT_FULL; snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT_FULL;
snapshot_event.snapshot_data = sim_string_from_tick(temp.arena, &G.tick); snapshot_event.snapshot_data = sim_string_from_tick(temp.arena, &ctx->tick);
struct sim_event_list l = ZI; struct sim_event_list l = ZI;
l.first = &snapshot_event; l.first = &snapshot_event;
l.last = &snapshot_event; l.last = &snapshot_event;
struct string msg = sim_string_from_events(temp.arena, l); struct string msg = sim_string_from_events(temp.arena, l);
host_queue_write(G.host, HOST_CHANNEL_ID_ALL, msg, 0); host_queue_write(ctx->host, HOST_CHANNEL_ID_ALL, msg, 0);
arena_temp_end(temp); arena_temp_end(temp);
} }
host_update(G.host); host_update(ctx->host);
__profframe("Sim"); __profframe("Sim");
/* ========================== * /* ========================== *
@ -1345,281 +1348,19 @@ INTERNAL void sim_update(void)
scratch_end(scratch); scratch_end(scratch);
} }
/* ========================== *
* Sim cmd
* ========================== */
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds)
{
__prof;
struct byte_writer bw = bw_from_arena(arena);
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
u64 start = bw_pos(&bw);
bw_write_i8(&bw, cmd->kind);
bw_write_i8(&bw, cmd->state);
#if COLLIDER_DEBUG
bw_write_u32(&bw, cmd->collider_gjk_steps);
#endif
switch (cmd->kind) {
case SIM_CMD_KIND_PLAYER_MOVE:
{
bw_write_v2(&bw, cmd->move_dir);
bw_write_v2(&bw, cmd->aim_dir);
} break;
case SIM_CMD_KIND_CURSOR_MOVE:
{
bw_write_v2(&bw, cmd->cursor_pos);
} break;
default: break;
}
u64 size = bw_pos(&bw) - start;
bw_write_u64(&bw_size, size);
}
return bw_get_written(&bw);
}
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
{
__prof;
for (u64 i = 0; i < host_events.count; ++i) {
struct host_event host_event = host_events.events[i];
enum host_event_kind host_event_kind = host_event.kind;
switch (host_event_kind) {
case HOST_EVENT_KIND_CHANNEL_OPENED:
{
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_CONNECT;
cmd->channel_id = host_event.channel_id;
if (cmds_out->last) {
cmds_out->last->next = cmd;
} else {
cmds_out->first = cmd;
}
cmds_out->last = cmd;
} break;
case HOST_EVENT_KIND_CHANNEL_CLOSED:
{
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_DISCONNECT;
cmd->disconnect_reason = LIT("Connection lost");
if (cmds_out->last) {
cmds_out->last->next = cmd;
} else {
cmds_out->first = cmd;
}
cmds_out->last = cmd;
} break;
case HOST_EVENT_KIND_MSG:
{
struct byte_reader br = br_from_buffer(host_event.msg);
while (br_bytes_left(&br) > 0) {
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
u64 cmd_size = br_read_u64(&br);
u64 cmd_pos_end = br_pos(&br) + cmd_size;
cmd->kind = br_read_i8(&br);
cmd->state = br_read_i8(&br);
#if COLLIDER_DEBUG
cmd->collider_gjk_steps = br_read_u32(&br);
#endif
switch (cmd->kind) {
case SIM_CMD_KIND_PLAYER_MOVE:
{
cmd->move_dir = br_read_v2(&br);
cmd->aim_dir = br_read_v2(&br);
} break;
case SIM_CMD_KIND_CURSOR_MOVE:
{
cmd->cursor_pos = br_read_v2(&br);
} break;
default: break;
}
ASSERT(br_pos(&br) == cmd_pos_end);
br_seek_to(&br, cmd_pos_end);
if (cmds_out->last) {
cmds_out->last->next = cmd;
} else {
cmds_out->first = cmd;
}
cmds_out->last = cmd;
}
} break;
default: break;
}
}
}
/* ========================== *
* Sim event
* ========================== */
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events)
{
__prof;
struct byte_writer bw = bw_from_arena(arena);
for (struct sim_event *event = events.first; event; event = event->next) {
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
u64 start = bw_pos(&bw);
bw_write_i8(&bw, event->kind);
switch (event->kind) {
case SIM_EVENT_KIND_SNAPSHOT_FULL:
{
bw_write_string(&bw, event->snapshot_data);
} break;
default: break;
}
u64 size = bw_pos(&bw) - start;
bw_write_u64(&bw_size, size);
}
return bw_get_written(&bw);
}
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out)
{
__prof;
for (u64 i = 0; i < host_events.count; ++i) {
struct sim_event *sim_event = arena_push_zero(arena, struct sim_event);
struct host_event host_event = host_events.events[i];
enum host_event_kind host_event_kind = host_event.kind;
sim_event->channel_id = host_event.channel_id;
switch (host_event_kind) {
case HOST_EVENT_KIND_CHANNEL_OPENED:
{
sim_event->kind = SIM_EVENT_KIND_CONNECT;
} break;
case HOST_EVENT_KIND_CHANNEL_CLOSED:
{
sim_event->kind = SIM_EVENT_KIND_DISCONNECT;
sim_event->disconnect_reason = LIT("Connection lost");
} break;
case HOST_EVENT_KIND_MSG:
{
struct byte_reader br = br_from_buffer(host_event.msg);
while (br_bytes_left(&br) > 0) {
u64 event_size = br_read_u64(&br);
u64 event_pos_end = br_pos(&br) + event_size;
sim_event->kind = br_read_i8(&br);
switch (sim_event->kind) {
case SIM_EVENT_KIND_SNAPSHOT_FULL:
{
sim_event->snapshot_data = br_read_string(arena, &br);
} break;
default: break;
}
ASSERT(br_pos(&br) == event_pos_end);
br_seek_to(&br, event_pos_end);
}
} break;
default: break;
}
if (events_out->last) {
events_out->last->next = sim_event;
} else {
events_out->first = sim_event;
}
events_out->last = sim_event;
}
}
/* ========================== *
* Snapshot
* ========================== */
struct string sim_string_from_tick(struct arena *arena, struct world *tick)
{
__prof;
struct byte_writer bw = bw_from_arena(arena);
bw_write_var_uint(&bw, tick->continuity_gen);
bw_write_var_uint(&bw, tick->tick_id);
bw_write_var_sint(&bw, tick->publishtime_ns);
bw_write_f64(&bw, tick->timescale);
bw_write_var_sint(&bw, tick->dt_ns);
bw_write_var_sint(&bw, tick->time_ns);
u64 num_entities = tick->ent_store->num_reserved;
bw_write_var_uint(&bw, num_entities);
struct string entities_src = ZI;
entities_src.text = (u8 *)tick->ent_store->entities;
entities_src.len = sizeof(struct sim_ent) * num_entities;
br_write_bytes(&bw, entities_src);
return bw_get_written(&bw);
}
void sim_tick_from_string(struct string str, struct world *tick_out)
{
__prof;
struct byte_reader br = br_from_buffer(str);
tick_out->continuity_gen = br_read_var_uint(&br);
tick_out->tick_id = br_read_var_uint(&br);
tick_out->publishtime_ns = br_read_var_sint(&br);
tick_out->timescale = br_read_f64(&br);
tick_out->dt_ns = br_read_var_sint(&br);
tick_out->time_ns = br_read_var_sint(&br);
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;
tick_out->ent_store->num_allocated = 0;
struct sim_ent *entities_src = br_seek(&br, num_entities * sizeof(struct sim_ent));
if (entities_src) {
for (u64 i = 0; i < num_entities; ++i) {
struct sim_ent *src = &entities_src[i];
struct sim_ent *dst = &tick_out->ent_store->entities[i];
if (dst->valid) {
++tick_out->ent_store->num_allocated;
}
*dst = *src;
}
}
}
/* ========================== * /* ========================== *
* Sim thread * Sim thread
* ========================== */ * ========================== */
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg) INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg)
{ {
(UNUSED)arg; struct sim_ctx *ctx = (struct sim_ctx *)arg;
i64 last_frame_ns = 0; i64 last_frame_ns = 0;
i64 target_dt_ns = NS_FROM_SECONDS(SIM_FPS > (0) ? (1.0 / SIM_FPS) : 0); i64 target_dt_ns = NS_FROM_SECONDS(SIM_FPS > (0) ? (1.0 / SIM_FPS) : 0);
while (!atomic_i32_eval(&G.sim_thread_shutdown)) { while (!atomic_i32_eval(&ctx->sim_thread_shutdown)) {
__profscope(sim_update_w_sleep); __profscope(sim_update_w_sleep);
sleep_frame(last_frame_ns, target_dt_ns); sleep_frame(last_frame_ns, target_dt_ns);
last_frame_ns = sys_time_ns(); last_frame_ns = sys_time_ns();
sim_update(); sim_update(ctx);
} }
} }

121
src/sim.h
View File

@ -1,12 +1,8 @@
#ifndef SIM_H #ifndef SIM_H
#define SIM_H #define SIM_H
#include "host.h" struct sim_ctx;
struct world;
struct mixer_startup_receipt;
struct sprite_startup_receipt; struct sprite_startup_receipt;
struct sound_startup_receipt;
struct phys_startup_receipt; struct phys_startup_receipt;
struct host_startup_receipt; struct host_startup_receipt;
@ -20,116 +16,13 @@ struct host_startup_receipt;
#define SIM_LAYER_RELATIVE_DEFAULT 0 #define SIM_LAYER_RELATIVE_DEFAULT 0
#define SIM_LAYER_RELATIVE_WEAPON 1 #define SIM_LAYER_RELATIVE_WEAPON 1
struct sim_startup_receipt { i32 _; }; /* TODO: Get rid of startup receipts */
struct sim_startup_receipt sim_startup(struct mixer_startup_receipt *mixer_sr, struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
struct sprite_startup_receipt *sheet_sr, struct phys_startup_receipt *phys_sr,
struct sound_startup_receipt *sound_sr, struct host_startup_receipt *host_sr,
struct phys_startup_receipt *phys_sr, u16 host_port);
struct host_startup_receipt *host_sr);
void sim_ctx_release(struct sim_ctx *ctx);
/* ========================== *
* Sim cmd
* ========================== */
enum sim_cmd_state {
SIM_CMD_STATE_STOP = -1,
SIM_CMD_STATE_NO_CHANGE = 0,
SIM_CMD_STATE_START = 1
};
enum sim_cmd_kind {
SIM_CMD_KIND_NONE,
SIM_CMD_KIND_PLAYER_MOVE,
SIM_CMD_KIND_PLAYER_FIRE,
SIM_CMD_KIND_SIM_CLIENT_CONNECT,
SIM_CMD_KIND_SIM_CLIENT_DISCONNECT,
/* Testing */
SIM_CMD_KIND_CLEAR_ALL,
SIM_CMD_KIND_SPAWN_TEST,
SIM_CMD_KIND_PAUSE,
SIM_CMD_KIND_STEP,
SIM_CMD_KIND_DRAG_OBJECT,
SIM_CMD_KIND_CURSOR_MOVE,
SIM_CMD_KIND_COUNT
};
struct sim_cmd {
enum sim_cmd_kind kind;
enum sim_cmd_state state;
struct host_channel_id channel_id;
/* SIM_CMD_KIND_PLAYER_MOVE */
struct v2 move_dir;
struct v2 aim_dir;
/* SIM_CMD_KIND_CURSOR_MOVE */
struct v2 cursor_pos;
/* SIM_CMD_KIND_PLAYER_DISCONNECT */
struct string disconnect_reason;
#if RTC
u32 collider_gjk_steps;
#endif
struct sim_cmd *next;
};
struct sim_cmd_list {
struct sim_cmd *first;
struct sim_cmd *last;
};
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds);
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
/* ========================== *
* Sim event
* ========================== */
enum sim_event_kind {
SIM_EVENT_KIND_NONE,
SIM_EVENT_KIND_CONNECT,
SIM_EVENT_KIND_DISCONNECT,
SIM_EVENT_KIND_SNAPSHOT_FULL,
//SIM_EVENT_KIND_ENTITY_UPDATE,
//SIM_EVENT_KIND_ENTITY_CREATE,
//SIM_EVENT_KIND_ENTITY_DESTROY
};
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;
struct sim_event *next;
};
struct sim_event_list {
struct sim_event *first;
struct sim_event *last;
};
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events);
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
/* ========================== *
* Snapshot
* ========================== */
struct string sim_string_from_tick(struct arena *arena, struct world *tick);
void sim_tick_from_string(struct string str, struct world *tick_out);
#endif #endif

View File

@ -17,7 +17,7 @@ READONLY struct sim_client_store _g_sim_client_store_nil = { .valid = false };
* Store * Store
* ========================== */ * ========================== */
struct sim_client_store *client_store_alloc(void) struct sim_client_store *sim_client_store_alloc(void)
{ {
struct arena arena = arena_alloc(GIGABYTE(64)); struct arena arena = arena_alloc(GIGABYTE(64));
u64 num_channel_lookup_buckets = CHANNEL_LOOKUP_BUCKETS; u64 num_channel_lookup_buckets = CHANNEL_LOOKUP_BUCKETS;
@ -34,7 +34,7 @@ struct sim_client_store *client_store_alloc(void)
return store; return store;
} }
void client_store_release(struct sim_client_store *store) void sim_client_store_release(struct sim_client_store *store)
{ {
arena_release(&store->arena); arena_release(&store->arena);
} }
@ -60,7 +60,7 @@ INTERNAL u64 hash_from_channel_id(struct host_channel_id channel_id)
return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&channel_id)); return hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&channel_id));
} }
struct sim_client *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 client_handle handle)
{ {
if (handle.gen != 0 && handle.idx < store->clients_reserved) { if (handle.gen != 0 && handle.idx < store->clients_reserved) {
struct sim_client *client = &store->clients[handle.idx]; struct sim_client *client = &store->clients[handle.idx];
@ -71,7 +71,7 @@ struct sim_client *client_from_handle(struct sim_client_store *store, struct cli
return client_nil(); return client_nil();
} }
struct sim_client *client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id) struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id)
{ {
struct sim_client *res = client_nil(); struct sim_client *res = client_nil();
u64 channel_hash = hash_from_channel_id(channel_id); u64 channel_hash = hash_from_channel_id(channel_id);
@ -86,7 +86,7 @@ struct sim_client *client_from_channel_id(struct sim_client_store *store, struct
return res; return res;
} }
struct sim_client *client_alloc(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)
{ {
struct sim_client *client = NULL; struct sim_client *client = NULL;
struct client_handle handle = ZI; struct client_handle handle = ZI;
@ -122,7 +122,7 @@ struct sim_client *client_alloc(struct sim_client_store *store, struct host_chan
return client; return client;
} }
void client_release(struct sim_client *client) void sim_client_release(struct sim_client *client)
{ {
struct sim_client_store *store = client_store_from_client(client); struct sim_client_store *store = client_store_from_client(client);
client->valid = false; client->valid = false;

View File

@ -50,12 +50,12 @@ INLINE struct sim_client_store *client_store_nil(void)
return &_g_sim_client_store_nil; return &_g_sim_client_store_nil;
} }
struct sim_client_store *client_store_alloc(void); struct sim_client_store *sim_client_store_alloc(void);
void client_store_release(struct sim_client_store *store); 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_store *client_store_from_client(struct sim_client *client);
struct sim_client *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 client_handle handle);
struct sim_client *client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id); struct sim_client *sim_client_from_channel_id(struct sim_client_store *store, struct host_channel_id channel_id);
struct sim_client *client_alloc(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 client_release(struct sim_client *client); void sim_client_release(struct sim_client *client);
#endif #endif

265
src/sim_msg.c Normal file
View File

@ -0,0 +1,265 @@
#include "sim_msg.h"
#include "arena.h"
#include "byteio.h"
#include "world.h"
/* ========================== *
* Sim cmd
* ========================== */
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds)
{
__prof;
struct byte_writer bw = bw_from_arena(arena);
for (struct sim_cmd *cmd = cmds.first; cmd; cmd = cmd->next) {
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
u64 start = bw_pos(&bw);
bw_write_i8(&bw, cmd->kind);
bw_write_i8(&bw, cmd->state);
#if COLLIDER_DEBUG
bw_write_u32(&bw, cmd->collider_gjk_steps);
#endif
switch (cmd->kind) {
case SIM_CMD_KIND_PLAYER_MOVE:
{
bw_write_v2(&bw, cmd->move_dir);
bw_write_v2(&bw, cmd->aim_dir);
} break;
case SIM_CMD_KIND_CURSOR_MOVE:
{
bw_write_v2(&bw, cmd->cursor_pos);
} break;
default: break;
}
u64 size = bw_pos(&bw) - start;
bw_write_u64(&bw_size, size);
}
return bw_get_written(&bw);
}
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out)
{
__prof;
for (u64 i = 0; i < host_events.count; ++i) {
struct host_event host_event = host_events.events[i];
enum host_event_kind host_event_kind = host_event.kind;
switch (host_event_kind) {
case HOST_EVENT_KIND_CHANNEL_OPENED:
{
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_CONNECT;
cmd->channel_id = host_event.channel_id;
if (cmds_out->last) {
cmds_out->last->next = cmd;
} else {
cmds_out->first = cmd;
}
cmds_out->last = cmd;
} break;
case HOST_EVENT_KIND_CHANNEL_CLOSED:
{
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_DISCONNECT;
cmd->disconnect_reason = LIT("Connection lost");
if (cmds_out->last) {
cmds_out->last->next = cmd;
} else {
cmds_out->first = cmd;
}
cmds_out->last = cmd;
} break;
case HOST_EVENT_KIND_MSG:
{
struct byte_reader br = br_from_buffer(host_event.msg);
while (br_bytes_left(&br) > 0) {
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
u64 cmd_size = br_read_u64(&br);
u64 cmd_pos_end = br_pos(&br) + cmd_size;
cmd->kind = br_read_i8(&br);
cmd->state = br_read_i8(&br);
#if COLLIDER_DEBUG
cmd->collider_gjk_steps = br_read_u32(&br);
#endif
switch (cmd->kind) {
case SIM_CMD_KIND_PLAYER_MOVE:
{
cmd->move_dir = br_read_v2(&br);
cmd->aim_dir = br_read_v2(&br);
} break;
case SIM_CMD_KIND_CURSOR_MOVE:
{
cmd->cursor_pos = br_read_v2(&br);
} break;
default: break;
}
ASSERT(br_pos(&br) == cmd_pos_end);
br_seek_to(&br, cmd_pos_end);
if (cmds_out->last) {
cmds_out->last->next = cmd;
} else {
cmds_out->first = cmd;
}
cmds_out->last = cmd;
}
} break;
default: break;
}
}
}
/* ========================== *
* Sim event
* ========================== */
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events)
{
__prof;
struct byte_writer bw = bw_from_arena(arena);
for (struct sim_event *event = events.first; event; event = event->next) {
struct byte_writer bw_size = bw_branch(&bw, sizeof(u64));
u64 start = bw_pos(&bw);
bw_write_i8(&bw, event->kind);
switch (event->kind) {
case SIM_EVENT_KIND_SNAPSHOT_FULL:
{
bw_write_string(&bw, event->snapshot_data);
} break;
default: break;
}
u64 size = bw_pos(&bw) - start;
bw_write_u64(&bw_size, size);
}
return bw_get_written(&bw);
}
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out)
{
__prof;
for (u64 i = 0; i < host_events.count; ++i) {
struct sim_event *sim_event = arena_push_zero(arena, struct sim_event);
struct host_event host_event = host_events.events[i];
enum host_event_kind host_event_kind = host_event.kind;
sim_event->channel_id = host_event.channel_id;
switch (host_event_kind) {
case HOST_EVENT_KIND_CHANNEL_OPENED:
{
sim_event->kind = SIM_EVENT_KIND_CONNECT;
} break;
case HOST_EVENT_KIND_CHANNEL_CLOSED:
{
sim_event->kind = SIM_EVENT_KIND_DISCONNECT;
sim_event->disconnect_reason = LIT("Connection lost");
} break;
case HOST_EVENT_KIND_MSG:
{
struct byte_reader br = br_from_buffer(host_event.msg);
while (br_bytes_left(&br) > 0) {
u64 event_size = br_read_u64(&br);
u64 event_pos_end = br_pos(&br) + event_size;
sim_event->kind = br_read_i8(&br);
switch (sim_event->kind) {
case SIM_EVENT_KIND_SNAPSHOT_FULL:
{
sim_event->snapshot_data = br_read_string(arena, &br);
} break;
default: break;
}
ASSERT(br_pos(&br) == event_pos_end);
br_seek_to(&br, event_pos_end);
}
} break;
default: break;
}
if (events_out->last) {
events_out->last->next = sim_event;
} else {
events_out->first = sim_event;
}
events_out->last = sim_event;
}
}
/* ========================== *
* Snapshot
* ========================== */
struct string sim_string_from_tick(struct arena *arena, struct world *tick)
{
__prof;
struct byte_writer bw = bw_from_arena(arena);
bw_write_var_uint(&bw, tick->continuity_gen);
bw_write_var_uint(&bw, tick->tick_id);
bw_write_var_sint(&bw, tick->publishtime_ns);
bw_write_f64(&bw, tick->timescale);
bw_write_var_sint(&bw, tick->dt_ns);
bw_write_var_sint(&bw, tick->time_ns);
u64 num_entities = tick->ent_store->num_reserved;
bw_write_var_uint(&bw, num_entities);
struct string entities_src = ZI;
entities_src.text = (u8 *)tick->ent_store->entities;
entities_src.len = sizeof(struct sim_ent) * num_entities;
br_write_bytes(&bw, entities_src);
return bw_get_written(&bw);
}
void sim_tick_from_string(struct string str, struct world *tick_out)
{
__prof;
struct byte_reader br = br_from_buffer(str);
tick_out->continuity_gen = br_read_var_uint(&br);
tick_out->tick_id = br_read_var_uint(&br);
tick_out->publishtime_ns = br_read_var_sint(&br);
tick_out->timescale = br_read_f64(&br);
tick_out->dt_ns = br_read_var_sint(&br);
tick_out->time_ns = br_read_var_sint(&br);
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;
tick_out->ent_store->num_allocated = 0;
struct sim_ent *entities_src = br_seek(&br, num_entities * sizeof(struct sim_ent));
if (entities_src) {
for (u64 i = 0; i < num_entities; ++i) {
struct sim_ent *src = &entities_src[i];
struct sim_ent *dst = &tick_out->ent_store->entities[i];
if (dst->valid) {
++tick_out->ent_store->num_allocated;
}
*dst = *src;
}
}
}

112
src/sim_msg.h Normal file
View File

@ -0,0 +1,112 @@
#ifndef SIM_MSG_H
#define SIM_MSG_H
#include "host.h"
struct world;
/* ========================== *
* Sim cmd
* ========================== */
enum sim_cmd_state {
SIM_CMD_STATE_STOP = -1,
SIM_CMD_STATE_NO_CHANGE = 0,
SIM_CMD_STATE_START = 1
};
enum sim_cmd_kind {
SIM_CMD_KIND_NONE,
SIM_CMD_KIND_PLAYER_MOVE,
SIM_CMD_KIND_PLAYER_FIRE,
SIM_CMD_KIND_SIM_CLIENT_CONNECT,
SIM_CMD_KIND_SIM_CLIENT_DISCONNECT,
/* Testing */
SIM_CMD_KIND_CLEAR_ALL,
SIM_CMD_KIND_SPAWN_TEST,
SIM_CMD_KIND_PAUSE,
SIM_CMD_KIND_STEP,
SIM_CMD_KIND_DRAG_OBJECT,
SIM_CMD_KIND_CURSOR_MOVE,
SIM_CMD_KIND_COUNT
};
struct sim_cmd {
enum sim_cmd_kind kind;
enum sim_cmd_state state;
struct host_channel_id channel_id;
/* SIM_CMD_KIND_PLAYER_MOVE */
struct v2 move_dir;
struct v2 aim_dir;
/* SIM_CMD_KIND_CURSOR_MOVE */
struct v2 cursor_pos;
/* SIM_CMD_KIND_PLAYER_DISCONNECT */
struct string disconnect_reason;
#if RTC
u32 collider_gjk_steps;
#endif
struct sim_cmd *next;
};
struct sim_cmd_list {
struct sim_cmd *first;
struct sim_cmd *last;
};
struct string sim_string_from_cmds(struct arena *arena, struct sim_cmd_list cmds);
void sim_cmds_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_cmd_list *cmds_out);
/* ========================== *
* Sim event
* ========================== */
enum sim_event_kind {
SIM_EVENT_KIND_NONE,
SIM_EVENT_KIND_CONNECT,
SIM_EVENT_KIND_DISCONNECT,
SIM_EVENT_KIND_SNAPSHOT_FULL,
//SIM_EVENT_KIND_ENTITY_UPDATE,
//SIM_EVENT_KIND_ENTITY_CREATE,
//SIM_EVENT_KIND_ENTITY_DESTROY
};
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;
struct sim_event *next;
};
struct sim_event_list {
struct sim_event *first;
struct sim_event *last;
};
struct string sim_string_from_events(struct arena *arena, struct sim_event_list events);
void sim_events_from_host_events(struct arena *arena, struct host_event_array host_events, struct sim_event_list *events_out);
/* ========================== *
* Snapshot
* ========================== */
struct string sim_string_from_tick(struct arena *arena, struct world *tick);
void sim_tick_from_string(struct string str, struct world *tick_out);
#endif

View File

@ -8,13 +8,8 @@ enum sock_address_family {
SOCK_ADDRESS_FAMILY_IPV6 SOCK_ADDRESS_FAMILY_IPV6
}; };
struct sock { struct sock;
i32 _; struct sock_signal;
};
struct sock_signal {
i32 _;
};
struct sock_array { struct sock_array {
struct sock **socks; struct sock **socks;

View File

@ -2,6 +2,7 @@
#include "app.h" #include "app.h"
#include "sim.h" #include "sim.h"
#include "sim_ent.h" #include "sim_ent.h"
#include "sim_msg.h"
#include "renderer.h" #include "renderer.h"
#include "font.h" #include "font.h"
#include "sprite.h" #include "sprite.h"
@ -46,9 +47,8 @@ GLOBAL struct {
struct sys_thread user_thread; struct sys_thread user_thread;
struct arena arena; struct arena arena;
struct sys_window *window; struct sys_window *window;
struct sim_ctx *sim_ctx;
struct host *host; struct host *host;
/* Usage stats */ /* Usage stats */
@ -148,9 +148,10 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
struct font_startup_receipt *font_sr, struct font_startup_receipt *font_sr,
struct sprite_startup_receipt *sprite_sr, struct sprite_startup_receipt *sprite_sr,
struct draw_startup_receipt *draw_sr, struct draw_startup_receipt *draw_sr,
struct sim_startup_receipt *sim_sr,
struct asset_cache_startup_receipt *asset_cache_sr, struct asset_cache_startup_receipt *asset_cache_sr,
struct sound_startup_receipt *sound_sr,
struct mixer_startup_receipt *mixer_sr, struct mixer_startup_receipt *mixer_sr,
struct phys_startup_receipt *phys_sr,
struct host_startup_receipt *host_sr, struct host_startup_receipt *host_sr,
struct sys_window *window) struct sys_window *window)
{ {
@ -159,9 +160,10 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
(UNUSED)font_sr; (UNUSED)font_sr;
(UNUSED)sprite_sr; (UNUSED)sprite_sr;
(UNUSED)draw_sr; (UNUSED)draw_sr;
(UNUSED)sim_sr;
(UNUSED)asset_cache_sr; (UNUSED)asset_cache_sr;
(UNUSED)sound_sr;
(UNUSED)mixer_sr; (UNUSED)mixer_sr;
(UNUSED)phys_sr;
(UNUSED)host_sr; (UNUSED)host_sr;
G.arena = arena_alloc(GIGABYTE(64)); G.arena = arena_alloc(GIGABYTE(64));
@ -170,8 +172,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
world_alloc(&G.world); world_alloc(&G.world);
//struct sock_address bind_addr = sock_address_from_any_local_interface_with_dynamic_port(); //struct sock_address bind_addr = sock_address_from_any_local_interface_with_dynamic_port();
//G.host = host_alloc(0); G.host = host_alloc(0);
G.host = host_alloc(5920);
G.world_to_ui_xf = XFORM_IDENT; G.world_to_ui_xf = XFORM_IDENT;
G.world_cmd_buffer = renderer_cmd_buffer_alloc(); G.world_cmd_buffer = renderer_cmd_buffer_alloc();
@ -182,6 +183,8 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
G.window = window; G.window = window;
sys_window_register_event_callback(G.window, &window_event_callback); sys_window_register_event_callback(G.window, &window_event_callback);
G.sim_ctx = sim_ctx_alloc(sprite_sr, phys_sr, host_sr, 12345);
G.debug_draw = true; G.debug_draw = true;
G.user_thread = sys_thread_alloc(&user_thread_entry_point, NULL, LIT("[P1] User thread")); G.user_thread = sys_thread_alloc(&user_thread_entry_point, NULL, LIT("[P1] User thread"));
@ -195,6 +198,10 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(user_shutdown)
__prof; __prof;
atomic_i32_eval_exchange(&G.user_thread_shutdown, true); atomic_i32_eval_exchange(&G.user_thread_shutdown, true);
sys_thread_wait_release(&G.user_thread); sys_thread_wait_release(&G.user_thread);
if (G.sim_ctx) {
sim_ctx_release(G.sim_ctx);
}
} }
/* ========================== * /* ========================== *
@ -1620,10 +1627,10 @@ INTERNAL void user_update(void)
pos.y += spacing; pos.y += spacing;
pos.y += spacing; pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Client data read: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1024 / 1024, 2))); draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Client data read: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_read.last_second * 8 / 1000 / 1000, 2)));
pos.y += spacing; pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Client data sent: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_sent.last_second * 8 / 1024 / 1024, 2))); draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Client data sent: %F mbit/s"), FMT_FLOAT_P((f64)G.client_bytes_sent.last_second * 8 / 1000 / 1000, 2)));
pos.y += spacing; pos.y += spacing;
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory usage: %F MiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_committed) / 1024 / 1024, 2))); draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory usage: %F MiB"), FMT_FLOAT_P((f64)atomic_u64_eval(&app_statistics()->memory_committed) / 1024 / 1024, 2)));

View File

@ -7,9 +7,10 @@ struct renderer_startup_receipt;
struct font_startup_receipt; struct font_startup_receipt;
struct sprite_startup_receipt; struct sprite_startup_receipt;
struct draw_startup_receipt; struct draw_startup_receipt;
struct sim_startup_receipt;
struct asset_cache_startup_receipt; struct asset_cache_startup_receipt;
struct sound_startup_receipt;
struct mixer_startup_receipt; struct mixer_startup_receipt;
struct phys_startup_receipt;
struct host_startup_receipt; struct host_startup_receipt;
enum user_bind_kind { enum user_bind_kind {
@ -54,9 +55,10 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
struct font_startup_receipt *font_sr, struct font_startup_receipt *font_sr,
struct sprite_startup_receipt *sprite_sr, struct sprite_startup_receipt *sprite_sr,
struct draw_startup_receipt *draw_sr, struct draw_startup_receipt *draw_sr,
struct sim_startup_receipt *sim_sr,
struct asset_cache_startup_receipt *asset_cache_sr, struct asset_cache_startup_receipt *asset_cache_sr,
struct sound_startup_receipt *sound_sr,
struct mixer_startup_receipt *mixer_sr, struct mixer_startup_receipt *mixer_sr,
struct phys_startup_receipt *phys_sr,
struct host_startup_receipt *host_sr, struct host_startup_receipt *host_sr,
struct sys_window *window); struct sys_window *window);