sim ctx decoupling progress

This commit is contained in:
jacob 2025-02-14 17:01:44 -06:00
parent bc2dccb872
commit f6aa25760e
7 changed files with 285 additions and 184 deletions

View File

@ -45,9 +45,11 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
struct phys_collision_data_array res = ZI;
res.a = arena_dry_push(arena, struct phys_collision_data);
struct sim_snapshot *ss = ctx->ss;
struct sim_ent_lookup *contact_lookup = ctx->contact_lookup;
struct sim_ent_lookup *debug_lookup = ctx->debug_lookup;
struct space *space = ctx->space;
struct sim_ent_lookup *contact_lookup = &ss->contact_lookup;
struct space *space = ss->space;
#if COLLIDER_DEBUG
struct sim_ent_lookup *debug_lookup = &ss->collision_debug_lookup;
#endif
struct sim_ent *root = sim_ent_from_handle(ss, SIM_ENT_ROOT_HANDLE);
u64 tick = ss->tick;
@ -271,8 +273,6 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
dbg->closest1 = closest_points_res.p1;
}
}
#else
(UNUSED)debug_lookup;
#endif
}
space_iter_end(&iter);
@ -283,8 +283,8 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
void phys_prepare_contacts(struct phys_ctx *ctx, u64 phys_iteration)
{
__prof;
struct sim_ent_lookup *contact_lookup = ctx->contact_lookup;
struct sim_snapshot *ss = ctx->ss;
struct sim_ent_lookup *contact_lookup = &ss->contact_lookup;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *constraint_ent = &ss->ents[sim_ent_index];
@ -985,6 +985,7 @@ void phys_integrate_velocities(struct phys_ctx *ctx, f32 dt)
{
__prof;
struct sim_snapshot *ss = ctx->ss;
struct space *space = ss->space;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *ent = &ss->ents[sim_ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
@ -993,7 +994,7 @@ void phys_integrate_velocities(struct phys_ctx *ctx, f32 dt)
struct xform xf = get_derived_xform(ent, dt);
sim_ent_set_xform(ent, xf);
struct space_entry *space_entry = space_entry_from_handle(ctx->space, ent->space_handle);
struct space_entry *space_entry = space_entry_from_handle(space, ent->space_handle);
if (space_entry->valid) {
space_entry_update_aabb(space_entry, collider_aabb_from_collider(&ent->local_collider, xf));
}
@ -1008,7 +1009,7 @@ f32 phys_determine_earliest_toi_for_bullets(struct phys_ctx *ctx, f32 step_dt, f
{
__prof;
struct sim_snapshot *ss = ctx->ss;
struct space *space = ctx->space;
struct space *space = ss->space;
f32 smallest_t = 1;
for (u64 e0_index = 0; e0_index < ss->num_ents_reserved; ++e0_index) {
@ -1058,15 +1059,16 @@ f32 phys_determine_earliest_toi_for_bullets(struct phys_ctx *ctx, f32 step_dt, f
void phys_update_aabbs(struct phys_ctx *ctx)
{
struct sim_snapshot *ss = ctx->ss;
struct space *space = ss->space;
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *ent = &ss->ents[sim_ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (ent->local_collider.count <= 0) continue;
struct xform xf = sim_ent_get_xform(ent);
struct space_entry *space_entry = space_entry_from_handle(ctx->space, ent->space_handle);
struct space_entry *space_entry = space_entry_from_handle(space, ent->space_handle);
if (!space_entry->valid) {
space_entry = space_entry_alloc(ctx->space, ent->handle);
space_entry = space_entry_alloc(space, ent->handle);
ent->space_handle = space_entry->handle;
}
space_entry_update_aabb(space_entry, collider_aabb_from_collider(&ent->local_collider, xf));
@ -1078,11 +1080,13 @@ void phys_update_aabbs(struct phys_ctx *ctx)
* ========================== */
/* Returns phys iteration to be fed into next step. Supplied iteration must be > 0. */
u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_iteration)
void phys_step(struct phys_ctx *ctx, f32 timestep)
{
__prof;
phys_integrate_forces(ctx, timestep);
u64 phys_iteration = last_iteration;
u64 phys_iteration = ctx->ss->phys_iteration;
phys_update_aabbs(ctx);
f32 remaining_dt = timestep;
while (remaining_dt > 0) {
@ -1090,8 +1094,6 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_iteration)
++phys_iteration;
struct temp_arena scratch = scratch_begin_no_conflict();
phys_update_aabbs(ctx);
/* TOI */
f32 step_dt = remaining_dt;
{
@ -1115,7 +1117,7 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_iteration)
if (ctx->pre_solve_callback) {
__profscope(pre_solve_callback);
ctx->pre_solve_callback(collision_data, ctx->pre_solve_callback_udata);
ctx->pre_solve_callback(collision_data, ctx->ss);
}
f32 substep_dt = step_dt / SIM_PHYSICS_SUBSTEPS;
@ -1147,11 +1149,11 @@ u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 last_iteration)
if (ctx->post_solve_callback) {
__profscope(post_solve_callback);
ctx->post_solve_callback(collision_data, ctx->post_solve_callback_udata);
ctx->post_solve_callback(collision_data, ctx->ss);
}
scratch_end(scratch);
}
return phys_iteration;
ctx->ss->phys_iteration = phys_iteration;
}

View File

@ -6,6 +6,7 @@
struct space;
struct sim_ent_lookup;
struct sim_snapshot;
struct phys_contact_constraint;
struct phys_collision_data {
@ -24,22 +25,14 @@ struct phys_collision_data_array {
};
struct phys_collision_data;
#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, collision_data, udata);
#define PHYS_COLLISION_CALLBACK_FUNC_DEF(name, arg_collision_data, arg_ss) void name(struct phys_collision_data_array arg_collision_data, struct sim_snapshot *arg_ss)
typedef PHYS_COLLISION_CALLBACK_FUNC_DEF(phys_collision_callback_func, collision_data, ss);
/* Structure containing data used for a single physics step */
struct phys_ctx {
struct sim_snapshot *ss;
struct space *space;
struct sim_ent_lookup *contact_lookup;
phys_collision_callback_func *pre_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;
};
/* ========================== *
@ -208,6 +201,6 @@ void phys_update_aabbs(struct phys_ctx *ctx);
* Step
* ========================== */
u64 phys_step(struct phys_ctx *ctx, f32 timestep, u64 phys_iteration);
void phys_step(struct phys_ctx *ctx, f32 timestep);
#endif

292
src/sim.c
View File

@ -21,6 +21,7 @@
* Ctx
* ========================== */
#if 0
struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
struct phys_startup_receipt *phys_sr,
struct host_startup_receipt *host_sr,
@ -37,10 +38,10 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
(UNUSED)sim_snapshot_sr;
/* Intialize host */
ctx->host = host_alloc(host_port);
host = host_alloc(host_port);
/* Allocate encoder bitbuff */
ctx->encoder_bitbuff = bitbuff_alloc(GIGABYTE(64));
encoder_bitbuff = bitbuff_alloc(GIGABYTE(64));
/* Create bookkeeping */
ctx->contact_lookup = sim_ent_lookup_alloc(4096);
@ -50,8 +51,8 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
ctx->space = space_alloc(SPACE_CELL_SIZE, SPACE_CELL_BUCKETS_SQRT);
/* Create snapshot store */
ctx->snapshot_store = sim_snapshot_store_alloc();
ctx->world = sim_snapshot_nil();
snapshot_store = sim_snapshot_store_alloc();
world = sim_snapshot_nil();
return ctx;
}
@ -61,7 +62,7 @@ void sim_ctx_release(struct sim_ctx *ctx)
__prof;
/* Release snapshot store */
sim_snapshot_store_release(ctx->snapshot_store);
sim_snapshot_store_release(snapshot_store);
/* Release bookkeeping */
space_release(ctx->space);
@ -71,13 +72,14 @@ void sim_ctx_release(struct sim_ctx *ctx)
sim_ent_lookup_release(&ctx->contact_lookup);
/* Release encoder bitbuff */
bitbuff_release(&ctx->encoder_bitbuff);
bitbuff_release(&encoder_bitbuff);
/* Release host */
host_release(ctx->host);
host_release(host);
arena_release(&ctx->arena);
}
#endif
/* ========================== *
* Test
@ -85,9 +87,9 @@ void sim_ctx_release(struct sim_ctx *ctx)
/* TODO: Remove this */
INTERNAL void spawn_test_entities(struct sim_ctx *ctx, struct v2 offset)
INTERNAL void spawn_test_entities(struct sim_snapshot *world, struct v2 offset)
{
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE);
root->mass_unscaled = F32_INFINITY;
root->inertia_unscaled = F32_INFINITY;
@ -161,9 +163,9 @@ INTERNAL void spawn_test_entities(struct sim_ctx *ctx, struct v2 offset)
#endif
}
INTERNAL struct sim_ent *spawn_test_player(struct sim_ctx *ctx)
INTERNAL struct sim_ent *spawn_test_player(struct sim_snapshot *world)
{
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE);
/* Player */
struct sim_ent *player_ent = sim_ent_nil();
@ -236,9 +238,9 @@ INTERNAL struct sim_ent *spawn_test_player(struct sim_ctx *ctx)
return player_ent;
}
INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_ctx *ctx, struct sim_ent *player_ent)
INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_snapshot *world, struct sim_ent *player_ent)
{
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE);
struct sim_ent *camera_ent = sim_ent_nil();
if (player_ent->valid) {
@ -257,10 +259,10 @@ INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_ctx *ctx, struct si
return camera_ent;
}
INTERNAL void test_clear_level(struct sim_ctx *ctx)
INTERNAL void test_clear_level(struct sim_snapshot *world)
{
for (u64 j = 0; j < ctx->world->num_ents_reserved; ++j) {
struct sim_ent *ent = &ctx->world->ents[j];
for (u64 j = 0; j < world->num_ents_reserved; ++j) {
struct sim_ent *ent = &world->ents[j];
if (ent->valid) {
sim_ent_enable_prop(ent, SIM_ENT_PROP_RELEASE_NEXT_TICK);
}
@ -271,15 +273,15 @@ INTERNAL void test_clear_level(struct sim_ctx *ctx)
* Release entities
* ========================== */
INTERNAL void release_entities_with_prop(struct sim_ctx *ctx, enum sim_ent_prop prop)
INTERNAL void release_entities_with_prop(struct sim_snapshot *world, enum sim_ent_prop prop)
{
struct temp_arena scratch = scratch_begin_no_conflict();
struct space *space = ctx->space;
struct space *space = world->space;
struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *);
u64 ents_to_release_count = 0;
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (ent->valid && sim_ent_has_prop(ent, prop)) {
*arena_push(scratch.arena, struct sim_ent *) = ent;
++ents_to_release_count;
@ -315,17 +317,16 @@ INTERNAL void release_entities_with_prop(struct sim_ctx *ctx, enum sim_ent_prop
* Respond to physics collisions
* ========================== */
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, udata)
INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, world)
{
struct sim_ctx *ctx = (struct sim_ctx *)udata;
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE);
for (u64 i = 0; i < collision_data_array.count; ++i) {
struct phys_collision_data *data = &collision_data_array.a[i];
struct phys_contact_constraint *constraint = data->constraint;
struct sim_ent *e0 = sim_ent_from_handle(ctx->world, data->e0);
struct sim_ent *e1 = sim_ent_from_handle(ctx->world, data->e1);
struct sim_ent *e0 = sim_ent_from_handle(world, data->e0);
struct sim_ent *e1 = sim_ent_from_handle(world, data->e1);
if (sim_ent_is_valid_and_active(e0) && sim_ent_is_valid_and_active(e1)) {
/* Bullet hit entity */
@ -341,7 +342,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, ud
normal = v2_neg(normal);
vrel = v2_neg(vrel);
}
struct sim_ent *src = sim_ent_from_handle(ctx->world, bullet->bullet_src);
struct sim_ent *src = sim_ent_from_handle(world, bullet->bullet_src);
if (bullet->bullet_has_hit || sim_ent_handle_eq(src->top, target->top)) {
/* Ignore collision if bullet already spent or if weapon and
@ -356,7 +357,7 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, ud
sim_ent_enable_prop(bullet, SIM_ENT_PROP_RELEASE_THIS_TICK);
/* Update tracer */
struct sim_ent *tracer = sim_ent_from_handle(ctx->world, bullet->bullet_tracer);
struct sim_ent *tracer = sim_ent_from_handle(world, bullet->bullet_tracer);
if (sim_ent_is_valid_and_active(tracer)) {
struct xform xf = sim_ent_get_xform(tracer);
xf.og = point;
@ -402,61 +403,50 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, ud
* Update
* ========================== */
void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_snapshot_store *snapshot_store, struct sim_snapshot *prev_snapshot, i64 real_dt_ns, struct sim_cmd_list user_sim_cmds)
{
__prof;
{
__profscope(sim_update_sleep);
sleep_frame(ctx->last_tick_ns, target_dt_ns);
ctx->last_tick_ns = sys_time_ns();
}
struct temp_arena scratch = scratch_begin_no_conflict();
/* ========================== *
* Begin frame
* ========================== */
struct sim_snapshot *prev_snapshot = ctx->world;
ctx->world = sim_snapshot_alloc(ctx->snapshot_store, prev_snapshot, prev_snapshot->tick + 1);
struct sim_snapshot *world = sim_snapshot_alloc(snapshot_store, prev_snapshot, prev_snapshot->tick + 1);
#if 0
/* Release old snapshots */
{
/* TODO: Something better */
i64 release_tick = (i64)ctx->world->tick - 25; /* Arbitrary tick offset */
i64 release_tick = (i64)world->tick - 25; /* Arbitrary tick offset */
if (release_tick > 0) {
struct sim_snapshot *old = sim_snapshot_from_tick(ctx->snapshot_store, release_tick);
struct sim_snapshot *old = sim_snapshot_from_tick(snapshot_store, release_tick);
if (old->valid) {
sim_snapshot_release(old);
}
}
}
#endif
world->real_dt_ns = max_i64(0, real_dt_ns);
world->real_time_ns += world->real_dt_ns;
ctx->world->real_dt_ns = max_i64(0, target_dt_ns);
ctx->world->real_time_ns += ctx->world->real_dt_ns;
world->world_timescale = SIM_TIMESCALE;
world->world_dt_ns = max_i64(0, real_dt_ns * world->world_timescale);
world->world_time_ns += world->world_dt_ns;
ctx->world->world_timescale = SIM_TIMESCALE;
ctx->world->world_dt_ns = max_i64(0, target_dt_ns * ctx->world->world_timescale);
ctx->world->world_time_ns += ctx->world->world_dt_ns;
f64 sim_time = SECONDS_FROM_NS(ctx->world->world_time_ns);
ctx->sprite_frame_scope = sprite_scope_begin();
f64 real_dt = SECONDS_FROM_NS(ctx->world->real_dt_ns);
f64 real_time = SECONDS_FROM_NS(ctx->world->real_time_ns);
f64 world_dt = SECONDS_FROM_NS(ctx->world->world_dt_ns);
f64 world_time = SECONDS_FROM_NS(ctx->world->world_time_ns);
f64 real_dt = SECONDS_FROM_NS(world->real_dt_ns);
f64 real_time = SECONDS_FROM_NS(world->real_time_ns);
f64 world_dt = SECONDS_FROM_NS(world->world_dt_ns);
f64 world_time = SECONDS_FROM_NS(world->world_time_ns);
(UNUSED)real_dt;
(UNUSED)real_time;
(UNUSED)world_dt;
(UNUSED)world_time;
struct space *space = ctx->space;
struct sprite_scope *sprite_frame_scope = ctx->sprite_frame_scope;
struct sprite_scope *sprite_frame_scope = sprite_scope_begin();
struct sim_ent *root = sim_ent_from_handle(ctx->world, SIM_ENT_ROOT_HANDLE);
struct sim_ent *root = sim_ent_from_handle(world, SIM_ENT_ROOT_HANDLE);
/* ========================== *
* Spawn test entities
@ -468,7 +458,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
static b32 run = 0;
if (!run) {
run = 1;
spawn_test_entities(ctx, V2(0, 0));
spawn_test_entities(world, V2(0, 0));
}
}
@ -476,20 +466,20 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Release entities
* ========================== */
release_entities_with_prop(ctx, SIM_ENT_PROP_RELEASE_NEXT_TICK);
release_entities_with_prop(world, SIM_ENT_PROP_RELEASE_NEXT_TICK);
/* ========================== *
* Activate entities
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!ent->valid) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE)) {
u64 atick = ent->activation_tick;
if (atick != 0 || ctx->world->tick >= atick) {
sim_ent_activate(ent, ctx->world->tick);
if (atick != 0 || world->tick >= atick) {
sim_ent_activate(ent, world->tick);
}
}
}
@ -498,8 +488,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Reset triggered entities
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGER_NEXT_TICK)) {
@ -510,14 +500,21 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
}
}
/* ========================== *
* Create user client if it doesn't exist
* ========================== */
(UNUSED)user_sim_cmds;
/* ========================== *
* Process host events into sim cmds
* ========================== */
struct sim_cmd_list *client_cmds;
{
host_update(ctx->host);
struct host_event_array host_events = host_pop_events(scratch.arena, ctx->host);
host_update(host);
struct host_event_array host_events = host_pop_events(scratch.arena, host);
struct sim_cmd_list sim_cmds = ZI;
sim_cmds_decode(scratch.arena, host_events, &sim_cmds);
@ -526,20 +523,20 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
for (struct sim_cmd *cmd = sim_cmds.first; cmd; cmd = cmd->next) {
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->world, channel_id);
struct sim_client *client = sim_client_from_channel_id(world, channel_id);
if (!client->valid && kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id)) {
client = sim_client_alloc(ctx->world, channel_id);
client = sim_client_alloc(world, channel_id);
}
}
/* Split cmds by client */
client_cmds = arena_push_array_zero(scratch.arena, struct sim_cmd_list, ctx->world->num_clients_reserved);
client_cmds = arena_push_array_zero(scratch.arena, struct sim_cmd_list, world->num_clients_reserved);
{
struct sim_cmd *cmd = sim_cmds.first;
while (cmd) {
struct sim_cmd *next = cmd->next;
struct host_channel_id channel_id = cmd->channel_id;
struct sim_client *client = sim_client_from_channel_id(ctx->world, channel_id);
struct sim_client *client = sim_client_from_channel_id(world, channel_id);
if (client->valid) {
struct sim_cmd_list *cmd_list = &client_cmds[client->handle.idx];
if (cmd_list->last) {
@ -560,9 +557,9 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* ========================== */
/* Process client cmds */
ctx->oldest_client_ack_tick = ctx->world->tick;
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
struct sim_client *client = &ctx->world->clients[i];
u64 oldest_client_ack_tick = world->tick;
for (u64 i = 0; i < world->num_clients_reserved; ++i) {
struct sim_client *client = &world->clients[i];
if (client->valid) {
struct host_channel_id channel_id = client->channel_id;
struct sim_cmd_list cmds = client_cmds[client->handle.idx];
@ -626,7 +623,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
/* Clear level */
case SIM_CMD_KIND_CLEAR_ALL:
{
test_clear_level(ctx);
test_clear_level(world);
} break;
/* Spawn test */
@ -636,14 +633,14 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
u32 count = 1;
f32 spread = 1;
for (u32 j = 0; j < count; ++j) {
spawn_test_entities(ctx, V2(0, (((f32)j / (f32)count) - 0.5) * spread));
spawn_test_entities(world, V2(0, (((f32)j / (f32)count) - 0.5) * spread));
}
} break;
/* Disconnect client */
case SIM_CMD_KIND_SIM_CLIENT_DISCONNECT:
{
host_queue_disconnect(ctx->host, channel_id);
host_queue_disconnect(host, channel_id);
sim_client_release(client);
} break;
@ -651,8 +648,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
};
}
if (client->ack_tick < ctx->oldest_client_ack_tick || ctx->oldest_client_ack_tick == 0) {
ctx->oldest_client_ack_tick = client->ack_tick;
if (client->ack_tick < oldest_client_ack_tick || oldest_client_ack_tick == 0) {
oldest_client_ack_tick = client->ack_tick;
}
}
}
@ -661,21 +658,20 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Create client ents
* ========================== */
ctx->oldest_client_ack_tick = ctx->world->tick;
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
struct sim_client *client = &ctx->world->clients[i];
for (u64 i = 0; i < world->num_clients_reserved; ++i) {
struct sim_client *client = &world->clients[i];
if (client->valid) {
/* FIXME: Ents never released when client disconnects */
struct sim_ent *player_ent = sim_ent_from_handle(ctx->world, client->control_ent);
struct sim_ent *player_ent = sim_ent_from_handle(world, client->control_ent);
if (!player_ent->valid) {
player_ent = spawn_test_player(ctx);
player_ent = spawn_test_player(world);
sim_ent_enable_prop(player_ent, SIM_ENT_PROP_CONTROLLED);
client->control_ent = player_ent->handle;
player_ent->controlling_client = client->handle;
}
struct sim_ent *camera_ent = sim_ent_from_handle(ctx->world, client->camera_ent);
struct sim_ent *camera_ent = sim_ent_from_handle(world, client->camera_ent);
if (!camera_ent->valid) {
camera_ent = spawn_test_player_camera(ctx, player_ent);
camera_ent = spawn_test_player_camera(world, player_ent);
client->camera_ent = camera_ent->handle;
}
}
@ -685,12 +681,12 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Update entity control from client control
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
struct sim_client *client = sim_client_from_handle(ctx->world, ent->controlling_client);
struct sim_client *client = sim_client_from_handle(world, ent->controlling_client);
if (client->valid) {
ent->control = client->control;
/* TODO: Move this */
@ -707,8 +703,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Update entities from sprite
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (sprite_tag_is_nil(ent->sprite)) continue;
@ -802,12 +798,12 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Update attachments
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ATTACHED)) continue;
struct sim_ent *parent = sim_ent_from_handle(ctx->world, ent->parent);
struct sim_ent *parent = sim_ent_from_handle(world, ent->parent);
struct sprite_tag parent_sprite = parent->sprite;
struct sprite_sheet *parent_sheet = sprite_sheet_from_tag_await(sprite_frame_scope, parent_sprite);
@ -828,8 +824,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* ========================== */
#if 0
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TEST)) continue;
@ -878,12 +874,12 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Trigger equipped
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERING_EQUIPPED)) {
struct sim_ent *eq = sim_ent_from_handle(ctx->world, ent->equipped);
struct sim_ent *eq = sim_ent_from_handle(world, ent->equipped);
if (sim_ent_is_valid_and_active(eq)) {
sim_ent_enable_prop(eq, SIM_ENT_PROP_TRIGGERED_THIS_TICK);
}
@ -894,13 +890,13 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Process triggered entities
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERED_THIS_TICK)) continue;
if ((sim_time - ent->last_triggered < ent->trigger_delay) && ent->last_triggered != 0) continue;
if ((world_time - ent->last_triggered < ent->trigger_delay) && ent->last_triggered != 0) continue;
ent->last_triggered = sim_time;
ent->last_triggered = world_time;
/* Fire weapon */
if (sim_ent_has_prop(ent, SIM_ENT_PROP_WEAPON)) {
@ -958,12 +954,12 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Create motor joints from control move
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
struct sim_ent *joint_ent = sim_ent_from_handle(ctx->world, ent->move_joint);
struct sim_ent *joint_ent = sim_ent_from_handle(world, ent->move_joint);
if (!sim_ent_is_valid_and_active(joint_ent)) {
joint_ent = sim_ent_alloc(root);
joint_ent->mass_unscaled = F32_INFINITY;
@ -991,8 +987,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* ========================== */
#if SIM_PLAYER_AIM
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTROLLED)) {
@ -1000,7 +996,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
struct xform sprite_xf = xform_mul(xf, ent->sprite_local_xform);
/* Retrieve / create aim joint */
struct sim_ent *joint_ent = sim_ent_from_handle(ctx->world, ent->aim_joint);
struct sim_ent *joint_ent = sim_ent_from_handle(world, ent->aim_joint);
if (!sim_ent_is_valid_and_active(joint_ent)) {
joint_ent = sim_ent_alloc(root);
joint_ent->mass_unscaled = F32_INFINITY;
@ -1083,12 +1079,12 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Create motor joints from ground friction (gravity)
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
struct sim_ent *joint_ent = sim_ent_from_handle(ctx->world, ent->ground_friction_joint);
struct sim_ent *joint_ent = sim_ent_from_handle(world, ent->ground_friction_joint);
struct phys_motor_joint_def def = ZI;
def.e0 = root->handle;
@ -1111,15 +1107,15 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Create mouse joints from client debug drag
* ========================== */
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
struct sim_client *client = &ctx->world->clients[i];
for (u64 i = 0; i < world->num_clients_reserved; ++i) {
struct sim_client *client = &world->clients[i];
if (client->valid) {
struct v2 cursor = client->cursor_pos;
b32 start_dragging = client->dbg_drag_start;
b32 stop_dragging = client->dbg_drag_stop;
struct sim_ent *joint_ent = sim_ent_from_handle(ctx->world, client->dbg_drag_joint_ent);
struct sim_ent *target_ent = sim_ent_from_handle(ctx->world, joint_ent->mouse_joint_data.target);
struct sim_ent *joint_ent = sim_ent_from_handle(world, client->dbg_drag_joint_ent);
struct sim_ent *target_ent = sim_ent_from_handle(world, joint_ent->mouse_joint_data.target);
if (start_dragging) {
struct xform mouse_xf = xform_from_pos(cursor);
@ -1127,8 +1123,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
mouse_shape.points[0] = V2(0, 0);
mouse_shape.count = 1;
for (u64 sim_ent_index = 0; sim_ent_index < ctx->world->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *ent = &ctx->world->ents[sim_ent_index];
for (u64 sim_ent_index = 0; sim_ent_index < world->num_ents_reserved; ++sim_ent_index) {
struct sim_ent *ent = &world->ents[sim_ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_PHYSICAL_DYNAMIC)) continue;
@ -1183,25 +1179,19 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
{
struct phys_ctx phys = ZI;
phys.ss = ctx->world;
phys.space = space;
phys.contact_lookup = &ctx->contact_lookup;
phys.ss = world;
phys.pre_solve_callback = on_collision;
phys.pre_solve_callback_udata = ctx;
#if COLLIDER_DEBUG
phys.debug_lookup = &ctx->collision_debug_lookup;
#endif
/* Step */
ctx->last_phys_iteration = phys_step(&phys, world_dt, ctx->last_phys_iteration);
phys_step(&phys, world_dt);
}
/* ========================== *
* Update tracers
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TRACER)) continue;
@ -1224,13 +1214,13 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Initialize bullet kinematics from sources
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_BULLET)) continue;
if (ent->activation_tick == ctx->world->tick) {
struct sim_ent *src = sim_ent_from_handle(ctx->world, ent->bullet_src);
if (ent->activation_tick == world->tick) {
struct sim_ent *src = sim_ent_from_handle(world, ent->bullet_src);
struct xform src_xf = sim_ent_get_xform(src);
struct v2 pos = xform_mul_v2(src_xf, ent->bullet_src_pos);
@ -1241,7 +1231,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
/* Add shooter velocity to bullet */
{
/* TODO: Add angular velocity as well? */
struct sim_ent *top = sim_ent_from_handle(ctx->world, src->top);
struct sim_ent *top = sim_ent_from_handle(world, src->top);
impulse = v2_add(impulse, v2_mul(top->linear_velocity, dt));
}
#endif
@ -1253,7 +1243,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
sim_ent_apply_linear_impulse_to_center(ent, impulse);
/* Initialize tracer */
struct sim_ent *tracer = sim_ent_from_handle(ctx->world, ent->bullet_tracer);
struct sim_ent *tracer = sim_ent_from_handle(world, ent->bullet_tracer);
if (sim_ent_is_valid_and_active(tracer)) {
sim_ent_set_xform(tracer, xf);
sim_ent_enable_prop(tracer, SIM_ENT_PROP_PHYSICAL_KINEMATIC);
@ -1279,8 +1269,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Update cameras
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_CAMERA)) continue;
@ -1288,7 +1278,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
/* Camera follow */
{
struct sim_ent *follow = sim_ent_from_handle(ctx->world, ent->camera_follow);
struct sim_ent *follow = sim_ent_from_handle(world, ent->camera_follow);
f32 aspect_ratio = 1.0;
{
@ -1320,8 +1310,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
{
/* TODO: Update based on distance to quake */
ent->shake = 0;
for (u64 quake_ent_index = 0; quake_ent_index < ctx->world->num_ents_reserved; ++quake_ent_index) {
struct sim_ent *quake = &ctx->world->ents[quake_ent_index];
for (u64 quake_ent_index = 0; quake_ent_index < world->num_ents_reserved; ++quake_ent_index) {
struct sim_ent *quake = &world->ents[quake_ent_index];
if (!sim_ent_is_valid_and_active(quake)) continue;
if (!sim_ent_has_prop(quake, SIM_ENT_PROP_QUAKE)) continue;
ent->shake += quake->quake_intensity;
@ -1335,8 +1325,8 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Update quakes
* ========================== */
for (u64 ent_index = 0; ent_index < ctx->world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &ctx->world->ents[ent_index];
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
struct sim_ent *ent = &world->ents[ent_index];
if (!sim_ent_is_valid_and_active(ent)) continue;
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_QUAKE)) continue;
@ -1363,7 +1353,7 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
--stack_count;
i32 parent_layer = parent->final_layer;
for (struct sim_ent *child = sim_ent_from_handle(ctx->world, parent->first); child->valid; child = sim_ent_from_handle(ctx->world, child->next)) {
for (struct sim_ent *child = sim_ent_from_handle(world, parent->first); child->valid; child = sim_ent_from_handle(world, child->next)) {
if (sim_ent_is_valid_and_active(child)) {
child->final_layer = parent_layer + child->layer;
*arena_push(temp.arena, struct sim_ent *) = child;
@ -1379,21 +1369,21 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
* Release entities
* ========================== */
release_entities_with_prop(ctx, SIM_ENT_PROP_RELEASE_THIS_TICK);
release_entities_with_prop(world, SIM_ENT_PROP_RELEASE_THIS_TICK);
/* ========================== *
* Publish tick
* ========================== */
for (u64 i = 0; i < ctx->world->num_clients_reserved; ++i) {
struct sim_client *client = &ctx->world->clients[i];
for (u64 i = 0; i < world->num_clients_reserved; ++i) {
struct sim_client *client = &world->clients[i];
if (client->valid) {
struct temp_arena temp = arena_temp_begin(scratch.arena);
u64 ss0_tick = client->ack_tick;
u64 ss1_tick = ctx->world->tick;
struct sim_snapshot *ss0 = sim_snapshot_from_tick(ctx->snapshot_store, ss0_tick);
struct sim_snapshot *ss1 = ctx->world;
u64 ss1_tick = world->tick;
struct sim_snapshot *ss0 = sim_snapshot_from_tick(snapshot_store, ss0_tick);
struct sim_snapshot *ss1 = world;
ss0_tick = ss0->tick; /* In case ack tick is no longer in store we need to do a full resend */
struct sim_event_list l = ZI;
@ -1402,12 +1392,12 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
/* Create & encode snapshot event */
{
snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT;
snapshot_event.tick = ctx->world->tick;
snapshot_event.tick = world->tick;
snapshot_event.snapshot_tick_start = ss0_tick;
snapshot_event.snapshot_tick_end = ss1_tick;
{
struct bitbuff_writer bw = bw_from_bitbuff(&ctx->encoder_bitbuff);
struct bitbuff_writer bw = bw_from_bitbuff(encoder_bitbuff);
sim_snapshot_encode(&bw, ss0, ss1, client);
snapshot_event.snapshot_encoded = bw_get_written(temp.arena, &bw);
}
@ -1423,18 +1413,18 @@ void sim_update(struct sim_ctx *ctx, i64 target_dt_ns)
/* Encode events */
struct string events_msg = ZI;
{
struct bitbuff_writer bw = bw_from_bitbuff(&ctx->encoder_bitbuff);
struct bitbuff_writer bw = bw_from_bitbuff(encoder_bitbuff);
sim_events_encode(&bw, l);
events_msg = bw_get_written(temp.arena, &bw);
}
host_queue_write(ctx->host, client->channel_id, events_msg, 0);
host_queue_write(host, client->channel_id, events_msg, 0);
arena_temp_end(temp);
}
}
host_update(ctx->host);
host_update(host);
__profframe("Sim");
/* ========================== *

View File

@ -122,6 +122,7 @@ struct sim_event_list {
* Ctx
* ========================== */
#if 0
struct sim_ctx {
struct arena arena;
@ -162,8 +163,12 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
u16 host_port);
void sim_ctx_release(struct sim_ctx *ctx);
#endif
void sim_update(struct sim_ctx *ctx, i64 target_dt_ns);
struct host;
struct bitbuff;
struct sim_snapshot;
void sim_step(struct host *host, struct bitbuff *encoder_bitbuff, struct sim_snapshot_store *snapshot_store, struct sim_snapshot *prev_snapshot, i64 real_dt_ns, struct sim_cmd_list user_sim_cmds);
/* ========================== *
* Event & cmd encode/decode

View File

@ -4,6 +4,16 @@
#include "sim_ent.h"
#include "sim_client.h"
/* TODO: Remove this */
struct space;
struct sim_snapshot_store {
b32 valid;
struct arena arena;
@ -32,6 +42,49 @@ struct sim_snapshot {
struct arena arena;
/* FIXME: Remove this */
struct space *space;
/* FIXME: Encode / decode*/
u64 phys_iteration;
/* This is the oldest tick stored in ctx that we need to hold a reference to for delta encoding */
u64 oldest_client_ack_tick;
/* Bookkeeping structures */
/* TODO: Store in snapshot for determinism */
struct sim_ent_lookup contact_lookup;
#if COLLIDER_DEBUG
struct sim_ent_lookup collision_debug_lookup;
#endif
/* Real time (increases with clock assuming no lag) */
i64 real_dt_ns;
i64 real_time_ns;

View File

@ -17,7 +17,7 @@ struct space_entry {
};
/* Links a cell to a entry.
* Acts as both a list of entries contained by cell & a list of cells containing entry. */
* Acts as both a node in the list of entries contained by the cell, and a node in the list of cells containing the entry. */
struct space_cell_node {
struct space_entry *entry;
struct space_cell *cell;

View File

@ -205,6 +205,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
sys_window_register_event_callback(G.window, &window_event_callback);
/* TODO: Remove this */
#if 0
connect_address_str = STRING(0, 0);
if (connect_address_str.len == 0) {
G.local_sim_ctx = sim_ctx_alloc(sprite_sr, phys_sr, host_sr, sim_snapshot_sr, 12345);
@ -213,6 +214,9 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
} else {
G.connect_address_str = string_copy(&G.arena, connect_address_str);
}
#else
(UNUSED)connect_address_str;
#endif
G.debug_draw = true;
@ -228,11 +232,18 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(user_shutdown)
atomic_i32_eval_exchange(&G.user_thread_shutdown, true);
sys_thread_wait_release(&G.user_thread);
#if 0
if (G.local_sim_ctx) {
atomic_i32_eval_exchange(&G.local_sim_thread_shutdown, true);
sys_thread_wait_release(&G.local_sim_thread);
sim_ctx_release(G.local_sim_ctx);
}
#else
if (G.local_sim_ctx) {
atomic_i32_eval_exchange(&G.local_sim_thread_shutdown, true);
sys_thread_wait_release(&G.local_sim_thread);
}
#endif
}
/* ========================== *
@ -1743,7 +1754,7 @@ INTERNAL void user_update(void)
}
/* ========================== *
* User thread entry point
* User thread
* ========================== */
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_thread_entry_point, arg)
@ -1762,14 +1773,61 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_thread_entry_point, arg)
}
/* ========================== *
* Local sim thread entry point
* Local sim thread
* ========================== */
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
{
struct host *host = host_alloc(12345);
struct bitbuff encoder_bitbuff = bitbuff_alloc(GIGABYTE(64));
struct sim_snapshot_store *ss_store = sim_snapshot_store_alloc();
struct sim_ctx *ctx = (struct sim_ctx *)arg;
i64 last_tick_ns = 0;
i64 target_dt_ns = NS_FROM_SECONDS(1) / SIM_TICKS_PER_SECOND;;
while (!atomic_i32_eval(&G.local_sim_thread_shutdown)) {
sim_update(ctx, target_dt_ns);
{
__profscope(local_sim_sleep);
sleep_frame(last_tick_ns, target_dt_ns);
last_tick_ns = sys_time_ns();
}
struct temp_arena scratch = scratch_begin_no_conflict();
/* Copy user sim cmds */
struct sim_cmd_list user_sim_cmds = ZI;
{
struct sys_lock lock = sys_mutex_lock_s(&G.user_sim_cmds_arena);
for (struct sim_cmd *cmd = G.user_sim_cmds.first; cmd; cmd = cmd->next) {
struct sim_cmd *dst = arena_push(scratch.arena, struct sim_cmd);
*dst = *cmd;
dst->next = NULL;
if (user_sim_cmds.last) {
user_sim_cmds.last->next = dst;
} else {
user_sim_cmds.first = dst;
}
user_sim_cmds.last = dst;
}
sys_mutex_unlock(&lock);
}
sim_step(host, &encoder_bitbuff, snapshot_store, snapshot, target_dt_ns, user_sim_cmds);
scratch_end(scratch);
}
sim_snapshot_store_release(ss_store);
bitbuff_release(&encoder_bitbuff);
host_release(host);
}