From f5e45d6ba125f2d356c060ab1970f4fabbac6c0a Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 30 Oct 2024 14:47:17 -0500 Subject: [PATCH] game tick continuity gen. start removing static constraint lookup --- src/entity.c | 15 ------- src/entity.h | 1 - src/game.c | 50 +++++++++++++++++++---- src/game.h | 1 + src/user.c | 112 ++++++++++++++++++++++++++++++++------------------- src/world.h | 5 ++- 6 files changed, 117 insertions(+), 67 deletions(-) diff --git a/src/entity.c b/src/entity.c index 7a252062..5160c433 100644 --- a/src/entity.c +++ b/src/entity.c @@ -77,21 +77,6 @@ void entity_store_copy_replace(struct entity_store *dest, struct entity_store *s dest->entities = dest_entities; } -void entity_store_release_all_entities(struct entity_store *store) -{ -#if 0 - store->allocated = 0; - store->reserved = 0; - store->first_free = entity_nil_handle(); - arena_pop_to(&store->arena, STORE_ENTITIES_OFFSET); - store_make_root(store); -#else - struct entity *root = entity_from_handle(store, store->root); - entity_release(store, root); - store_make_root(store); -#endif -} - /* ========================== * * Allocation * ========================== */ diff --git a/src/entity.h b/src/entity.h index af9f3396..e6a7e740 100644 --- a/src/entity.h +++ b/src/entity.h @@ -436,7 +436,6 @@ INLINE b32 entity_is_valid_and_active(struct entity *ent) struct entity_store *entity_store_alloc(void); void entity_store_release(struct entity_store *store); void entity_store_copy_replace(struct entity_store *dest, struct entity_store *src); -void entity_store_release_all_entities(struct entity_store *store); /* Entity */ struct entity *entity_alloc(struct entity *parent); diff --git a/src/game.c b/src/game.c index 338c4861..90b84f53 100644 --- a/src/game.c +++ b/src/game.c @@ -24,6 +24,7 @@ GLOBAL struct { /* TODO: Remove this (testing) */ b32 extra_spawn; + b32 should_reset_level; /* Game thread input */ struct sys_mutex game_cmds_mutex; @@ -39,6 +40,7 @@ GLOBAL struct { /* Ticks */ struct sys_mutex prev_tick_mutex; struct atomic_u64 prev_tick_id; + struct atomic_u64 prev_tick_continuity_gen; struct world prev_tick; struct world tick; } G = ZI, DEBUG_ALIAS(G, G_game); @@ -49,6 +51,7 @@ GLOBAL struct { INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(game_shutdown); INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg); +INTERNAL void reset_world(void); struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr, struct sprite_startup_receipt *sheet_sr, @@ -79,14 +82,15 @@ struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr, G.game_cmds_mutex = sys_mutex_alloc(); G.game_cmds_arena = arena_alloc(GIGABYTE(64)); - /* Initialize ticks */ - world_alloc(&G.tick); + /* Initialize empty world */ + reset_world(); + + /* Initialize prev tick */ world_alloc(&G.prev_tick); /* FIXME: Make the world struct itself readonly as well */ arena_set_readonly(&G.prev_tick.entity_store->arena); G.prev_tick_mutex = sys_mutex_alloc(); - G.tick.timescale = GAME_TIMESCALE; G.game_thread = sys_thread_alloc(&game_thread_entry_point, NULL, STR("[P2] Game thread")); app_register_exit_callback(&game_shutdown); @@ -139,6 +143,22 @@ INTERNAL void activate_now(struct entity *ent) ++ent->continuity_gen; } +/* ========================== * + * Reset + * ========================== */ + +INTERNAL void reset_world(void) +{ + if (G.tick.entity_store) { + /* Release world */ + world_release(&G.tick); + } + /* Re-create world */ + world_alloc(&G.tick); + G.tick.continuity_gen = atomic_u64_eval(&G.prev_tick_continuity_gen) + 1; + G.tick.timescale = GAME_TIMESCALE; +} + /* ========================== * * Test * ========================== */ @@ -206,8 +226,7 @@ INTERNAL void spawn_test_entities(f32 offset) entity_set_xform(e, xf); - e->linear_ground_friction = 250; - e->angular_ground_friction = 200; + e->linear_ground_friction = 250;e->angular_ground_friction = 200; //e->control_force = 500; e->control_force = 500; @@ -1351,6 +1370,7 @@ INTERNAL void publish_game_tick(void) } arena_set_readonly(&G.prev_tick.entity_store->arena); atomic_u64_eval_exchange(&G.prev_tick_id, G.prev_tick.tick_id); + atomic_u64_eval_exchange(&G.prev_tick_continuity_gen, G.prev_tick.continuity_gen); sys_mutex_unlock(&lock); } @@ -1360,6 +1380,17 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct temp_arena scratch = scratch_begin_no_conflict(); + /* ========================== * + * Reset level if necessary + * ========================== */ + + if (G.should_reset_level) { + logf_info("Clearing level"); + G.should_reset_level = false; + G.extra_spawn = false; + reset_world(); + } + /* ========================== * * Begin frame * ========================== */ @@ -1412,9 +1443,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) /* Clear level */ case GAME_CMD_KIND_CLEAR_ALL: { - logf_info("Clearing level"); - entity_store_release_all_entities(store); - G.extra_spawn = false; + G.should_reset_level = true; } break; /* Spawn test */ @@ -2235,6 +2264,11 @@ u64 game_get_latest_tick_id(void) return atomic_u64_eval(&G.prev_tick_id); } +u64 game_get_latest_tick_continuity_gen(void) +{ + return atomic_u64_eval(&G.prev_tick_continuity_gen); +} + void game_push_cmds(struct game_cmd_array cmd_array) { push_cmds(cmd_array); diff --git a/src/game.h b/src/game.h index e13c0354..97ade7df 100644 --- a/src/game.h +++ b/src/game.h @@ -57,6 +57,7 @@ struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr, void game_get_latest_tick(struct world *dest); u64 game_get_latest_tick_id(void); +u64 game_get_latest_tick_continuity_gen(void); void game_push_cmds(struct game_cmd_array cmd_array); diff --git a/src/user.c b/src/user.c index 7a09a4b4..7c5f3043 100644 --- a/src/user.c +++ b/src/user.c @@ -255,57 +255,87 @@ INTERNAL struct interp_ticks pull_ticks(f64 blend_time) } } - /* Pull new tick from game thread if necessary */ - if (!newest_tick || game_get_latest_tick_id() > newest_tick->tick_id) { - struct blend_tick *latest_bt = blend_tick_alloc(); - newest_tick = &latest_bt->world; - game_get_latest_tick(newest_tick); - } - - /* Find oldest tick */ - struct world *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; - } - } - - /* Find closest ticks to blend time */ - struct world *from_tick = oldest_tick; - struct world *to_tick = newest_tick; - for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { - f64 bt_time = sys_timestamp_seconds(bt->world.tick_ts); - - if (bt_time < blend_time && bt_time > sys_timestamp_seconds(from_tick->tick_ts)) { - from_tick = &bt->world; + struct world *from_tick; + struct world *to_tick; + if (newest_tick && game_get_latest_tick_continuity_gen() == newest_tick->continuity_gen) { + /* Pull new tick from game thread if necessary */ + if (!newest_tick || game_get_latest_tick_id() > newest_tick->tick_id) { + struct blend_tick *latest_bt = blend_tick_alloc(); + newest_tick = &latest_bt->world; + game_get_latest_tick(newest_tick); } - if (bt_time > blend_time && bt_time < sys_timestamp_seconds(to_tick->tick_ts)) { - to_tick = &bt->world; - } - } - - /* Free any unused old ticks */ - { - struct temp_arena scratch = scratch_begin_no_conflict(); - struct blend_tick **bts_to_free = arena_dry_push(scratch.arena, struct blend_tick *); - u64 bts_to_free_count = 0; - + /* Find oldest tick */ + struct world *oldest_tick = NULL; for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { - f64 bt_time = sys_timestamp_seconds(bt->world.tick_ts); - if (bt_time < sys_timestamp_seconds(from_tick->tick_ts)) { - *arena_push(scratch.arena, struct blend_tick *) = bt; - ++bts_to_free_count; + if (!oldest_tick || bt->world.tick_id < oldest_tick->tick_id) { + oldest_tick = &bt->world; } } - for (u64 i = 0; i < bts_to_free_count; ++i) { - blend_tick_release(bts_to_free[i]); + /* Find closest ticks to blend time */ + from_tick = oldest_tick; + to_tick = newest_tick; + for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { + f64 bt_time = sys_timestamp_seconds(bt->world.tick_ts); + + if (bt_time < blend_time && bt_time > sys_timestamp_seconds(from_tick->tick_ts)) { + from_tick = &bt->world; + } + + if (bt_time > blend_time && bt_time < sys_timestamp_seconds(to_tick->tick_ts)) { + to_tick = &bt->world; + } } - scratch_end(scratch); + /* Free any unused old ticks */ + { + struct temp_arena scratch = scratch_begin_no_conflict(); + struct blend_tick **bts_to_free = arena_dry_push(scratch.arena, struct blend_tick *); + u64 bts_to_free_count = 0; + + for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { + f64 bt_time = sys_timestamp_seconds(bt->world.tick_ts); + if (bt_time < sys_timestamp_seconds(from_tick->tick_ts)) { + *arena_push(scratch.arena, struct blend_tick *) = bt; + ++bts_to_free_count; + } + } + + for (u64 i = 0; i < bts_to_free_count; ++i) { + blend_tick_release(bts_to_free[i]); + } + + scratch_end(scratch); + } + } else { + /* Latest tick is discontinuous */ + + /* Free all blend ticks */ + { + struct temp_arena scratch = scratch_begin_no_conflict(); + struct blend_tick **bts_to_free = arena_dry_push(scratch.arena, struct blend_tick *); + u64 bts_to_free_count = 0; + for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) { + *arena_push(scratch.arena, struct blend_tick *) = bt; + ++bts_to_free_count; + } + for (u64 i = 0; i < bts_to_free_count; ++i) { + blend_tick_release(bts_to_free[i]); + } + scratch_end(scratch); + } + + /* Allocate new blend tick */ + struct blend_tick *bt = blend_tick_alloc(); + struct world *tick = &bt->world; + game_get_latest_tick(tick); + + from_tick = tick; + to_tick = tick; } + return (struct interp_ticks) { .from_tick = from_tick, .to_tick = to_tick diff --git a/src/world.h b/src/world.h index b9cfc500..a7c870e8 100644 --- a/src/world.h +++ b/src/world.h @@ -4,8 +4,9 @@ #include "entity.h" struct world { - u64 tick_id; /* Starts at 1 */ - u64 tick_ts; /* When was this tick simulated in program time */ + u64 continuity_gen; /* Starts at 1 */ + u64 tick_id; /* Starts at 1 */ + u64 tick_ts; /* When was this tick simulated in program time */ /* World time */ f64 timescale;