From f000bd7e65df93d25924e4d3afc5fd995b06d705 Mon Sep 17 00:00:00 2001 From: jacob Date: Sun, 9 Feb 2025 15:22:43 -0600 Subject: [PATCH] progress & fix buddy bug --- src/buddy.c | 22 +++-- src/incbin.c | 2 +- src/intrinsics.h | 2 +- src/phys.c | 4 +- src/phys.h | 2 +- src/sim.c | 224 +++++++++++++++------------------------------ src/sim.h | 26 +++++- src/sim_client.c | 7 +- src/sim_client.h | 2 +- src/sim_ent.c | 8 +- src/sim_ent.h | 4 +- src/sim_msg.c | 69 +++++++------- src/sim_msg.h | 7 +- src/sim_snapshot.c | 18 ++++ src/sim_snapshot.h | 30 ++++++ src/user.c | 110 ++++++++++++---------- src/world.c | 34 ------- src/world.h | 30 ------ 18 files changed, 282 insertions(+), 319 deletions(-) create mode 100644 src/sim_snapshot.c create mode 100644 src/sim_snapshot.h delete mode 100644 src/world.c delete mode 100644 src/world.h diff --git a/src/buddy.c b/src/buddy.c index f8142617..29ec3684 100644 --- a/src/buddy.c +++ b/src/buddy.c @@ -73,6 +73,18 @@ INTERNAL struct buddy_block *buddy_block_get_unused(struct buddy_ctx *ctx, struc { struct buddy_block *block = NULL; + + + + + if (level->tier > 30) { + DEBUGBREAKABLE; + } + + + + + /* TODO: Tier oob check */ if (level->first_unused_block) { block = level->first_unused_block; @@ -156,17 +168,15 @@ INTERNAL struct buddy_block *buddy_block_get_unused(struct buddy_ctx *ctx, struc INTERNAL void buddy_block_mark_unused(struct buddy_block *block) { block->used = false; - struct buddy_block *sibling = block->sibling; struct buddy_level *level = block->level; - if (sibling && !sibling->used) { + struct buddy_block *parent = block->parent; + struct buddy_block *sibling = block->sibling; + if (!sibling->used && parent != NULL) { /* Merge siblings */ struct buddy_ctx *ctx = level->ctx; - struct buddy_block *parent = block->parent; buddy_block_release_internal(ctx, level, block); buddy_block_release_internal(ctx, level, sibling); - if (parent) { - buddy_block_mark_unused(parent); - } + buddy_block_mark_unused(parent); } else { if (level->first_unused_block) { block->next = level->first_unused_block; diff --git a/src/incbin.c b/src/incbin.c index 111679c5..ef48005d 100644 --- a/src/incbin.c +++ b/src/incbin.c @@ -27,7 +27,7 @@ INTERNAL BOOL CALLBACK enum_func(HMODULE module, LPCWSTR type, LPCWSTR wstr_entr { struct temp_arena scratch = scratch_begin_no_conflict(); struct rc_search_params *params = (struct rc_search_params *)udata; - struct string entry_name_lower = string_lower(scratch.arena, string_from_wstr(scratch.arena, (LPWSTR)wstr_entry_name)); + struct string entry_name_lower = string_lower(scratch.arena, string_from_wstr_no_limit(scratch.arena, (LPWSTR)wstr_entry_name)); params->found = false; params->data = STRING(0, 0); if (string_eq(entry_name_lower, params->name_lower)) { diff --git a/src/intrinsics.h b/src/intrinsics.h index fd4c8c01..3dc45654 100644 --- a/src/intrinsics.h +++ b/src/intrinsics.h @@ -115,7 +115,7 @@ INLINE void ix_pause(void) _mm_pause(); } -INLINE i64 ix_clock(void) +INLINE u64 ix_clock(void) { return __rdtsc(); } diff --git a/src/phys.c b/src/phys.c index 1ba1e025..c2f48110 100644 --- a/src/phys.c +++ b/src/phys.c @@ -43,7 +43,7 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a __prof; struct phys_collision_data_array res = ZI; res.a = arena_dry_push(arena, struct phys_collision_data); - u64 tick_id = ctx->tick_id; + u64 tick = ctx->tick; struct sim_ent_lookup *contact_lookup = ctx->contact_lookup; struct sim_ent_lookup *debug_lookup = ctx->debug_lookup; struct space *space = ctx->space; @@ -133,7 +133,7 @@ struct phys_collision_data_array phys_create_and_update_contacts(struct arena *a /* TODO: Should we recalculate normal as more contact points are added? */ sim_ent_enable_prop(constraint_ent, SIM_ENT_PROP_CONTACT_CONSTRAINT); - sim_ent_activate(constraint_ent, tick_id); + sim_ent_activate(constraint_ent, tick); ASSERT(!constraint_entry); /* Existing entry should never be present here */ sim_ent_lookup_set(contact_lookup, key, constraint_ent->handle); } diff --git a/src/phys.h b/src/phys.h index 6279e7b5..f6ffaeda 100644 --- a/src/phys.h +++ b/src/phys.h @@ -30,7 +30,7 @@ typedef PHYS_COLLISION_CALLBACK_FUNC_DEF(phys_collision_callback_func, collision /* Structure containing data used for a single physics step */ struct phys_ctx { - u64 tick_id; + u64 tick; struct space *space; struct sim_ent_store *store; struct sim_ent_lookup *contact_lookup; diff --git a/src/sim.c b/src/sim.c index a032024f..b73db5bd 100644 --- a/src/sim.c +++ b/src/sim.c @@ -2,9 +2,9 @@ #include "sim_ent.h" #include "sim_client.h" #include "sim_msg.h" +#include "sim_snapshot.h" #include "sys.h" #include "util.h" -#include "world.h" #include "sprite.h" #include "math.h" #include "scratch.h" @@ -18,41 +18,10 @@ #include "byteio.h" #include "host.h" -struct sim_ctx { - struct arena arena; - struct atomic_i32 sim_thread_shutdown; - struct sys_thread sim_thread; - - u64 last_phys_iteration; - - struct sprite_scope *sprite_frame_scope; - - struct host *host; - - /* TODO: Remove this (testing) */ - b32 extra_spawn; - b32 should_reset_level; - - struct sim_ent *root; - - /* Bookkeeping structures */ - struct sim_ent_lookup contact_lookup; -#if COLLIDER_DEBUG - struct sim_ent_lookup collision_debug_lookup; -#endif - struct space *space; - - /* Tick */ - struct world tick; -}; - /* ========================== * * Ctx * ========================== */ -INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg); -INTERNAL void test_sim_world_alloc(struct sim_ctx *ctx); -INTERNAL void test_sim_world_release(struct sim_ctx *ctx); struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr, struct phys_startup_receipt *phys_sr, @@ -70,33 +39,6 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr, /* Intialize host */ ctx->host = host_alloc(host_port); - /* Initialize empty world */ - test_sim_world_alloc(ctx); - - ctx->sim_thread = sys_thread_alloc(&sim_thread_entry_point, ctx, LIT("[P2] Sim thread")); - - return ctx; -} - -void sim_ctx_release(struct sim_ctx *ctx) -{ - __prof; - atomic_i32_eval_exchange(&ctx->sim_thread_shutdown, true); - sys_thread_wait_release(&ctx->sim_thread); - - test_sim_world_release(ctx); - host_release(ctx->host); - arena_release(&ctx->arena); -} - -/* ========================== * - * Reset - * ========================== */ - -/* TODO: Remove this */ - -INTERNAL void test_sim_world_alloc(struct sim_ctx *ctx) -{ /* Create bookkeeping */ ctx->contact_lookup = sim_ent_lookup_alloc(4096); #if COLLIDER_DEBUG @@ -104,21 +46,29 @@ INTERNAL void test_sim_world_alloc(struct sim_ctx *ctx) #endif ctx->space = space_alloc(SPACE_CELL_SIZE, SPACE_CELL_BUCKETS_SQRT); - /* Re-create world */ - world_alloc(&ctx->tick); - ctx->tick.timescale = SIM_TIMESCALE; + /* Create emtpy snapshot */ + sim_snapshot_alloc(&ctx->world); + ctx->world.world_timescale = SIM_TIMESCALE; + + return ctx; } -INTERNAL void test_sim_world_release(struct sim_ctx *ctx) +void sim_ctx_release(struct sim_ctx *ctx) { - /* Release world */ - world_release(&ctx->tick); + __prof; + + /* Release snapshot */ + sim_snapshot_release(&ctx->world); + /* Release bookkeeping */ space_release(ctx->space); #if COLLIDER_DEBUG sim_ent_lookup_release(&ctx->collision_debug_lookup); #endif sim_ent_lookup_release(&ctx->contact_lookup); + + host_release(ctx->host); + arena_release(&ctx->arena); } /* ========================== * @@ -129,7 +79,7 @@ INTERNAL void test_sim_world_release(struct sim_ctx *ctx) INTERNAL void spawn_test_entities(struct sim_ctx *ctx) { - struct sim_ent *root = sim_ent_from_handle(ctx->tick.ent_store, ctx->tick.ent_store->root); + struct sim_ent *root = sim_ent_from_handle(ctx->world.ent_store, ctx->world.ent_store->root); root->mass_unscaled = F32_INFINITY; root->inertia_unscaled = F32_INFINITY; @@ -199,13 +149,11 @@ INTERNAL void spawn_test_entities(struct sim_ctx *ctx) e->linear_ground_friction = 0.001; } #endif - - ctx->extra_spawn = true; } INTERNAL struct sim_ent *spawn_test_player(struct sim_ctx *ctx) { - struct sim_ent_store *store = ctx->tick.ent_store; + struct sim_ent_store *store = ctx->world.ent_store; struct sim_ent *root = sim_ent_from_handle(store, store->root); /* Player */ @@ -224,21 +172,11 @@ INTERNAL struct sim_ent *spawn_test_player(struct sim_ctx *ctx) //f32 r = PI / 4; f32 r = 0; - if (!ctx->extra_spawn) { + { sim_ent_enable_prop(e, SIM_ENT_PROP_TEST); e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase")); e->mass_unscaled = 10; e->inertia_unscaled = 5; - } else { - sim_ent_enable_prop(e, SIM_ENT_PROP_TEST); - e->sprite = sprite_tag_from_path(LIT("res/graphics/tim.ase")); - e->mass_unscaled = 10; - e->inertia_unscaled = 5; -#if 0 - e->sprite = sprite_tag_from_path(LIT("res/graphics/box.ase")); - e->mass_unscaled = 100; - e->inertia_unscaled = 100; -#endif } e->local_collider.points[0] = v2_with_len(V2(0.08f, 0.17f), 0.15f); @@ -281,8 +219,8 @@ INTERNAL struct sim_ent *spawn_test_player(struct sim_ctx *ctx) e->layer = SIM_LAYER_RELATIVE_WEAPON; sim_ent_enable_prop(e, SIM_ENT_PROP_WEAPON); - //e->trigger_delay = 1.0f / 10.0f; - e->trigger_delay = 1.0f / 100.0f; + e->trigger_delay = 1.0f / 10.0f; + //e->trigger_delay = 1.0f / 100.0f; player_ent->equipped = e->handle; } @@ -292,7 +230,7 @@ INTERNAL struct sim_ent *spawn_test_player(struct sim_ctx *ctx) INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_ctx *ctx, struct sim_ent *player_ent) { - struct sim_ent_store *store = ctx->tick.ent_store; + struct sim_ent_store *store = ctx->world.ent_store; struct sim_ent *root = sim_ent_from_handle(store, store->root); struct sim_ent *camera_ent = sim_ent_nil(); @@ -319,7 +257,7 @@ INTERNAL struct sim_ent *spawn_test_player_camera(struct sim_ctx *ctx, struct si INTERNAL void release_entities_with_prop(struct sim_ctx *ctx, enum sim_ent_prop prop) { struct temp_arena scratch = scratch_begin_no_conflict(); - struct sim_ent_store *store = ctx->tick.ent_store; + struct sim_ent_store *store = ctx->world.ent_store; struct space *space = ctx->space; struct sim_ent **ents_to_release = arena_dry_push(scratch.arena, struct sim_ent *); @@ -366,7 +304,7 @@ INTERNAL void release_entities_with_prop(struct sim_ctx *ctx, enum sim_ent_prop INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, udata) { struct sim_ctx *ctx = (struct sim_ctx *)udata; - struct sim_ent_store *store = ctx->tick.ent_store; + struct sim_ent_store *store = ctx->world.ent_store; struct sim_ent *root = sim_ent_from_handle(store, store->root); for (u64 i = 0; i < collision_data_array.count; ++i) { @@ -451,45 +389,41 @@ INTERNAL PHYS_COLLISION_CALLBACK_FUNC_DEF(on_collision, collision_data_array, ud * Update * ========================== */ -INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) +void sim_update(struct sim_ctx *ctx, i64 target_dt_ns) { __prof; struct temp_arena scratch = scratch_begin_no_conflict(); - /* ========================== * - * Reset level if necessary - * ========================== */ - - if (ctx->should_reset_level) { - logf_info("Clearing level"); - ctx->should_reset_level = false; - ctx->extra_spawn = false; - test_sim_world_release(ctx); - test_sim_world_alloc(ctx); - } - /* ========================== * * Begin frame * ========================== */ - ++ctx->tick.tick_id; + ++ctx->world.tick; - ctx->tick.dt_ns = NS_FROM_SECONDS(max_f64(0.0, dt * ctx->tick.timescale)); - ctx->tick.time_ns += ctx->tick.dt_ns; + ctx->world.real_dt_ns = max_i64(0, target_dt_ns); + ctx->world.real_time_ns += ctx->world.real_dt_ns; - f64 time = SECONDS_FROM_NS(ctx->tick.time_ns); + 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(); - ctx->root = sim_ent_from_handle(ctx->tick.ent_store, ctx->tick.ent_store->root); - struct sim_ent *root = ctx->root; - struct sim_ent_store *ent_store = ctx->tick.ent_store; + 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); + (UNUSED)real_dt; + (UNUSED)real_time; + (UNUSED)world_dt; + (UNUSED)world_time; + + struct sim_ent *root = sim_ent_from_handle(ctx->world.ent_store, ctx->world.ent_store->root);; + struct sim_ent_store *ent_store = ctx->world.ent_store; struct space *space = ctx->space; struct sprite_scope *sprite_frame_scope = ctx->sprite_frame_scope; - (UNUSED)dt; - (UNUSED)time; - /* ========================== * * Spawn test entities * ========================== */ @@ -520,8 +454,8 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) if (!sim_ent_has_prop(ent, SIM_ENT_PROP_ACTIVE)) { u64 atick = ent->activation_tick; - if (atick != 0 || ctx->tick.tick_id >= atick) { - sim_ent_activate(ent, ctx->tick.tick_id); + if (atick != 0 || ctx->world.tick >= atick) { + sim_ent_activate(ent, ctx->world.tick); } } } @@ -548,17 +482,19 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) struct sim_cmd_list *client_cmds; { - struct sim_cmd_list sim_cmds = ZI; + host_update(ctx->host); struct host_event_array host_events = host_pop_events(scratch.arena, ctx->host); + + struct sim_cmd_list sim_cmds = ZI; sim_cmds_from_host_events(scratch.arena, host_events, &sim_cmds); /* Create connecting clients */ 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->tick.client_store, channel_id); + struct sim_client *client = sim_client_from_channel_id(ctx->world.client_store, channel_id); if (!client->valid && kind == SIM_CMD_KIND_SIM_CLIENT_CONNECT && !host_channel_id_is_nil(channel_id)) { - client = sim_client_alloc(ctx->tick.client_store, channel_id); + client = sim_client_alloc(ctx->world.client_store, channel_id); /* TODO: Create player ent not here */ /* FIXME: Player ent never released upon disconnect */ struct sim_ent *player_ent = spawn_test_player(ctx); @@ -571,13 +507,13 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) } /* Split cmds by client */ - client_cmds = arena_push_array_zero(scratch.arena, struct sim_cmd_list, ctx->tick.client_store->num_reserved); + client_cmds = arena_push_array_zero(scratch.arena, struct sim_cmd_list, ctx->world.client_store->num_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->tick.client_store, channel_id); + struct sim_client *client = sim_client_from_channel_id(ctx->world.client_store, channel_id); if (client->valid) { struct sim_cmd_list *cmd_list = &client_cmds[client->handle.idx]; if (cmd_list->last) { @@ -598,8 +534,8 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) * ========================== */ /* Process client cmds */ - for (u64 i = 0; i < ctx->tick.client_store->num_reserved; ++i) { - struct sim_client *client = &ctx->tick.client_store->clients[i]; + for (u64 i = 0; i < ctx->world.client_store->num_reserved; ++i) { + struct sim_client *client = &ctx->world.client_store->clients[i]; if (client->valid) { struct host_channel_id channel_id = client->channel_id; struct sim_cmd_list cmds = client_cmds[client->handle.idx]; @@ -659,7 +595,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) /* Clear level */ case SIM_CMD_KIND_CLEAR_ALL: { - ctx->should_reset_level = true; + /* TODO */ } break; /* Spawn test */ @@ -691,7 +627,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) 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->tick.client_store, ent->controlling_client); + struct sim_client *client = sim_client_from_handle(ctx->world.client_store, ent->controlling_client); if (client->valid) { ent->control = client->control; /* TODO: Move this */ @@ -719,7 +655,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) { struct sprite_sheet_span span = sprite_sheet_get_span(sheet, ent->sprite_span_name); - f64 time_in_frame = ent->animation_time_in_frame + dt; + f64 time_in_frame = ent->animation_time_in_frame + world_dt; u64 frame_index = ent->animation_frame; if (frame_index < span.start || frame_index > span.end) { frame_index = span.start; @@ -899,9 +835,9 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) struct sim_ent *ent = &ent_store->entities[ent_index]; if (!sim_ent_is_valid_and_active(ent)) continue; if (!sim_ent_has_prop(ent, SIM_ENT_PROP_TRIGGERED_THIS_TICK)) continue; - if ((time - ent->last_triggered < ent->trigger_delay) && ent->last_triggered != 0) continue; + if ((sim_time - ent->last_triggered < ent->trigger_delay) && ent->last_triggered != 0) continue; - ent->last_triggered = time; + ent->last_triggered = sim_time; /* Fire weapon */ if (sim_ent_has_prop(ent, SIM_ENT_PROP_WEAPON)) { @@ -1019,7 +955,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) } /* Set correction rate dynamically since motor velocity is only set for one frame */ - joint_ent->motor_joint_data.correction_rate = 10 * dt; + joint_ent->motor_joint_data.correction_rate = 10 * world_dt; /* Solve for final angle using law of sines */ @@ -1072,7 +1008,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) f32 diff = math_unwind_angle(new_angle - xform_get_rotation(joint_xf)); if (math_fabs(diff) > angle_error_allowed) { /* Instantly snap joint ent to new angle */ - new_vel = diff / dt; + new_vel = diff / real_dt; } } sim_ent_set_angular_velocity(joint_ent, new_vel); @@ -1112,8 +1048,8 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) * Create mouse joints from client debug drag * ========================== */ - for (u64 i = 0; i < ctx->tick.client_store->num_reserved; ++i) { - struct sim_client *client = &ctx->tick.client_store->clients[i]; + for (u64 i = 0; i < ctx->world.client_store->num_reserved; ++i) { + struct sim_client *client = &ctx->world.client_store->clients[i]; if (client->valid) { struct v2 cursor = client->cursor_pos; b32 start_dragging = client->dbg_drag_start; @@ -1182,7 +1118,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) { struct phys_ctx phys = ZI; - phys.tick_id = ctx->tick.tick_id; + phys.tick = ctx->world.tick; phys.store = ent_store; phys.space = space; phys.contact_lookup = &ctx->contact_lookup; @@ -1193,7 +1129,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) #endif /* Step */ - ctx->last_phys_iteration = phys_step(&phys, dt, ctx->last_phys_iteration); + ctx->last_phys_iteration = phys_step(&phys, world_dt, ctx->last_phys_iteration); } /* ========================== * @@ -1207,7 +1143,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) struct v2 end = sim_ent_get_xform(ent).og; - struct v2 tick_velocity = v2_mul(ent->tracer_start_velocity, dt); + struct v2 tick_velocity = v2_mul(ent->tracer_start_velocity, world_dt); struct v2 gradient_start = v2_add(ent->tracer_gradient_start, tick_velocity); struct v2 gradient_end = v2_add(ent->tracer_gradient_end, tick_velocity); @@ -1229,7 +1165,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) 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->tick.tick_id) { + if (ent->activation_tick == ctx->world.tick) { struct sim_ent *src = sim_ent_from_handle(ent_store, ent->bullet_src); struct xform src_xf = sim_ent_get_xform(src); @@ -1307,7 +1243,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) /* Lerp camera */ if (ent->camera_applied_lerp_continuity_gen_plus_one == ent->camera_lerp_continuity_gen + 1) { - f32 t = 1 - math_pow(2.f, -20.f * (f32)dt); + f32 t = 1 - math_pow(2.f, -20.f * (f32)world_dt); xf = xform_lerp(xf, ent->camera_xform_target, t); } else { /* Skip lerp */ @@ -1340,7 +1276,7 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) if (!sim_ent_is_valid_and_active(ent)) continue; if (!sim_ent_has_prop(ent, SIM_ENT_PROP_QUAKE)) continue; - ent->quake_intensity = max_f32(0, ent->quake_intensity - (ent->quake_fade * dt)); + ent->quake_intensity = max_f32(0, ent->quake_intensity - (ent->quake_fade * world_dt)); if (ent->quake_intensity <= 0) { sim_ent_enable_prop(ent, SIM_ENT_PROP_RELEASE_NEXT_TICK); } @@ -1385,15 +1321,16 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) * Publish tick * ========================== */ - for (u64 i = 0; i < ctx->tick.client_store->num_reserved; ++i) { - struct sim_client *client = &ctx->tick.client_store->clients[i]; + for (u64 i = 0; i < ctx->world.client_store->num_reserved; ++i) { + struct sim_client *client = &ctx->world.client_store->clients[i]; if (client->valid) { struct temp_arena temp = arena_temp_begin(scratch.arena); /* TODO: Not like this */ struct sim_event snapshot_event = ZI; + snapshot_event.tick = ctx->world.tick; snapshot_event.kind = SIM_EVENT_KIND_SNAPSHOT; - snapshot_event.snapshot_data = sim_string_from_tick(temp.arena, client, &ctx->tick); + snapshot_event.snapshot_data = sim_snapshot_encode(temp.arena, client, &ctx->world); struct sim_event_list l = ZI; l.first = &snapshot_event; @@ -1418,20 +1355,3 @@ INTERNAL void sim_update(struct sim_ctx *ctx, f64 dt) scratch_end(scratch); } - -/* ========================== * - * Sim thread - * ========================== */ - -INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sim_thread_entry_point, arg) -{ - struct sim_ctx *ctx = (struct sim_ctx *)arg; - i64 last_frame_ns = 0; - i64 target_dt_ns = NS_FROM_SECONDS(SIM_FPS > (0) ? (1.0 / SIM_FPS) : 0); - while (!atomic_i32_eval(&ctx->sim_thread_shutdown)) { - __profscope(sim_update_w_sleep); - sleep_frame(last_frame_ns, target_dt_ns); - last_frame_ns = sys_time_ns(); - sim_update(ctx, (1.0 / SIM_FPS)); - } -} diff --git a/src/sim.h b/src/sim.h index 372afaca..8e172635 100644 --- a/src/sim.h +++ b/src/sim.h @@ -1,7 +1,9 @@ #ifndef SIM_H #define SIM_H -struct sim_ctx; +#include "sim_ent.h" +#include "sim_snapshot.h" + struct sprite_startup_receipt; struct phys_startup_receipt; struct host_startup_receipt; @@ -16,6 +18,26 @@ struct host_startup_receipt; #define SIM_LAYER_RELATIVE_DEFAULT 0 #define SIM_LAYER_RELATIVE_WEAPON 1 +struct sim_ctx { + struct arena arena; + + u64 last_phys_iteration; + + struct sprite_scope *sprite_frame_scope; + + struct host *host; + + /* Bookkeeping structures */ + struct sim_ent_lookup contact_lookup; +#if COLLIDER_DEBUG + struct sim_ent_lookup collision_debug_lookup; +#endif + struct space *space; + + /* Tick */ + struct sim_snapshot world; +}; + /* TODO: Get rid of startup receipts */ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr, struct phys_startup_receipt *phys_sr, @@ -24,5 +46,7 @@ struct sim_ctx *sim_ctx_alloc(struct sprite_startup_receipt *sprite_sr, void sim_ctx_release(struct sim_ctx *ctx); +void sim_update(struct sim_ctx *ctx, i64 target_dt_ns); + #endif diff --git a/src/sim_client.c b/src/sim_client.c index 7850365f..b5164f7d 100644 --- a/src/sim_client.c +++ b/src/sim_client.c @@ -2,6 +2,7 @@ #include "host.h" #include "arena.h" #include "util.h" +#include "arena.h" #define CHANNEL_LOOKUP_BUCKETS 4096 @@ -21,11 +22,11 @@ struct sim_client_channel_lookup_bucket { * Store * ========================== */ -struct sim_client_store *sim_client_store_alloc(void) +struct sim_client_store *sim_client_store_alloc(u64 arena_reserve) { - struct arena arena = arena_alloc(GIGABYTE(64)); + struct arena arena = arena_alloc(arena_reserve); u64 num_channel_lookup_buckets = CHANNEL_LOOKUP_BUCKETS; - u64 channel_lookup_buckets = arena_push_array_zero(&arena, struct sim_client_channel_lookup_bucket, num_channel_lookup_buckets); + struct sim_client_channel_lookup_bucket *channel_lookup_buckets = arena_push_array_zero(&arena, struct sim_client_channel_lookup_bucket, num_channel_lookup_buckets); struct sim_client_store *store = arena_push_zero(&arena, struct sim_client_store); store->clients = arena_dry_push(&arena, struct sim_client); diff --git a/src/sim_client.h b/src/sim_client.h index 084be734..0fd7ede4 100644 --- a/src/sim_client.h +++ b/src/sim_client.h @@ -52,7 +52,7 @@ INLINE struct sim_client_store *client_store_nil(void) return &_g_sim_client_store_nil; } -struct sim_client_store *sim_client_store_alloc(void); +struct sim_client_store *sim_client_store_alloc(u64 arena_reserve); void sim_client_store_release(struct sim_client_store *store); struct sim_client_store *client_store_from_client(struct sim_client *client); struct sim_client *sim_client_from_handle(struct sim_client_store *store, struct sim_client_handle handle); diff --git a/src/sim_ent.c b/src/sim_ent.c index dc0285f4..0b495bca 100644 --- a/src/sim_ent.c +++ b/src/sim_ent.c @@ -37,9 +37,9 @@ INTERNAL void store_make_root(struct sim_ent_store *store) store->root = root->handle; } -struct sim_ent_store *sim_ent_store_alloc(void) +struct sim_ent_store *sim_ent_store_alloc(u64 arena_reserve) { - struct arena arena = arena_alloc(GIGABYTE(64)); + struct arena arena = arena_alloc(arena_reserve); struct sim_ent_store *store = arena_push_zero(&arena, struct sim_ent_store); store->valid = true; store->arena = arena; @@ -500,9 +500,9 @@ struct sim_ent_lookup_key sim_ent_lookup_key_from_two_handles(struct sim_ent_han * Activate * ========================== */ -void sim_ent_activate(struct sim_ent *ent, u64 current_tick_id) +void sim_ent_activate(struct sim_ent *ent, u64 current_tick) { sim_ent_enable_prop(ent, SIM_ENT_PROP_ACTIVE); - ent->activation_tick = current_tick_id; + ent->activation_tick = current_tick; ++ent->continuity_gen; } diff --git a/src/sim_ent.h b/src/sim_ent.h index c5ab55a3..92b704e0 100644 --- a/src/sim_ent.h +++ b/src/sim_ent.h @@ -372,7 +372,7 @@ INLINE b32 sim_ent_is_valid_and_active(struct sim_ent *ent) * ========================== */ /* Entity store */ -struct sim_ent_store *sim_ent_store_alloc(void); +struct sim_ent_store *sim_ent_store_alloc(u64 arena_reserve); void sim_ent_store_release(struct sim_ent_store *store); void sim_ent_store_copy_replace(struct sim_ent_store *dest, struct sim_ent_store *src); @@ -414,6 +414,6 @@ void sim_ent_lookup_remove(struct sim_ent_lookup *l, struct sim_ent_lookup_entry struct sim_ent_lookup_key sim_ent_lookup_key_from_two_handles(struct sim_ent_handle h0, struct sim_ent_handle h1); /* Activate */ -void sim_ent_activate(struct sim_ent *ent, u64 current_tick_id); +void sim_ent_activate(struct sim_ent *ent, u64 current_tick); #endif diff --git a/src/sim_msg.c b/src/sim_msg.c index 81d6ab10..99b20bf5 100644 --- a/src/sim_msg.c +++ b/src/sim_msg.c @@ -1,7 +1,7 @@ #include "sim_msg.h" +#include "sim_snapshot.h" #include "arena.h" #include "byteio.h" -#include "world.h" /* ========================== * * Sim cmd @@ -135,6 +135,7 @@ struct string sim_string_from_events(struct arena *arena, struct sim_event_list for (struct sim_event *event = events.first; event; event = event->next) { struct byte_writer bw_size = bw_branch(&bw, sizeof(u64)); u64 start = bw_pos(&bw); + bw_write_var_uint(&bw, event->tick); bw_write_i8(&bw, event->kind); switch (event->kind) { @@ -179,6 +180,7 @@ void sim_events_from_host_events(struct arena *arena, struct host_event_array ho u64 event_size = br_read_u64(&br); u64 event_pos_end = br_pos(&br) + event_size; + sim_event->tick = br_read_var_uint(&br); sim_event->kind = br_read_i8(&br); switch (sim_event->kind) { case SIM_EVENT_KIND_SNAPSHOT: @@ -210,72 +212,77 @@ void sim_events_from_host_events(struct arena *arena, struct host_event_array ho * Snapshot * ========================== */ -struct string sim_string_from_tick(struct arena *arena, struct sim_client *client, struct world *tick) +struct string sim_snapshot_encode(struct arena *arena, struct sim_client *client, struct sim_snapshot *snapshot) { __prof; struct byte_writer bw = bw_from_arena(arena); - bw_write_var_uint(&bw, tick->continuity_gen); - bw_write_var_uint(&bw, tick->tick_id); - bw_write_var_sint(&bw, tick->publishtime_ns); + bw_write_var_uint(&bw, snapshot->continuity_gen); + bw_write_var_sint(&bw, snapshot->publishtime_ns); - bw_write_f64(&bw, tick->timescale); - bw_write_var_sint(&bw, tick->dt_ns); - bw_write_var_sint(&bw, tick->time_ns); + bw_write_var_sint(&bw, snapshot->real_dt_ns); + bw_write_var_sint(&bw, snapshot->real_time_ns); + + bw_write_f64(&bw, snapshot->world_timescale); + bw_write_var_sint(&bw, snapshot->world_dt_ns); + bw_write_var_sint(&bw, snapshot->world_time_ns); bw_write_var_uint(&bw, client->handle.gen); bw_write_var_uint(&bw, client->handle.idx); /* Client store */ - u64 num_clients = tick->client_store->num_reserved; + u64 num_clients = snapshot->client_store->num_reserved; bw_write_var_uint(&bw, num_clients); struct string clients_src = ZI; - clients_src.text = (u8 *)tick->client_store->clients; + clients_src.text = (u8 *)snapshot->client_store->clients; clients_src.len = sizeof(struct sim_client) * num_clients; br_write_bytes(&bw, clients_src); /* Entity store */ - u64 num_entities = tick->ent_store->num_reserved; + u64 num_entities = snapshot->ent_store->num_reserved; bw_write_var_uint(&bw, num_entities); struct string entities_src = ZI; - entities_src.text = (u8 *)tick->ent_store->entities; + entities_src.text = (u8 *)snapshot->ent_store->entities; entities_src.len = sizeof(struct sim_ent) * num_entities; br_write_bytes(&bw, entities_src); return bw_get_written(&bw); } -void sim_tick_from_string(struct string str, struct world *tick_out) +void sim_snapshot_decode(struct string str, struct sim_snapshot *snapshot, u64 tick) { __prof; struct byte_reader br = br_from_buffer(str); - tick_out->continuity_gen = br_read_var_uint(&br); - tick_out->tick_id = br_read_var_uint(&br); - tick_out->publishtime_ns = br_read_var_sint(&br); + snapshot->tick = tick; + snapshot->continuity_gen = br_read_var_uint(&br); + snapshot->publishtime_ns = br_read_var_sint(&br); - tick_out->timescale = br_read_f64(&br); - tick_out->dt_ns = br_read_var_sint(&br); - tick_out->time_ns = br_read_var_sint(&br); + snapshot->real_dt_ns = br_read_var_sint(&br); + snapshot->real_time_ns = br_read_var_sint(&br); - tick_out->local_client.gen = br_read_var_uint(&br); - tick_out->local_client.idx = br_read_var_uint(&br); + snapshot->world_timescale = br_read_f64(&br); + snapshot->world_dt_ns = br_read_var_sint(&br); + snapshot->world_time_ns = br_read_var_sint(&br); + + snapshot->local_client.gen = br_read_var_uint(&br); + snapshot->local_client.idx = br_read_var_uint(&br); /* Client store */ u64 num_clients = br_read_var_uint(&br); - arena_push_array(&tick_out->client_store->arena, struct sim_client, num_clients - tick_out->client_store->num_reserved); - tick_out->client_store->num_reserved = num_clients; + arena_push_array(&snapshot->client_store->arena, struct sim_client, num_clients - snapshot->client_store->num_reserved); + snapshot->client_store->num_reserved = num_clients; - tick_out->client_store->num_allocated = 0; + snapshot->client_store->num_allocated = 0; struct sim_client *clients_src = br_seek(&br, num_clients * sizeof(struct sim_client)); if (clients_src) { for (u64 i = 0; i < num_clients; ++i) { struct sim_client *src = &clients_src[i]; - struct sim_client *dst = &tick_out->client_store->clients[i]; + struct sim_client *dst = &snapshot->client_store->clients[i]; if (dst->valid) { - ++tick_out->client_store->num_allocated; + ++snapshot->client_store->num_allocated; } *dst = *src; } @@ -283,17 +290,17 @@ void sim_tick_from_string(struct string str, struct world *tick_out) /* Entity store */ u64 num_entities = br_read_var_uint(&br); - arena_push_array(&tick_out->ent_store->arena, struct sim_ent, num_entities - tick_out->ent_store->num_reserved); - tick_out->ent_store->num_reserved = num_entities; + arena_push_array(&snapshot->ent_store->arena, struct sim_ent, num_entities - snapshot->ent_store->num_reserved); + snapshot->ent_store->num_reserved = num_entities; - tick_out->ent_store->num_allocated = 0; + snapshot->ent_store->num_allocated = 0; struct sim_ent *entities_src = br_seek(&br, num_entities * sizeof(struct sim_ent)); if (entities_src) { for (u64 i = 0; i < num_entities; ++i) { struct sim_ent *src = &entities_src[i]; - struct sim_ent *dst = &tick_out->ent_store->entities[i]; + struct sim_ent *dst = &snapshot->ent_store->entities[i]; if (dst->valid) { - ++tick_out->ent_store->num_allocated; + ++snapshot->ent_store->num_allocated; } *dst = *src; } diff --git a/src/sim_msg.h b/src/sim_msg.h index fcc3fc85..9c9fff16 100644 --- a/src/sim_msg.h +++ b/src/sim_msg.h @@ -3,7 +3,7 @@ #include "host.h" -struct world; +struct sim_snapshot; struct sim_client; /* ========================== * @@ -83,6 +83,7 @@ enum sim_event_kind { }; struct sim_event { + u64 tick; enum sim_event_kind kind; struct host_channel_id channel_id; @@ -106,7 +107,7 @@ void sim_events_from_host_events(struct arena *arena, struct host_event_array ho * Snapshot * ========================== */ -struct string sim_string_from_tick(struct arena *arena, struct sim_client *client, struct world *tick); -void sim_tick_from_string(struct string str, struct world *tick_out); +struct string sim_snapshot_encode(struct arena *arena, struct sim_client *client, struct sim_snapshot *snapshot); +void sim_snapshot_decode(struct string str, struct sim_snapshot *snapshot, u64 tick); #endif diff --git a/src/sim_snapshot.c b/src/sim_snapshot.c new file mode 100644 index 00000000..4baa7b40 --- /dev/null +++ b/src/sim_snapshot.c @@ -0,0 +1,18 @@ +#include "sim_snapshot.h" +#include "sim_ent.h" +#include "sim_client.h" +#include "arena.h" +#include "scratch.h" + +void sim_snapshot_alloc(struct sim_snapshot *sim_snapshot) +{ + MEMZERO_STRUCT(sim_snapshot); + sim_snapshot->client_store = sim_client_store_alloc(GIGABYTE(64)); + sim_snapshot->ent_store = sim_ent_store_alloc(GIGABYTE(64)); +} + +void sim_snapshot_release(struct sim_snapshot *sim_snapshot) +{ + sim_ent_store_release(sim_snapshot->ent_store); + sim_client_store_release(sim_snapshot->client_store); +} diff --git a/src/sim_snapshot.h b/src/sim_snapshot.h new file mode 100644 index 00000000..6e601ad9 --- /dev/null +++ b/src/sim_snapshot.h @@ -0,0 +1,30 @@ +#ifndef SIM_SNAPSHOT_H +#define SIM_SNAPSHOT_H + +#include "sim_ent.h" +#include "sim_client.h" + +struct sim_snapshot { + u64 continuity_gen; /* Starts at 1 */ + u64 tick; /* Starts at 1 */ + i64 publishtime_ns; /* When was this tick simulated in program time */ + + /* Real time (increases with clock assuming no lag) */ + i64 real_dt_ns; + i64 real_time_ns; + + /* World time (affected by timescale) */ + f64 world_timescale; + i64 world_dt_ns; + i64 world_time_ns; + + struct sim_client_handle local_client; + + struct sim_client_store *client_store; + struct sim_ent_store *ent_store; +}; + +void sim_snapshot_alloc(struct sim_snapshot *sim_snapshot); +void sim_snapshot_release(struct sim_snapshot *sim_snapshot); + +#endif diff --git a/src/user.c b/src/user.c index be7c8fd0..d2184b8e 100644 --- a/src/user.c +++ b/src/user.c @@ -3,6 +3,7 @@ #include "sim.h" #include "sim_ent.h" #include "sim_msg.h" +#include "sim_snapshot.h" #include "renderer.h" #include "font.h" #include "sprite.h" @@ -14,7 +15,6 @@ #include "scratch.h" #include "math.h" #include "sys.h" -#include "world.h" #include "mixer.h" #include "atomic.h" #include "collider.h" @@ -30,12 +30,6 @@ struct bind_state { u32 num_releases; /* How many times was this bind released since last frame */ }; -struct blend_tick { - struct blend_tick *next; - struct blend_tick *prev; - struct world world; -}; - struct second_stat { u64 last_second_start; u64 last_second_end; @@ -46,6 +40,9 @@ GLOBAL struct { struct atomic_i32 user_thread_shutdown; struct sys_thread user_thread; + struct atomic_i32 sim_thread_shutdown; + struct sys_thread sim_thread; + struct arena arena; struct sys_window *window; struct sim_ctx *sim_ctx; @@ -70,9 +67,7 @@ GLOBAL struct { struct xform world_to_ui_xf; - struct blend_tick *head_free_blend_tick; - struct blend_tick *head_blend_tick; - struct world world; + struct sim_snapshot world; struct bind_state bind_states[USER_BIND_KIND_COUNT]; @@ -87,8 +82,6 @@ GLOBAL struct { struct arena sys_events_arena; /* Per-frame */ - i64 time_ns; - i64 dt_ns; struct v2 screen_size; struct v2 screen_cursor; struct v2 ui_screen_offset; @@ -136,6 +129,23 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = { #endif }; +/* ========================== * + * Sim thread + * ========================== */ + +INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_sim_thread_entry_point, arg) +{ + struct sim_ctx *ctx = (struct sim_ctx *)arg; + i64 last_frame_ns = 0; + i64 target_dt_ns = NS_FROM_SECONDS(1) / SIM_FPS;; + while (!atomic_i32_eval(&G.sim_thread_shutdown)) { + __profscope(sim_update_w_sleep); + sleep_frame(last_frame_ns, target_dt_ns); + last_frame_ns = sys_time_ns(); + sim_update(ctx, target_dt_ns); + } +} + /* ========================== * * Startup * ========================== */ @@ -171,7 +181,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, G.arena = arena_alloc(GIGABYTE(64)); G.sys_events_mutex = sys_mutex_alloc(); G.sys_events_arena = arena_alloc(GIGABYTE(64)); - world_alloc(&G.world); + sim_snapshot_alloc(&G.world); //struct sock_address bind_addr = sock_address_from_any_local_interface_with_dynamic_port(); G.host = host_alloc(0); @@ -188,6 +198,7 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, if (connect_address_str.len == 0) { G.sim_ctx = sim_ctx_alloc(sprite_sr, phys_sr, host_sr, 12345); G.connect_address_str = LIT("127.0.0.1:12345"); + G.sim_thread = sys_thread_alloc(&user_sim_thread_entry_point, G.sim_ctx, LIT("[P2] Sim thread")); } else { G.connect_address_str = string_copy(&G.arena, connect_address_str); } @@ -207,6 +218,8 @@ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(user_shutdown) sys_thread_wait_release(&G.user_thread); if (G.sim_ctx) { + atomic_i32_eval_exchange(&G.sim_thread_shutdown, true); + sys_thread_wait_release(&G.sim_thread); sim_ctx_release(G.sim_ctx); } } @@ -252,11 +265,11 @@ INTERNAL struct blend_tick *blend_tick_alloc(void) bt = G.head_free_blend_tick; G.head_free_blend_tick = bt->next; *bt = (struct blend_tick) { - .world = bt->world + .sim_snapshot = bt->sim_snapshot }; } else { bt = arena_push_zero(&G.arena, struct blend_tick); - world_alloc(&bt->world); + sim_snapshot_alloc(&bt->sim_snapshot); } if (G.head_blend_tick) { bt->next = G.head_blend_tick; @@ -289,8 +302,8 @@ INTERNAL void blend_tick_release(struct blend_tick *bt) } struct interp_ticks { - struct world *from_tick; - struct world *to_tick; + struct sim_snapshot *from_tick; + struct sim_snapshot *to_tick; }; INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns) @@ -298,28 +311,28 @@ INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns) __prof; /* Find newest stored tick */ - struct world *newest_tick = NULL; + struct sim_snapshot *newest_tick = NULL; for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { - if (!newest_tick || bt->world.tick_id > newest_tick->tick_id) { - newest_tick = &bt->world; + if (!newest_tick || bt->sim_snapshot.tick > newest_tick->tick) { + newest_tick = &bt->sim_snapshot; } } - struct world *from_tick; - struct world *to_tick; + struct sim_snapshot *from_tick; + struct sim_snapshot *to_tick; if (newest_tick && sim_get_latest_tick_continuity_gen() == newest_tick->continuity_gen) { /* Pull new tick from sim thread if necessary */ - if (!newest_tick || sim_get_latest_tick_id() > newest_tick->tick_id) { + if (!newest_tick || sim_get_latest_tick() > newest_tick->tick) { struct blend_tick *latest_bt = blend_tick_alloc(); - newest_tick = &latest_bt->world; + newest_tick = &latest_bt->sim_snapshot; sim_get_latest_tick(newest_tick); } /* Find oldest tick */ - struct world *oldest_tick = NULL; + struct sim_snapshot *oldest_tick = NULL; for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { - if (!oldest_tick || bt->world.tick_id < oldest_tick->tick_id) { - oldest_tick = &bt->world; + if (!oldest_tick || bt->sim_snapshot.tick < oldest_tick->tick) { + oldest_tick = &bt->sim_snapshot; } } @@ -327,14 +340,14 @@ INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns) from_tick = oldest_tick; to_tick = newest_tick; for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { - i64 bt_time_ns = bt->world.publishtime_ns; + i64 bt_time_ns = bt->sim_snapshot.publishtime_ns; if (bt_time_ns < blend_time_ns && bt_time_ns > from_tick->publishtime_ns) { - from_tick = &bt->world; + from_tick = &bt->sim_snapshot; } if (bt_time_ns > blend_time_ns && bt_time_ns < to_tick->publishtime_ns) { - to_tick = &bt->world; + to_tick = &bt->sim_snapshot; } } @@ -345,7 +358,7 @@ INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns) u64 bts_to_free_count = 0; for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { - i64 bt_time_ns = bt->world.publishtime_ns; + i64 bt_time_ns = bt->sim_snapshot.publishtime_ns; if (bt_time_ns < from_tick->publishtime_ns) { *arena_push(scratch.arena, struct blend_tick *) = bt; ++bts_to_free_count; @@ -378,7 +391,7 @@ INTERNAL struct interp_ticks pull_ticks(i64 blend_time_ns) /* Allocate new blend tick */ struct blend_tick *bt = blend_tick_alloc(); - struct world *tick = &bt->world; + struct sim_snapshot *tick = &bt->sim_snapshot; sim_get_latest_tick(tick); from_tick = tick; @@ -527,8 +540,6 @@ INTERNAL void user_update(void) * ========================== */ i64 now_ns = sys_time_ns(); - G.dt_ns = max_f64(0.0, now_ns - G.time_ns); - G.time_ns += G.dt_ns; G.screen_size = sys_window_get_size(G.window); struct sim_ent_store *store = G.world.ent_store; @@ -550,8 +561,8 @@ INTERNAL void user_update(void) /* Pull ticks */ struct interp_ticks interp_ticks = pull_ticks(blend_time_ns); - struct world *t0 = interp_ticks.from_tick; - struct world *t1 = interp_ticks.to_tick; + struct sim_snapshot *t0 = interp_ticks.from_tick; + struct sim_snapshot *t1 = interp_ticks.to_tick; f32 tick_blend = 0; { @@ -565,11 +576,11 @@ INTERNAL void user_update(void) tick_blend = clamp_f32(tick_blend, 0.0f, 1.0f); } - world_copy_replace(&G.world, t0); + world_copy_replace(&G.sim_snapshot, t0); /* Blend world globals */ - G.world.time_ns = math_lerp_i64(t0->time_ns, t1->time_ns, (f64)tick_blend); - G.world.dt_ns = math_lerp_i64(t0->dt_ns, t1->dt_ns, (f64)tick_blend); + G.sim_snapshot.time_ns = math_lerp_i64(t0->time_ns, t1->time_ns, (f64)tick_blend); + G.sim_snapshot.dt_ns = math_lerp_i64(t0->dt_ns, t1->dt_ns, (f64)tick_blend); /* Blend entities */ u64 num_entities = min_u64(t0->ent_store->num_reserved, t1->ent_store->num_reserved); @@ -617,8 +628,8 @@ INTERNAL void user_update(void) } #else struct interp_ticks interp_ticks = pull_ticks(G.time); - world_copy_replace(&G.world, interp_ticks.to_tick); - tick_is_first_frame = G.world.tick_id == 0; + world_copy_replace(&G.sim_snapshot, interp_ticks.to_tick); + tick_is_first_frame = G.sim_snapshot.tick == 0; #endif } #endif @@ -629,6 +640,7 @@ INTERNAL void user_update(void) struct sim_event_list sim_events = ZI; { + host_update(G.host); struct host_event_array host_events = host_pop_events(scratch.arena, G.host); sim_events_from_host_events(scratch.arena, host_events, &sim_events); } @@ -647,6 +659,7 @@ INTERNAL void user_update(void) } for (struct sim_event *event = sim_events.first; event; event = event->next) { + u64 tick = event->tick; enum sim_event_kind kind = event->kind; switch (kind) { @@ -663,7 +676,7 @@ INTERNAL void user_update(void) case SIM_EVENT_KIND_SNAPSHOT: { struct string snapshot_data = event->snapshot_data; - sim_tick_from_string(snapshot_data, &G.world); + sim_snapshot_decode(snapshot_data, &G.world, tick); } break; default: break; @@ -782,7 +795,7 @@ INTERNAL void user_update(void) f32 shake = ent->shake; if (shake > 0) { u64 basis = hash_fnv64(HASH_FNV64_BASIS, STRING_FROM_STRUCT(&ent->handle)); - u64 angle_seed0 = basis + (u64)(G.world.time_ns / frequency_ns); + u64 angle_seed0 = basis + (u64)(G.world.world_time_ns / frequency_ns); u64 angle_seed1 = angle_seed0 + 1; f32 angle0 = rng_noise_f32(angle_seed0, 0, TAU); f32 angle1 = rng_noise_f32(angle_seed1, 0, TAU); @@ -792,7 +805,7 @@ INTERNAL void user_update(void) struct v2 vec1 = v2_with_len(v2_from_angle(angle1), shake); /* TODO: Cubic interp? */ - f32 blend = (f32)(G.world.time_ns % frequency_ns) / (f32)frequency_ns; + f32 blend = (f32)(G.world.world_time_ns % frequency_ns) / (f32)frequency_ns; struct v2 vec = v2_lerp(vec0, vec1, blend); struct xform xf = sim_ent_get_xform(ent); @@ -1620,13 +1633,16 @@ INTERNAL void user_update(void) if (font) { struct temp_arena temp = arena_temp_begin(scratch.arena); - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.time_ns)))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("sim tick: %F"), FMT_UINT(G.world.tick))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("world time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.world.time_ns)))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("sim real time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.world.real_time_ns)))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("entities: %F/%F"), FMT_UINT(G.world.ent_store->num_allocated), FMT_UINT(G.world.ent_store->num_reserved))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("sim world time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.world.world_time_ns)))); + pos.y += spacing; + + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("sim entities: %F/%F"), FMT_UINT(G.world.ent_store->num_allocated), FMT_UINT(G.world.ent_store->num_reserved))); pos.y += spacing; pos.y += spacing; diff --git a/src/world.c b/src/world.c deleted file mode 100644 index 0b9c14e6..00000000 --- a/src/world.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "world.h" -#include "sim_ent.h" -#include "sim_client.h" -#include "arena.h" -#include "scratch.h" - -void world_alloc(struct world *world) -{ - MEMZERO_STRUCT(world); - world->client_store = sim_client_store_alloc(); - world->ent_store = sim_ent_store_alloc(); -} - -void world_release(struct world *world) -{ - sim_ent_store_release(world->ent_store); - sim_client_store_release(world->client_store); -} - -#if 0 -void world_copy_replace(struct world *dest, struct world *src) -{ - __prof; - struct temp_arena scratch = scratch_begin_no_conflict(); - struct world *old = arena_push(scratch.arena, struct world); - *old = *dest; - - MEMCPY_STRUCT(dest, src); - dest->ent_store = old->ent_store; - sim_ent_store_copy_replace(dest->ent_store, src->ent_store); - - scratch_end(scratch); -} -#endif diff --git a/src/world.h b/src/world.h deleted file mode 100644 index 2e2828c4..00000000 --- a/src/world.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef WORLD_H -#define WORLD_H - -#include "sim_ent.h" -#include "sim_client.h" - -struct world { - u64 continuity_gen; /* Starts at 1 */ - u64 tick_id; /* Starts at 1 */ - i64 publishtime_ns; /* When was this tick simulated in program time */ - - /* World time */ - f64 timescale; - i64 dt_ns; - i64 time_ns; - - struct sim_client_handle local_client; - - struct sim_client_store *client_store; - struct sim_ent_store *ent_store; -}; - -void world_alloc(struct world *world); -void world_release(struct world *world); - -#if 0 -void world_copy_replace(struct world *dest, struct world *src); -#endif - -#endif