game tick continuity gen. start removing static constraint lookup
This commit is contained in:
parent
c071e17305
commit
f5e45d6ba1
15
src/entity.c
15
src/entity.c
@ -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
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
50
src/game.c
50
src/game.c
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
112
src/user.c
112
src/user.c
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user