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 }