From f7a1e9bd05fb9640b8e7b2aeb2fa3fd28bdcbd4b Mon Sep 17 00:00:00 2001 From: Mergul Date: Wed, 22 Apr 2020 16:23:42 +0200 Subject: [PATCH] More test and fixes: -added test for addEntityCopy -test order of onAddEntity, onRemoveEntity, onChangeEntity callbacks calls -testing onAddEntity, onRemoveEntity, onChangeEntity callback -test callEntityFunction call -fixed bug with crashing ECS (setting callers for entity change callbacks) -commented debug asserts conering duplicated components ids (to further consideration) --- source/ecs/manager.d | 23 ++-- tests/basic.d | 249 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 250 insertions(+), 22 deletions(-) diff --git a/source/ecs/manager.d b/source/ecs/manager.d index 49662dc..1b9b959 100644 --- a/source/ecs/manager.d +++ b/source/ecs/manager.d @@ -1187,7 +1187,7 @@ export struct EntityManager (cast(Ev*) pointer).onDestroy(); } - info.destroy_callback = &callDestroy; + info.destroy_callback = cast(void function(void*) nothrow @nogc)&callDestroy; } info.size = Ev.sizeof; @@ -1214,7 +1214,7 @@ export struct EntityManager "Can't call function with system which hasn't EntitesData structure."); static assert(__traits(hasMember, Sys, "onUpdate"), "Can't call function with system which hasn't onUpdate function callback."); - static assert(is(T == typeof(&s.onUpdate)), "Function must match system update function."); + static assert(is(SetFunctionAttributes!(T,functionLinkage!(s.onUpdate), functionAttributes!(s.onUpdate)) == typeof(&s.onUpdate)), "Function must match system update function."); static assert(__traits(hasMember, Sys, "system_id"), "Sys must be system type."); System* system = getSystem(Sys.system_id); @@ -1527,8 +1527,8 @@ export struct EntityManager ids[j] = ids[i]; j++; } - else - debug assert(0, "Duplicated components in template!!!"); + //else + // debug assert(0, "Duplicated components in template!!!"); } ids = ids[0 .. j]; } @@ -1544,8 +1544,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;*/ } return temp; @@ -1593,8 +1591,8 @@ export struct EntityManager ids[j] = ids[i]; j++; } - else - debug assert(0, "Duplicated components in template!!!"); + //else + // debug assert(0, "Duplicated components in template!!!"); } ids = ids[0 .. j]; } @@ -1747,7 +1745,7 @@ export struct EntityManager int j; for (j = 0; j < add_len; j++) { - if (systems[i].priority > systems[tmp_add[j]].priority) + if (systems[i].priority < systems[tmp_add[j]].priority) break; } add_len++; @@ -1767,7 +1765,7 @@ export struct EntityManager int j; for (j = 0; j < rem_len; j++) { - if (systems[i].priority > systems[tmp_rem[j]].priority) + if (systems[i].priority < systems[tmp_rem[j]].priority) break; } rem_len++; @@ -1787,7 +1785,7 @@ export struct EntityManager int j; for (j = 0; j < ch_len; j++) { - if (systems[i].priority > systems[tmp_ch[j]].priority) + if (systems[i].priority < systems[tmp_ch[j]].priority) break; } ch_len++; @@ -2727,6 +2725,7 @@ export struct EntityManager call_data); } } + if(events[i].destroy_callback)events[i].destroy_callback(event_pointer); event_pointer += events[i].size; } block = block.next; @@ -2957,7 +2956,7 @@ export struct EntityManager ushort size; ushort alignment; EventCaller[] callers; - void function(void* pointer) destroy_callback; + void function(void* pointer) nothrow @nogc destroy_callback; } /************************************************************************************************************************ diff --git a/tests/basic.d b/tests/basic.d index 38b5605..f3f2832 100644 --- a/tests/basic.d +++ b/tests/basic.d @@ -5,6 +5,8 @@ import ecs.manager; import ecs.system; import ecs.attributes; +import std.array : staticArray; + struct CInt { mixin ECS.Component; @@ -137,6 +139,13 @@ unittest assert(entity.getComponent!CFloat); assert(*entity.getComponent!CInt == 1); assert(*entity.getComponent!CFloat == 2.0); + *entity.getComponent!CInt = 2; + + Entity* entity2 = gEM.addEntityCopy(entity.id); + assert(entity2.getComponent!CInt); + assert(entity2.getComponent!CFloat); + assert(*entity2.getComponent!CInt == 2); + assert(*entity2.getComponent!CFloat == 2.0); } //allocate templates @@ -146,6 +155,8 @@ unittest //basic template allocation ushort[2] ids = [CInt.component_id, CFloat.component_id]; EntityTemplate* tmpl_ = gEM.allocateTemplate(ids); + EntityTemplate* tmpl_d = gEM.allocateTemplate([CFloat.component_id, CInt.component_id, CFloat.component_id].staticArray); + assert(tmpl_d.info == tmpl_.info); assert(tmpl_.info.components.length == 2); assert(tmpl_.getComponent!CInt); assert(tmpl_.getComponent!CFloat); @@ -221,6 +232,7 @@ unittest assert(*tmpl_7.getComponent!CDouble == 3.0); assert(*tmpl_7.getComponent!CLong == 10); + gEM.freeTemplate(tmpl_d); gEM.freeTemplate(tmpl_); gEM.freeTemplate(tmpl_2); gEM.freeTemplate(tmpl_3); @@ -497,7 +509,9 @@ unittest @("SystemEntityCallbacks") unittest { - //TODO: this test is WIP by now + static int add_order = 0; + static int rem_order = 0; + static int change_order = 0; struct TestSystem { mixin ECS.System!16; @@ -514,16 +528,22 @@ unittest void onAddEntity(EntitiesData data) { add++; + assert(add_order == 1); + add_order++; } void onRemoveEntity(EntitiesData data) { remove++; + assert(rem_order == 1); + rem_order++; } void onChangeEntity(EntitiesData data) { change++; + assert(change_order == 1); + change_order++; } void onUpdate(EntitiesData data) @@ -535,9 +555,83 @@ unittest int change = 0; } + struct TestSystem2 + { + mixin ECS.System!16; + + mixin ECS.ExcludedComponents!(CShort); + + struct EntitiesData + { + int length; + CLong[] long_; + @optional CInt[] int_; + } + + void onAddEntity(EntitiesData data) + { + assert(add_order == 2); + add_order = 0; + } + + void onRemoveEntity(EntitiesData data) + { + assert(rem_order == 2); + rem_order = 0 ; + } + + void onChangeEntity(EntitiesData data) + { + assert(change_order == 2); + change_order = 0; + } + + void onUpdate(EntitiesData data) + { + } + } + + struct TestSystem3 + { + mixin ECS.System!16; + + mixin ECS.ExcludedComponents!(CShort); + + struct EntitiesData + { + int length; + CLong[] long_; + @optional CInt[] int_; + } + + void onAddEntity(EntitiesData data) + { + assert(add_order == 0); + add_order++; + } + + void onRemoveEntity(EntitiesData data) + { + assert(rem_order == 0); + rem_order++; + } + + void onChangeEntity(EntitiesData data) + { + assert(change_order == 0); + change_order++; + } + + void onUpdate(EntitiesData data) + { + } + } + gEM.beginRegister(); + gEM.registerSystem!TestSystem3(-1); gEM.registerSystem!TestSystem(0); + gEM.registerSystem!TestSystem2(1); gEM.endRegister(); @@ -547,28 +641,80 @@ unittest assert(system.remove == 0); assert(system.change == 0); - ushort[2] ids = [CLong.component_id,CFloat.component_id]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); + EntityTemplate* tmpl = gEM.allocateTemplate([CLong.component_id,CFloat.component_id].staticArray); scope (exit) gEM.freeTemplate(tmpl); EntityID id0 = gEM.addEntity(tmpl).id; gEM.commit(); assert(system.add == 1); - ushort[2] ids2 = [CLong.component_id, CInt.component_id]; - EntityTemplate* tmpl2 = gEM.allocateTemplate(ids2); + EntityTemplate* tmpl2 = gEM.allocateTemplate([CLong.component_id, CInt.component_id].staticArray); scope (exit) gEM.freeTemplate(tmpl2); EntityID id1 = gEM.addEntity(tmpl2).id; gEM.commit(); assert(system.add == 2); - ushort[2] ids3 = [CLong.component_id, CShort.component_id]; - EntityTemplate* tmpl3 = gEM.allocateTemplate(ids3); + EntityTemplate* tmpl3 = gEM.allocateTemplate([CLong.component_id, CShort.component_id].staticArray); scope (exit) gEM.freeTemplate(tmpl3); EntityID id2 = gEM.addEntity(tmpl3).id; gEM.commit(); assert(system.add == 2); + gEM.beginRegister(); + gEM.endRegister(); + + gEM.removeComponents(id0, [CFloat.component_id].staticArray); gEM.commit(); + assert(system.add == 2); + assert(system.remove == 0); + assert(system.change == 0); + + gEM.removeComponents(id1, [CInt.component_id].staticArray); + gEM.commit(); + assert(system.add == 2); + assert(system.remove == 0); + assert(system.change == 1); + + gEM.removeComponents(id2, [CShort.component_id].staticArray); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 0); + assert(system.change == 1); + + gEM.addComponents(id2, CShort(1)); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 1); + assert(system.change == 1); + + gEM.removeEntity(id0); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 2); + assert(system.change == 1); + + gEM.addComponents(id1, CInt(1)); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 2); + assert(system.change == 2); + + gEM.addComponents(id0, CFloat(1)); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 2); + assert(system.change == 2); + + gEM.removeEntity(id1); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 3); + assert(system.change == 2); + + gEM.removeEntity(id2); + gEM.commit(); + assert(system.add == 3); + assert(system.remove == 3); + assert(system.change == 2); } @("TemplateCoverage") @@ -699,6 +845,12 @@ unittest TestSystem* system = gEM.getSystem!TestSystem; TestEmptySystem* empty_system = gEM.getSystem!TestEmptySystem; + ushort[2] ids = [CLong.component_id,CFloat.component_id]; + EntityTemplate* tmpl = gEM.allocateTemplate(ids); + scope (exit) gEM.freeTemplate(tmpl); + EntityTemplate* tmpl2 = gEM.allocateTemplate([CLong.component_id,CInt.component_id,CShort.component_id,CFloat.component_id].staticArray); + scope (exit) gEM.freeTemplate(tmpl2); + gEM.begin(); gEM.updateMT("custom"); @@ -709,9 +861,6 @@ unittest assert(system.entities == 0); assert(empty_system.update == 1); - ushort[2] ids = [CLong.component_id,CFloat.component_id]; - EntityTemplate* tmpl = gEM.allocateTemplate(ids); - scope (exit) gEM.freeTemplate(tmpl); gEM.addEntity(tmpl); gEM.begin(); @@ -866,7 +1015,14 @@ unittest struct ETest2 { mixin ECS.Event; + + void onDestroy() + { + destory++; + } + int super_liczba = 0; + static int destory = 0; } struct TestSystem @@ -937,6 +1093,9 @@ unittest gEM.registerEvent!ETest; gEM.registerEvent!ETest2; + gEM.registerEvent!ETest; + gEM.registerEvent!ETest2; + gEM.registerSystem!TestSystem2(1); gEM.registerSystem!TestSystem(0); @@ -961,6 +1120,7 @@ unittest gEM.sendEvent(id2,ETest()); gEM.sendEvent(id2,ETest2(id2,12)); gEM.commit(); + assert(ETest2.destory == 2); entity = gEM.getEntity(id); entity2 = gEM.getEntity(id2); @@ -971,6 +1131,7 @@ unittest gEM.sendEvent(id,ETest()); gEM.sendEvent(id,ETest2(id,2)); gEM.commit(); + assert(ETest2.destory == 3); entity = gEM.getEntity(id); assert(*entity.getComponent!CLong == 66); @@ -986,9 +1147,77 @@ unittest result += 8; } gEM.commit(); + assert(ETest2.destory == 10003); entity = gEM.getEntity(id); assert(*entity.getComponent!CLong == result); //cover funcion to clearEvents before destroying manager gEM.sendEvent(id,ETest()); +} + +@("EntitiesFunction") +unittest +{ + struct TestSystem + { + mixin ECS.System; + + struct EntitiesData + { + uint length; + CInt[] int_; + } + + void onUpdate(EntitiesData entities) + { + + } + } + + void func1(TestSystem.EntitiesData entities) + { + foreach(i;0 .. entities.length) + { + entities.int_[i] += entities.int_[i] / 2; + } + } + + void func2(TestSystem.EntitiesData entities) + { + foreach(i;0 .. entities.length) + { + entities.int_[i] += 8; + } + } + + gEM.beginRegister(); + + gEM.registerSystem!TestSystem(1); + + gEM.endRegister(); + + EntityTemplate* tmpl = gEM.allocateTemplate([CInt.component_id].staticArray); + scope (exit) gEM.freeTemplate(tmpl); + EntityID id1 = gEM.addEntity(tmpl).id; + + EntityTemplate* tmpl2 = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray); + scope (exit) gEM.freeTemplate(tmpl2); + EntityID id2 = gEM.addEntity(tmpl2).id; + + gEM.begin(); + + Entity* entity1 = gEM.getEntity(id1); + Entity* entity2 = gEM.getEntity(id2); + assert(*entity1.getComponent!CInt == 1); + assert(*entity2.getComponent!CInt == 1); + + gEM.callEntitiesFunction!TestSystem(&func2); + assert(*entity1.getComponent!CInt == 9); + assert(*entity2.getComponent!CInt == 9); + + gEM.callEntitiesFunction!TestSystem(&func1); + assert(*entity1.getComponent!CInt == 13); + assert(*entity2.getComponent!CInt == 13); + + gEM.end(); } \ No newline at end of file