1 /************************************************************************************************************************ 2 Entity module. 3 4 Copyright: Copyright © 2018-2023, Dawid Masiukiewicz, Michał Masiukiewicz 5 License: BSD 3-clause, see LICENSE file in project root folder. 6 */ 7 module bubel.ecs.entity; 8 9 import bubel.ecs.system; 10 import bubel.ecs.manager; 11 public import bubel.ecs.traits : becsID; 12 13 /************************************************************************************************************************ 14 Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference! 15 */ 16 struct EntityID 17 { 18 ///Index to entity in IDManager. 19 uint id; 20 ///Counter required for reusing ID. 21 uint counter; 22 } 23 24 /************************************************************************************************************************ 25 Structure of Entity. It's have only ID, but have full konwlege to get to components memory (If pointer to it is proper). 26 */ 27 struct Entity 28 { 29 ///Entity ID. 30 EntityID id; 31 32 /************************************************************************************************************************ 33 Get specified component. If component doesn't exist function retun null. Pointer is valid only before next "commit()", "begin()" or "end()" 34 function is called. Returned pointer shouldn't be used to store reference to entity data. 35 */ 36 T* getComponent(T)() const 37 { 38 /*EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); 39 EntityManager.EntityInfo* info = block.type_info; 40 if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) 41 return null; 42 43 return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof);*/ 44 return cast(T*)getComponent(becsID!T); 45 } 46 47 void* getComponent(ushort component_id) const 48 { 49 EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); 50 EntityManager.EntityInfo* info = block.type_info; 51 if (component_id >= info.deltas.length || info.deltas[component_id] == 0) 52 return null; 53 54 return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEntityManager.components[component_id].size); 55 } 56 57 bool hasComponent(ushort component_id) const 58 { 59 EntityManager.EntitiesBlock* block = gEntityManager.getMetaData(&this); 60 EntityManager.EntityInfo* info = block.type_info; 61 if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; 62 return true; 63 } 64 65 EntityMeta getMeta() const 66 { 67 EntityMeta meta; 68 meta.block = gEntityManager.getMetaData(&this); 69 meta.index = meta.block.entityIndex(&this); 70 return meta; 71 } 72 } 73 74 struct EntityMeta 75 { 76 EntityManager.EntitiesBlock* block; 77 ushort index; 78 79 T* getComponent(T)() const 80 { 81 /*const (EntityManager.EntityInfo)* info = block.type_info; 82 if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) 83 return null; 84 return cast(T*)(cast(void*)block + info.deltas[T.component_id] + index * T.sizeof);*/ 85 return cast(T*)getComponent(becsID!T); 86 } 87 88 void* getComponent(ushort component_id) const 89 { 90 const (EntityManager.EntityInfo)* info = block.type_info; 91 92 if (component_id >= info.deltas.length || info.deltas[component_id] == 0) 93 return null; 94 95 return (cast(void*)block + info.deltas[component_id] + index * gEntityManager.components[component_id].size); 96 } 97 98 bool hasComponent(ushort component_id) const 99 { 100 const EntityManager.EntityInfo* info = block.type_info; 101 if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; 102 return true; 103 } 104 } 105 106 /************************************************************************************************************************ 107 Entity template structure. 108 109 Entity contain whole information needed to create new entity. Allocating EntityTemplate is considered as more expensive operation 110 than adding entity. Whole components memory is stored in EntityTemplate and is copyied to newly added entity. 111 If you want to place several entity with small difference in data then you should take pointer to component and change it before every 112 entity addition. 113 114 There is no restriction about number of allocated templates. Single template can be used from multiple threads, but if you 115 want to changes some components data before add entity (entity position for example) it's better to use multiple templates. 116 */ 117 export struct EntityTemplate 118 { 119 ///Entity components data 120 ubyte[] entity_data; 121 ///Pointer to entity type info. 122 EntityManager.EntityInfo* info; 123 124 /************************************************************************************************************************ 125 Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime. 126 */ 127 T* getComponent(T)() nothrow @nogc 128 { 129 if(becsID!T >= info.tmpl_deltas.length || info.tmpl_deltas[becsID!T] == ushort.max)return null; 130 return cast(T*)(entity_data.ptr + info.tmpl_deltas[becsID!T]); 131 } 132 133 /************************************************************************************************************************ 134 Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime. 135 */ 136 void* getComponent(ushort component_id) const nothrow @nogc 137 { 138 if(component_id >= info.tmpl_deltas.length || info.tmpl_deltas[component_id] == ushort.max)return null; 139 return cast(void*)(entity_data.ptr + info.tmpl_deltas[component_id]); 140 } 141 } 142 143 /************************************************************************************************************************ 144 ComponentRef contain component ID and pointer to it. It used to add component data to entity. 145 */ 146 export struct ComponentRef 147 { 148 ///pointer to component 149 void* ptr; 150 ///component index 151 ushort component_id; 152 }