📦Archetypes📦
This commit is contained in:
		
							parent
							
								
									f313d64d4a
								
							
						
					
					
						commit
						6bd041342a
					
				
					 1 changed files with 113 additions and 15 deletions
				
			
		
							
								
								
									
										128
									
								
								zecsy.hpp
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								zecsy.hpp
									
									
									
									
									
								
							|  | @ -1,4 +1,5 @@ | ||||||
| #pragma once | #pragma once | ||||||
|  | #include <algorithm> | ||||||
| #include <concepts> | #include <concepts> | ||||||
| #include <cstdint> | #include <cstdint> | ||||||
| #include <cstdlib> | #include <cstdlib> | ||||||
|  | @ -74,30 +75,60 @@ namespace zecsy | ||||||
|         struct component_pool |         struct component_pool | ||||||
|         { |         { | ||||||
|             std::vector<uint8_t> data; |             std::vector<uint8_t> data; | ||||||
|             std::vector<size_t> free_list; // Reusable indices
 |             std::vector<size_t> free_list; | ||||||
|             std::unordered_map<entity_id, size_t> entity_to_index; |             std::unordered_map<entity_id, size_t> entity_to_index; | ||||||
|             std::unordered_map<size_t, entity_id> index_to_entity; |             std::unordered_map<size_t, entity_id> index_to_entity; | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         std::unordered_map<comp_id, component_pool> pools; |         std::unordered_map<comp_id, component_pool> pools; | ||||||
| 
 | 
 | ||||||
|         template<typename T> |         using archetype_signature = std::vector<comp_id>; | ||||||
|         static comp_id get_component_id() |         using entity_group = std::vector<entity_id>; | ||||||
|  | 
 | ||||||
|  |         struct archetype_hash | ||||||
|         { |         { | ||||||
|             static comp_id id = next_component_id++; |             size_t operator()(const archetype_signature& vec) const; | ||||||
|             return id; |         }; | ||||||
|         } | 
 | ||||||
|  |         std::unordered_map<archetype_signature, entity_group, archetype_hash> | ||||||
|  |             archetypes; | ||||||
|  | 
 | ||||||
|  |         template<Component T> | ||||||
|  |         static comp_id get_component_id(); | ||||||
| 
 | 
 | ||||||
|         static comp_id next_component_id; |         static comp_id next_component_id; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     inline size_t world::archetype_hash::operator()( | ||||||
|  |         const world::archetype_signature& vec) const | ||||||
|  |     { | ||||||
|  |         size_t seed = vec.size(); | ||||||
|  |         for(const auto& id: vec) | ||||||
|  |         { | ||||||
|  |             seed ^= id + 0x9e3779b9 + (seed << 6) + (seed >> 2); | ||||||
|  |         } | ||||||
|  |         return seed; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     template<Component T> | ||||||
|  |     inline world::comp_id world::get_component_id() | ||||||
|  |     { | ||||||
|  |         static comp_id id = next_component_id++; | ||||||
|  |         return id; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     inline world::comp_id world::next_component_id = 0; |     inline world::comp_id world::next_component_id = 0; | ||||||
| 
 | 
 | ||||||
|     inline entity_id world::make_entity() |     inline entity_id world::make_entity() | ||||||
|     { |     { | ||||||
|         auto id = ++entity_counter; |         auto id = ++entity_counter; | ||||||
|         alive_entities.emplace(id); |         alive_entities.emplace(id); | ||||||
|         // entity_to_comps[id] = {};
 |         entity_to_comps[id] = {}; | ||||||
|  | 
 | ||||||
|  |         std::vector<comp_id> key; | ||||||
|  |         auto& group = archetypes[key]; | ||||||
|  |         group.emplace_back(id); | ||||||
|  | 
 | ||||||
|         return id; |         return id; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -105,7 +136,18 @@ namespace zecsy | ||||||
|     { |     { | ||||||
|         alive_entities.erase(e); |         alive_entities.erase(e); | ||||||
| 
 | 
 | ||||||
|         for(comp_id id: entity_to_comps[e]) |         auto& comp_set = entity_to_comps[e]; | ||||||
|  |         std::vector<comp_id> key(comp_set.begin(), comp_set.end()); | ||||||
|  | 
 | ||||||
|  |         auto& group = archetypes[key]; | ||||||
|  |         group.erase(std::remove(group.begin(), group.end(), e), group.end()); | ||||||
|  | 
 | ||||||
|  |         if(archetypes[key].empty()) | ||||||
|  |         { | ||||||
|  |             archetypes.erase(key); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for(comp_id id: comp_set) | ||||||
|         { |         { | ||||||
|             auto& pool = pools[id]; |             auto& pool = pools[id]; | ||||||
|             auto index = pool.entity_to_index[e]; |             auto index = pool.entity_to_index[e]; | ||||||
|  | @ -169,7 +211,26 @@ namespace zecsy | ||||||
|         pool.entity_to_index[e] = index; |         pool.entity_to_index[e] = index; | ||||||
|         pool.index_to_entity[index] = e; |         pool.index_to_entity[index] = e; | ||||||
| 
 | 
 | ||||||
|         entity_to_comps[e].emplace(id); |         auto& comp_set = entity_to_comps[e]; | ||||||
|  |         std::set<comp_id> old_set = comp_set; | ||||||
|  |         auto [it, inserted] = comp_set.insert(id); | ||||||
|  | 
 | ||||||
|  |         if(inserted) | ||||||
|  |         { | ||||||
|  |             std::vector<comp_id> old_key(old_set.begin(), old_set.end()); | ||||||
|  | 
 | ||||||
|  |             auto& group = archetypes[old_key]; | ||||||
|  |             group.erase(std::remove(group.begin(), group.end(), e), | ||||||
|  |                         group.end()); | ||||||
|  | 
 | ||||||
|  |             if(archetypes[old_key].empty()) | ||||||
|  |             { | ||||||
|  |                 archetypes.erase(old_key); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             std::vector<comp_id> new_key(comp_set.begin(), comp_set.end()); | ||||||
|  |             archetypes[new_key].emplace_back(e); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     template<Component T> |     template<Component T> | ||||||
|  | @ -182,18 +243,38 @@ namespace zecsy | ||||||
|     inline void world::remove(entity_id e) |     inline void world::remove(entity_id e) | ||||||
|     { |     { | ||||||
|         auto id = get_component_id<T>(); |         auto id = get_component_id<T>(); | ||||||
|         if(!has<T>(e)) |         auto& comp_set = entity_to_comps[e]; | ||||||
|  | 
 | ||||||
|  |         if(!comp_set.contains(id)) | ||||||
|         { |         { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         std::set<comp_id> old_set = comp_set; | ||||||
|  |         size_t removed = comp_set.erase(id); | ||||||
|  | 
 | ||||||
|  |         if(removed > 0) | ||||||
|  |         { | ||||||
|  |             std::vector<comp_id> old_key(old_set.begin(), old_set.end()); | ||||||
|  | 
 | ||||||
|  |             auto& group = archetypes[old_key]; | ||||||
|  |             group.erase(std::remove(group.begin(), group.end(), e), | ||||||
|  |                         group.end()); | ||||||
|  | 
 | ||||||
|  |             if(archetypes[old_key].empty()) | ||||||
|  |             { | ||||||
|  |                 archetypes.erase(old_key); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             std::vector<comp_id> new_key(comp_set.begin(), comp_set.end()); | ||||||
|  |             archetypes[new_key].emplace_back(e); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         auto& pool = pools[id]; |         auto& pool = pools[id]; | ||||||
|         auto index = pool.entity_to_index[e]; |         auto index = pool.entity_to_index[e]; | ||||||
| 
 |  | ||||||
|         pool.free_list.push_back(index); |         pool.free_list.push_back(index); | ||||||
|         pool.entity_to_index.erase(e); |         pool.entity_to_index.erase(e); | ||||||
|         pool.index_to_entity.erase(index); |         pool.index_to_entity.erase(index); | ||||||
|         entity_to_comps[e].erase(id); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     template<Component First, Component Second, Component... Rest> |     template<Component First, Component Second, Component... Rest> | ||||||
|  | @ -230,11 +311,28 @@ namespace zecsy | ||||||
|     template<Component... T> |     template<Component... T> | ||||||
|     inline void world::query(std::invocable<entity_id, T&...> auto&& system) |     inline void world::query(std::invocable<entity_id, T&...> auto&& system) | ||||||
|     { |     { | ||||||
|         for(auto e: alive_entities) |         std::vector<comp_id> required = {get_component_id<T>()...}; | ||||||
|  |         std::sort(required.begin(), required.end()); | ||||||
|  | 
 | ||||||
|  |         for(const auto& [archetype_key, entities]: archetypes) | ||||||
|         { |         { | ||||||
|             if((has<T...>(e))) |             bool match = true; | ||||||
|  |             for(comp_id req_id: required) | ||||||
|             { |             { | ||||||
|                 system(e, get<T>(e)...); |                 if(!std::binary_search(archetype_key.begin(), | ||||||
|  |                                        archetype_key.end(), req_id)) | ||||||
|  |                 { | ||||||
|  |                     match = false; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(match) | ||||||
|  |             { | ||||||
|  |                 for(entity_id e: entities) | ||||||
|  |                 { | ||||||
|  |                     system(e, get<T>(e)...); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue