#include #include #include #include #include #include struct C0 { C0(int x = 0, int y = 0) : x(x), y(y) {} int x, y; }; struct C1 { int vx, vy; }; struct C2 {}; struct C3 {}; struct T0 {}; struct T1 {}; using ListComponentsAll = EC::Meta::TypeList; using ListComponentsSome = EC::Meta::TypeList; using ListTagsAll = EC::Meta::TypeList; using ListAll = EC::Meta::TypeList; using EmptyList = EC::Meta::TypeList<>; using MixedList = EC::Meta::TypeList; typedef std::unique_ptr C0Ptr; struct Base { virtual int getInt() { return 0; } }; struct Derived : public Base { virtual int getInt() override { return 1; } }; typedef std::unique_ptr TestPtr; TEST(EC, Bitset) { { EC::Bitset bitset; bitset[1] = true; bitset[3] = true; auto genBitset = EC::Bitset::generateBitset(); EXPECT_EQ(bitset, genBitset); } { EC::Bitset bitset; bitset[2] = true; bitset[5] = true; auto genBitset = EC::Bitset::generateBitset(); EXPECT_EQ(bitset, genBitset); } } TEST(EC, Manager) { EC::Manager manager; std::size_t e0 = manager.addEntity(); std::size_t e1 = manager.addEntity(); manager.addComponent(e0, 5, 5); manager.addComponent(e0); manager.addComponent(e1); manager.addComponent(e1); manager.addTag(e1); { auto& vel = manager.getEntityData(e0); vel.vx = 1; vel.vy = 1; } auto posUpdate = [] (std::size_t id, C0& pos, C1& vel) { pos.x += vel.vx; pos.y += vel.vy; }; auto updateTag = [] (std::size_t id, C0& pos, C1& vel) { pos.x = pos.y = vel.vx = vel.vy = 0; }; manager.forMatchingSignature >(posUpdate); manager.forMatchingSignature >(posUpdate); manager.forMatchingSignature >(updateTag); { auto& pos = manager.getEntityData(e0); EXPECT_EQ(pos.x, 7); EXPECT_EQ(pos.y, 7); } { bool has = manager.hasComponent(e1); EXPECT_TRUE(has); has = manager.hasTag(e1); EXPECT_TRUE(has); } manager.deleteEntity(e0); manager.cleanup(); std::size_t edata = std::get(manager.getEntityInfo(0)); EXPECT_EQ(edata, 1); std::size_t e2 = manager.addEntity(); manager.addTag(e2); std::size_t count = 0; auto updateTagOnly = [&count] (std::size_t id) { std::cout << "UpdateTagOnly was run." << std::endl; ++count; }; manager.forMatchingSignature >(updateTagOnly); EXPECT_EQ(2, count); manager.deleteEntity(e1); manager.deleteEntity(e2); manager.cleanup(); } TEST(EC, MoveComponentWithUniquePtr) { { EC::Manager, EC::Meta::TypeList<> > manager; std::size_t e = manager.addEntity(); { C0Ptr ptr = std::make_unique(5, 10); manager.addComponent(e, std::move(ptr)); } int x = 0; int y = 0; manager.forMatchingSignature >([&x, &y] (std::size_t eID, C0Ptr& ptr) { x = ptr->x; y = ptr->y; }); EXPECT_EQ(5, x); EXPECT_EQ(10, y); } { EC::Manager, EC::Meta::TypeList<> > manager; std::size_t e = manager.addEntity(); { TestPtr ptrBase = std::make_unique(); manager.addComponent(e, std::move(ptrBase)); } int result = 0; auto getResultFunction = [&result] (std::size_t eID, TestPtr& ptr) { result = ptr->getInt(); }; manager.forMatchingSignature >(getResultFunction); EXPECT_EQ(0, result); { TestPtr ptrDerived = std::make_unique(); manager.addComponent(e, std::move(ptrDerived)); } manager.forMatchingSignature >(getResultFunction); EXPECT_EQ(1, result); } } TEST(EC, DeletedEntities) { EC::Manager manager; for(unsigned int i = 0; i < 4; ++i) { auto eid = manager.addEntity(); manager.addComponent(eid); if(i >= 2) { manager.deleteEntity(eid); } } manager.cleanup(); for(unsigned int i = 0; i < 4; ++i) { if(i < 2) { EXPECT_TRUE(manager.hasComponent(i)); } else { EXPECT_FALSE(manager.hasComponent(i)); } } for(unsigned int i = 0; i < 2; ++i) { auto eid = manager.addEntity(); EXPECT_FALSE(manager.hasComponent(eid)); } } TEST(EC, FunctionStorage) { EC::Manager manager; auto eid = manager.addEntity(); manager.addComponent(eid, 0, 1); manager.addComponent(eid); manager.addComponent(eid); manager.addComponent(eid); auto f0index = manager.addForMatchingFunction>( [] (std::size_t eid, C0& c0) { ++c0.x; ++c0.y; }); auto f1index = manager.addForMatchingFunction>( [] (std::size_t eid, C0& c0, C1& c1) { c1.vx = c0.x + 10; c1.vy = c1.vy + c1.vx + c0.y + 10; }); auto f2index = manager.addForMatchingFunction>( [] (std::size_t eid, C0& c0) { c0.x = c0.y = 9999; }); auto f3index = manager.addForMatchingFunction>( [] (std::size_t eid, C1& c1) { c1.vx = c1.vy = 10000; }); EXPECT_EQ(2, manager.removeSomeMatchingFunctions({f2index, f3index})); auto f4index = manager.addForMatchingFunction>( [] (std::size_t eid, C0& c0) { c0.x = 999; c0.y = 888; }); { auto set = std::set({f4index}); EXPECT_EQ(1, manager.removeSomeMatchingFunctions(set)); } auto f5index = manager.addForMatchingFunction>( [] (std::size_t eid, C0& c0) { c0.x = 777; c0.y = 666; }); auto lastIndex = f5index; { auto set = std::unordered_set({f5index}); EXPECT_EQ(1, manager.removeSomeMatchingFunctions(set)); } manager.callForMatchingFunctions(); { auto c0 = manager.getEntityData(eid); EXPECT_EQ(1, c0.x); EXPECT_EQ(2, c0.y); auto c1 = manager.getEntityData(eid); EXPECT_EQ(11, c1.vx); EXPECT_EQ(23, c1.vy); } EXPECT_TRUE(manager.callForMatchingFunction(f0index)); EXPECT_FALSE(manager.callForMatchingFunction(lastIndex + 1)); { auto& c0 = manager.getEntityData(eid); EXPECT_EQ(2, c0.x); EXPECT_EQ(3, c0.y); c0.x = 1; c0.y = 2; auto c1 = manager.getEntityData(eid); EXPECT_EQ(11, c1.vx); EXPECT_EQ(23, c1.vy); } EXPECT_EQ(1, manager.keepSomeMatchingFunctions({f1index})); { std::vector indices{f1index}; EXPECT_EQ(0, manager.keepSomeMatchingFunctions(indices)); } { std::set indices{f1index}; EXPECT_EQ(0, manager.keepSomeMatchingFunctions(indices)); } { std::unordered_set indices{f1index}; EXPECT_EQ(0, manager.keepSomeMatchingFunctions(indices)); } manager.callForMatchingFunctions(); { auto c0 = manager.getEntityData(eid); EXPECT_EQ(1, c0.x); EXPECT_EQ(2, c0.y); auto c1 = manager.getEntityData(eid); EXPECT_EQ(11, c1.vx); EXPECT_EQ(46, c1.vy); } EXPECT_TRUE(manager.removeForMatchingFunction(f1index)); EXPECT_FALSE(manager.removeForMatchingFunction(f1index)); manager.callForMatchingFunctions(); { auto c0 = manager.getEntityData(eid); EXPECT_EQ(1, c0.x); EXPECT_EQ(2, c0.y); auto c1 = manager.getEntityData(eid); EXPECT_EQ(11, c1.vx); EXPECT_EQ(46, c1.vy); } manager.clearForMatchingFunctions(); manager.callForMatchingFunctions(); { auto c0 = manager.getEntityData(eid); EXPECT_EQ(1, c0.x); EXPECT_EQ(2, c0.y); auto c1 = manager.getEntityData(eid); EXPECT_EQ(11, c1.vx); EXPECT_EQ(46, c1.vy); } } /* This test demonstrates that while entity ids may change after cleanup, pointers to their components do not. */ TEST(EC, DataPointers) { EC::Manager manager; auto first = manager.addEntity(); auto second = manager.addEntity(); manager.addComponent(first, 5, 5); manager.addComponent(second, 10, 10); manager.addTag(second); auto* cptr = &manager.getEntityData(second); EXPECT_EQ(10, cptr->x); EXPECT_EQ(10, cptr->y); manager.deleteEntity(first); manager.cleanup(); auto newSecond = second; manager.forMatchingSignature>( [&newSecond] (auto eid) { newSecond = eid; }); EXPECT_NE(newSecond, second); auto* newcptr = &manager.getEntityData(newSecond); EXPECT_EQ(newcptr, cptr); EXPECT_EQ(10, newcptr->x); EXPECT_EQ(10, newcptr->y); } TEST(EC, DeletedEntityID) { EC::Manager manager; auto e0 = manager.addEntity(); auto e1 = manager.addEntity(); auto e2 = manager.addEntity(); manager.deleteEntity(e0); auto changedMap = manager.cleanup(); for(decltype(changedMap)::value_type& p : changedMap) { if(p.first == 0) { EXPECT_FALSE(p.second.first); } else if(p.first == 2) { EXPECT_TRUE(p.second.first); EXPECT_EQ(0, p.second.second); } } EXPECT_FALSE(manager.hasEntity(2)); EXPECT_TRUE(manager.hasEntity(0)); } TEST(EC, MultiThreaded) { EC::Manager manager; for(unsigned int i = 0; i < 17; ++i) { manager.addEntity(); manager.addComponent(i, 0, 0); EXPECT_EQ(0, manager.getEntityData(i).x); EXPECT_EQ(0, manager.getEntityData(i).y); } manager.forMatchingSignature >( [] (const std::size_t& eid, C0& c) { c.x = 1; c.y = 2; } ); for(unsigned int i = 0; i < 17; ++i) { EXPECT_EQ(1, manager.getEntityData(i).x); EXPECT_EQ(2, manager.getEntityData(i).y); } for(unsigned int i = 3; i < 17; ++i) { manager.deleteEntity(i); } manager.cleanup(); for(unsigned int i = 0; i < 3; ++i) { EXPECT_EQ(1, manager.getEntityData(i).x); EXPECT_EQ(2, manager.getEntityData(i).y); } manager.forMatchingSignature >( [] (const std::size_t& eid, C0& c) { c.x = 3; c.y = 4; }, 8 ); for(unsigned int i = 0; i < 3; ++i) { EXPECT_EQ(3, manager.getEntityData(i).x); EXPECT_EQ(4, manager.getEntityData(i).y); } manager.reset(); for(unsigned int i = 0; i < 17; ++i) { manager.addEntity(); manager.addComponent(i, 0, 0); EXPECT_EQ(0, manager.getEntityData(i).x); EXPECT_EQ(0, manager.getEntityData(i).y); } auto f0 = manager.addForMatchingFunction >( [] (const std::size_t& eid, C0& c) { c.x = 1; c.y = 2; } ); manager.callForMatchingFunctions(2); for(unsigned int i = 0; i < 17; ++i) { EXPECT_EQ(1, manager.getEntityData(i).x); EXPECT_EQ(2, manager.getEntityData(i).y); } auto f1 = manager.addForMatchingFunction >( [] (const std::size_t& eid, C0& c) { c.x = 3; c.y = 4; } ); manager.callForMatchingFunction(f1, 4); for(unsigned int i = 0; i < 17; ++i) { EXPECT_EQ(3, manager.getEntityData(i).x); EXPECT_EQ(4, manager.getEntityData(i).y); } for(unsigned int i = 4; i < 17; ++i) { manager.deleteEntity(i); } manager.cleanup(); manager.callForMatchingFunction(f0, 8); for(unsigned int i = 0; i < 4; ++i) { EXPECT_EQ(1, manager.getEntityData(i).x); EXPECT_EQ(2, manager.getEntityData(i).y); } manager.callForMatchingFunction(f1, 8); for(unsigned int i = 0; i < 4; ++i) { EXPECT_EQ(3, manager.getEntityData(i).x); EXPECT_EQ(4, manager.getEntityData(i).y); } }