diff --git a/src/entity.c b/src/entity.c index 87f8c41a..d3a0d33d 100644 --- a/src/entity.c +++ b/src/entity.c @@ -36,7 +36,6 @@ INTERNAL void store_make_root(struct entity_store *store) { struct entity *root = entity_alloc_unlinked(store); root->is_root = true; - root->active = true; root->local_xform = XFORM_IDENT; root->cached_global_xform = XFORM_IDENT; root->cached_global_xform_dirty = false; @@ -130,7 +129,6 @@ INTERNAL void entity_release_internal(struct entity_store *store, struct entity /* Release */ ++ent->handle.gen; ent->valid = false; - ent->active = false; ent->next_free = store->first_free; store->first_free = ent->handle; } diff --git a/src/entity.h b/src/entity.h index 91838a22..ddd18748 100644 --- a/src/entity.h +++ b/src/entity.h @@ -7,6 +7,9 @@ enum entity_prop { ENTITY_PROP_NONE, + ENTITY_PROP_ACTIVE, + ENTITY_PROP_RELEASE_AT_END_OF_TICK, + ENTITY_PROP_PLAYER_CONTROLLED, ENTITY_PROP_CAMERA, ENTITY_PROP_CAMERA_ACTIVE, @@ -14,7 +17,7 @@ enum entity_prop { ENTITY_PROP_WEAPON, ENTITY_PROP_TRIGGERING_EQUIPPED, ENTITY_PROP_TRIGGERED_THIS_TICK, - ENTITY_PROP_TRIGGERED_NEXT_TICK, + ENTITY_PROP_TRIGGER_NEXT_TICK, /* Test props */ @@ -61,12 +64,6 @@ struct entity { struct entity_handle first; struct entity_handle last; - /* ====================================================================== */ - /* Active */ - - /* Is this entity ready to interact with the world (subset of 'valid') */ - b32 active; - /* ====================================================================== */ /* Position */ @@ -193,25 +190,25 @@ INLINE struct entity_store *entity_store_nil(void) * Property helpers * ========================== */ -INLINE void entity_enable_prop(struct entity *entity, enum entity_prop prop) +INLINE void entity_enable_prop(struct entity *ent, enum entity_prop prop) { u64 index = prop / 64; u64 bit = prop % 64; - entity->props[index] |= ((u64)1 << bit); + ent->props[index] |= ((u64)1 << bit); } -INLINE void entity_disable_prop(struct entity *entity, enum entity_prop prop) +INLINE void entity_disable_prop(struct entity *ent, enum entity_prop prop) { u64 index = prop / 64; u64 bit = prop % 64; - entity->props[index] &= ~((u64)1 << bit); + ent->props[index] &= ~((u64)1 << bit); } -INLINE b32 entity_has_prop(struct entity *entity, enum entity_prop prop) +INLINE b32 entity_has_prop(struct entity *ent, enum entity_prop prop) { u64 index = prop / 64; u64 bit = prop % 64; - return !!(entity->props[index] & ((u64)1 << bit)); + return !!(ent->props[index] & ((u64)1 << bit)); } /* ========================== * @@ -228,7 +225,7 @@ void entity_store_reset(struct entity_store *store); struct entity *entity_alloc_unlinked(struct entity_store *store); struct entity *entity_alloc_top(struct entity_store *store); struct entity *entity_alloc_child(struct entity *parent); -void entity_release(struct entity_store *store, struct entity *entity); +void entity_release(struct entity_store *store, struct entity *ent); /* Xform */ struct xform entity_get_xform(struct entity *ent); diff --git a/src/game.c b/src/game.c index 1dbe3c14..75e9af41 100644 --- a/src/game.c +++ b/src/game.c @@ -243,7 +243,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { struct entity *ent = &store->entities[entity_index]; - if (!ent->active) continue; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; if (sprite_tag_is_nil(ent->sprite)) continue; /* Update animation */ @@ -295,7 +295,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { struct entity *ent = &store->entities[entity_index]; - if (!ent->active) continue; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { /* Process cmds */ @@ -314,12 +314,14 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) * start and immediate stop cmd should still move the player a * tad. */ switch (cmd.kind) { - case GAME_CMD_KIND_PLAYER_MOVE: { + case GAME_CMD_KIND_PLAYER_MOVE: + { move = cmd.move_dir; focus = v2_sub(cmd.aim_pos, entity_get_xform(ent).og); } break; - case GAME_CMD_KIND_PLAYER_FIRE: { + case GAME_CMD_KIND_PLAYER_FIRE: + { if (start) { firing = true; } else if (stop) { @@ -354,7 +356,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { struct entity *ent = &store->entities[entity_index]; - if (!ent->active) continue; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; if (entity_has_prop(ent, ENTITY_PROP_TEST)) { if (!ent->test_initialized) { @@ -389,12 +391,12 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { struct entity *ent = &store->entities[entity_index]; - if (!ent->active) continue; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; /* Trigger equipped */ if (entity_has_prop(ent, ENTITY_PROP_TRIGGERING_EQUIPPED)) { struct entity *eq = entity_from_handle(store, ent->equipped); - if (eq->active) { + if (entity_has_prop(eq, ENTITY_PROP_ACTIVE)) { entity_enable_prop(eq, ENTITY_PROP_TRIGGERED_THIS_TICK); } } @@ -407,7 +409,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { struct entity *ent = &store->entities[entity_index]; - if (!ent->active) continue; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; if (!entity_has_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK)) continue; if ((time - ent->last_triggered < ent->trigger_delay) && ent->last_triggered != 0) continue; @@ -445,7 +447,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { struct entity *ent = &store->entities[entity_index]; - if (!ent->active) continue; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; /* Player angle */ @@ -535,9 +537,9 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { struct entity *ent = &store->entities[entity_index]; - if (!ent->active) continue; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; - /* Camera follow */ + /* Camera follow */ if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) { struct entity *follow = entity_from_handle(store, ent->camera_follow); @@ -580,7 +582,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { struct entity *ent = &store->entities[entity_index]; - if (!ent->active) continue; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; if (entity_has_prop(ent, ENTITY_PROP_TEST_SOUND_EMITTER)) { struct mixer_desc desc = ent->sound_desc; @@ -599,11 +601,40 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) } } + /* ========================== * + * Release entities + * ========================== */ + + /* TODO: Breadth first iteration to only release parent entities (since + * child entities will be released along with parent anyway) */ + + { + struct temp_arena temp = arena_temp_begin(scratch.arena); + + struct entity **ents_to_release = arena_dry_push(temp.arena, struct entity *); + u64 ents_to_release_count = 0; + for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { + struct entity *ent = &store->entities[entity_index]; + if (!ent->valid) continue; + + if (entity_has_prop(ent, ENTITY_PROP_RELEASE_AT_END_OF_TICK)) { + *arena_push(temp.arena, struct entity *) = ent; + ++ents_to_release_count; + } + } + + for (u64 i = 0; i < ents_to_release_count; ++i) { + entity_release(store, ents_to_release[i]); + } + + arena_temp_end(temp); + } + /* ========================== * * Publish tick * ========================== */ - /* Update cached global xforms to ensure they're accurate in published tick */ + /* Update cached global xforms to ensure they're accurate in published tick */ { struct temp_arena temp = arena_temp_begin(scratch.arena); @@ -655,10 +686,10 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { struct entity *ent = &store->entities[entity_index]; - if (!ent->active) continue; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; - if (entity_has_prop(ent, ENTITY_PROP_TRIGGERED_NEXT_TICK)) { - entity_disable_prop(ent, ENTITY_PROP_TRIGGERED_NEXT_TICK); + if (entity_has_prop(ent, ENTITY_PROP_TRIGGER_NEXT_TICK)) { + entity_disable_prop(ent, ENTITY_PROP_TRIGGER_NEXT_TICK); entity_enable_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK); } else if (entity_has_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK)) { entity_disable_prop(ent, ENTITY_PROP_TRIGGERED_THIS_TICK); @@ -673,8 +704,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct entity *ent = &store->entities[entity_index]; if (!ent->valid) continue; - if (!ent->active) { - ent->active = true; + if (!entity_has_prop(ent, ENTITY_PROP_ACTIVE)) { + entity_enable_prop(ent, ENTITY_PROP_ACTIVE); ++ent->continuity_gen; } } diff --git a/src/user.c b/src/user.c index 4683ef90..dcf6c8ce 100644 --- a/src/user.c +++ b/src/user.c @@ -456,7 +456,7 @@ INTERNAL void user_update(void) struct entity *e0 = &t0->entity_store->entities[i]; struct entity *e1 = &t1->entity_store->entities[i]; struct entity *e = &store->entities[i]; - ASSERT(e->cached_global_xform_dirty == false); /* Game thread should have cached all global xforms before publishing */ + ASSERT(!e->valid || e->cached_global_xform_dirty == false); /* Game thread should have cached all global xforms before publishing */ if (e0->handle.gen == e1->handle.gen && e0->continuity_gen == e1->continuity_gen) { e->local_xform = xform_lerp(e0->local_xform, e1->local_xform, tick_blend); e->cached_global_xform = xform_lerp(e0->cached_global_xform, e1->cached_global_xform, tick_blend); @@ -773,7 +773,7 @@ INTERNAL void user_update(void) for (u64 entity_index = 0; entity_index < store->count; ++entity_index) { __profscope(user_entity_iter); struct entity *ent = &store->entities[entity_index]; - if (!ent->active) continue; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; if (ent->is_root) continue; struct sprite_tag sprite = ent->sprite; @@ -905,7 +905,7 @@ INTERNAL void user_update(void) } /* Draw hierarchy */ - if (parent->active && !parent->is_root) { + if (entity_has_prop(parent, ENTITY_PROP_ACTIVE) && !parent->is_root) { u32 color = RGBA_32_F(0.6, 0.6, 1, 0.75); f32 thickness = 5; f32 arrow_height = 15;