sim ctx decoupling progress
This commit is contained in:
parent
3204e97dcf
commit
8e5b2bd773
4
build.c
4
build.c
@ -581,12 +581,14 @@ void OnBuild(StringList cli_args)
|
|||||||
OS_Exit(1);
|
OS_Exit(1);
|
||||||
}
|
}
|
||||||
StringListAppend(&perm, &compile_args, Lit("-DPROFILING=1"));
|
StringListAppend(&perm, &compile_args, Lit("-DPROFILING=1"));
|
||||||
|
|
||||||
/* Tracy flags */
|
/* Tracy flags */
|
||||||
StringListAppend(&perm, &compile_args, Lit("-DTRACY_ENABLE=1"));
|
StringListAppend(&perm, &compile_args, Lit("-DTRACY_ENABLE=1"));
|
||||||
if (!arg_profiler_sampling) {
|
if (!arg_profiler_sampling) {
|
||||||
StringListAppend(&perm, &compile_args, Lit("-DTRACY_NO_SAMPLING -DTRACY_NO_SYSTEM_TRACING -DTRACY_NO_CALLSTACK"));
|
StringListAppend(&perm, &compile_args, Lit("-DTRACY_NO_SAMPLING -DTRACY_NO_SYSTEM_TRACING -DTRACY_NO_CALLSTACK"));
|
||||||
}
|
}
|
||||||
/* Disable compile_warnings when compiling tracy client */
|
|
||||||
|
/* Disable compiler warnings when compiling tracy client */
|
||||||
compile_warnings = (StringList) { 0 };
|
compile_warnings = (StringList) { 0 };
|
||||||
link_warnings = (StringList) { 0 };
|
link_warnings = (StringList) { 0 };
|
||||||
StringListAppend(&perm, &compile_warnings, Lit("-Wno-everything"));
|
StringListAppend(&perm, &compile_warnings, Lit("-Wno-everything"));
|
||||||
|
|||||||
@ -33,7 +33,7 @@
|
|||||||
#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_TICKS_PER_SECOND 100.0
|
#define SIM_TICKS_PER_SECOND 50.0
|
||||||
#define SIM_TIMESCALE 1
|
#define SIM_TIMESCALE 1
|
||||||
|
|
||||||
#define SIM_PHYSICS_SUBSTEPS 4
|
#define SIM_PHYSICS_SUBSTEPS 4
|
||||||
|
|||||||
12
src/phys.c
12
src/phys.c
@ -45,10 +45,10 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a
|
|||||||
struct phys_collision_data_array res = ZI;
|
struct phys_collision_data_array res = ZI;
|
||||||
res.a = arena_dry_push(arena, struct phys_collision_data);
|
res.a = arena_dry_push(arena, struct phys_collision_data);
|
||||||
struct sim_snapshot *ss = ctx->ss;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
struct sim_ent_lookup *contact_lookup = &ss->contact_lookup;
|
struct space *space = ctx->space;
|
||||||
struct space *space = ss->space;
|
struct sim_ent_lookup *contact_lookup = ctx->contact_lookup;
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
struct sim_ent_lookup *debug_lookup = &ss->collision_debug_lookup;
|
struct sim_ent_lookup *debug_lookup = ctx->collision_debug_lookup;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct sim_ent *root = sim_ent_from_handle(ss, SIM_ENT_ROOT_HANDLE);
|
struct sim_ent *root = sim_ent_from_handle(ss, SIM_ENT_ROOT_HANDLE);
|
||||||
@ -284,7 +284,7 @@ void phys_prepare_contacts(struct phys_ctx *ctx, u64 phys_iteration)
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_snapshot *ss = ctx->ss;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
struct sim_ent_lookup *contact_lookup = &ss->contact_lookup;
|
struct sim_ent_lookup *contact_lookup = ctx->contact_lookup;
|
||||||
|
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
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];
|
struct sim_ent *constraint_ent = &ss->ents[sim_ent_index];
|
||||||
@ -1003,7 +1003,7 @@ f32 phys_determine_earliest_toi_for_bullets(struct phys_ctx *ctx, f32 step_dt, f
|
|||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct sim_snapshot *ss = ctx->ss;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
struct space *space = ss->space;
|
struct space *space = ctx->space;
|
||||||
f32 smallest_t = 1;
|
f32 smallest_t = 1;
|
||||||
|
|
||||||
for (u64 e0_index = 0; e0_index < ss->num_ents_reserved; ++e0_index) {
|
for (u64 e0_index = 0; e0_index < ss->num_ents_reserved; ++e0_index) {
|
||||||
@ -1053,7 +1053,7 @@ f32 phys_determine_earliest_toi_for_bullets(struct phys_ctx *ctx, f32 step_dt, f
|
|||||||
void phys_update_aabbs(struct phys_ctx *ctx)
|
void phys_update_aabbs(struct phys_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct sim_snapshot *ss = ctx->ss;
|
struct sim_snapshot *ss = ctx->ss;
|
||||||
struct space *space = ss->space;
|
struct space *space = ctx->space;
|
||||||
for (u64 sim_ent_index = 0; sim_ent_index < ss->num_ents_reserved; ++sim_ent_index) {
|
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];
|
struct sim_ent *ent = &ss->ents[sim_ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
|
|||||||
@ -33,6 +33,12 @@ struct phys_ctx {
|
|||||||
struct sim_snapshot *ss;
|
struct sim_snapshot *ss;
|
||||||
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;
|
||||||
|
|
||||||
|
struct space *space;
|
||||||
|
struct sim_ent_lookup *contact_lookup;
|
||||||
|
#if COLLIDER_DEBUG
|
||||||
|
struct sim_ent_lookup *collision_debug_lookup;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
174
src/sim.c
174
src/sim.c
@ -52,7 +52,7 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr,
|
|||||||
|
|
||||||
/* Create snapshot store */
|
/* Create snapshot store */
|
||||||
snapshot_store = sim_snapshot_store_alloc();
|
snapshot_store = sim_snapshot_store_alloc();
|
||||||
world = sim_snapshot_nil();
|
ss_blended = sim_snapshot_nil();
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
@ -277,15 +277,16 @@ INTERNAL void test_clear_level(struct sim_snapshot *world)
|
|||||||
* Release entities
|
* Release entities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
INTERNAL void release_entities_with_prop(struct sim_snapshot *world, enum sim_ent_prop prop)
|
#if 0
|
||||||
|
INTERNAL void release_entities_with_prop(struct sim_snapshot *ss_blended, enum sim_ent_prop prop)
|
||||||
{
|
{
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
struct space *space = world->space;
|
struct space *space = ss_blended->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;
|
||||||
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ss_blended->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &world->ents[ent_index];
|
struct sim_ent *ent = &ss_blended->ents[ent_index];
|
||||||
if (ent->valid && sim_ent_has_prop(ent, prop)) {
|
if (ent->valid && sim_ent_has_prop(ent, prop)) {
|
||||||
*arena_push(scratch.arena, struct sim_ent *) = ent;
|
*arena_push(scratch.arena, struct sim_ent *) = ent;
|
||||||
++ents_to_release_count;
|
++ents_to_release_count;
|
||||||
@ -316,6 +317,34 @@ INTERNAL void release_entities_with_prop(struct sim_snapshot *world, enum sim_en
|
|||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
INTERNAL void release_entities_with_prop(struct sim_snapshot *world, enum sim_ent_prop prop)
|
||||||
|
{
|
||||||
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
|
|
||||||
|
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 < 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release from snapshot */
|
||||||
|
/* TODO: Breadth first iteration to only release parent entities (since
|
||||||
|
* child entities will be released along with parent anyway) */
|
||||||
|
for (u64 i = 0; i < ents_to_release_count; ++i) {
|
||||||
|
struct sim_ent *ent = ents_to_release[i];
|
||||||
|
if (ent->is_top && !ent->is_root) {
|
||||||
|
sim_ent_release(ent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Respond to physics collisions
|
* Respond to physics collisions
|
||||||
@ -423,7 +452,7 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
|||||||
/* Release old snapshots */
|
/* Release old snapshots */
|
||||||
{
|
{
|
||||||
/* TODO: Something better */
|
/* TODO: Something better */
|
||||||
i64 release_tick = (i64)world->tick - 25; /* Arbitrary tick offset */
|
i64 release_tick = (i64)ss_blended->tick - 25; /* Arbitrary tick offset */
|
||||||
if (release_tick > 0) {
|
if (release_tick > 0) {
|
||||||
struct sim_snapshot *old = sim_snapshot_from_tick(snapshot_store, release_tick);
|
struct sim_snapshot *old = sim_snapshot_from_tick(snapshot_store, release_tick);
|
||||||
if (old->valid) {
|
if (old->valid) {
|
||||||
@ -438,14 +467,36 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
|||||||
|
|
||||||
|
|
||||||
/* TODO: Remove this */
|
/* TODO: Remove this */
|
||||||
world->space = prev_snapshot->space;
|
|
||||||
world->contact_lookup = prev_snapshot->contact_lookup;
|
/* Acceleration structures */
|
||||||
if (!world->space) {
|
struct space *space = space_alloc(1, 256);
|
||||||
world->space = space_alloc(1, 256);
|
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;
|
||||||
|
|
||||||
|
MEMZERO_STRUCT(&ent->space_handle);
|
||||||
}
|
}
|
||||||
if (!world->contact_lookup.arena.base) {
|
|
||||||
world->contact_lookup = sim_ent_lookup_alloc(4096);
|
#if COLLIDER_DEBUG
|
||||||
|
struct sim_ent_lookup collision_debug_lookup = sim_ent_lookup_alloc(4096);
|
||||||
|
#endif
|
||||||
|
struct sim_ent_lookup contact_lookup = sim_ent_lookup_alloc(4096);
|
||||||
|
for (u64 sim_ent_index = 0; sim_ent_index < world->num_ents_reserved; ++sim_ent_index) {
|
||||||
|
struct sim_ent *constraint_ent = &world->ents[sim_ent_index];
|
||||||
|
if (!sim_ent_is_valid_and_active(constraint_ent)) continue;
|
||||||
|
if (!sim_ent_has_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) continue;
|
||||||
|
|
||||||
|
struct sim_ent_lookup_key key = sim_ent_lookup_key_from_two_handles(constraint_ent->contact_constraint_data.e0, constraint_ent->contact_constraint_data.e1);
|
||||||
|
sim_ent_lookup_set(&contact_lookup, key, constraint_ent->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
world->phys_iteration = prev_snapshot->phys_iteration;
|
world->phys_iteration = prev_snapshot->phys_iteration;
|
||||||
|
|
||||||
|
|
||||||
@ -539,14 +590,22 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
|||||||
{
|
{
|
||||||
/* Create connecting clients */
|
/* Create connecting clients */
|
||||||
for (struct sim_cmd_frame *frame = input_frames.first; frame; frame = frame->next) {
|
for (struct sim_cmd_frame *frame = input_frames.first; frame; frame = frame->next) {
|
||||||
struct host_channel_id channel_id = frame->channel;
|
struct sim_client *client;
|
||||||
struct sim_client *client = sim_client_from_channel_id(world, channel_id);
|
if (frame->sender_is_local) {
|
||||||
if (!client->valid) {
|
client = sim_client_from_handle(world, world->local_client);
|
||||||
for (struct sim_cmd *cmd = frame->first; cmd; cmd = cmd->next) {
|
if (!client->valid) {
|
||||||
enum sim_cmd_kind kind = cmd->kind;
|
client = sim_client_alloc(world, HOST_CHANNEL_ID_NIL, SIM_CLIENT_KIND_LOCAL);
|
||||||
if (kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id)) {
|
world->local_client = client->handle;
|
||||||
client = sim_client_alloc(world, channel_id);
|
}
|
||||||
break;
|
} else {
|
||||||
|
client = sim_client_from_channel_id(world, frame->sender_channel);
|
||||||
|
if (!client->valid) {
|
||||||
|
for (struct sim_cmd *cmd = frame->first; cmd; cmd = cmd->next) {
|
||||||
|
enum sim_cmd_kind kind = cmd->kind;
|
||||||
|
if (kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(frame->sender_channel)) {
|
||||||
|
client = sim_client_alloc(world, frame->sender_channel, SIM_CLIENT_KIND_NETSIM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -554,7 +613,12 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
|||||||
/* Sort cmd frames by client */
|
/* Sort cmd frames by client */
|
||||||
client_frames = arena_push_array_zero(scratch.arena, struct sim_cmd_frame *, world->num_clients_reserved);
|
client_frames = arena_push_array_zero(scratch.arena, struct sim_cmd_frame *, world->num_clients_reserved);
|
||||||
for (struct sim_cmd_frame *frame = input_frames.first; frame; frame = frame->next) {
|
for (struct sim_cmd_frame *frame = input_frames.first; frame; frame = frame->next) {
|
||||||
struct sim_client *client = sim_client_from_channel_id(world, frame->channel);
|
struct sim_client *client;
|
||||||
|
if (frame->sender_is_local) {
|
||||||
|
client = sim_client_from_handle(world, world->local_client);
|
||||||
|
} else {
|
||||||
|
client = sim_client_from_channel_id(world, frame->sender_channel);
|
||||||
|
}
|
||||||
if (client->valid && frame->tick == world->tick) {
|
if (client->valid && frame->tick == world->tick) {
|
||||||
client_frames[client->handle.idx] = frame;
|
client_frames[client->handle.idx] = frame;
|
||||||
}
|
}
|
||||||
@ -694,25 +758,30 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
|||||||
/* Update animation */
|
/* Update animation */
|
||||||
{
|
{
|
||||||
struct sprite_sheet_span span = sprite_sheet_get_span(sheet, ent->sprite_span_name);
|
struct sprite_sheet_span span = sprite_sheet_get_span(sheet, ent->sprite_span_name);
|
||||||
|
if (ent->animation_last_frame_change_time_ns == 0) {
|
||||||
|
ent->animation_last_frame_change_time_ns = world_time;
|
||||||
|
}
|
||||||
|
|
||||||
f64 time_in_frame = ent->animation_time_in_frame + world_dt;
|
f64 time_in_frame = SECONDS_FROM_NS(world->world_time_ns - ent->animation_last_frame_change_time_ns);
|
||||||
u64 frame_index = ent->animation_frame;
|
u64 frame_index = ent->animation_frame;
|
||||||
if (frame_index < span.start || frame_index > span.end) {
|
if (frame_index < span.start || frame_index > span.end) {
|
||||||
frame_index = span.start;
|
frame_index = span.start;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sprite_sheet_frame frame = sprite_sheet_get_frame(sheet, frame_index);
|
if (span.end > span.start + 1) {
|
||||||
while (time_in_frame > frame.duration) {
|
struct sprite_sheet_frame frame = sprite_sheet_get_frame(sheet, frame_index);
|
||||||
time_in_frame -= frame.duration;
|
while (time_in_frame > frame.duration) {
|
||||||
++frame_index;
|
time_in_frame -= frame.duration;
|
||||||
if (frame_index > span.end) {
|
++frame_index;
|
||||||
/* Loop animation */
|
if (frame_index > span.end) {
|
||||||
frame_index = span.start;
|
/* Loop animation */
|
||||||
|
frame_index = span.start;
|
||||||
|
}
|
||||||
|
frame = sprite_sheet_get_frame(sheet, frame_index);
|
||||||
|
ent->animation_last_frame_change_time_ns = world->world_time_ns;
|
||||||
}
|
}
|
||||||
frame = sprite_sheet_get_frame(sheet, frame_index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ent->animation_time_in_frame = time_in_frame;
|
|
||||||
ent->animation_frame = frame_index;
|
ent->animation_frame = frame_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,8 +874,8 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
|||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < ss_blended->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &world->ents[ent_index];
|
struct sim_ent *ent = &ss_blended->ents[ent_index];
|
||||||
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_TEST)) continue;
|
if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TEST)) continue;
|
||||||
|
|
||||||
@ -1162,6 +1231,11 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
|||||||
struct phys_ctx phys = ZI;
|
struct phys_ctx phys = ZI;
|
||||||
phys.ss = world;
|
phys.ss = world;
|
||||||
phys.pre_solve_callback = on_collision;
|
phys.pre_solve_callback = on_collision;
|
||||||
|
phys.space = space;
|
||||||
|
phys.contact_lookup = &contact_lookup;
|
||||||
|
#if COLLIDER_DEBUG
|
||||||
|
phys.collision_debug_lookup = collision_debug_lookup;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Step */
|
/* Step */
|
||||||
phys_step(&phys, world_dt);
|
phys_step(&phys, world_dt);
|
||||||
@ -1212,7 +1286,7 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
|||||||
/* Add shooter velocity to bullet */
|
/* Add shooter velocity to bullet */
|
||||||
{
|
{
|
||||||
/* TODO: Add angular velocity as well? */
|
/* TODO: Add angular velocity as well? */
|
||||||
struct sim_ent *top = sim_ent_from_handle(world, src->top);
|
struct sim_ent *top = sim_ent_from_handle(ss_blended, src->top);
|
||||||
impulse = v2_add(impulse, v2_mul(top->linear_velocity, dt));
|
impulse = v2_add(impulse, v2_mul(top->linear_velocity, dt));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1358,19 +1432,19 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
|||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
struct sim_cmd_queue_list output_cmds = ZI;
|
struct sim_cmd_queue_list output_cmds = ZI;
|
||||||
for (u64 i = 0; i < world->num_clients_reserved; ++i) {
|
for (u64 i = 0; i < ss_blended->num_clients_reserved; ++i) {
|
||||||
struct sim_client *client = &world->clients[i];
|
struct sim_client *client = &ss_blended->clients[i];
|
||||||
if (client->valid) {
|
if (client->valid) {
|
||||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||||
|
|
||||||
struct sim_snapshot *ss0 = sim_snapshot_from_tick(snapshot_store, client->ack);
|
struct sim_snapshot *ss0 = sim_snapshot_from_tick(snapshot_store, client->ack);
|
||||||
struct sim_snapshot *ss1 = world;
|
struct sim_snapshot *ss1 = ss_blended;
|
||||||
|
|
||||||
/* Create & encode snapshot cmd */
|
/* Create & encode snapshot cmd */
|
||||||
{
|
{
|
||||||
struct sim_cmd *cmd = arena_push(arena, struct sim_cmd);
|
struct sim_cmd *cmd = arena_push(arena, struct sim_cmd);
|
||||||
cmd->kind = SIM_CMD_KIND_SNAPSHOT;
|
cmd->kind = SIM_CMD_KIND_SNAPSHOT;
|
||||||
cmd->tick = world->tick;
|
cmd->tick = ss_blended->tick;
|
||||||
cmd->snapshot_tick_start = ss0->tick;
|
cmd->snapshot_tick_start = ss0->tick;
|
||||||
cmd->snapshot_tick_end = ss1->tick;
|
cmd->snapshot_tick_end = ss1->tick;
|
||||||
|
|
||||||
@ -1404,11 +1478,27 @@ struct sim_snapshot *sim_step(struct sim_snapshot_store *snapshot_store, struct
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* End frame cache scopes
|
* End frame
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: Remove this */
|
||||||
|
#if COLLIDER_DEBUG
|
||||||
|
sim_ent_lookup_release(&collision_debug_lookup);
|
||||||
|
#endif
|
||||||
|
sim_ent_lookup_release(&contact_lookup);
|
||||||
|
space_release(space);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sprite_scope_end(sprite_frame_scope);
|
sprite_scope_end(sprite_frame_scope);
|
||||||
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
@ -1472,7 +1562,7 @@ void sim_cmd_frames_decode(struct arena *arena, struct host_event_array host_eve
|
|||||||
{
|
{
|
||||||
/* Create a stand-alone cmd frame for connecting */
|
/* Create a stand-alone cmd frame for connecting */
|
||||||
struct sim_cmd_frame *frame = arena_push_zero(arena, struct sim_cmd_frame);
|
struct sim_cmd_frame *frame = arena_push_zero(arena, struct sim_cmd_frame);
|
||||||
frame->channel = host_event.channel_id;
|
frame->sender_channel = host_event.channel_id;
|
||||||
|
|
||||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||||
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_CONNECT;
|
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_CONNECT;
|
||||||
@ -1492,7 +1582,7 @@ void sim_cmd_frames_decode(struct arena *arena, struct host_event_array host_eve
|
|||||||
{
|
{
|
||||||
/* Create a stand-alone cmd frame for disconnecting */
|
/* Create a stand-alone cmd frame for disconnecting */
|
||||||
struct sim_cmd_frame *frame = arena_push_zero(arena, struct sim_cmd_frame);
|
struct sim_cmd_frame *frame = arena_push_zero(arena, struct sim_cmd_frame);
|
||||||
frame->channel = host_event.channel_id;
|
frame->sender_channel = host_event.channel_id;
|
||||||
|
|
||||||
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
struct sim_cmd *cmd = arena_push_zero(arena, struct sim_cmd);
|
||||||
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_DISCONNECT;
|
cmd->kind = SIM_CMD_KIND_SIM_CLIENT_DISCONNECT;
|
||||||
@ -1515,7 +1605,7 @@ void sim_cmd_frames_decode(struct arena *arena, struct host_event_array host_eve
|
|||||||
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
||||||
|
|
||||||
struct sim_cmd_frame *frame = arena_push_zero(arena, struct sim_cmd_frame);
|
struct sim_cmd_frame *frame = arena_push_zero(arena, struct sim_cmd_frame);
|
||||||
frame->channel = host_event.channel_id;
|
frame->sender_channel = host_event.channel_id;
|
||||||
frame->tick = br_read_uv(&br);
|
frame->tick = br_read_uv(&br);
|
||||||
frame->ack = br_read_uv(&br);
|
frame->ack = br_read_uv(&br);
|
||||||
|
|
||||||
|
|||||||
10
src/sim.h
10
src/sim.h
@ -89,9 +89,11 @@ struct sim_cmd {
|
|||||||
|
|
||||||
/* Represents all cmds generated by a user/sim for a particular channel in a single tick. */
|
/* Represents all cmds generated by a user/sim for a particular channel in a single tick. */
|
||||||
struct sim_cmd_frame {
|
struct sim_cmd_frame {
|
||||||
struct host_channel_id channel; /* Sender's channel id (if this cmd frame was received by a host) */
|
struct host_channel_id sender_channel; /* Sender's channel ID will be nil if sender_is_local = true */
|
||||||
u64 tick; /* Sender's tick (this will always be 0 for user -> local sim cmds) */
|
b32 sender_is_local;
|
||||||
u64 ack; /* Sender's last received cmd frame tick from dst channel */
|
|
||||||
|
u64 tick; /* The tick that this cmd frame is meant to execute on */
|
||||||
|
u64 ack; /* Sender's last received cmd frame tick */
|
||||||
|
|
||||||
struct sim_cmd *first;
|
struct sim_cmd *first;
|
||||||
struct sim_cmd *last;
|
struct sim_cmd *last;
|
||||||
@ -152,7 +154,7 @@ struct sim_ctx {
|
|||||||
|
|
||||||
/* Snapshot */
|
/* Snapshot */
|
||||||
struct sim_snapshot_store *snapshot_store;
|
struct sim_snapshot_store *snapshot_store;
|
||||||
struct sim_snapshot *world;
|
struct sim_snapshot *ss_blended;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO: Get rid of startup receipts */
|
/* TODO: Get rid of startup receipts */
|
||||||
|
|||||||
@ -41,7 +41,7 @@ struct sim_client *sim_client_from_channel_id(struct sim_snapshot *ss, struct ho
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id)
|
struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id, enum sim_client_kind kind)
|
||||||
{
|
{
|
||||||
struct sim_client_handle handle = ZI;
|
struct sim_client_handle handle = ZI;
|
||||||
struct sim_client *client = sim_client_from_handle(ss, ss->first_free_client);
|
struct sim_client *client = sim_client_from_handle(ss, ss->first_free_client);
|
||||||
@ -58,24 +58,28 @@ struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel
|
|||||||
++ss->num_clients_allocated;
|
++ss->num_clients_allocated;
|
||||||
*client = *sim_client_nil();
|
*client = *sim_client_nil();
|
||||||
client->valid = true;
|
client->valid = true;
|
||||||
|
client->kind = kind;
|
||||||
client->handle = handle;
|
client->handle = handle;
|
||||||
|
|
||||||
u64 channel_hash = hash_from_channel_id(channel_id);
|
if (kind == SIM_CLIENT_KIND_NETSIM) {
|
||||||
client->channel_id = channel_id;
|
ASSERT(!host_channel_id_is_nil(channel_id));
|
||||||
client->channel_hash = channel_hash;
|
u64 channel_hash = hash_from_channel_id(channel_id);
|
||||||
|
client->channel_id = channel_id;
|
||||||
|
client->channel_hash = channel_hash;
|
||||||
|
|
||||||
/* Insert into channel lookup */
|
/* Insert into channel lookup */
|
||||||
u64 bucket_index = channel_hash % ss->num_client_lookup_buckets;
|
u64 bucket_index = channel_hash % ss->num_client_lookup_buckets;
|
||||||
struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index];
|
struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index];
|
||||||
{
|
{
|
||||||
struct sim_client *prev_in_bucket = sim_client_from_handle(ss, bucket->last);
|
struct sim_client *prev_in_bucket = sim_client_from_handle(ss, bucket->last);
|
||||||
if (prev_in_bucket->valid) {
|
if (prev_in_bucket->valid) {
|
||||||
prev_in_bucket->next_in_bucket = client->handle;
|
prev_in_bucket->next_in_bucket = client->handle;
|
||||||
client->prev_in_bucket = prev_in_bucket->handle;
|
client->prev_in_bucket = prev_in_bucket->handle;
|
||||||
} else {
|
} else {
|
||||||
bucket->first = client->handle;
|
bucket->first = client->handle;
|
||||||
|
}
|
||||||
|
bucket->last = client->handle;
|
||||||
}
|
}
|
||||||
bucket->last = client->handle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
@ -91,19 +95,21 @@ void sim_client_release(struct sim_client *client)
|
|||||||
--ss->num_clients_allocated;
|
--ss->num_clients_allocated;
|
||||||
|
|
||||||
/* Remove from channel lookup */
|
/* Remove from channel lookup */
|
||||||
u64 bucket_index = client->channel_hash % ss->num_client_lookup_buckets;
|
if (client->kind == SIM_CLIENT_KIND_NETSIM) {
|
||||||
struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index];
|
u64 bucket_index = client->channel_hash % ss->num_client_lookup_buckets;
|
||||||
struct sim_client *prev = sim_client_from_handle(ss, client->prev_in_bucket);
|
struct sim_client_lookup_bucket *bucket = &ss->client_lookup_buckets[bucket_index];
|
||||||
struct sim_client *next = sim_client_from_handle(ss, client->next_in_bucket);
|
struct sim_client *prev = sim_client_from_handle(ss, client->prev_in_bucket);
|
||||||
if (prev->valid) {
|
struct sim_client *next = sim_client_from_handle(ss, client->next_in_bucket);
|
||||||
prev->next_in_bucket = next->handle;
|
if (prev->valid) {
|
||||||
} else {
|
prev->next_in_bucket = next->handle;
|
||||||
bucket->first = next->handle;
|
} else {
|
||||||
}
|
bucket->first = next->handle;
|
||||||
if (next->valid) {
|
}
|
||||||
next->prev_in_bucket = prev->handle;
|
if (next->valid) {
|
||||||
} else {
|
next->prev_in_bucket = prev->handle;
|
||||||
bucket->last = prev->handle;
|
} else {
|
||||||
|
bucket->last = prev->handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,12 @@
|
|||||||
struct sim_client_channel_lookup_bucket;
|
struct sim_client_channel_lookup_bucket;
|
||||||
struct sim_snapshot;
|
struct sim_snapshot;
|
||||||
|
|
||||||
|
enum sim_client_kind {
|
||||||
|
SIM_CLIENT_KIND_INVALID,
|
||||||
|
SIM_CLIENT_KIND_LOCAL,
|
||||||
|
SIM_CLIENT_KIND_NETSIM
|
||||||
|
};
|
||||||
|
|
||||||
struct sim_client_lookup_bucket {
|
struct sim_client_lookup_bucket {
|
||||||
struct sim_client_handle first;
|
struct sim_client_handle first;
|
||||||
struct sim_client_handle last;
|
struct sim_client_handle last;
|
||||||
@ -15,6 +21,7 @@ struct sim_client_lookup_bucket {
|
|||||||
|
|
||||||
struct sim_client {
|
struct sim_client {
|
||||||
b32 valid;
|
b32 valid;
|
||||||
|
enum sim_client_kind kind;
|
||||||
struct sim_client_handle handle;
|
struct sim_client_handle handle;
|
||||||
struct sim_snapshot *ss;
|
struct sim_snapshot *ss;
|
||||||
|
|
||||||
@ -51,7 +58,7 @@ INLINE struct sim_client *sim_client_nil(void)
|
|||||||
|
|
||||||
struct sim_client *sim_client_from_handle(struct sim_snapshot *ss, struct sim_client_handle handle);
|
struct sim_client *sim_client_from_handle(struct sim_snapshot *ss, struct sim_client_handle handle);
|
||||||
struct sim_client *sim_client_from_channel_id(struct sim_snapshot *ss, struct host_channel_id channel_id);
|
struct sim_client *sim_client_from_channel_id(struct sim_snapshot *ss, struct host_channel_id channel_id);
|
||||||
struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id);
|
struct sim_client *sim_client_alloc(struct sim_snapshot *ss, struct host_channel_id channel_id, enum sim_client_kind kind);
|
||||||
void sim_client_release(struct sim_client *client);
|
void sim_client_release(struct sim_client *client);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
@ -464,7 +464,7 @@ void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64
|
|||||||
e->control.focus = v2_lerp(e0->control.focus, e1->control.focus, blend);
|
e->control.focus = v2_lerp(e0->control.focus, e1->control.focus, blend);
|
||||||
|
|
||||||
e->sprite_local_xform = xform_lerp(e0->sprite_local_xform, e1->sprite_local_xform, blend);
|
e->sprite_local_xform = xform_lerp(e0->sprite_local_xform, e1->sprite_local_xform, blend);
|
||||||
e->animation_time_in_frame = math_lerp_f64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)blend);
|
e->animation_last_frame_change_time_ns = math_lerp_i64(e0->animation_last_frame_change_time_ns, e1->animation_last_frame_change_time_ns, (f64)blend);
|
||||||
e->animation_frame = (u32)math_round_to_int(math_lerp_f32(e0->animation_frame, e1->animation_frame, blend));
|
e->animation_frame = (u32)math_round_to_int(math_lerp_f32(e0->animation_frame, e1->animation_frame, blend));
|
||||||
|
|
||||||
e->camera_quad_xform = xform_lerp(e0->camera_quad_xform, e1->camera_quad_xform, blend);
|
e->camera_quad_xform = xform_lerp(e0->camera_quad_xform, e1->camera_quad_xform, blend);
|
||||||
|
|||||||
@ -212,7 +212,7 @@ struct sim_ent {
|
|||||||
/* Animation */
|
/* Animation */
|
||||||
|
|
||||||
/* SIM_ENT_PROP_ANIMATING */
|
/* SIM_ENT_PROP_ANIMATING */
|
||||||
f64 animation_time_in_frame;
|
i64 animation_last_frame_change_time_ns;
|
||||||
u32 animation_frame;
|
u32 animation_frame;
|
||||||
|
|
||||||
/* ====================================================================== */
|
/* ====================================================================== */
|
||||||
|
|||||||
@ -47,15 +47,7 @@ struct sim_snapshot {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* FIXME: Remove this */
|
|
||||||
struct space *space;
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
420
src/user.c
420
src/user.c
@ -49,9 +49,9 @@ GLOBAL struct {
|
|||||||
struct host *host;
|
struct host *host;
|
||||||
struct string connect_address_str;
|
struct string connect_address_str;
|
||||||
|
|
||||||
struct sim_snapshot_store *sim_snapshot_store; /* Contains buffered snapshots from sim */
|
struct sim_snapshot_store *unblended_snapshot_store; /* Contains buffered snapshots from sim */
|
||||||
struct sim_snapshot_store *world_snapshot_store; /* Contains single world snapshot from result of blending sim snapshots */
|
struct sim_snapshot_store *blended_snapshot_store; /* Contains single world snapshot from result of blending sim snapshots */
|
||||||
struct sim_snapshot *world;
|
struct sim_snapshot *ss_blended;
|
||||||
|
|
||||||
/* Dynamic bitbuff used by encoders */
|
/* Dynamic bitbuff used by encoders */
|
||||||
struct bitbuff encoder_bitbuff;
|
struct bitbuff encoder_bitbuff;
|
||||||
@ -82,15 +82,26 @@ GLOBAL struct {
|
|||||||
|
|
||||||
b32 debug_draw;
|
b32 debug_draw;
|
||||||
|
|
||||||
/* User thread input */
|
/* Window -> user */
|
||||||
struct sys_mutex sys_events_mutex;
|
struct sys_mutex sys_events_mutex;
|
||||||
struct arena sys_events_arena;
|
struct arena sys_events_arena;
|
||||||
|
|
||||||
|
/* User -> local sim */
|
||||||
|
struct sys_mutex user_sim_cmd_mutex;
|
||||||
|
struct sim_control user_sim_cmd_control;
|
||||||
|
struct v2 user_sim_cmd_control_cursor_pos;
|
||||||
|
u64 user_sim_cmd_ack;
|
||||||
|
|
||||||
|
/* Local sim -> user */
|
||||||
|
struct sys_mutex local_sim_ss_mutex;
|
||||||
|
struct sim_snapshot_store *local_sim_ss_store;
|
||||||
|
|
||||||
i64 real_dt_ns;
|
i64 real_dt_ns;
|
||||||
i64 real_time_ns;
|
i64 real_time_ns;
|
||||||
|
|
||||||
u64 local_sim_last_known_tick;
|
u64 local_sim_last_known_tick;
|
||||||
i64 local_sim_last_known_time_ns;
|
i64 local_sim_last_known_time_ns;
|
||||||
|
i64 last_snapshot_received_at_ns;
|
||||||
|
|
||||||
/* Calculated from <last snapshot receive time + time since packet receive> */
|
/* Calculated from <last snapshot receive time + time since packet receive> */
|
||||||
i64 local_sim_predicted_time_ns;
|
i64 local_sim_predicted_time_ns;
|
||||||
@ -180,13 +191,22 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr,
|
|||||||
(UNUSED)sim_snapshot_sr;
|
(UNUSED)sim_snapshot_sr;
|
||||||
|
|
||||||
G.arena = arena_alloc(GIGABYTE(64));
|
G.arena = arena_alloc(GIGABYTE(64));
|
||||||
|
|
||||||
|
/* Snapshot store */
|
||||||
|
G.unblended_snapshot_store = sim_snapshot_store_alloc();
|
||||||
|
G.blended_snapshot_store = sim_snapshot_store_alloc();
|
||||||
|
G.ss_blended = sim_snapshot_nil();
|
||||||
|
|
||||||
|
/* Sys events */
|
||||||
G.sys_events_mutex = sys_mutex_alloc();
|
G.sys_events_mutex = sys_mutex_alloc();
|
||||||
G.sys_events_arena = arena_alloc(GIGABYTE(64));
|
G.sys_events_arena = arena_alloc(GIGABYTE(64));
|
||||||
|
|
||||||
/* Snapshot store */
|
/* User sim control */
|
||||||
G.sim_snapshot_store = sim_snapshot_store_alloc();
|
G.user_sim_cmd_mutex = sys_mutex_alloc();
|
||||||
G.world_snapshot_store = sim_snapshot_store_alloc();
|
|
||||||
G.world = sim_snapshot_nil();
|
/* Local sim snapshot store */
|
||||||
|
G.local_sim_ss_mutex = sys_mutex_alloc();
|
||||||
|
G.local_sim_ss_store = sim_snapshot_store_alloc();
|
||||||
|
|
||||||
//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);
|
||||||
@ -245,10 +265,8 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(user_shutdown)
|
|||||||
sim_ctx_release(G.local_sim_ctx);
|
sim_ctx_release(G.local_sim_ctx);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (G.local_sim_ctx) {
|
atomic_i32_eval_exchange(&G.local_sim_thread_shutdown, true);
|
||||||
atomic_i32_eval_exchange(&G.local_sim_thread_shutdown, true);
|
sys_thread_wait_release(&G.local_sim_thread);
|
||||||
sys_thread_wait_release(&G.local_sim_thread);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,47 +382,6 @@ INTERNAL SORT_COMPARE_FUNC_DEF(ent_draw_order_cmp, arg_a, arg_b, udata)
|
|||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Update
|
* Update
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
INTERNAL void queue_sim_cmd(struct arena *arena, struct sim_cmd_frame *frame, struct sim_cmd src)
|
|
||||||
{
|
|
||||||
struct sim_cmd *cmd = arena_push(arena, struct sim_cmd);
|
|
||||||
*cmd = src;
|
|
||||||
if (frame->last) {
|
|
||||||
frame->last->next = cmd;
|
|
||||||
} else {
|
|
||||||
frame->first = cmd;
|
|
||||||
}
|
|
||||||
frame->last = cmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
INTERNAL void user_update(void)
|
INTERNAL void user_update(void)
|
||||||
{
|
{
|
||||||
@ -419,8 +396,8 @@ INTERNAL void user_update(void)
|
|||||||
G.screen_size = sys_window_get_size(G.window);
|
G.screen_size = sys_window_get_size(G.window);
|
||||||
|
|
||||||
struct sprite_scope *sprite_frame_scope = sprite_scope_begin();
|
struct sprite_scope *sprite_frame_scope = sprite_scope_begin();
|
||||||
struct sim_cmd_frame cmd_frame = ZI;
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Process host events into sim cmds
|
* Process host events into sim cmds
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -444,6 +421,7 @@ INTERNAL void user_update(void)
|
|||||||
* Process sim cmd frame
|
* Process sim cmd frame
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
|
#if 0
|
||||||
{
|
{
|
||||||
static f64 last_try_connect = 0;
|
static f64 last_try_connect = 0;
|
||||||
f64 now = SECONDS_FROM_NS(sys_time_ns());
|
f64 now = SECONDS_FROM_NS(sys_time_ns());
|
||||||
@ -470,7 +448,7 @@ INTERNAL void user_update(void)
|
|||||||
case SIM_CMD_KIND_SNAPSHOT:
|
case SIM_CMD_KIND_SNAPSHOT:
|
||||||
{
|
{
|
||||||
/* TODO: Only read newest tick cmd */
|
/* TODO: Only read newest tick cmd */
|
||||||
if (cmd->snapshot_tick_end > G.world->tick) {
|
if (cmd->snapshot_tick_end > G.ss_blended->tick) {
|
||||||
u64 ss0_tick = cmd->snapshot_tick_start;
|
u64 ss0_tick = cmd->snapshot_tick_start;
|
||||||
u64 ss1_tick = cmd->snapshot_tick_end;
|
u64 ss1_tick = cmd->snapshot_tick_end;
|
||||||
struct sim_snapshot *ss0 = sim_snapshot_from_tick(G.sim_snapshot_store, ss0_tick);
|
struct sim_snapshot *ss0 = sim_snapshot_from_tick(G.sim_snapshot_store, ss0_tick);
|
||||||
@ -495,13 +473,64 @@ INTERNAL void user_update(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
for (struct sim_cmd *cmd = incoming_cmd_frame.first; cmd; cmd = cmd->next) {
|
||||||
|
enum sim_cmd_kind kind = cmd->kind;
|
||||||
|
switch (kind) {
|
||||||
|
case SIM_CMD_KIND_SNAPSHOT:
|
||||||
|
{
|
||||||
|
/* TODO: Only read newest tick cmd */
|
||||||
|
if (cmd->snapshot_tick_end > G.ss_blended->tick) {
|
||||||
|
u64 ss0_tick = cmd->snapshot_tick_start;
|
||||||
|
u64 ss1_tick = cmd->snapshot_tick_end;
|
||||||
|
struct sim_snapshot *ss0 = sim_snapshot_from_tick(G.sim_snapshot_store, ss0_tick);
|
||||||
|
struct sim_snapshot *ss1 = sim_snapshot_from_tick(G.sim_snapshot_store, ss1_tick);
|
||||||
|
if (ss0->tick == ss0_tick) {
|
||||||
|
if (!ss1->valid) {
|
||||||
|
ss1 = sim_snapshot_alloc(G.sim_snapshot_store, ss0, ss1_tick);
|
||||||
|
ss1->received_at_ns = G.real_time_ns;
|
||||||
|
|
||||||
|
struct bitbuff bb = bitbuff_from_string(cmd->snapshot_encoded);
|
||||||
|
struct bitbuff_reader br = br_from_bitbuff(&bb);
|
||||||
|
sim_snapshot_decode(&br, ss1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* User should always have src tick present */
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* Pull latest snapshot
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
{
|
||||||
|
struct sys_lock lock = sys_mutex_lock_e(&G.local_sim_ss_mutex);
|
||||||
|
u64 old_last_tick = G.unblended_snapshot_store->last_tick;
|
||||||
|
u64 last_tick = G.local_sim_ss_store->last_tick;
|
||||||
|
if (last_tick > old_last_tick) {
|
||||||
|
struct sim_snapshot *src = sim_snapshot_from_tick(G.local_sim_ss_store, last_tick);
|
||||||
|
sim_snapshot_alloc(G.unblended_snapshot_store, src, src->tick);
|
||||||
|
G.last_snapshot_received_at_ns = G.real_time_ns;
|
||||||
|
}
|
||||||
|
sys_mutex_unlock(&lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Create user world from blended snapshots
|
* Create user world from blended snapshots
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
{
|
{
|
||||||
struct sim_snapshot *newest_snapshot = sim_snapshot_from_tick(G.sim_snapshot_store, G.sim_snapshot_store->last_tick);
|
struct sim_snapshot *newest_snapshot = sim_snapshot_from_tick(G.unblended_snapshot_store, G.unblended_snapshot_store->last_tick);
|
||||||
G.local_sim_last_known_time_ns = newest_snapshot->real_time_ns;
|
G.local_sim_last_known_time_ns = newest_snapshot->real_time_ns;
|
||||||
G.local_sim_last_known_tick = newest_snapshot->tick;
|
G.local_sim_last_known_tick = newest_snapshot->tick;
|
||||||
|
|
||||||
@ -515,11 +544,11 @@ INTERNAL void user_update(void)
|
|||||||
* to variance in snapshot receive time. */
|
* to variance in snapshot receive time. */
|
||||||
/* TODO: Use a value that indicates desired dt to next frame, rather than real dt from last frame? */
|
/* TODO: Use a value that indicates desired dt to next frame, rather than real dt from last frame? */
|
||||||
f64 sim_time_smoothed_correction_rate = SECONDS_FROM_NS(G.real_dt_ns) / 0.05;
|
f64 sim_time_smoothed_correction_rate = SECONDS_FROM_NS(G.real_dt_ns) / 0.05;
|
||||||
i64 time_since_newest_tick_ns = G.real_time_ns - newest_snapshot->received_at_ns;
|
i64 time_since_newest_tick_ns = G.real_time_ns - G.last_snapshot_received_at_ns;
|
||||||
G.local_sim_predicted_time_ns = newest_snapshot->real_time_ns + time_since_newest_tick_ns;
|
G.local_sim_predicted_time_ns = newest_snapshot->real_time_ns + time_since_newest_tick_ns;
|
||||||
G.local_sim_predicted_time_smoothed_ns += G.real_dt_ns;
|
G.local_sim_predicted_time_smoothed_ns += G.real_dt_ns;
|
||||||
/* FIXME: Signed overflow check */
|
|
||||||
G.local_sim_predicted_time_smoothed_ns += (G.local_sim_predicted_time_ns - G.local_sim_predicted_time_smoothed_ns) * sim_time_smoothed_correction_rate;
|
G.local_sim_predicted_time_smoothed_ns += (G.local_sim_predicted_time_ns - G.local_sim_predicted_time_smoothed_ns) * sim_time_smoothed_correction_rate;
|
||||||
|
/* FIXME: Signed overflow check */
|
||||||
|
|
||||||
#if USER_INTERP_ENABLED
|
#if USER_INTERP_ENABLED
|
||||||
i64 render_time_ns = G.local_sim_predicted_time_smoothed_ns - (USER_INTERP_RATIO * newest_snapshot->real_dt_ns);
|
i64 render_time_ns = G.local_sim_predicted_time_smoothed_ns - (USER_INTERP_RATIO * newest_snapshot->real_dt_ns);
|
||||||
@ -528,7 +557,7 @@ INTERNAL void user_update(void)
|
|||||||
struct sim_snapshot *left_snapshot = sim_snapshot_nil();
|
struct sim_snapshot *left_snapshot = sim_snapshot_nil();
|
||||||
struct sim_snapshot *right_snapshot = newest_snapshot;
|
struct sim_snapshot *right_snapshot = newest_snapshot;
|
||||||
{
|
{
|
||||||
struct sim_snapshot *ss = sim_snapshot_from_tick(G.sim_snapshot_store, G.sim_snapshot_store->first_tick);
|
struct sim_snapshot *ss = sim_snapshot_from_tick(G.unblended_snapshot_store, G.unblended_snapshot_store->first_tick);
|
||||||
while (ss->valid) {
|
while (ss->valid) {
|
||||||
u64 next_tick = ss->next_tick;
|
u64 next_tick = ss->next_tick;
|
||||||
i64 ss_time_ns = ss->real_time_ns;
|
i64 ss_time_ns = ss->real_time_ns;
|
||||||
@ -542,29 +571,29 @@ INTERNAL void user_update(void)
|
|||||||
if (ss_time_ns > render_time_ns && ss_time_ns < right_snapshot->real_time_ns) {
|
if (ss_time_ns > render_time_ns && ss_time_ns < right_snapshot->real_time_ns) {
|
||||||
right_snapshot = ss;
|
right_snapshot = ss;
|
||||||
}
|
}
|
||||||
ss = sim_snapshot_from_tick(G.sim_snapshot_store, next_tick);
|
ss = sim_snapshot_from_tick(G.unblended_snapshot_store, next_tick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create world from blended snapshots */
|
/* Create world from blended snapshots */
|
||||||
if (left_snapshot->valid && right_snapshot->valid) {
|
if (left_snapshot->valid && right_snapshot->valid) {
|
||||||
f64 blend = (f64)(render_time_ns - left_snapshot->real_time_ns) / (f64)(right_snapshot->real_time_ns - left_snapshot->real_time_ns);
|
f64 blend = (f64)(render_time_ns - left_snapshot->real_time_ns) / (f64)(right_snapshot->real_time_ns - left_snapshot->real_time_ns);
|
||||||
G.world = sim_snapshot_alloc_from_lerp(G.world_snapshot_store, left_snapshot, right_snapshot, blend);
|
G.ss_blended = sim_snapshot_alloc_from_lerp(G.blended_snapshot_store, left_snapshot, right_snapshot, blend);
|
||||||
} else if (left_snapshot->valid) {
|
} else if (left_snapshot->valid) {
|
||||||
G.world = sim_snapshot_alloc(G.world_snapshot_store, left_snapshot, left_snapshot->tick);
|
G.ss_blended = sim_snapshot_alloc(G.blended_snapshot_store, left_snapshot, left_snapshot->tick);
|
||||||
} else if (right_snapshot->valid) {
|
} else if (right_snapshot->valid) {
|
||||||
G.world = sim_snapshot_alloc(G.world_snapshot_store, right_snapshot, right_snapshot->tick);
|
G.ss_blended = sim_snapshot_alloc(G.blended_snapshot_store, right_snapshot, right_snapshot->tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release all other render snapshots */
|
/* Release all other render snapshots */
|
||||||
{
|
{
|
||||||
struct sim_snapshot *ss = sim_snapshot_from_tick(G.world_snapshot_store, G.world_snapshot_store->first_tick);
|
struct sim_snapshot *ss = sim_snapshot_from_tick(G.blended_snapshot_store, G.blended_snapshot_store->first_tick);
|
||||||
while (ss->valid) {
|
while (ss->valid) {
|
||||||
u64 next_tick = ss->next_tick;
|
u64 next_tick = ss->next_tick;
|
||||||
if (ss != G.world) {
|
if (ss != G.ss_blended) {
|
||||||
sim_snapshot_release(ss);
|
sim_snapshot_release(ss);
|
||||||
}
|
}
|
||||||
ss = sim_snapshot_from_tick(G.world_snapshot_store, next_tick);
|
ss = sim_snapshot_from_tick(G.blended_snapshot_store, next_tick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,11 +611,11 @@ INTERNAL void user_update(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (G.world->tick != newest_snapshot->tick) {
|
if (G.ss_blended->tick != newest_snapshot->tick) {
|
||||||
if (G.world->valid) {
|
if (G.ss_blended->valid) {
|
||||||
sim_snapshot_release(G.world);
|
sim_snapshot_release(G.ss_blended);
|
||||||
}
|
}
|
||||||
G.world = sim_snapshot_alloc(G.world_snapshot_store, newest_snapshot, newest_snapshot->tick);
|
G.ss_blended = sim_snapshot_alloc(G.blended_snapshot_store, newest_snapshot, newest_snapshot->tick);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -684,16 +713,16 @@ INTERNAL void user_update(void)
|
|||||||
* Find local entities
|
* Find local entities
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct sim_client *local_client = sim_client_from_handle(G.world, G.world->local_client);
|
struct sim_client *local_client = sim_client_from_handle(G.ss_blended, G.ss_blended->local_client);
|
||||||
struct sim_ent *local_player = sim_ent_from_handle(G.world, local_client->control_ent);
|
struct sim_ent *local_player = sim_ent_from_handle(G.ss_blended, local_client->control_ent);
|
||||||
struct sim_ent *local_camera = sim_ent_from_handle(G.world, local_client->camera_ent);
|
struct sim_ent *local_camera = sim_ent_from_handle(G.ss_blended, local_client->camera_ent);
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Apply shake
|
* Apply shake
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
for (u64 ent_index = 0; ent_index < G.world->num_ents_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < G.ss_blended->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &G.world->ents[ent_index];
|
struct sim_ent *ent = &G.ss_blended->ents[ent_index];
|
||||||
if (!sim_ent_is_valid_and_active(ent)) continue;
|
if (!sim_ent_is_valid_and_active(ent)) continue;
|
||||||
|
|
||||||
/* How much time between camera shakes */
|
/* How much time between camera shakes */
|
||||||
@ -701,7 +730,7 @@ INTERNAL void user_update(void)
|
|||||||
f32 shake = ent->shake;
|
f32 shake = ent->shake;
|
||||||
if (shake > 0) {
|
if (shake > 0) {
|
||||||
u64 basis = hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&ent->handle));
|
u64 basis = hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&ent->handle));
|
||||||
u64 angle_seed0 = basis + (u64)(G.world->world_time_ns / frequency_ns);
|
u64 angle_seed0 = basis + (u64)(G.ss_blended->world_time_ns / frequency_ns);
|
||||||
u64 angle_seed1 = angle_seed0 + 1;
|
u64 angle_seed1 = angle_seed0 + 1;
|
||||||
f32 angle0 = rng_noise_f32(angle_seed0, 0, TAU);
|
f32 angle0 = rng_noise_f32(angle_seed0, 0, TAU);
|
||||||
f32 angle1 = rng_noise_f32(angle_seed1, 0, TAU);
|
f32 angle1 = rng_noise_f32(angle_seed1, 0, TAU);
|
||||||
@ -711,7 +740,7 @@ INTERNAL void user_update(void)
|
|||||||
struct v2 vec1 = v2_with_len(v2_from_angle(angle1), shake);
|
struct v2 vec1 = v2_with_len(v2_from_angle(angle1), shake);
|
||||||
|
|
||||||
/* TODO: Cubic interp? */
|
/* TODO: Cubic interp? */
|
||||||
f32 blend = (f32)(G.world->world_time_ns % frequency_ns) / (f32)frequency_ns;
|
f32 blend = (f32)(G.ss_blended->world_time_ns % frequency_ns) / (f32)frequency_ns;
|
||||||
struct v2 vec = v2_lerp(vec0, vec1, blend);
|
struct v2 vec = v2_lerp(vec0, vec1, blend);
|
||||||
|
|
||||||
struct xform xf = sim_ent_get_xform(ent);
|
struct xform xf = sim_ent_get_xform(ent);
|
||||||
@ -860,8 +889,8 @@ INTERNAL void user_update(void)
|
|||||||
/* Copy valid entities */
|
/* Copy valid entities */
|
||||||
{
|
{
|
||||||
__profscope(copy_sprites_for_sorting);
|
__profscope(copy_sprites_for_sorting);
|
||||||
for (u64 ent_index = 0; ent_index < G.world->num_ents_reserved; ++ent_index) {
|
for (u64 ent_index = 0; ent_index < G.ss_blended->num_ents_reserved; ++ent_index) {
|
||||||
struct sim_ent *ent = &G.world->ents[ent_index];
|
struct sim_ent *ent = &G.ss_blended->ents[ent_index];
|
||||||
if (sim_ent_is_valid_and_active(ent)) {
|
if (sim_ent_is_valid_and_active(ent)) {
|
||||||
*arena_push(scratch.arena, struct sim_ent *) = ent;
|
*arena_push(scratch.arena, struct sim_ent *) = ent;
|
||||||
++sorted_count;
|
++sorted_count;
|
||||||
@ -888,7 +917,7 @@ INTERNAL void user_update(void)
|
|||||||
|
|
||||||
struct sprite_tag sprite = ent->sprite;
|
struct sprite_tag sprite = ent->sprite;
|
||||||
|
|
||||||
struct sim_ent *parent = sim_ent_from_handle(G.world, ent->parent);
|
struct sim_ent *parent = sim_ent_from_handle(G.ss_blended, ent->parent);
|
||||||
|
|
||||||
struct xform xf = sim_ent_get_xform(ent);
|
struct xform xf = sim_ent_get_xform(ent);
|
||||||
struct xform parent_xf = sim_ent_get_xform(parent);
|
struct xform parent_xf = sim_ent_get_xform(parent);
|
||||||
@ -1073,8 +1102,8 @@ INTERNAL void user_update(void)
|
|||||||
/* Draw contact constraint */
|
/* Draw contact constraint */
|
||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) {
|
if (sim_ent_has_prop(ent, SIM_ENT_PROP_CONTACT_CONSTRAINT)) {
|
||||||
struct phys_contact_constraint *data = &ent->contact_constraint_data;
|
struct phys_contact_constraint *data = &ent->contact_constraint_data;
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(G.world, data->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(G.ss_blended, data->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(G.world, data->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(G.ss_blended, data->e1);
|
||||||
(UNUSED)e0;
|
(UNUSED)e0;
|
||||||
(UNUSED)e1;
|
(UNUSED)e1;
|
||||||
|
|
||||||
@ -1147,8 +1176,8 @@ INTERNAL void user_update(void)
|
|||||||
if (sim_ent_has_prop(ent, SIM_ENT_PROP_COLLISION_DEBUG)) {
|
if (sim_ent_has_prop(ent, SIM_ENT_PROP_COLLISION_DEBUG)) {
|
||||||
struct phys_collision_debug *data = &ent->collision_debug_data;
|
struct phys_collision_debug *data = &ent->collision_debug_data;
|
||||||
struct collider_collision_points_result collider_res = data->res;
|
struct collider_collision_points_result collider_res = data->res;
|
||||||
struct sim_ent *e0 = sim_ent_from_handle(G.world, data->e0);
|
struct sim_ent *e0 = sim_ent_from_handle(G.ss_blended, data->e0);
|
||||||
struct sim_ent *e1 = sim_ent_from_handle(G.world, data->e1);
|
struct sim_ent *e1 = sim_ent_from_handle(G.ss_blended, data->e1);
|
||||||
struct collider_shape e0_collider = e0->local_collider;
|
struct collider_shape e0_collider = e0->local_collider;
|
||||||
struct collider_shape e1_collider = e1->local_collider;
|
struct collider_shape e1_collider = e1->local_collider;
|
||||||
(UNUSED)e0_collider;
|
(UNUSED)e0_collider;
|
||||||
@ -1472,11 +1501,16 @@ INTERNAL void user_update(void)
|
|||||||
control.flags |= SIM_CONTROL_FLAG_SPAWN_TEST;
|
control.flags |= SIM_CONTROL_FLAG_SPAWN_TEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
queue_sim_cmd(scratch.arena, &cmd_frame, (struct sim_cmd) {
|
/* Set user sim control */
|
||||||
.kind = SIM_CMD_KIND_CLIENT_CONTROL,
|
{
|
||||||
.control = control,
|
struct sys_lock lock = sys_mutex_lock_e(&G.user_sim_cmd_mutex);
|
||||||
.cursor_pos = G.world_cursor,
|
u32 old_flags = G.user_sim_cmd_control.flags;
|
||||||
});
|
G.user_sim_cmd_control = control;
|
||||||
|
G.user_sim_cmd_control.flags |= old_flags;
|
||||||
|
G.user_sim_cmd_control_cursor_pos = G.world_cursor;
|
||||||
|
G.user_sim_cmd_ack = G.local_sim_last_known_tick;
|
||||||
|
sys_mutex_unlock(&lock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
@ -1515,13 +1549,13 @@ 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("user entities: %F/%F"), FMT_UINT(G.world->num_ents_allocated), FMT_UINT(G.world->num_ents_reserved)));
|
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("user entities: %F/%F"), FMT_UINT(G.ss_blended->num_ents_allocated), FMT_UINT(G.ss_blended->num_ents_reserved)));
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("user tick: %F"), FMT_UINT(G.world->tick)));
|
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("user tick: %F"), FMT_UINT(G.ss_blended->tick)));
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("user time: %F"), FMT_FLOAT_P(SECONDS_FROM_NS(G.world->real_time_ns), 3)));
|
draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("user time: %F"), FMT_FLOAT_P(SECONDS_FROM_NS(G.ss_blended->real_time_ns), 3)));
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
pos.y += spacing;
|
pos.y += spacing;
|
||||||
|
|
||||||
@ -1602,6 +1636,7 @@ INTERNAL void user_update(void)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* Publish sim cmds */
|
/* Publish sim cmds */
|
||||||
{
|
{
|
||||||
struct sim_cmd_frame_list l = ZI;
|
struct sim_cmd_frame_list l = ZI;
|
||||||
@ -1615,6 +1650,7 @@ INTERNAL void user_update(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
host_update(G.host);
|
host_update(G.host);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Update network usage stats */
|
/* Update network usage stats */
|
||||||
G.client_bytes_read.last_second_end = G.host->bytes_received;
|
G.client_bytes_read.last_second_end = G.host->bytes_received;
|
||||||
@ -1768,18 +1804,11 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
|
|||||||
#else
|
#else
|
||||||
struct host *host = host_alloc(12345);
|
struct host *host = host_alloc(12345);
|
||||||
#endif
|
#endif
|
||||||
|
(UNUSED)arg;
|
||||||
|
|
||||||
struct bitbuff encoder_bitbuff = bitbuff_alloc(GIGABYTE(64));
|
struct bitbuff encoder_bitbuff = bitbuff_alloc(GIGABYTE(64));
|
||||||
struct sim_snapshot_store *snapshot_store = sim_snapshot_store_alloc();
|
struct sim_snapshot_store *snapshot_store = sim_snapshot_store_alloc();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(UNUSED)arg;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
|
|
||||||
struct sim_snapshot *prev_ss = sim_snapshot_nil();
|
struct sim_snapshot *prev_ss = sim_snapshot_nil();
|
||||||
|
|
||||||
i64 last_tick_ns = 0;
|
i64 last_tick_ns = 0;
|
||||||
@ -1810,109 +1839,72 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sim_cmd_frame_list raw_input_cmd_frames = ZI;
|
/* Retrieve cmds */
|
||||||
|
struct sim_cmd_frame_list input_cmds = ZI;
|
||||||
{
|
{
|
||||||
host_update(host);
|
/* Grab cmds from host */
|
||||||
struct host_event_array host_events = host_pop_events(scratch.arena, host);
|
{
|
||||||
sim_cmd_frames_decode(scratch.arena, host_events, &raw_input_cmd_frames);
|
host_update(host);
|
||||||
}
|
struct host_event_array host_events = host_pop_events(scratch.arena, host);
|
||||||
|
sim_cmd_frames_decode(scratch.arena, host_events, &input_cmds);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
b32 should_break = false;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Merge cmd frames from user thread */
|
|
||||||
struct sim_cmd *user_control_cmd = NULL;
|
|
||||||
struct sim_cmd_frame user_cmd_frame = ZI;
|
|
||||||
struct sim_cmd_frame_list input_cmd_frames = ZI;
|
|
||||||
{
|
|
||||||
struct sim_cmd_frame *frame = raw_input_cmd_frames.first;
|
|
||||||
while (frame) {
|
|
||||||
struct sim_cmd_frame *next_frame = frame->next;
|
|
||||||
/* FIXME: Only do this for user cmds */
|
|
||||||
if (frame->tick == 0) {
|
|
||||||
/* All cmd frames from the user thread need to be merged into a single cmd frame representing inputs for one sim tick */
|
|
||||||
if (user_cmd_frame.tick == 0) {
|
|
||||||
user_cmd_frame = *frame;
|
|
||||||
user_cmd_frame.tick = prev_ss->tick + 1;
|
|
||||||
user_cmd_frame.next = NULL;
|
|
||||||
}
|
|
||||||
if (frame->ack > user_cmd_frame.ack) {
|
|
||||||
user_cmd_frame.ack = frame->ack;
|
|
||||||
}
|
|
||||||
struct sim_cmd *cmd = frame->first;
|
|
||||||
while (cmd) {
|
|
||||||
struct sim_cmd *next_cmd = cmd->next;
|
|
||||||
b32 should_insert = true;
|
|
||||||
if (cmd->kind == SIM_CMD_KIND_CLIENT_CONTROL) {
|
|
||||||
if (user_control_cmd) {
|
|
||||||
/* Merge with existing control cmd */
|
|
||||||
|
|
||||||
if (cmd->control.flags & SIM_CONTROL_FLAG_CLEAR_ALL) {
|
|
||||||
should_break = true;
|
|
||||||
DEBUGBREAKABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
should_insert = false;
|
|
||||||
u32 flags = user_control_cmd->control.flags;
|
|
||||||
*user_control_cmd = *cmd;
|
|
||||||
user_control_cmd->control.flags |= flags;
|
|
||||||
} else {
|
|
||||||
user_control_cmd = cmd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (should_insert) {
|
|
||||||
if (user_cmd_frame.last) {
|
|
||||||
user_cmd_frame.last->next = cmd;
|
|
||||||
} else {
|
|
||||||
user_cmd_frame.first = cmd;
|
|
||||||
}
|
|
||||||
user_cmd_frame.last = cmd;
|
|
||||||
}
|
|
||||||
cmd->next = NULL;
|
|
||||||
cmd = next_cmd;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (input_cmd_frames.last) {
|
|
||||||
input_cmd_frames.last = frame;
|
|
||||||
} else {
|
|
||||||
input_cmd_frames.first = frame;
|
|
||||||
}
|
|
||||||
input_cmd_frames.last = frame;
|
|
||||||
}
|
|
||||||
frame->next = NULL;
|
|
||||||
frame = next_frame;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (user_cmd_frame.tick != 0) {
|
/* Generate user sim cmd from user thread */
|
||||||
if (input_cmd_frames.last) {
|
struct sim_cmd_frame *user_cmd_frame;
|
||||||
input_cmd_frames.last->next = &user_cmd_frame;
|
{
|
||||||
|
struct sys_lock lock = sys_mutex_lock_e(&G.user_sim_cmd_mutex);
|
||||||
|
user_cmd_frame = arena_push_zero(scratch.arena, struct sim_cmd_frame);
|
||||||
|
user_cmd_frame->tick = prev_ss->tick + 1;
|
||||||
|
user_cmd_frame->ack = G.user_sim_cmd_ack;
|
||||||
|
user_cmd_frame->sender_is_local = true;
|
||||||
|
|
||||||
|
struct sim_cmd *user_cmd = arena_push_zero(scratch.arena, struct sim_cmd);
|
||||||
|
user_cmd->kind = SIM_CMD_KIND_CLIENT_CONTROL;
|
||||||
|
user_cmd->control = G.user_sim_cmd_control;
|
||||||
|
user_cmd->cursor_pos = G.user_sim_cmd_control_cursor_pos;
|
||||||
|
user_cmd_frame->first = user_cmd;
|
||||||
|
user_cmd_frame->last = user_cmd;
|
||||||
|
|
||||||
|
G.user_sim_cmd_control.flags = 0;
|
||||||
|
|
||||||
|
sys_mutex_unlock(&lock);
|
||||||
|
}
|
||||||
|
if (input_cmds.last) {
|
||||||
|
input_cmds.last->next = user_cmd_frame;
|
||||||
} else {
|
} else {
|
||||||
input_cmd_frames.first = &user_cmd_frame;
|
input_cmds.first = user_cmd_frame;
|
||||||
}
|
}
|
||||||
input_cmd_frames.last = &user_cmd_frame;
|
input_cmds.last = user_cmd_frame;
|
||||||
}
|
|
||||||
|
|
||||||
if (input_cmd_frames.first && input_cmd_frames.first->first && input_cmd_frames.first->first->control.flags & SIM_CONTROL_FLAG_CLEAR_ALL) {
|
|
||||||
DEBUGBREAKABLE;
|
|
||||||
} else if (should_break) {
|
|
||||||
DEBUGBREAKABLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step */
|
/* Step */
|
||||||
struct sim_snapshot *ss = sim_step(snapshot_store, prev_ss, input_cmd_frames, target_dt_ns);
|
struct sim_snapshot *ss = sim_step(snapshot_store, prev_ss, input_cmds, target_dt_ns);
|
||||||
|
|
||||||
/* Publish snapshot cmds */
|
/* Publish snapshot to user */
|
||||||
|
/* TODO: Double buffer */
|
||||||
|
{
|
||||||
|
struct sys_lock lock = sys_mutex_lock_e(&G.local_sim_ss_mutex);
|
||||||
|
sim_snapshot_alloc(G.local_sim_ss_store, ss, ss->tick);
|
||||||
|
|
||||||
|
struct sim_snapshot *remss = sim_snapshot_from_tick(G.local_sim_ss_store, G.local_sim_ss_store->first_tick);
|
||||||
|
while (remss) {
|
||||||
|
u64 next_tick = remss->next_tick;
|
||||||
|
if (remss->tick < ss->tick) {
|
||||||
|
sim_snapshot_release(remss);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
remss = sim_snapshot_from_tick(G.local_sim_ss_store, next_tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_mutex_unlock(&lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Publish snapshot cmds to networked clients */
|
||||||
u64 oldest_ack_tick = 0;
|
u64 oldest_ack_tick = 0;
|
||||||
for (u64 i = 0; i < ss->num_clients_reserved; ++i) {
|
for (u64 i = 0; i < ss->num_clients_reserved; ++i) {
|
||||||
struct sim_client *client = &ss->clients[i];
|
struct sim_client *client = &ss->clients[i];
|
||||||
if (client->valid) {
|
if (client->valid && client->kind == SIM_CLIENT_KIND_NETSIM) {
|
||||||
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
struct temp_arena temp = arena_temp_begin(scratch.arena);
|
||||||
|
|
||||||
if (oldest_ack_tick == 0 || client->ack < oldest_ack_tick) {
|
if (oldest_ack_tick == 0 || client->ack < oldest_ack_tick) {
|
||||||
@ -1967,50 +1959,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg)
|
|||||||
prev_ss = ss;
|
prev_ss = ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
|
||||||
{
|
|
||||||
__profscope(local_sim_sleep);
|
|
||||||
sleep_frame(last_tick_ns, target_dt_ns);
|
|
||||||
last_tick_ns = sys_time_ns();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sim_cmd_frame user_frame = ZI;
|
|
||||||
user_frame.tick = prev_ss->tick + 1;
|
|
||||||
user_frame.ack = prev_ss->tick;
|
|
||||||
|
|
||||||
/* Read cmds from host */
|
|
||||||
host_update(host);
|
|
||||||
struct host_event_array host_events = host_pop_events(scratch.arena, host);
|
|
||||||
sim_cmds_decode(scratch.arena, host_events, &sim_cmds);
|
|
||||||
|
|
||||||
/* Step */
|
|
||||||
struct sim_snapshot *ss = sim_step(ss_store, prev_ss, user_cmds, target_dt_ns);
|
|
||||||
|
|
||||||
/* Encode & enqueue sim_cmd frames */
|
|
||||||
for (struct sim_cmd_frame *f = output_cmds.first; f; f = f->next) {
|
|
||||||
struct host_channel_id channel_id = f->dst_channel;
|
|
||||||
struct string cmd_frame_msg = ZI;
|
|
||||||
struct bitbuff_writer bw = bw_from_bitbuff(&encoder_bitbuff);
|
|
||||||
sim_cmd_frame_encode(&bw, q);
|
|
||||||
cmd_frame_msg = bw_get_written(temp.arena, &bw);
|
|
||||||
host_queue_write(host, channel_id, cmd_frame_msg, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send host messages */
|
|
||||||
//host_update(host);
|
|
||||||
__profframe("Local sim");
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sim_snapshot_store_release(snapshot_store);
|
sim_snapshot_store_release(snapshot_store);
|
||||||
bitbuff_release(&encoder_bitbuff);
|
bitbuff_release(&encoder_bitbuff);
|
||||||
host_release(host);
|
host_release(host);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user