From d3222eefbbeac9f66a310ae169be1b79acb31231 Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 12 Sep 2018 17:38:41 +0200 Subject: [PATCH] -some usefull functions for IDManager -added EntityManager.removeEntity(EntityID) -EntitiesBlock now has ID usefull for updating first_free_block in EntityInfo --- source/ecs/id_manager.d | 15 +++++++++++ source/ecs/manager.d | 60 ++++++++++++++++++++++++++++++++--------- source/ecs/system.d | 31 ++++++++++++--------- tests/tests.d | 28 ++++++++++++++++++- 4 files changed, 109 insertions(+), 25 deletions(-) diff --git a/source/ecs/id_manager.d b/source/ecs/id_manager.d index ab3a076..007611b 100644 --- a/source/ecs/id_manager.d +++ b/source/ecs/id_manager.d @@ -30,6 +30,19 @@ struct IDManager m_ids_array[entity.id.id].entity = &entity; } + Entity* getEntityPointer(EntityID id) + { + Data* data = &m_ids_array[id.id]; + if(data.counter != id.counter)return null; + else return data.entity; + } + + bool isExist(EntityID id) + { + Data* data = &m_ids_array[id.id]; + return data.counter == id.counter; + } + struct Data { uint counter = 0; @@ -61,5 +74,7 @@ unittest assert(id1 == EntityID(1,2)); assert(id2 == EntityID(0,2)); assert(id3 == EntityID(2,1)); + assert(manager.isExist(id3)); + assert(!manager.isExist(EntityID(0,1))); } \ No newline at end of file diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 4fcf742..7b33448 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -54,7 +54,7 @@ class EntityManager string ret; foreach (i, param; Parameters!(Sys.update)) { - ret ~= "system.components[" ~ i.to!string + ret ~= "system.m_components[" ~ i.to!string ~ "] = components_map.get(types[" ~ i.to!string ~ "].stringof);\n"; } return ret; @@ -66,7 +66,7 @@ class EntityManager { static if (hasMember!(Sys, "update")) { - Sys* s = cast(Sys*) data.system.system_pointer; + Sys* s = cast(Sys*) data.system.m_system_pointer; EntitiesBlock* block = data.info.first_block; while (block !is null) @@ -83,7 +83,7 @@ class EntityManager } } - system.update = &callUpdate; + system.m_update = &callUpdate; } static if (hasMember!(Sys, "onEnable")) @@ -110,9 +110,9 @@ class EntityManager system.m_disable = &callDisable; } - system.system_pointer = cast(void*) Mallocator.instance.make!Sys; + system.m_system_pointer = cast(void*) Mallocator.instance.make!Sys; - system.components = Mallocator.instance.makeArray!uint(types.length); + system.m_components = Mallocator.instance.makeArray!uint(types.length); mixin(genCompList()); systems.add(system); @@ -142,7 +142,7 @@ class EntityManager foreach (data; info.callers) { if (data.system.enabled) - (cast(SytemFuncType) data.system.update)(data, null); //caller(call_data,null); + (cast(SytemFuncType) data.system.m_update)(data, null); //caller(call_data,null); } } } @@ -176,7 +176,7 @@ class EntityManager foreach (ref system; systems) { - if (system.update is null) + if (system.m_update is null) continue; addEntityCaller(*info, system); } @@ -193,9 +193,9 @@ class EntityManager void addEntityCaller(ref EntityInfo entity, ref System system) { CallData call_data = CallData(&system, &entity, null); - ushort[] deltas = (cast(ushort*) alloca(system.components.length * ushort.sizeof))[0 - .. system.components.length]; - foreach (i, id; system.components) + ushort[] deltas = (cast(ushort*) alloca(system.m_components.length * ushort.sizeof))[0 + .. system.m_components.length]; + foreach (i, id; system.m_components) { deltas[i] = ushort.max; foreach (i2, id2; entity.components) @@ -214,7 +214,7 @@ class EntityManager } if (deltas) { - call_data.deltas = Mallocator.instance.makeArray(deltas); //Mallocator.instance.makeArray!ushort(system.components.length); + call_data.deltas = Mallocator.instance.makeArray(deltas); //Mallocator.instance.makeArray!ushort(system.m_components.length); entity.callers.add(call_data); } } @@ -225,7 +225,7 @@ class EntityManager Mallocator.instance.dispose(template_); } - void addEntity(EntityTemplate* tmpl) + ref Entity addEntity(EntityTemplate* tmpl) { EntitiesBlock* previous_block; EntitiesBlock* block = tmpl.info.first_with_free_space; //tmpl.info.first_block; @@ -241,10 +241,12 @@ class EntityManager if (previous_block is null) { tmpl.info.first_block = block; + block.id = 0; } else { previous_block.next_block = block; + block.id = previous_block.id + 1; } tmpl.info.first_with_free_space = block; break; // new block certainly has free space @@ -267,6 +269,37 @@ class EntityManager entity.id = id_manager.getNewID(); entity.updateID(); block.entities_count++; + return *entity; + } + + void removeEntity(EntityID id) + { + Entity* entity = id_manager.getEntityPointer(id); + if(entity is null)return; + EntitiesBlock* block = getMetaData(entity); + id_manager.releaseID(id); + + void* data_begin = block.dataBegin(); + uint pos = cast(int)(cast(void*)entity - data_begin) / block.type_data.size; + + block.entities_count--; + + if(block.type_data.first_with_free_space.id > block.id)block.type_data.first_with_free_space = block; + + if(pos == block.entities_count)return; + + void* src = data_begin + block.entities_count * block.type_data.size; + void* dst = data_begin + pos * block.type_data.size; + + memcpy(dst,src,block.type_data.size); + + entity = cast(Entity*) dst; + entity.updateID(); + } + + EntitiesBlock* getMetaData(void* pointer) + { + return cast(EntitiesBlock*)(cast(size_t) pointer & (~cast(size_t)(page_size - 1))); } struct ComponentInfo @@ -304,6 +337,7 @@ class EntityManager EntityInfo* type_data; uint entities_count; + uint id; EntitiesBlock* next_block; ///there is a loooot of data (4kB, pure magic) } @@ -317,7 +351,9 @@ class EntityManager alias SytemFuncType = void function(ref EntityManager.CallData data, void* entity); + ///Single page size. Must be power of two. enum page_size = 4096; + ///Number of pages in block. enum pages_in_block = 128; IDManager id_manager; diff --git a/source/ecs/system.d b/source/ecs/system.d index 9734c92..9979341 100644 --- a/source/ecs/system.d +++ b/source/ecs/system.d @@ -5,15 +5,6 @@ import ecs.manager; struct System { - ///should system update and catch events? - bool m_enabled = false; - ///system priority - int prority; - ///pointer to system implementation - void* system_pointer; - - uint[] components; - bool enabled() { return m_enabled; @@ -21,18 +12,34 @@ struct System void enable() { - if(!m_enabled && m_enable)m_enable(system_pointer); + if(!m_enabled && m_enable)m_enable(m_system_pointer); m_enabled = true; } void disable() { - if(m_enabled && m_disable)m_disable(system_pointer); + if(m_enabled && m_disable)m_disable(m_system_pointer); m_enabled = false; } + int priority() + { + return m_priority; + } + +package: + + ///should system update and catch events? + bool m_enabled = false; + ///system priority + int m_priority; + ///pointer to system implementation + void* m_system_pointer; + + uint[] m_components; + //void function(ref EntityManager.CallData data, void* entity) update; - void* update; ///workaroud for DMD bug with upper line + void* m_update; ///workaroud for DMD bug with upper line void function(void* system_pointer) m_enable; void function(void* system_pointer) m_disable; diff --git a/tests/tests.d b/tests/tests.d index 9a48aa9..a82d138 100644 --- a/tests/tests.d +++ b/tests/tests.d @@ -135,7 +135,33 @@ int main() time = MonoTime.currTime; - foreach(i; 0..1_000_000)gEM.addEntity(tmpl); + //foreach(i; 0..1_000_000)gEM.addEntity(tmpl); + + //foreach(i; 0..1_000_000)gEM.removeEntity(gEM.addEntity(tmpl).id); + + EntityID[1000] idss; + + foreach(i; 0..1_000) + { + foreach(j; 0..1_000)idss[j] = gEM.addEntity(tmpl).id; + foreach(j; 0..1_000)gEM.removeEntity(idss[j]); + } + + uint blocks = 0; + foreach(info; &gEM.entities_infos.byValue) + { + EntityManager.EntitiesBlock* block = info.first_block; + while(block !is null) + { + block = block.next_block; + blocks++; + } + } + writeln("Entities blocks: ",blocks); + + /*Entity entity = gEM.addEntity(tmpl); + gEM.removeEntity(entity.id); + gEM.addEntity(tmpl);*/ dur = (MonoTime.currTime - time).total!"usecs"; writeln("Entities adding: ",dur," usecs");