game tick continuity gen. start removing static constraint lookup

This commit is contained in:
jacob 2024-10-30 14:47:17 -05:00
parent c071e17305
commit f5e45d6ba1
6 changed files with 117 additions and 67 deletions

View File

@ -77,21 +77,6 @@ void entity_store_copy_replace(struct entity_store *dest, struct entity_store *s
dest->entities = dest_entities; 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 * Allocation
* ========================== */ * ========================== */

View File

@ -436,7 +436,6 @@ INLINE b32 entity_is_valid_and_active(struct entity *ent)
struct entity_store *entity_store_alloc(void); struct entity_store *entity_store_alloc(void);
void entity_store_release(struct entity_store *store); void entity_store_release(struct entity_store *store);
void entity_store_copy_replace(struct entity_store *dest, struct entity_store *src); void entity_store_copy_replace(struct entity_store *dest, struct entity_store *src);
void entity_store_release_all_entities(struct entity_store *store);
/* Entity */ /* Entity */
struct entity *entity_alloc(struct entity *parent); struct entity *entity_alloc(struct entity *parent);

View File

@ -24,6 +24,7 @@ GLOBAL struct {
/* TODO: Remove this (testing) */ /* TODO: Remove this (testing) */
b32 extra_spawn; b32 extra_spawn;
b32 should_reset_level;
/* Game thread input */ /* Game thread input */
struct sys_mutex game_cmds_mutex; struct sys_mutex game_cmds_mutex;
@ -39,6 +40,7 @@ GLOBAL struct {
/* Ticks */ /* Ticks */
struct sys_mutex prev_tick_mutex; struct sys_mutex prev_tick_mutex;
struct atomic_u64 prev_tick_id; struct atomic_u64 prev_tick_id;
struct atomic_u64 prev_tick_continuity_gen;
struct world prev_tick; struct world prev_tick;
struct world tick; struct world tick;
} G = ZI, DEBUG_ALIAS(G, G_game); } G = ZI, DEBUG_ALIAS(G, G_game);
@ -49,6 +51,7 @@ GLOBAL struct {
INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(game_shutdown); INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(game_shutdown);
INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg); 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 game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr,
struct sprite_startup_receipt *sheet_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_mutex = sys_mutex_alloc();
G.game_cmds_arena = arena_alloc(GIGABYTE(64)); G.game_cmds_arena = arena_alloc(GIGABYTE(64));
/* Initialize ticks */ /* Initialize empty world */
world_alloc(&G.tick); reset_world();
/* Initialize prev tick */
world_alloc(&G.prev_tick); world_alloc(&G.prev_tick);
/* FIXME: Make the world struct itself readonly as well */ /* FIXME: Make the world struct itself readonly as well */
arena_set_readonly(&G.prev_tick.entity_store->arena); arena_set_readonly(&G.prev_tick.entity_store->arena);
G.prev_tick_mutex = sys_mutex_alloc(); 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")); G.game_thread = sys_thread_alloc(&game_thread_entry_point, NULL, STR("[P2] Game thread"));
app_register_exit_callback(&game_shutdown); app_register_exit_callback(&game_shutdown);
@ -139,6 +143,22 @@ INTERNAL void activate_now(struct entity *ent)
++ent->continuity_gen; ++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 * Test
* ========================== */ * ========================== */
@ -206,8 +226,7 @@ INTERNAL void spawn_test_entities(f32 offset)
entity_set_xform(e, xf); entity_set_xform(e, xf);
e->linear_ground_friction = 250; e->linear_ground_friction = 250;e->angular_ground_friction = 200;
e->angular_ground_friction = 200;
//e->control_force = 500; //e->control_force = 500;
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); 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_id, G.prev_tick.tick_id);
atomic_u64_eval_exchange(&G.prev_tick_continuity_gen, G.prev_tick.continuity_gen);
sys_mutex_unlock(&lock); 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(); 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 * Begin frame
* ========================== */ * ========================== */
@ -1412,9 +1443,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds)
/* Clear level */ /* Clear level */
case GAME_CMD_KIND_CLEAR_ALL: case GAME_CMD_KIND_CLEAR_ALL:
{ {
logf_info("Clearing level"); G.should_reset_level = true;
entity_store_release_all_entities(store);
G.extra_spawn = false;
} break; } break;
/* Spawn test */ /* Spawn test */
@ -2235,6 +2264,11 @@ u64 game_get_latest_tick_id(void)
return atomic_u64_eval(&G.prev_tick_id); 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) void game_push_cmds(struct game_cmd_array cmd_array)
{ {
push_cmds(cmd_array); push_cmds(cmd_array);

View File

@ -57,6 +57,7 @@ struct game_startup_receipt game_startup(struct mixer_startup_receipt *mixer_sr,
void game_get_latest_tick(struct world *dest); void game_get_latest_tick(struct world *dest);
u64 game_get_latest_tick_id(void); 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); void game_push_cmds(struct game_cmd_array cmd_array);

View File

@ -255,57 +255,87 @@ INTERNAL struct interp_ticks pull_ticks(f64 blend_time)
} }
} }
/* Pull new tick from game thread if necessary */ struct world *from_tick;
if (!newest_tick || game_get_latest_tick_id() > newest_tick->tick_id) { struct world *to_tick;
struct blend_tick *latest_bt = blend_tick_alloc(); if (newest_tick && game_get_latest_tick_continuity_gen() == newest_tick->continuity_gen) {
newest_tick = &latest_bt->world; /* Pull new tick from game thread if necessary */
game_get_latest_tick(newest_tick); 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;
/* Find oldest tick */ game_get_latest_tick(newest_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;
} }
if (bt_time > blend_time && bt_time < sys_timestamp_seconds(to_tick->tick_ts)) { /* Find oldest tick */
to_tick = &bt->world; struct world *oldest_tick = NULL;
}
}
/* 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) { for (struct blend_tick *bt = G.head_blend_tick; bt; bt = bt->next) {
f64 bt_time = sys_timestamp_seconds(bt->world.tick_ts); if (!oldest_tick || bt->world.tick_id < oldest_tick->tick_id) {
if (bt_time < sys_timestamp_seconds(from_tick->tick_ts)) { oldest_tick = &bt->world;
*arena_push(scratch.arena, struct blend_tick *) = bt;
++bts_to_free_count;
} }
} }
for (u64 i = 0; i < bts_to_free_count; ++i) { /* Find closest ticks to blend time */
blend_tick_release(bts_to_free[i]); 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) { return (struct interp_ticks) {
.from_tick = from_tick, .from_tick = from_tick,
.to_tick = to_tick .to_tick = to_tick

View File

@ -4,8 +4,9 @@
#include "entity.h" #include "entity.h"
struct world { struct world {
u64 tick_id; /* Starts at 1 */ u64 continuity_gen; /* Starts at 1 */
u64 tick_ts; /* When was this tick simulated in program time */ u64 tick_id; /* Starts at 1 */
u64 tick_ts; /* When was this tick simulated in program time */
/* World time */ /* World time */
f64 timescale; f64 timescale;