diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 0e91095..9f26584 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1374,8 +1374,6 @@ export struct EntityManager { memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], components[comp].init_data.ptr, components[comp].size); - /*temp.entity_data[info.tmpl_deltas[comp] .. info.tmpl_deltas[comp] + components[comp].size] - = components[comp].init_data;*/ } } else @@ -1383,7 +1381,7 @@ export struct EntityManager ushort index = block.entityIndex(entity); foreach (comp; info.components) { - memcpy(cast(void*) temp.entity_data + info.tmpl_deltas[comp], + memcpy(cast(void*) temp.entity_data.ptr + info.tmpl_deltas[comp], cast(void*) block + info.deltas[comp] + components[comp].size * index, components[comp].size); } @@ -1440,6 +1438,74 @@ export struct EntityManager return temp; } + /************************************************************************************************************************ + *Allocate EntityTemplate with specifed components and returns pointer to it. + * + *Params: + *components_ids = array of components allocated with template + */ + export EntityTemplate* allocateTemplate(EntityTemplate* base_tmpl, ushort[] components_ids, ushort[] remove_components_ids = null) + { + size_t len = base_tmpl.info.components.length + components_ids.length; + ushort[] ids = (cast(ushort*) alloca(ushort.sizeof * len))[0 + .. len]; + memcpy(ids.ptr, base_tmpl.info.components.ptr, ushort.sizeof * base_tmpl.info.components.length); + memcpy(ids.ptr + base_tmpl.info.components.length, components_ids.ptr, ushort.sizeof * components_ids.length); + + qsort(ids.ptr, ids.length, ushort.sizeof, &compareUShorts); + qsort(remove_components_ids.ptr, remove_components_ids.length, ushort.sizeof, &compareUShorts); + { + uint k = 0; + uint j = 1; + foreach (i; 1 .. ids.length) + { + assert(ids[i] != ushort.max); + if(k < remove_components_ids.length) + { + while(k < remove_components_ids.length && remove_components_ids[k] < ids[i]) + { + k++; + } + if(k < remove_components_ids.length) + { + if(remove_components_ids[k] == ids[i])continue; + } + } + if (ids[i] != ids[j - 1]) + { + ids[j] = ids[i]; + j++; + } + else + debug assert(0, "Duplicated components in template!!!"); + } + ids = ids[0 .. j]; + } + + EntityInfo* info = getEntityInfo(ids); + + EntityTemplate* temp = Mallocator.make!EntityTemplate; + temp.entity_data = Mallocator.makeArray!ubyte(info.size); + temp.info = info; + + //fill components with default data and copy from base template + foreach (comp; info.components) + { + if(comp < base_tmpl.info.deltas.length && base_tmpl.info.deltas[comp] != ushort.max) //copy data from base component + { + memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], + base_tmpl.entity_data.ptr + base_tmpl.info.tmpl_deltas[comp], components[comp].size); + } + else //fill with default data + { + memcpy(temp.entity_data.ptr + info.tmpl_deltas[comp], + components[comp].init_data.ptr, components[comp].size); + } + } + + return temp; + } + /************************************************************************************************************************ *Returns entity type info. * diff --git a/tests/basic.d b/tests/basic.d index c359fe3..33006a7 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -1,2 +1,174 @@ module tests.basic; +import ecs.manager; +import ecs.core; + +struct CInt +{ + mixin ECS.Component; + + alias value this; + + int value = 1; +} + +struct CFloat +{ + mixin ECS.Component; + + alias value this; + + float value = 2.0; +} + +struct CDouble +{ + mixin ECS.Component; + + alias value this; + + double value = 3.0; +} + +struct CLong +{ + mixin ECS.Component; + + alias value this; + + long value = 10; +} + +struct CShort +{ + mixin ECS.Component; + + alias value this; + + short value = 12; +} + +void beforeEveryTest() +{ + gEM.initialize(1); + + gEM.registerComponent!CInt; + gEM.registerComponent!CFloat; + gEM.registerComponent!CDouble; + gEM.registerComponent!CLong; + gEM.registerComponent!CShort; +} + +void afterEveryTest() +{ + gEM.destroy(); +} + +@("AddEntity") +unittest +{ + ushort[2] ids = [CInt.component_id, CFloat.component_id]; + EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); + assert(tmpl_.info.components.length == 2); + assert(tmpl_.getComponent!CInt); + assert(tmpl_.getComponent!CFloat); + assert(*tmpl_.getComponent!CInt == 1); + assert(*tmpl_.getComponent!CFloat == 2.0); + + Entity* entity = gEM.addEntity(tmpl_); + assert(entity.getComponent!CInt); + assert(entity.getComponent!CFloat); + assert(*entity.getComponent!CInt == 1); + assert(*entity.getComponent!CFloat == 2.0); +} + +//allocate templates +@("AllocateTemplates") +unittest +{ + //basic template allocation + ushort[2] ids = [CInt.component_id, CFloat.component_id]; + EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); + assert(tmpl_.info.components.length == 2); + assert(tmpl_.getComponent!CInt); + assert(tmpl_.getComponent!CFloat); + assert(*tmpl_.getComponent!CInt == 1); + assert(*tmpl_.getComponent!CFloat == 2.0); + *tmpl_.getComponent!CInt = 4; + *tmpl_.getComponent!CFloat = 5.0; + + //allocate template from template with additional component + ushort[1] ids2 = [CDouble.component_id]; + EntityTemplate* tmpl_2 = gEM.allocateTemplate(tmpl_, ids2); + assert(tmpl_2.info.components.length == 3); + assert(tmpl_2.getComponent!CInt); + assert(tmpl_2.getComponent!CFloat); + assert(tmpl_2.getComponent!CDouble); + assert(*tmpl_2.getComponent!CInt == 4); + assert(*tmpl_2.getComponent!CFloat == 5.0); + assert(*tmpl_2.getComponent!CDouble == 3.0); + + Entity* entity = gEM.addEntity(tmpl_); + gEM.addComponents(entity.id, CDouble(8.0)); + + //apply entity changes + gEM.commit(); + + //allocate template as entity copy + EntityTemplate* tmpl_3 = gEM.allocateTemplate(entity.id); + assert(tmpl_3.info.components.length == 3); + assert(tmpl_3.getComponent!CInt); + assert(tmpl_3.getComponent!CFloat); + assert(tmpl_3.getComponent!CDouble); + assert(*tmpl_3.getComponent!CInt == 4); + assert(*tmpl_3.getComponent!CFloat == 5.0); + assert(*tmpl_3.getComponent!CDouble == 8.0); + + //allocate template with entity data but default values + EntityTemplate* tmpl_4 = gEM.allocateTemplate(entity.id, true); + assert(tmpl_4.info.components.length == 3); + assert(tmpl_4.getComponent!CInt); + assert(tmpl_4.getComponent!CFloat); + assert(tmpl_4.getComponent!CDouble); + assert(*tmpl_4.getComponent!CInt == 1); + assert(*tmpl_4.getComponent!CFloat == 2.0); + assert(*tmpl_4.getComponent!CDouble == 3.0); + + //allocate template from template with two additional component + ushort[2] ids3 = [CDouble.component_id, CLong.component_id]; + EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_, ids3); + assert(tmpl_5.info.components.length == 4); + assert(tmpl_5.getComponent!CInt); + assert(tmpl_5.getComponent!CFloat); + assert(tmpl_5.getComponent!CDouble); + assert(tmpl_5.getComponent!CLong); + assert(*tmpl_5.getComponent!CInt == 4); + assert(*tmpl_5.getComponent!CFloat == 5.0); + assert(*tmpl_5.getComponent!CDouble == 3.0); + assert(*tmpl_5.getComponent!CLong == 10); + + //allocate template from template without one component + ushort[1] rem_ids = [CFloat.component_id]; + EntityTemplate* tmpl_6 = gEM.allocateTemplate(tmpl_, null, rem_ids); + assert(tmpl_6.info.components.length == 1); + assert(tmpl_6.getComponent!CInt); + assert(*tmpl_6.getComponent!CInt == 4); + + //allocate template from template without one component and two additional + EntityTemplate* tmpl_7 = gEM.allocateTemplate(tmpl_, ids3, rem_ids); + assert(tmpl_7.info.components.length == 3); + assert(tmpl_7.getComponent!CInt); + assert(tmpl_7.getComponent!CDouble); + assert(tmpl_7.getComponent!CLong); + assert(*tmpl_7.getComponent!CInt == 4); + assert(*tmpl_7.getComponent!CDouble == 3.0); + assert(*tmpl_7.getComponent!CLong == 10); + + gEM.freeTemplate(tmpl_); + gEM.freeTemplate(tmpl_2); + gEM.freeTemplate(tmpl_3); + gEM.freeTemplate(tmpl_4); + gEM.freeTemplate(tmpl_5); + gEM.freeTemplate(tmpl_6); + gEM.freeTemplate(tmpl_7); +} \ No newline at end of file diff --git a/tests/runner.d b/tests/runner.d index 4aa2ed1..105a7a2 100644 --- a/tests/runner.d +++ b/tests/runner.d @@ -130,6 +130,7 @@ struct TestRunner(Args...) { TestSuite* suite = &suites[i]; suite.name = module_.stringof; + static if(__traits(hasMember, module_, "beforeEveryTest"))module_.beforeEveryTest(); foreach (index, unittest_; __traits(getUnitTests, module_)) { enum attributes = __traits(getAttributes, unittest_); @@ -161,6 +162,7 @@ struct TestRunner(Args...) } passed += suite.passed; failed += suite.failed; + static if(__traits(hasMember, module_, "afterEveryTest"))module_.afterEveryTest(); } }