/************************************************************************************************************************ Entity module. Copyright: Copyright © 2018-2019, Dawid Masiukiewicz, Michał Masiukiewicz License: BSD 3-clause, see LICENSE file in project root folder. */ module bubel.ecs.entity; import bubel.ecs.system; import bubel.ecs.manager; import bubel.ecs.traits : ecsID; /************************************************************************************************************************ Entity ID structure. Used as reference to Entity. Pointer to entity should be ever used to store entity reference! */ struct EntityID { ///Index to entity in IDManager. uint id; ///Counter required for reusing ID. uint counter; } /************************************************************************************************************************ Structure of Entity. It's have only ID, but have full konwlege to get to components memory (If pointer to it is proper). */ struct Entity { ///Entity ID. EntityID id; /************************************************************************************************************************ Get specified component. If component doesn't exist function retun null. Pointer is valid only before next "commit()", "begin()" or "end()" function is called. Returned pointer shouldn't be used to store reference to entity data. */ T* getComponent(T)() const { /*EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) return null; return cast(T*)(cast(void*)block + info.deltas[T.component_id] + block.entityIndex(&this) * T.sizeof);*/ return cast(T*)getComponent(ecsID!T); } void* getComponent(ushort component_id) const { EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; if (component_id >= info.deltas.length || info.deltas[component_id] == 0) return null; return (cast(void*)block + info.deltas[component_id] + block.entityIndex(&this) * gEM.components[component_id].size); } bool hasComponent(ushort component_id) const { EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); EntityManager.EntityInfo* info = block.type_info; if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; return true; } EntityMeta getMeta() const { EntityMeta meta; meta.block = gEM.getMetaData(&this); meta.index = meta.block.entityIndex(&this); return meta; } } struct EntityMeta { EntityManager.EntitiesBlock* block; ushort index; T* getComponent(T)() const { /*const (EntityManager.EntityInfo)* info = block.type_info; if (T.component_id >= info.deltas.length || info.deltas[T.component_id] == 0) return null; return cast(T*)(cast(void*)block + info.deltas[T.component_id] + index * T.sizeof);*/ return cast(T*)getComponent(ecsID!T); } void* getComponent(ushort component_id) const { const (EntityManager.EntityInfo)* info = block.type_info; if (component_id >= info.deltas.length || info.deltas[component_id] == 0) return null; return (cast(void*)block + info.deltas[component_id] + index * gEM.components[component_id].size); } bool hasComponent(ushort component_id) const { const EntityManager.EntityInfo* info = block.type_info; if (component_id >= info.deltas.length || info.deltas[component_id] == 0)return false; return true; } } /************************************************************************************************************************ Entity template structure. Entity contain whole information needed to create new entity. Allocating EntityTemplate is considered as more expensive operation than adding entity. Whole components memory is stored in EntityTemplate and is copyied to newly added entity. If you want to place several entity with small difference in data then you should take pointer to component and change it before every entity addition. There is no restriction about number of allocated templates. Single template can be used from multiple threads, but if you want to changes some components data before add entity (entity position for example) it's better to use multiple templates. */ export struct EntityTemplate { ///Entity components data ubyte[] entity_data; ///Pointer to entity type info. EntityManager.EntityInfo* info; /************************************************************************************************************************ Get specified component. If component doesn't exist function return null. Returned pointer is valid during EntityTemplate lifetime. */ T* getComponent(T)() nothrow @nogc { if(ecsID!T >= info.tmpl_deltas.length || info.tmpl_deltas[ecsID!T] == ushort.max)return null; return cast(T*)(entity_data.ptr + info.tmpl_deltas[ecsID!T]); } } /************************************************************************************************************************ ComponentRef contain component ID and pointer to it. It used to add component data to entity. */ export struct ComponentRef { ///pointer to component void* ptr; ///component index ushort component_id; }