progress & fix buddy bug

This commit is contained in:
jacob 2025-02-09 15:22:43 -06:00
parent 6fa3517d7a
commit f000bd7e65
18 changed files with 282 additions and 319 deletions

View File

@ -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;

View File

@ -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)) {

View File

@ -115,7 +115,7 @@ INLINE void ix_pause(void)
_mm_pause();
}
INLINE i64 ix_clock(void)
INLINE u64 ix_clock(void)
{
return __rdtsc();
}

View File

@ -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);
}

View File

@ -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;

224
src/sim.c
View File

@ -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));
}
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

18
src/sim_snapshot.c Normal file
View File

@ -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);
}

30
src/sim_snapshot.h Normal file
View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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