📦Archetypes, entities, components introspection📦
This commit is contained in:
		
							parent
							
								
									8055ac0cac
								
							
						
					
					
						commit
						cb05c2cf1d
					
				
					 2 changed files with 198 additions and 0 deletions
				
			
		
							
								
								
									
										133
									
								
								tests/zecsy.cpp
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								tests/zecsy.cpp
									
									
									
									
									
								
							| 
						 | 
					@ -409,3 +409,136 @@ TEST_CASE("Systems handle negative delta time")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    REQUIRE(count == 2);
 | 
					    REQUIRE(count == 2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("Entity count tracking")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    world w;
 | 
				
			||||||
 | 
					    REQUIRE(w.entity_count() == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto e1 = w.make_entity();
 | 
				
			||||||
 | 
					    const auto e2 = w.make_entity();
 | 
				
			||||||
 | 
					    REQUIRE(w.entity_count() == 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    w.destroy_entity(e1);
 | 
				
			||||||
 | 
					    REQUIRE(w.entity_count() == 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("Component counting mechanisms")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct Health
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        int value;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Position
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        float x, y;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    world w;
 | 
				
			||||||
 | 
					    auto e = w.make_entity();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    REQUIRE(w.component_count<Health>() == 0);
 | 
				
			||||||
 | 
					    REQUIRE(w.total_component_count() == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    w.set<Health>(e);
 | 
				
			||||||
 | 
					    REQUIRE(w.component_count<Health>() == 1);
 | 
				
			||||||
 | 
					    REQUIRE(w.total_component_count() == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    w.set<Position>(e);
 | 
				
			||||||
 | 
					    REQUIRE(w.component_count<Position>() == 1);
 | 
				
			||||||
 | 
					    REQUIRE(w.total_component_count() == 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    w.remove<Health>(e);
 | 
				
			||||||
 | 
					    REQUIRE(w.component_count<Health>() == 0);
 | 
				
			||||||
 | 
					    REQUIRE(w.total_component_count() == 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("Archetype signature management")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct A
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct B
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct C
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    world w;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Initial state: empty archetype
 | 
				
			||||||
 | 
					    REQUIRE(w.archetype_count() == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto e = w.make_entity();
 | 
				
			||||||
 | 
					    REQUIRE(w.archetype_count() == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Add first component
 | 
				
			||||||
 | 
					    w.set<A>(e);
 | 
				
			||||||
 | 
					    REQUIRE(w.archetype_count() == 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("Component distribution across archetypes")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct A
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct B
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    world w;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Create 10 entities in different configurations
 | 
				
			||||||
 | 
					    for(int i = 0; i < 5; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto e = w.make_entity();
 | 
				
			||||||
 | 
					        w.set<A>(e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for(int i = 0; i < 3; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto e = w.make_entity();
 | 
				
			||||||
 | 
					        w.set<A, B>(e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for(int i = 0; i < 2; ++i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto e = w.make_entity();
 | 
				
			||||||
 | 
					        w.set<B>(e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Verify distribution
 | 
				
			||||||
 | 
					    REQUIRE(w.entity_count() == 10);
 | 
				
			||||||
 | 
					    REQUIRE(w.component_count<A>() == 8);
 | 
				
			||||||
 | 
					    REQUIRE(w.component_count<B>() == 5);
 | 
				
			||||||
 | 
					    REQUIRE(w.archetype_count() == 3); //<A>, <A, B>, <B>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_CASE("Entity inspection")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct Transform
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        float x, y;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Renderable
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    world w;
 | 
				
			||||||
 | 
					    auto e = w.make_entity();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    REQUIRE(w.components_in_entity(e) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    w.set<Transform>(e);
 | 
				
			||||||
 | 
					    REQUIRE(w.components_in_entity(e) == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    w.set<Renderable>(e);
 | 
				
			||||||
 | 
					    REQUIRE(w.components_in_entity(e) == 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    w.remove<Transform>(e);
 | 
				
			||||||
 | 
					    REQUIRE(w.components_in_entity(e) == 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										65
									
								
								zecsy.hpp
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								zecsy.hpp
									
									
									
									
									
								
							| 
						 | 
					@ -34,6 +34,14 @@ namespace zecsy
 | 
				
			||||||
        entity_id make_entity();
 | 
					        entity_id make_entity();
 | 
				
			||||||
        void destroy_entity(entity_id e);
 | 
					        void destroy_entity(entity_id e);
 | 
				
			||||||
        bool is_alive(entity_id e) const;
 | 
					        bool is_alive(entity_id e) const;
 | 
				
			||||||
 | 
					        size_t components_in_entity(entity_id e) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        size_t entity_count() const;
 | 
				
			||||||
 | 
					        size_t total_component_count() const;
 | 
				
			||||||
 | 
					        size_t archetype_count() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        template<Component T>
 | 
				
			||||||
 | 
					        size_t component_count();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        template<Component T>
 | 
					        template<Component T>
 | 
				
			||||||
        bool has(entity_id e) const;
 | 
					        bool has(entity_id e) const;
 | 
				
			||||||
| 
						 | 
					@ -66,12 +74,18 @@ namespace zecsy
 | 
				
			||||||
        template<Component... T>
 | 
					        template<Component... T>
 | 
				
			||||||
        void query(std::invocable<entity_id, T&...> auto&& system);
 | 
					        void query(std::invocable<entity_id, T&...> auto&& system);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        size_t get_archetypes_checked() const;
 | 
				
			||||||
 | 
					        size_t get_entities_processed() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
        using comp_id = size_t;
 | 
					        using comp_id = size_t;
 | 
				
			||||||
        std::set<entity_id> alive_entities;
 | 
					        std::set<entity_id> alive_entities;
 | 
				
			||||||
        std::unordered_map<entity_id, std::set<comp_id>> entity_to_comps;
 | 
					        std::unordered_map<entity_id, std::set<comp_id>> entity_to_comps;
 | 
				
			||||||
        entity_id entity_counter = 0;
 | 
					        entity_id entity_counter = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        size_t query_archetypes_checked = 0;
 | 
				
			||||||
 | 
					        size_t query_entities_processed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        struct component_pool
 | 
					        struct component_pool
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            std::vector<uint8_t> data;
 | 
					            std::vector<uint8_t> data;
 | 
				
			||||||
| 
						 | 
					@ -119,6 +133,51 @@ namespace zecsy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline world::comp_id world::next_component_id = 0;
 | 
					    inline world::comp_id world::next_component_id = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline size_t world::components_in_entity(entity_id e) const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return entity_to_comps.contains(e) ? entity_to_comps.at(e).size() : 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline size_t world::entity_count() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return alive_entities.size();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline size_t world::total_component_count() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        size_t count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(const auto& [id, pool]: pools)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            count += pool.entity_to_index.size();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return count;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline size_t world::archetype_count() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return archetypes.size();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template<Component T>
 | 
				
			||||||
 | 
					    inline size_t world::component_count()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        const comp_id id = get_component_id<T>();
 | 
				
			||||||
 | 
					        const auto it = pools.find(id);
 | 
				
			||||||
 | 
					        return it != pools.end() ? it->second.entity_to_index.size() : 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline size_t world::get_archetypes_checked() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return query_archetypes_checked;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline size_t world::get_entities_processed() const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return query_entities_processed;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    inline entity_id world::make_entity()
 | 
					    inline entity_id world::make_entity()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        auto id = ++entity_counter;
 | 
					        auto id = ++entity_counter;
 | 
				
			||||||
| 
						 | 
					@ -305,8 +364,13 @@ namespace zecsy
 | 
				
			||||||
        std::vector<comp_id> required = {get_component_id<T>()...};
 | 
					        std::vector<comp_id> required = {get_component_id<T>()...};
 | 
				
			||||||
        std::sort(required.begin(), required.end());
 | 
					        std::sort(required.begin(), required.end());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        query_archetypes_checked = 0;
 | 
				
			||||||
 | 
					        query_entities_processed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for(const auto& [archetype_key, entities]: archetypes)
 | 
					        for(const auto& [archetype_key, entities]: archetypes)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            query_archetypes_checked++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bool match = true;
 | 
					            bool match = true;
 | 
				
			||||||
            for(comp_id req_id: required)
 | 
					            for(comp_id req_id: required)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
| 
						 | 
					@ -320,6 +384,7 @@ namespace zecsy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if(match)
 | 
					            if(match)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					                query_entities_processed += entities.size();
 | 
				
			||||||
                for(entity_id e: entities)
 | 
					                for(entity_id e: entities)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    system(e, get<T>(e)...);
 | 
					                    system(e, get<T>(e)...);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue