#include void World_multi_world_empty(void) { flecs::world *w1 = new flecs::world(); delete w1; flecs::world *w2 = new flecs::world(); delete w2; test_assert(true); } class FooModule { public: FooModule(flecs::world& world) { world.module(); } }; typedef struct TestInteropModule { int dummy; } TestInteropModule; static void TestInteropModuleImport(ecs_world_t *world) { ECS_MODULE(world, TestInteropModule); ECS_COMPONENT(world, Position); ECS_COMPONENT(world, Velocity); } namespace test { namespace interop { class module : TestInteropModule { public: struct Velocity : ::Velocity { }; module(flecs::world& ecs) { TestInteropModuleImport(ecs); ecs.module(); ecs.component("::test::interop::module::Position"); ecs.component("::test::interop::module::Velocity"); } }; } } namespace ns { struct FooComp { int value; }; struct namespace_module { namespace_module(flecs::world& ecs) { ecs.module(); ecs.component(); import_count ++; ecs.system() .kind(flecs::OnUpdate) .each([](flecs::entity entity, FooComp &sc) { namespace_module::system_invoke_count ++; }); } static int import_count; static int system_invoke_count; }; int namespace_module::import_count = 0; int namespace_module::system_invoke_count = 0; } void World_builtin_components(void) { flecs::world ecs; test_assert(ecs.component() == ecs_id(EcsComponent)); test_assert(ecs.component() == ecs_id(EcsIdentifier)); test_assert(ecs.component() == ecs_id(EcsPoly)); test_assert(ecs.component() == ecs_id(EcsTarget)); test_assert(ecs.component() == ecs_id(EcsRateFilter)); test_assert(ecs.component() == ecs_id(EcsTickSource)); test_assert(flecs::Name == EcsName); test_assert(flecs::Symbol == EcsSymbol); test_assert(flecs::System == EcsSystem); test_assert(flecs::Observer == EcsObserver); test_assert(flecs::Query == EcsQuery); } void World_multi_world_component(void) { flecs::world w1; flecs::world w2; auto p_1 = w1.component(); auto v_1 = w1.component(); auto v_2 = w2.component(); auto m_2 = w2.component(); test_assert(v_1.id() == v_2.id()); test_assert(p_1.id() != m_2.id()); test_assert(m_2.id() > v_2.id()); auto m_1 = w2.component(); test_assert(m_1.id() == m_2.id()); } namespace A { struct Comp { float x; float y; }; } void World_multi_world_component_namespace(void) { flecs::world *w = new flecs::world(); auto c = w->component(); auto id_1 = c.id(); delete w; w = new flecs::world(); c = w->component(); auto id_2 = c.id(); test_assert(id_1 == id_2); delete w; } void World_multi_world_module(void) { flecs::world world1; world1.import(); flecs::world world2; world2.import(); world1.entity().add(); world2.entity().add(); world1.progress(); test_int(ns::namespace_module::system_invoke_count, 1); world2.progress(); test_int(ns::namespace_module::system_invoke_count, 2); } void World_multi_world_recycled_component(void) { flecs::entity c; { flecs::world ecs; for (int i = 0; i < FLECS_HI_COMPONENT_ID; i ++) { ecs_new_low_id(ecs); } ecs.entity().destruct(); c = ecs.component(); } { flecs::world ecs; test_assert((c == ecs.component())); } } void World_multi_world_recycled_component_different_generation(void) { flecs::entity c; { flecs::world ecs; for (int i = 0; i < FLECS_HI_COMPONENT_ID; i ++) { ecs_new_low_id(ecs); } ecs.entity().destruct(); c = ecs.component(); } { flecs::world ecs; for (int i = 0; i < FLECS_HI_COMPONENT_ID; i ++) { ecs_new_low_id(ecs); } ecs.entity().destruct(); test_assert((c == ecs.component())); } } void World_type_id(void) { flecs::world ecs; auto p = ecs.component(); test_assert(p.id() == flecs::type_id()); } void World_different_comp_same_name(void) { install_test_abort(); flecs::world ecs; test_expect_abort(); ecs.component("Position"); ecs.component("Position"); } void World_reregister_after_reset(void) { flecs::world ecs; auto p1 = ecs.component("Position"); // Simulate different binary flecs::_::cpp_type::reset(); auto p2 = ecs.component("Position"); test_assert(p1.id() == p2.id()); } void World_implicit_reregister_after_reset(void) { flecs::world ecs; ecs.entity().add(); flecs::entity_t p_id_1 = flecs::type_id(); // Simulate different binary flecs::_::cpp_type::reset(); ecs.entity().add(); flecs::entity_t p_id_2 = flecs::type_id(); test_assert(p_id_1 == p_id_2); } void World_reregister_after_reset_w_namespace(void) { flecs::world ecs; ecs.component(); flecs::entity_t p_id_1 = flecs::type_id(); // Simulate different binary flecs::_::cpp_type::reset(); ecs.component(); flecs::entity_t p_id_2 = flecs::type_id(); test_assert(p_id_1 == p_id_2); } void World_reregister_namespace(void) { flecs::world ecs; ecs.component(); flecs::entity_t p_id_1 = flecs::type_id(); ecs.component(); flecs::entity_t p_id_2 = flecs::type_id(); test_assert(p_id_1 == p_id_2); } void World_reregister_after_reset_different_name(void) { install_test_abort(); flecs::world ecs; test_expect_abort(); ecs.component("Position"); // Simulate different binary flecs::_::cpp_type::reset(); ecs.component("Velocity"); } void World_register_component_w_reset_in_multithreaded(void) { flecs::world ecs; ecs.set_threads(2); flecs::entity pos = ecs.component(); flecs::entity e = ecs.entity(); flecs::_::cpp_type::reset(); ecs.readonly_begin(); e.set({10, 20}); ecs.readonly_end(); test_assert(e.has()); test_assert(e.has(pos)); const Position *p = e.get(); test_assert(p != nullptr); test_int(p->x, 10); test_int(p->y, 20); } struct Module { }; void World_register_component_w_core_name(void) { flecs::world ecs; flecs::entity c = ecs.component(); test_assert(c != 0); test_str(c.path().c_str(), "::Module"); } template struct Tmp { int32_t v; }; struct Test { }; void World_register_short_template(void) { flecs::world ecs; auto c = ecs.component>(); test_assert(c != 0); test_str(c.name(), "Tmp"); const EcsComponent *ptr = c.get(); test_assert(ptr != NULL); test_int(ptr->size, 4); test_int(ptr->alignment, 4); } void World_reimport(void) { flecs::world ecs; auto m1 = ecs.import(); auto m2 = ecs.import(); test_assert(m1.id() == m2.id()); } void World_reimport_module_after_reset(void) { flecs::world ecs; auto m1 = ecs.import(); // Simulate different binary flecs::_::cpp_type::reset(); auto m2 = ecs.import(); test_assert(m1.id() == m2.id()); } void World_reimport_module_new_world(void) { flecs::entity e1; { flecs::world ecs; e1 = ecs.import(); } { flecs::world ecs; auto e2 = ecs.import(); test_assert(e1.id() == e2.id()); } } void World_reimport_namespaced_module(void) { flecs::world ecs; test_int(ns::namespace_module::import_count, 0); // Import first time, should call module constructor. ecs.import(); test_int(ns::namespace_module::import_count, 1); // Import second time, should not call constructor. ecs.import(); test_int(ns::namespace_module::import_count, 1); } void World_c_interop_module(void) { flecs::world ecs; ecs.import(); auto e_pos = ecs.lookup("test::interop::module::Position"); test_assert(e_pos.id() != 0); } void World_c_interop_after_reset(void) { flecs::world ecs; ecs.import(); auto e_pos = ecs.lookup("test::interop::module::Position"); test_assert(e_pos.id() != 0); flecs::_::cpp_type::reset(); ecs.import(); } void World_implicit_register_w_new_world(void) { { flecs::world ecs; auto e = ecs.entity().set({10, 20}); test_assert(e.has()); auto *p = e.get(); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); } { /* Recreate world, does not reset static state */ flecs::world ecs; auto e = ecs.entity().set({10, 20}); test_assert(e.has()); auto *p = e.get(); test_assert(p != NULL); test_int(p->x, 10); test_int(p->y, 20); } } void World_implicit_register_after_reset_register_w_custom_name(void) { flecs::world ecs; flecs::entity c = ecs.component("MyPosition"); test_str(c.name(), "MyPosition"); flecs::reset(); // Simulate working across boundary auto e = ecs.entity().add(); test_assert(e.has()); test_assert(e.has(c)); } void World_register_after_reset_register_w_custom_name(void) { flecs::world ecs; flecs::entity c1 = ecs.component("MyPosition"); test_str(c1.name(), "MyPosition"); flecs::reset(); // Simulate working across boundary flecs::entity c2 = ecs.component(); test_str(c2.name(), "MyPosition"); } void World_register_builtin_after_reset(void) { flecs::world ecs; auto c1 = ecs.component(); test_assert(c1 == ecs_id(EcsComponent)); flecs::reset(); // Simulate working across boundary auto c2 = ecs.component(); test_assert(c2 == ecs_id(EcsComponent)); test_assert(c1 == c2); } void World_register_meta_after_reset(void) { flecs::world ecs; auto c1 = ecs.component(); flecs::reset(); // Simulate working across boundary auto c2 = ecs.component() .member("x") .member("y"); test_assert(c1 == c2); } void World_count(void) { flecs::world ecs; test_int(ecs.count(), 0); ecs.entity().add(); ecs.entity().add(); ecs.entity().add(); ecs.entity().add().add(); ecs.entity().add().add(); ecs.entity().add().add(); test_int(ecs.count(), 6); } void World_count_id(void) { flecs::world ecs; auto ent = ecs.entity(); test_int(ecs.count(ent), 0); ecs.entity().add(ent); ecs.entity().add(ent); ecs.entity().add(ent); ecs.entity().add(ent).add(); ecs.entity().add(ent).add(); ecs.entity().add(ent).add(); test_int(ecs.count(ent), 6); } void World_count_pair(void) { flecs::world ecs; auto parent = ecs.entity(); test_int(ecs.count(flecs::ChildOf, parent), 0); ecs.entity().add(flecs::ChildOf, parent); ecs.entity().add(flecs::ChildOf, parent); ecs.entity().add(flecs::ChildOf, parent); ecs.entity().add(flecs::ChildOf, parent).add(); ecs.entity().add(flecs::ChildOf, parent).add(); ecs.entity().add(flecs::ChildOf, parent).add(); test_int(ecs.count(flecs::ChildOf, parent), 6); } void World_count_pair_type_id(void) { flecs::world ecs; struct Rel { }; auto parent = ecs.entity(); test_int(ecs.count(parent), 0); ecs.entity().add(parent); ecs.entity().add(parent); ecs.entity().add(parent); ecs.entity().add(parent).add(); ecs.entity().add(parent).add(); ecs.entity().add(parent).add(); test_int(ecs.count(parent), 6); } void World_count_pair_id(void) { flecs::world ecs; struct Rel { }; auto rel = ecs.entity(); auto parent = ecs.entity(); test_int(ecs.count(rel, parent), 0); ecs.entity().add(rel, parent); ecs.entity().add(rel, parent); ecs.entity().add(rel, parent); ecs.entity().add(rel, parent).add(); ecs.entity().add(rel, parent).add(); ecs.entity().add(rel, parent).add(); test_int(ecs.count(rel, parent), 6); } void World_staged_count(void) { flecs::world ecs; flecs::world stage = ecs.get_stage(0); ecs.readonly_begin(); test_int(stage.count(), 0); ecs.readonly_end(); ecs.readonly_begin(); stage.entity().add(); stage.entity().add(); stage.entity().add(); stage.entity().add().add(); stage.entity().add().add(); stage.entity().add().add(); test_int(stage.count(), 0); ecs.readonly_end(); test_int(stage.count(), 6); } void World_async_stage_add(void) { flecs::world ecs; ecs.component(); auto e = ecs.entity(); flecs::world async = ecs.async_stage(); e.mut(async).add(); test_assert(!e.has()); async.merge(); test_assert(e.has()); } void World_with_tag(void) { flecs::world ecs; auto Tag = ecs.entity(); ecs.with(Tag, [&]{ auto e1 = ecs.entity(); e1.set({e1}); auto e2 = ecs.entity(); e2.set({e2}); auto e3 = ecs.entity(); e3.set({e3}); }); // Ensures that while Self is (implicitly) registered within the with, it // does not get any contents from the with. auto self = ecs.component(); test_assert(!self.has(Tag)); auto q = ecs.query_builder<>().term(Tag).build(); int32_t count = 0; q.each([&](flecs::entity e) { test_assert(e.has(Tag)); test_bool(e.get([&](const Self& s) { test_assert(s.value == e); }), true); count ++; }); count ++; } void World_with_tag_type(void) { flecs::world ecs; struct Tag { }; ecs.with([&]{ auto e1 = ecs.entity(); e1.set({e1}); auto e2 = ecs.entity(); e2.set({e2}); auto e3 = ecs.entity(); e3.set({e3}); }); // Ensures that while Self is (implicitly) registered within the with, it // does not get any contents from the with. auto self = ecs.component(); test_assert(!self.has()); auto q = ecs.query_builder<>().term().build(); int32_t count = 0; q.each([&](flecs::entity e) { test_assert(e.has()); test_bool(e.get([&](const Self& s) { test_assert(s.value == e); }), true); count ++; }); count ++; } void World_with_relation(void) { flecs::world ecs; auto Likes = ecs.entity(); auto Bob = ecs.entity(); ecs.with(Likes, Bob, [&]{ auto e1 = ecs.entity(); e1.set({e1}); auto e2 = ecs.entity(); e2.set({e2}); auto e3 = ecs.entity(); e3.set({e3}); }); // Ensures that while Self is (implicitly) registered within the with, it // does not get any contents from the with. auto self = ecs.component(); test_assert(!self.has(Likes, Bob)); auto q = ecs.query_builder<>().term(Likes, Bob).build(); int32_t count = 0; q.each([&](flecs::entity e) { test_assert(e.has(Likes, Bob)); test_bool(e.get([&](const Self& s) { test_assert(s.value == e); }), true); count ++; }); count ++; } void World_with_relation_type(void) { flecs::world ecs; struct Likes { }; auto Bob = ecs.entity(); ecs.with(Bob, [&]{ auto e1 = ecs.entity(); e1.set({e1}); auto e2 = ecs.entity(); e2.set({e2}); auto e3 = ecs.entity(); e3.set({e3}); }); // Ensures that while Self is (implicitly) registered within the with, it // does not get any contents from the with. auto self = ecs.component(); test_assert(!self.has(Bob)); auto q = ecs.query_builder<>().term(Bob).build(); int32_t count = 0; q.each([&](flecs::entity e) { test_assert(e.has(Bob)); test_bool(e.get([&](const Self& s) { test_assert(s.value == e); }), true); count ++; }); count ++; } void World_with_relation_object_type(void) { flecs::world ecs; struct Likes { }; struct Bob { }; ecs.with([&]{ auto e1 = ecs.entity(); e1.set({e1}); auto e2 = ecs.entity(); e2.set({e2}); auto e3 = ecs.entity(); e3.set({e3}); }); // Ensures that while Self is (implicitly) registered within the with, it // does not get any contents from the with. auto self = ecs.component(); test_assert(!(self.has())); auto q = ecs.query_builder<>().term().build(); int32_t count = 0; q.each([&](flecs::entity e) { test_assert((e.has())); test_bool(e.get([&](const Self& s) { test_assert(s.value == e); }), true); count ++; }); count ++; } void World_with_scope(void) { flecs::world ecs; auto parent = ecs.entity("P"); ecs.scope(parent, [&]{ auto e1 = ecs.entity("C1"); e1.set({e1}); auto e2 = ecs.entity("C2"); e2.set({e2}); auto e3 = ecs.entity("C3"); e3.set({e3}); // Ensure relative lookups work test_assert(ecs.lookup("C1") == e1); test_assert(ecs.lookup("C2") == e2); test_assert(ecs.lookup("C3") == e3); test_assert(parent.lookup("C1") == e1); test_assert(parent.lookup("C2") == e2); test_assert(parent.lookup("C3") == e3); test_assert(ecs.lookup("::P::C1") == e1); test_assert(ecs.lookup("::P::C2") == e2); test_assert(ecs.lookup("::P::C3") == e3); }); test_assert(parent.lookup("C1") != 0); test_assert(parent.lookup("C2") != 0); test_assert(parent.lookup("C3") != 0); test_assert(ecs.lookup("P::C1") == parent.lookup("C1")); test_assert(ecs.lookup("P::C2") == parent.lookup("C2")); test_assert(ecs.lookup("P::C3") == parent.lookup("C3")); // Ensures that while Self is (implicitly) registered within the with, it // does not become a child of the parent. auto self = ecs.component(); test_assert(!self.has(flecs::ChildOf, parent)); int count = 0; auto q = ecs.query_builder<>().term(flecs::ChildOf, parent).build(); q.each([&](flecs::entity e) { test_assert(e.has(flecs::ChildOf, parent)); test_bool(e.get([&](const Self& s){ test_assert(s.value == e); }), true); count ++; }); test_int(count, 3); } struct ParentScope { }; void World_with_scope_type(void) { flecs::world ecs; ecs.scope([&]{ ecs.entity("Child"); }); auto parent = ecs.lookup("ParentScope"); test_assert(parent != 0); auto child = ecs.lookup("ParentScope::Child"); test_assert(child != 0); test_assert(child == parent.lookup("Child")); } void World_with_scope_type_staged(void) { flecs::world ecs; flecs::entity e; flecs::world stage = ecs.get_stage(0); ecs.readonly_begin(); stage.scope([&]{ e = stage.entity("Child"); }); ecs.readonly_end(); test_assert( e.has(flecs::ChildOf, ecs.id()) ); auto parent = ecs.lookup("ParentScope"); test_assert(parent != 0); auto child = ecs.lookup("ParentScope::Child"); test_assert(child != 0); test_assert(child == parent.lookup("Child")); } void World_with_scope_no_lambda(void) { flecs::world ecs; auto parent = ecs.entity("Parent"); auto child = ecs.scope(parent).entity("Child"); test_assert(child.has(flecs::ChildOf, parent)); test_assert(ecs.get_scope() == 0); } void World_with_scope_type_no_lambda(void) { flecs::world ecs; auto child = ecs.scope().entity("Child"); test_assert(child.has(flecs::ChildOf, ecs.id())); test_assert(ecs.get_scope() == 0); } void World_with_tag_nested(void) { flecs::world ecs; auto Tier1 = ecs.entity(); ecs.with(Tier1, [&]{ ecs.entity("Tier2").with([&]{ ecs.entity("Tier3"); }); }); auto Tier2 = ecs.lookup("Tier2"); test_assert(Tier2 != 0); auto Tier3 = ecs.lookup("Tier3"); test_assert(Tier3 != 0); test_assert(Tier2.has(Tier1)); test_assert(Tier3.has(Tier2)); } void World_with_scope_nested(void) { flecs::world ecs; auto parent = ecs.entity("P"); ecs.scope(parent, [&]{ auto child = ecs.entity("C").scope([&]{ auto gchild = ecs.entity("GC"); test_assert(gchild == ecs.lookup("GC")); test_assert(gchild == ecs.lookup("::P::C::GC")); }); // Ensure relative lookups work test_assert(ecs.lookup("C") == child); test_assert(ecs.lookup("::P::C") == child); test_assert(ecs.lookup("::P::C::GC") != 0); }); test_assert(0 == ecs.lookup("C")); test_assert(0 == ecs.lookup("GC")); test_assert(0 == ecs.lookup("C::GC")); auto child = ecs.lookup("P::C"); test_assert(0 != child); test_assert(child.has(flecs::ChildOf, parent)); auto gchild = ecs.lookup("P::C::GC"); test_assert(0 != gchild); test_assert(gchild.has(flecs::ChildOf, child)); } void World_recursive_lookup(void) { flecs::world ecs; auto A = ecs.entity("A"); auto B = ecs.entity("B"); auto P = ecs.entity("P"); P.scope([&]{ auto CA = ecs.entity("A"); test_assert(CA != A); test_assert(CA == ecs.lookup("A")); test_assert(CA == ecs.lookup("P::A")); test_assert(CA == ecs.lookup("::P::A")); test_assert(A == ecs.lookup("::A")); test_assert(B == ecs.lookup("B")); test_assert(B == ecs.lookup("::B")); }); } void World_type_w_tag_name(void) { flecs::world ecs; auto c = ecs.component(); test_assert(c != flecs::entity()); test_str(c.path().c_str(), "::Tag"); test_assert(c != flecs::Tag); } void World_entity_w_tag_name(void) { flecs::world ecs; auto c = ecs.entity("Tag"); test_assert(c != flecs::entity()); test_str(c.path().c_str(), "::Tag"); test_assert(c != flecs::Tag); } template struct TemplateType { }; void World_template_component_name(void) { flecs::world ecs; auto c = ecs.component>(); test_str(c.name().c_str(), "TemplateType"); test_str(c.path().c_str(), "::TemplateType"); } namespace ns { template struct TemplateType { }; struct foo { }; } void World_template_component_w_namespace_name(void) { flecs::world ecs; auto c = ecs.component>(); test_str(c.name().c_str(), "TemplateType"); test_str(c.path().c_str(), "::ns::TemplateType"); } void World_template_component_w_namespace_name_and_namespaced_arg(void) { flecs::world ecs; auto c = ecs.component>(); test_str(c.name().c_str(), "TemplateType"); test_str(c.path().c_str(), "::ns::TemplateType"); } namespace foo { template struct foo { }; struct bar { }; } void World_template_component_w_same_namespace_name(void) { flecs::world ecs; auto c = ecs.component>(); test_str(c.name().c_str(), "foo"); test_str(c.path().c_str(), "::foo::foo"); } void World_template_component_w_same_namespace_name_and_namespaced_arg(void) { flecs::world ecs; auto c = ecs.component>(); test_str(c.name().c_str(), "foo"); test_str(c.path().c_str(), "::foo::foo"); } struct module_w_template_component { struct Foo { }; struct Bar { }; template struct TypeWithArgs { }; module_w_template_component(flecs::world &world) { world.module(); world.component>(); }; }; void World_template_component_from_module_2_args(void) { flecs::world ecs; auto m = ecs.import(); test_assert(m == ecs.lookup("module_w_template_component")); auto tid = ecs.id>(); test_assert(tid != 0); auto mid = m.lookup("TypeWithArgs"); if (mid == 0) { mid = m.lookup("TypeWithArgs"); } test_assert(mid != 0); test_assert(tid == mid); } void World_entity_as_tag(void) { flecs::world ecs; auto e = ecs.entity(); test_assert(e.id() != 0); auto t = ecs.component(); test_assert(t.id() != 0); test_assert(e == t); auto e2 = ecs.entity() .add(); test_bool(e2.has(), true); test_bool(e2.has(e), true); test_str(e.name(), "Tag"); } void World_entity_w_name_as_tag(void) { flecs::world ecs; auto e = ecs.entity("Foo"); test_assert(e.id() != 0); auto t = ecs.component(); test_assert(t.id() != 0); test_assert(e == t); auto e2 = ecs.entity() .add(); test_bool(e2.has(), true); test_bool(e2.has(e), true); test_str(e.name(), "Foo"); } void World_entity_as_component(void) { flecs::world ecs; auto e = ecs.entity(); test_assert(e.id() != 0); auto t = ecs.component(); test_assert(t.id() != 0); test_assert(e == t); auto e2 = ecs.entity() .set({10, 20}); test_bool(e2.has(), true); test_bool(e2.has(e), true); test_str(e.name(), "Position"); } void World_entity_w_name_as_component(void) { flecs::world ecs; auto e = ecs.entity("Foo"); test_assert(e.id() != 0); auto t = ecs.component(); test_assert(t.id() != 0); test_assert(e == t); auto e2 = ecs.entity() .set({10, 20}); test_bool(e2.has(), true); test_bool(e2.has(e), true); test_str(e.name(), "Foo"); } void World_entity_as_component_2_worlds(void) { flecs::world ecs_1; auto e_1 = ecs_1.entity(); test_assert(e_1.id() != 0); flecs::world ecs_2; auto e_2 = ecs_2.entity(); test_assert(e_2.id() != 0); test_assert(e_1 == e_2); test_assert(e_1 == ecs_1.component()); test_assert(e_2 == ecs_2.component()); } struct Parent { struct Child { }; }; void World_entity_as_namespaced_component_2_worlds(void) { flecs::world ecs_1; auto e_1 = ecs_1.entity(); test_assert(e_1.id() != 0); auto e_1_1 = ecs_1.entity(); test_assert(e_1_1.id() != 0); flecs::world ecs_2; auto e_2 = ecs_2.entity(); test_assert(e_2.id() != 0); auto e_2_1 = ecs_2.entity(); test_assert(e_2_1.id() != 0); test_assert(e_1 == e_2); test_assert(e_1 == ecs_1.component()); test_assert(e_2 == ecs_2.component()); test_assert(e_1_1 == e_2_1); test_assert(e_1_1 == ecs_1.component()); test_assert(e_2_1 == ecs_2.component()); } void World_entity_as_component_2_worlds_implicit_namespaced(void) { flecs::world ecs_1; auto e_1 = ecs_1.entity(); test_assert(e_1.id() != 0); ecs_1.entity().add(); flecs::world ecs_2; auto e_2 = ecs_2.entity(); test_assert(e_2.id() != 0); ecs_2.entity().add(); test_assert(e_1 == e_2); test_assert(e_1 == ecs_1.component()); test_assert(e_2 == ecs_2.component()); test_assert(ecs_1.component() == ecs_2.component()); } struct PositionDerived : Position { PositionDerived() { } PositionDerived(float x, float y) : Position{x, y} { } }; void World_delete_with_id(void) { flecs::world ecs; flecs::id tag = ecs.entity(); auto e_1 = ecs.entity().add(tag); auto e_2 = ecs.entity().add(tag); auto e_3 = ecs.entity().add(tag); ecs.delete_with(tag); test_assert(!e_1.is_alive()); test_assert(!e_2.is_alive()); test_assert(!e_3.is_alive()); } void World_delete_with_type(void) { flecs::world ecs; auto e_1 = ecs.entity().add(); auto e_2 = ecs.entity().add(); auto e_3 = ecs.entity().add(); ecs.delete_with(); test_assert(!e_1.is_alive()); test_assert(!e_2.is_alive()); test_assert(!e_3.is_alive()); } void World_delete_with_pair(void) { flecs::world ecs; flecs::id rel = ecs.entity(); flecs::id obj = ecs.entity(); auto e_1 = ecs.entity().add(rel, obj); auto e_2 = ecs.entity().add(rel, obj); auto e_3 = ecs.entity().add(rel, obj); ecs.delete_with(rel, obj); test_assert(!e_1.is_alive()); test_assert(!e_2.is_alive()); test_assert(!e_3.is_alive()); } void World_delete_with_pair_type(void) { flecs::world ecs; struct Rel { }; struct Obj { }; auto e_1 = ecs.entity().add(); auto e_2 = ecs.entity().add(); auto e_3 = ecs.entity().add(); ecs.delete_with(); test_assert(!e_1.is_alive()); test_assert(!e_2.is_alive()); test_assert(!e_3.is_alive()); } void World_delete_with_implicit(void) { flecs::world ecs; ecs.delete_with(); test_assert(true); } void World_delete_with_pair_implicit(void) { flecs::world ecs; struct Rel { }; struct Obj { }; ecs.delete_with(); test_assert(true); } void World_remove_all_id(void) { flecs::world ecs; flecs::id tag_a = ecs.entity(); flecs::id tag_b = ecs.entity(); auto e_1 = ecs.entity().add(tag_a); auto e_2 = ecs.entity().add(tag_a); auto e_3 = ecs.entity().add(tag_a).add(tag_b); ecs.remove_all(tag_a); test_assert(e_1.is_alive()); test_assert(e_2.is_alive()); test_assert(e_3.is_alive()); test_assert(!e_1.has(tag_a)); test_assert(!e_2.has(tag_a)); test_assert(!e_3.has(tag_a)); test_assert(e_3.has(tag_b)); } void World_remove_all_type(void) { flecs::world ecs; auto e_1 = ecs.entity().add(); auto e_2 = ecs.entity().add(); auto e_3 = ecs.entity().add().add(); ecs.remove_all(); test_assert(e_1.is_alive()); test_assert(e_2.is_alive()); test_assert(e_3.is_alive()); test_assert(!e_1.has()); test_assert(!e_2.has()); test_assert(!e_3.has()); test_assert(e_3.has()); } void World_remove_all_pair(void) { flecs::world ecs; flecs::id rel = ecs.entity(); flecs::id obj_a = ecs.entity(); flecs::id obj_b = ecs.entity(); auto e_1 = ecs.entity().add(rel, obj_a); auto e_2 = ecs.entity().add(rel, obj_a); auto e_3 = ecs.entity().add(rel, obj_a).add(rel, obj_b); ecs.remove_all(rel, obj_a); test_assert(e_1.is_alive()); test_assert(e_2.is_alive()); test_assert(e_3.is_alive()); test_assert(!e_1.has(rel, obj_a)); test_assert(!e_2.has(rel, obj_a)); test_assert(!e_3.has(rel, obj_a)); test_assert(e_3.has(rel, obj_b)); } void World_remove_all_pair_type(void) { flecs::world ecs; struct Rel { }; struct ObjA { }; struct ObjB { }; auto e_1 = ecs.entity().add(); auto e_2 = ecs.entity().add(); auto e_3 = ecs.entity().add().add(); ecs.remove_all(); test_assert(e_1.is_alive()); test_assert(e_2.is_alive()); test_assert(e_3.is_alive()); test_assert((!e_1.has())); test_assert((!e_2.has())); test_assert((!e_3.has())); test_assert((!e_1.has())); test_assert((!e_2.has())); test_assert((e_3.has())); } void World_remove_all_implicit(void) { flecs::world ecs; ecs.remove_all(); test_assert(true); } void World_remove_all_pair_implicit(void) { flecs::world ecs; struct Rel { }; struct Obj { }; ecs.remove_all(); test_assert(true); } void World_get_scope(void) { flecs::world ecs; auto e = ecs.entity("scope"); ecs.set_scope(e); auto s = ecs.get_scope(); test_assert(s == e); test_str(s.name(), "scope"); } void World_get_scope_type(void) { flecs::world ecs; ecs.set_scope(); auto s = ecs.get_scope(); test_assert(s == ecs.id()); test_str(s.name(), "ParentScope"); } struct Outer { struct Inner { }; }; void World_register_namespace_after_component(void) { flecs::world ecs; auto inn = ecs.component(); auto out = ecs.component(); test_str(inn.path().c_str(), "::Outer::Inner"); test_str(out.path().c_str(), "::Outer"); const char *inn_sym = ecs_get_symbol(ecs, inn); const char *out_sym = ecs_get_symbol(ecs, out); test_str(inn_sym, "Outer.Inner"); test_str(out_sym, "Outer"); } void World_is_alive(void) { flecs::world ecs; auto e = ecs.entity(); test_bool(ecs.is_alive(e), true); test_bool(ecs.is_alive(1000), false); e.destruct(); test_bool(ecs.is_alive(e), false); } void World_is_valid(void) { flecs::world ecs; auto e = ecs.entity(); test_bool(ecs.is_valid(e), true); test_bool(ecs.is_valid(1000), true); test_bool(ecs.is_valid(0), false); e.destruct(); test_bool(ecs.is_valid(e), false); } void World_exists(void) { flecs::world ecs; auto e = ecs.entity(); test_bool(ecs.exists(e), true); test_bool(ecs.exists(1000), false); } void World_get_alive(void) { flecs::world ecs; auto e_1 = ecs.entity(); auto e_no_gen = flecs::strip_generation(e_1); test_assert(e_1 == e_no_gen); e_1.destruct(); auto e_2 = ecs.entity(); test_assert(e_1 != e_2); test_assert(e_no_gen == flecs::strip_generation(e_2)); test_assert(ecs.get_alive(e_no_gen) == e_2); } void World_ensure(void) { flecs::world ecs; auto e_1 = ecs.entity(); e_1.destruct(); test_assert(!e_1.is_alive()); auto e_2 = ecs.entity(); test_assert(e_1 != e_2); test_assert(e_1 == flecs::strip_generation(e_2)); e_2.destruct(); test_assert(!e_2.is_alive()); auto e_3 = ecs.ensure(e_2); test_assert(e_2 == e_3); test_assert(e_3.is_alive()); } void World_reset_all(void) { flecs::entity pos, vel; { flecs::world ecs; pos = ecs.component(); vel = ecs.component(); } test_assert(flecs::type_id() == pos); test_assert(flecs::type_id() == vel); flecs::reset(); test_assert(flecs::type_id() == 0); /* Register components in opposite order, should result in different ids */ { flecs::world ecs; test_assert(ecs.component() != 0); test_assert(ecs.component() != 0); } } void World_get_tick(void) { flecs::world ecs; test_int(ecs.get_info()->frame_count_total, 0); ecs.progress(); test_int(ecs.get_info()->frame_count_total, 1); ecs.progress(); test_int(ecs.get_info()->frame_count_total, 2); } struct Scope { }; struct FromScope { }; namespace Nested { struct FromScope { }; } void World_register_from_scope(void) { flecs::world ecs; ecs.set_scope(); auto c = ecs.component(); ecs.set_scope(0); test_assert(c.has(flecs::ChildOf, ecs.id())); } void World_register_nested_from_scope(void) { flecs::world ecs; ecs.set_scope(); auto c = ecs.component(); ecs.set_scope(0); test_assert(c.has(flecs::ChildOf, ecs.id())); } void World_register_w_root_name(void) { flecs::world ecs; auto c = ecs.component("::Root"); test_assert(!c.has(flecs::ChildOf, flecs::Wildcard)); test_str(c.path().c_str(), "::Root"); } void World_register_nested_w_root_name(void) { flecs::world ecs; auto c = ecs.component("::Root"); test_assert(!c.has(flecs::ChildOf, flecs::Wildcard)); test_str(c.path().c_str(), "::Root"); } void World_set_lookup_path(void) { flecs::world ecs; auto parent = ecs.entity("Parent"); auto child = ecs.scope(parent).entity("Child"); test_assert(ecs.lookup("Parent") == parent); test_assert(ecs.lookup("Child") == 0); test_assert(ecs.lookup("Parent::Child") == child); flecs::entity_t lookup_path[] = { parent, 0 }; flecs::entity_t *old_path = ecs.set_lookup_path(lookup_path); test_assert(ecs.lookup("Parent") == parent); test_assert(ecs.lookup("Child") == child); test_assert(ecs.lookup("Parent::Child") == child); ecs.set_lookup_path(old_path); } void World_run_post_frame(void) { flecs::world ecs; int ctx = 10; ecs.system() .iter([&](flecs::iter& it) { it.world().run_post_frame([](flecs::world_t *w, void *ctx) { int *i = static_cast(ctx); test_int(*i, 10); i[0] ++; }, &ctx); }); test_int(ctx, 10); ecs.progress(); test_int(ctx, 11); } void World_component_w_low_id(void) { flecs::world ecs; flecs::entity p = ecs.component(); test_assert(p.id() < FLECS_HI_COMPONENT_ID); } void World_reregister_after_reset_w_hooks_and_in_use(void) { flecs::world ecs; ecs.component(); ecs.entity().add(); test_int(1, Pod::ctor_invoked); flecs::reset(); ecs.component(); ecs.entity().add(); test_int(2, Pod::ctor_invoked); } void World_reregister_after_reset_w_hooks_and_in_use_implicit(void) { flecs::world ecs; ecs.component(); ecs.entity().add(); test_int(1, Pod::ctor_invoked); flecs::reset(); ecs.entity().add(); test_int(2, Pod::ctor_invoked); } void World_get_ref() { flecs::world ecs; struct Space { int v; }; ecs.set({12}); auto space = ecs.get_ref(); test_int(12, space->v); } void World_get_set_log_level(void) { test_int(flecs::log::get_level(), -1); flecs::log::set_level(4); test_int(flecs::log::get_level(), 4); } void World_reset_world(void) { flecs::world ecs; flecs::entity e = ecs.entity(); test_assert(ecs.exists(e)); ecs.reset(); test_assert(!ecs.exists(e)); } void World_id_from_pair_type(void) { flecs::world ecs; flecs::id id = ecs.id>(); test_assert(id.is_pair()); test_assert(id.first() == ecs.id()); test_assert(id.second() == ecs.id()); } void World_scope_w_name(void) { flecs::world ecs; flecs::entity parent = ecs.entity("parent"); flecs::entity child = ecs.scope("parent").entity(); test_assert(child.has(flecs::ChildOf, parent)); } void World_set_get_context(void) { flecs::world ecs; int ctx; ecs.set_ctx(&ctx); test_assert(ecs.get_ctx() == &ctx); test_assert(ecs.get_binding_ctx() == nullptr); } void World_set_get_binding_context(void) { flecs::world ecs; int ctx; ecs.set_binding_ctx(&ctx); test_assert(ecs.get_binding_ctx() == &ctx); test_assert(ecs.get_ctx() == nullptr); } static void ctx_free(void *ctx) { static_cast(ctx)[0] = 10; } void World_set_get_context_w_free(void) { int ctx = 0; { flecs::world ecs; ecs.set_ctx(&ctx, ctx_free); test_assert(ecs.get_ctx() == &ctx); test_assert(ecs.get_binding_ctx() == nullptr); test_int(ctx, 0); } test_int(ctx, 10); } void World_set_get_binding_context_w_free(void) { int ctx = 0; { flecs::world ecs; ecs.set_binding_ctx(&ctx, ctx_free); test_assert(ecs.get_binding_ctx() == &ctx); test_assert(ecs.get_ctx() == nullptr); test_int(ctx, 0); } test_int(ctx, 10); } void World_make_pair(void) { flecs::world ecs; flecs::entity r = ecs.entity(); flecs::entity t = ecs.entity(); flecs::id id = ecs.pair(r, t); test_assert(id.is_pair()); test_assert(id.first() == r); test_assert(id.second() == t); } void World_make_pair_of_pair_id(void) { install_test_abort(); flecs::world ecs; flecs::entity r = ecs.entity(); flecs::entity t = ecs.entity(); flecs::id id = ecs.pair(r, t); test_expect_abort(); ecs.pair(id, t); } void World_make_pair_of_pair_id_tgt(void) { install_test_abort(); flecs::world ecs; flecs::entity r = ecs.entity(); flecs::entity t = ecs.entity(); flecs::id id = ecs.pair(r, t); test_expect_abort(); ecs.pair(r, id); } void World_make_pair_of_pair_type(void) { install_test_abort(); flecs::world ecs; flecs::entity t = ecs.entity(); flecs::id id = ecs.pair(t); test_assert(id.is_pair()); test_assert(id.first() == ecs.id()); test_assert(id.second() == t); } void World_delta_time(void) { flecs::world ecs; float dt = 0; ecs.entity().add(); ecs.system() .each([&](flecs::entity e, Tag) { dt = e.world().delta_time(); }); ecs.progress(2); test_int(dt, 2); }