Mostly bugfix update + empty components support and remove EntityID from Event structure

-empty components now take no memory, so flag components is now far better
-added test for critical bug
-fixed critical bug with adding/removing entities form inside events
-fixed small bug with TestRunner
-improve basic tests
-fixed betterC compilation on DMD
-remove EntityID form Event structure
-added "return" attribute to some functions
-moved some code from Tempalte side to actual implementation
-fixed bug with EntityTemplate copying
-commented out some possibliy unused code
-use code formatter
This commit is contained in:
Mergul 2020-05-27 17:03:44 +02:00
parent 15cd57dbcb
commit 6929f5a748
16 changed files with 988 additions and 544 deletions

View file

@ -68,6 +68,11 @@ struct CUnregistered
short value = 12;
}
struct CFlag
{
mixin ECS.Component;
}
struct LongAddSystem
{
mixin ECS.System;
@ -110,6 +115,7 @@ struct EmptySystem
void beforeEveryTest()
{
CUnregistered.component_id = ushort.max;
gEM.initialize(0);
gEM.beginRegister();
@ -119,6 +125,7 @@ void beforeEveryTest()
gEM.registerComponent!CDouble;
gEM.registerComponent!CLong;
gEM.registerComponent!CShort;
gEM.registerComponent!CFlag;
gEM.endRegister();
}
@ -131,11 +138,12 @@ void afterEveryTest()
@("AddEntity")
unittest
{
ushort[2] ids = [CInt.component_id, CFloat.component_id];
EntityTemplate* tmpl_ = gEM.allocateTemplate(ids);
assert(tmpl_.info.components.length == 2);
EntityTemplate* tmpl_ = gEM.allocateTemplate([CInt.component_id, CFloat.component_id, CFlag.component_id].staticArray);
assert(tmpl_.info.components.length == 3);
assert(tmpl_.info.size == (CInt.sizeof + CFloat.sizeof + EntityID.sizeof));
assert(tmpl_.getComponent!CInt);
assert(tmpl_.getComponent!CFloat);
assert(tmpl_.getComponent!CFlag);
assert(!tmpl_.getComponent!CLong);
assert(!tmpl_.getComponent!CUnregistered);
assert(*tmpl_.getComponent!CInt == 1);
@ -154,13 +162,66 @@ unittest
assert(*entity2.getComponent!CInt == 2);
assert(*entity2.getComponent!CFloat == 2.0);
CInt cint = CInt(10);
CLong clong;
Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray);
//CInt cint = CInt(10);
//CLong clong;
//Entity* entity3 = gEM.addEntity(tmpl_, [cint.ref_, clong.ref_].staticArray);
Entity* entity3 = gEM.addEntity(tmpl_, [CInt(10).ref_, CLong().ref_, CFlag().ref_].staticArray);
EntityID id = entity3.id;
assert(entity3.getComponent!CInt);
assert(entity3.getComponent!CFloat);
assert(*entity3.getComponent!CInt == 10);
assert(*entity3.getComponent!CFloat == 2.0);
gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_]);
gEM.commit();
entity3 = gEM.getEntity(id);
assert(entity3.getComponent!CInt);
assert(entity3.getComponent!CFloat);
assert(entity3.getComponent!CFlag);
assert(entity3.getComponent!CShort);
assert(*entity3.getComponent!CInt == 10);
assert(*entity3.getComponent!CFloat == 2.0);
assert(*entity3.getComponent!CShort == 2);
gEM.removeComponents(entity3.id, [CFlag().component_id,CShort(2).component_id]);
gEM.commit();
entity3 = gEM.getEntity(id);
assert(entity3.getComponent!CInt);
assert(entity3.getComponent!CFloat);
assert(!entity3.getComponent!CFlag);
assert(!entity3.getComponent!CShort);
assert(*entity3.getComponent!CInt == 10);
assert(*entity3.getComponent!CFloat == 2.0);
gEM.addComponents(entity3.id, [CFlag().ref_,CShort(2).ref_]);
gEM.removeComponents(entity3.id, [CUnregistered.component_id]);
gEM.commit();
entity3 = gEM.getEntity(id);
assert(entity3.getComponent!CInt);
assert(entity3.getComponent!CFloat);
assert(entity3.getComponent!CFlag);
assert(entity3.getComponent!CShort);
assert(*entity3.getComponent!CInt == 10);
assert(*entity3.getComponent!CFloat == 2.0);
assert(*entity3.getComponent!CShort == 2);
gEM.beginRegister();
gEM.registerComponent!CUnregistered;
gEM.endRegister();
gEM.addComponents(entity3.id, [CUnregistered(4).ref_]);
gEM.commit();
entity3 = gEM.getEntity(id);
assert(entity3.getComponent!CUnregistered);
assert(*entity3.getComponent!CUnregistered == 4);
gEM.removeComponents(entity3.id, [CUnregistered.component_id]);
gEM.commit();
entity3 = gEM.getEntity(id);
assert(!entity3.getComponent!CUnregistered);
}
//allocate templates
@ -171,32 +232,48 @@ unittest
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);
EntityTemplate* tmpl_cp = gEM.allocateTemplate(tmpl_);
assert(tmpl_d.info == tmpl_.info);
assert(tmpl_cp.info == tmpl_cp.info);
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);
assert(tmpl_cp.getComponent!CFloat);
assert(tmpl_cp.getComponent!CInt);
assert(tmpl_.getComponent!CInt != tmpl_cp.getComponent!CInt);
assert(tmpl_.getComponent!CFloat != tmpl_cp.getComponent!CFloat);
assert(*tmpl_.getComponent!CInt == *tmpl_cp.getComponent!CInt);
assert(*tmpl_.getComponent!CFloat == *tmpl_cp.getComponent!CFloat);
*tmpl_.getComponent!CInt = 4;
*tmpl_.getComponent!CFloat = 5.0;
//allocate template from template with additional component
ushort[1] ids2 = [CDouble.component_id];
//allocate template from template with additional components
ushort[2] ids2 = [CDouble.component_id,CFlag.component_id];
EntityTemplate* tmpl_2 = gEM.allocateTemplate(tmpl_, ids2);
assert(tmpl_2.info.components.length == 3);
assert(tmpl_2.info.components.length == 4);
assert(tmpl_2.getComponent!CInt);
assert(tmpl_2.getComponent!CFloat);
assert(tmpl_2.getComponent!CDouble);
assert(tmpl_2.getComponent!CFlag);
assert(*tmpl_2.getComponent!CInt == 4);
assert(*tmpl_2.getComponent!CFloat == 5.0);
assert(*tmpl_2.getComponent!CDouble == 3.0);
assert(tmpl_.info.blocksCount() == 0);
Entity* entity = gEM.addEntity(tmpl_);
gEM.addComponents(entity.id, CDouble(8.0));
gEM.addComponents(entity.id, CFloat(100));
gEM.addComponents(entity.id, CDouble(8.0), CFloat(100));
assert(tmpl_.info.blocksCount() == 1);
//apply entity changes
gEM.commit();
assert(tmpl_.info.blocksCount() == 0);
//allocate template as entity copy
EntityTemplate* tmpl_3 = gEM.allocateTemplate(entity.id);
assert(tmpl_3.info.components.length == 3);
@ -217,18 +294,20 @@ unittest
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);
//allocate template from template with three additional component
ushort[3] ids3 = [CDouble.component_id, CLong.component_id, CShort.component_id];
EntityTemplate* tmpl_5 = gEM.allocateTemplate(tmpl_2, ids3);
assert(tmpl_5.info.components.length == 6);
assert(tmpl_5.getComponent!CInt);
assert(tmpl_5.getComponent!CFloat);
assert(tmpl_5.getComponent!CDouble);
assert(tmpl_5.getComponent!CLong);
assert(tmpl_5.getComponent!CShort);
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);
assert(*tmpl_5.getComponent!CShort == 12);
//allocate template from template without one component
ushort[1] rem_ids = [CFloat.component_id];
@ -239,7 +318,7 @@ unittest
//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.info.components.length == 4);
assert(tmpl_7.getComponent!CInt);
assert(tmpl_7.getComponent!CDouble);
assert(tmpl_7.getComponent!CLong);
@ -496,6 +575,10 @@ unittest
gEM.endRegister();
assert(gEM.getPass("custom"));
assert(!gEM.getPass("custommm"));
LongAddSystem* system = gEM.getSystem!LongAddSystem;
assert(system !is null);
assert(system.updates_count == 0);
@ -1131,9 +1214,9 @@ unittest
assert(*entity2.getComponent!CShort == 12);
gEM.sendEvent(id,ETest());
gEM.sendEvent(id,ETest2(id,10));
gEM.sendEvent(id,ETest2(10));
gEM.sendEvent(id2,ETest());
gEM.sendEvent(id2,ETest2(id2,12));
gEM.sendEvent(id2,ETest2(12));
gEM.commit();
assert(ETest2.destory == 2);
@ -1144,7 +1227,7 @@ unittest
gEM.addComponents(id, CInt(2), CShort(1));
gEM.sendEvent(id,ETest());
gEM.sendEvent(id,ETest2(id,2));
gEM.sendEvent(id,ETest2(2));
gEM.commit();
assert(ETest2.destory == 3);
@ -1157,7 +1240,7 @@ unittest
foreach(i;0..10000)
{
gEM.sendEvent(id,ETest());
gEM.sendEvent(id,ETest2(id,4));
gEM.sendEvent(id,ETest2(4));
result += 16;
result += 8;
}
@ -1321,22 +1404,6 @@ unittest
}
}
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(0);
@ -1462,22 +1529,6 @@ unittest
}
}
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.registerDependency(TestDependency);

142
tests/bugs.d Normal file
View file

@ -0,0 +1,142 @@
module tests.bugs;
import tests.basic;
import bubel.ecs.core;
import bubel.ecs.manager;
import bubel.ecs.system;
import bubel.ecs.attributes;
version(GNU)
{
pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a)
{
return a;
}
}
else import std.array : staticArray;
@("Bug0001")
unittest
{
struct Event1
{
mixin ECS.Event;
EntityID id;
}
struct Event2
{
mixin ECS.Event;
}
struct System1
{
mixin ECS.System;
struct EntitiesData
{
CInt[] int_;
}
EntityTemplate* tmpl;
EntityID id;
void onCreate()
{
tmpl = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray);
}
void onDestroy()
{
gEM.freeTemplate(tmpl);
}
void handleEvent(Entity* entity, Event1 event)
{
gEM.removeEntity(event.id);
gEM.sendEvent(entity.id,Event2());
}
void handleEvent(Entity* entity, Event2 event)
{
id = gEM.addEntity(tmpl,[CInt(2).ref_, CLong(8).ref_].staticArray).id;
}
}
struct System2
{
mixin ECS.System;
struct EntitiesData
{
Entity[] entity;
}
///check if every entity was removed correctly
void onUpdate(EntitiesData data)
{
assert(0);
}
}
struct System3
{
mixin ECS.System;
struct EntitiesData
{
uint length;
Entity[] entity;
}
///remove every entity
void onUpdate(EntitiesData data)
{
foreach(i;0..data.length)gEM.removeEntity(data.entity[i].id);
}
}
gEM.initialize(0);
gEM.beginRegister();
gEM.registerComponent!CInt;
gEM.registerComponent!CFloat;
gEM.registerComponent!CDouble;
gEM.registerComponent!CLong;
gEM.registerComponent!CShort;
gEM.registerComponent!CFlag;
gEM.registerEvent!Event1;
gEM.registerEvent!Event2;
gEM.registerSystem!System1(0);
gEM.registerSystem!System2(-200);
gEM.registerSystem!System3(-200);
gEM.endRegister();
EntityTemplate* tmpl = gEM.allocateTemplate([CInt.component_id, CLong.component_id].staticArray);
EntityID id = gEM.addEntity(tmpl,[CLong(10).ref_, CInt(6).ref_].staticArray).id;
EntityID id2 = gEM.addEntity(tmpl,[CInt(4).ref_].staticArray).id;
gEM.freeTemplate(tmpl);
gEM.commit();
gEM.sendEvent(id2, Event1(id));
gEM.getSystem(System2.system_id).disable();
gEM.begin();
gEM.update();
gEM.end();
gEM.getSystem(System2.system_id).enable();
gEM.begin();
gEM.update();
gEM.end();
gEM.destroy();
}

View file

@ -210,7 +210,7 @@ struct TestRunner(Args...)
else
test.name = attributes[0];
static if (__traits(hasMember, module_, "beforeEveryTest"))
static if (__traits(hasMember, module_, "beforeEveryTest") && __traits(compiles, module_.beforeEveryTest()))
module_.beforeEveryTest();
if(before)before();
@ -256,7 +256,7 @@ struct TestRunner(Args...)
else
suite.failed++;
suite.tests ~= test;
static if (__traits(hasMember, module_, "afterEveryTest"))
static if (__traits(hasMember, module_, "afterEveryTest") && __traits(compiles, module_.beforeEveryTest()))
module_.afterEveryTest();
}
passed += suite.passed;
@ -420,7 +420,7 @@ extern (C) int main(int argc, char** args)
}
}
TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf) runner;
TestRunner!(tests.id_manager, tests.vector, tests.basic, tests.perf, tests.access_perf, tests.bugs) runner;
runner.runTests(include[], exclude[]);