diff --git a/source/ecs/attributes.d b/source/ecs/attributes.d index 67c09c1..69667ec 100644 --- a/source/ecs/attributes.d +++ b/source/ecs/attributes.d @@ -1,4 +1,6 @@ module ecs.attributes; +///Used to mark optional components for system. enum optional = "optional"; +///Used to mark absen components for system. Enum 'AbsenComponents' should be used instead of it. enum absen = "absen"; \ No newline at end of file diff --git a/source/ecs/entity.d b/source/ecs/entity.d index d23bab6..854385a 100644 --- a/source/ecs/entity.d +++ b/source/ecs/entity.d @@ -2,21 +2,36 @@ module ecs.entity; import ecs.manager; +/************************************************************************************************************************ +*Entity ID structure. +*/ 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; + /************************************************************************************************************************ + *Update pointer to it in IDManager + */ void updateID() { EntityManager.instance.id_manager.update(this); } + /************************************************************************************************************************ + *Get specified component. If component doesn't exist function retun null. + */ T* getComponent(T)() const { EntityManager.EntitiesBlock* block = gEM.getMetaData(&this); @@ -32,11 +47,19 @@ struct Entity } } +/************************************************************************************************************************ +*Entity template structure. +*/ 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. + */ T* getComponent(T)() { if(T.component_id >= info.tmpl_deltas.length)return null; diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index 86542e3..cd2fbb7 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -3,8 +3,14 @@ module ecs.id_manager; import ecs.entity; import ecs.vector; +/************************************************************************************************************************ +*IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program. +*/ struct IDManager { + /************************************************************************************************************************ + *Get new ID. + */ EntityID getNewID() { if (m_next_id >= m_ids_array.length) @@ -18,6 +24,9 @@ struct IDManager return id; } + /************************************************************************************************************************ + *Release ID. + */ void releaseID(EntityID id) { Data* data = &m_ids_array[id.id]; @@ -29,11 +38,17 @@ struct IDManager m_next_id = id.id; } + /************************************************************************************************************************ + *Update pointer to entity. The purpose of this function is to ensure that pointer to entity is always correct. + */ void update(ref Entity entity) { if(entity.id.counter == m_ids_array[entity.id.id].counter)m_ids_array[entity.id.id].entity = &entity; } + /************************************************************************************************************************ + *Returns pointer to entity. + */ export Entity* getEntityPointer(EntityID id) { Data* data = &m_ids_array[id.id]; @@ -43,20 +58,24 @@ struct IDManager return data.entity; } + /************************************************************************************************************************ + *Check if entity with specified ID exist. + */ export bool isExist(EntityID id) { Data* data = &m_ids_array[id.id]; return data.counter == id.counter; } - struct Data + private static struct Data { uint counter = 0; uint next_id = uint.max; Entity* entity = null; } - private uint m_next_id = 0; +private: + uint m_next_id; Vector!Data m_ids_array; } diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 1d17aa6..95fd7b0 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -49,12 +49,23 @@ class EntityManager instance = null; } + /************************************************************************************************************************ + *Default constructor. + */ this() { //event_manager = EventManager(this); //event_manager.manager = this; } + /************************************************************************************************************************ + *Register new System into EntityManager. This funcion generate glue between EntityManager and System. + *Systems can be registered from external dynamic library, and can be registered after adding entities too. + *System mustn't be registered before components which system want to use, in this case functions call assertion. + * + *params: + *priority = system priority. Priority determines order of execution of systems updates. + */ void registerSystem(Sys)(int priority) { alias STC = ParameterStorageClass; @@ -392,6 +403,9 @@ class EntityManager return cast(Sys*) systems[Sys.system_id].m_system_pointer; } + /************************************************************************************************************************ + *Register component into EntityManager. + */ void registerComponent(Comp)() { ComponentInfo info; @@ -469,6 +483,9 @@ class EntityManager } } + /************************************************************************************************************************ + *Update systems. Should be called only between begin() and end(). + */ export void update() { foreach (info; &entities_infos.byValue) @@ -486,10 +503,10 @@ class EntityManager num = cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); //num += alignment - (num & (alignment - 1)); } - static ushort alignedNum(ushort num, ushort alignment) + /*static ushort alignedNum(ushort num, ushort alignment) { return cast(ushort)((num + alignment - 1) & (-cast(int) alignment)); - } + }*/ extern (C) static int compareUShorts(const void* a, const void* b) { @@ -503,6 +520,12 @@ class EntityManager return 1; } + /************************************************************************************************************************ + *Allocate EntityTemplate with specifed components and returns pointer to it. + * + *params: + *components_ids = array of components allocated with template + */ export EntityTemplate* allocateTemplate(ushort[] components_ids) { @@ -541,6 +564,12 @@ class EntityManager return temp; } + /************************************************************************************************************************ + *Returns entity type info. + * + *params: + *ids = array of components + */ export EntityInfo* getEntityInfo(ushort[] ids) { EntityInfo* info = entities_infos.get(ids, null); @@ -651,11 +680,24 @@ class EntityManager entity.callers.add(call_data, index); } + /************************************************************************************************************************ + *Returns pointer to entity. + * + *params: + *id = ID of entity + */ export Entity* getEntity(EntityID id) { return cast(Entity*) id_manager.getEntityPointer(id); } + /************************************************************************************************************************ + *Remove components from entity by IDs. Components will be removed on end of frame. + * + *params: + *entity_id = ID of entity + *del_ids = array of components IDs + */ export void removeComponents(EntityID entity_id, ushort[] del_ids) { uint num = cast(uint) del_ids.length; @@ -725,6 +767,13 @@ class EntityManager removeEntityNoID(entity, block); } + /************************************************************************************************************************ + *Remove coponents from entity. + * + *params: + *Compoenents = components types to remove + *entity_id = ID of entity + */ void removeComponents(Components...)(EntityID entity_id) { const uint num = Components.length; @@ -861,6 +910,13 @@ class EntityManager removeEntityNoID(entity, block); } + /************************************************************************************************************************ + *Add components to entity. Components will be added on end of frame. + * + *params: + *entity_id = ID of entity to remove + *tmpl = pointer entity template allocated by EntityManager. + */ void addComponents(Components...)(const EntityID entity_id, Components comps) { const uint num = Components.length; @@ -895,12 +951,24 @@ class EntityManager //__addComponents(entity_id, new_ids, pointers); } + /************************************************************************************************************************ + *Free template memory. + * + *params: + *tmpl = pointer entity template allocated by EntityManager. + */ export void freeTemplate(EntityTemplate* template_) { Mallocator.instance.dispose(template_.entity_data); Mallocator.instance.dispose(template_); } + /************************************************************************************************************************ + *Add entity to system. + * + *params: + *tmpl = pointer entity template allocated by EntityManager. + */ export ref Entity addEntity(EntityTemplate* tmpl) { EntitiesBlock* block = findBlockWithFreeSpace(tmpl.info); @@ -969,6 +1037,12 @@ class EntityManager return block; } + /************************************************************************************************************************ + *Remove entity by ID. Entity will be removed on frame end. + * + *params: + *id = id of entity to remove + */ export void removeEntity(EntityID id) { entities_to_remove.add(id); @@ -1125,6 +1199,9 @@ class EntityManager entities_to_remove.clear(); } + /************************************************************************************************************************ + *Begin of update process. Should be called before any update is called. + */ export void begin() { updateBlocks(); @@ -1137,6 +1214,9 @@ class EntityManager } } + /************************************************************************************************************************ + *End of update process. Should be called after every update function. + */ export void end() { foreach (ref system; instance.systems) @@ -1151,11 +1231,18 @@ class EntityManager //clearEvents(); } + /************************************************************************************************************************ + *Component info; + */ struct ComponentInfo { + ///Component size ushort size; + ///Component data alignment ushort alignment; + ///Initialization data ubyte[] init_data; + ///Pointer to component destroy callback void function(void* pointer) destroy_callback; } diff --git a/source/ecs/system.d b/source/ecs/system.d index b202d94..38722e4 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -3,13 +3,22 @@ module ecs.system; import ecs.entity; import ecs.manager; +/************************************************************************************************************************ +*System contain data required to proper glue EntityManager with Systems. +*/ struct System { + /************************************************************************************************************************ + *Check if system is enabled. + */ export bool enabled() { return m_enabled; } + /************************************************************************************************************************ + *Enable system. If actually it is enabled function do nothing. + */ export void enable() { if (!m_enabled && m_enable) @@ -17,6 +26,9 @@ struct System m_enabled = true; } + /************************************************************************************************************************ + *Disable system. If actually it is disabled function do nothing. + */ export void disable() { if (m_enabled && m_disable) @@ -24,6 +36,9 @@ struct System m_enabled = false; } + /************************************************************************************************************************ + *Get system priority. + */ export int priority() { return m_priority; @@ -38,10 +53,14 @@ package: ///pointer to system implementation void* m_system_pointer; + ///system name const (char)[] name; + ///required components ushort[] m_components; + ///absen components ushort[] m_absen_components; + ///optional components ushort[] m_optional_components; //void function(ref EntityManager.CallData data, void* entity) update;