From 5198f46f5e55c10d221c0916d45ae6949186a669 Mon Sep 17 00:00:00 2001 From: Ubpa <641614112@qq.com> Date: Wed, 2 Sep 2020 02:21:19 +0800 Subject: [PATCH] EntityMngr += copy and swap --- CMakeLists.txt | 2 +- include/UECS/EntityMngr.h | 9 ++++-- include/UECS/System.h | 1 + include/UECS/World.h | 1 + include/UECS/detail/Archetype.h | 3 ++ src/core/Archetype.cpp | 41 +++++++++++++++++++++++-- src/core/EntityMngr.cpp | 50 ++++++++++++++++++++++++++++--- src/core/World.cpp | 4 +-- src/test/02_order/main.cpp | 2 +- src/test/11_runtime_cmpt/main.cpp | 2 +- src/test/12_framegraph/main.cpp | 2 +- src/test/14_serialize/main.cpp | 4 +-- src/test/15_chunk_job/main.cpp | 2 +- src/test/16_singleton/main.cpp | 2 +- src/test/17_serial/main.cpp | 2 +- src/test/18_copy/CMakeLists.txt | 6 ++++ src/test/18_copy/main.cpp | 45 ++++++++++++++++++++++++++++ 17 files changed, 157 insertions(+), 21 deletions(-) create mode 100644 src/test/18_copy/CMakeLists.txt create mode 100644 src/test/18_copy/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 68a857e..dd17712 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -project(UECS VERSION 0.12.1) +project(UECS VERSION 0.12.2) message(STATUS "[Project] ${PROJECT_NAME}") include(cmake/InitUCMake.cmake) diff --git a/include/UECS/EntityMngr.h b/include/UECS/EntityMngr.h index a09bf79..b7ef721 100644 --- a/include/UECS/EntityMngr.h +++ b/include/UECS/EntityMngr.h @@ -28,7 +28,11 @@ namespace Ubpa::UECS { // - when free entries is empty, use new entity entry (version is 0) class EntityMngr { public: - RTDCmptTraits cmptTraits; + EntityMngr(World* world) : world{ world } {} + EntityMngr(const EntityMngr& em); + + // same world + void Swap(EntityMngr& rhs) noexcept; template std::tuple Create(); @@ -91,12 +95,11 @@ namespace Ubpa::UECS { private: Pool sharedChunkPool; // destruct finally + World* world; friend class World; friend class Archetype; - EntityMngr() = default; - static bool IsSet(const CmptType* types, size_t num) noexcept; template diff --git a/include/UECS/System.h b/include/UECS/System.h index 1a0a0a5..bd890a4 100644 --- a/include/UECS/System.h +++ b/include/UECS/System.h @@ -5,6 +5,7 @@ namespace Ubpa::UECS { class World; + // stateless class System { public: System(World* world, std::string name) noexcept : world{ world }, name{ name } {} diff --git a/include/UECS/World.h b/include/UECS/World.h index e6b5fce..5609594 100644 --- a/include/UECS/World.h +++ b/include/UECS/World.h @@ -18,6 +18,7 @@ namespace Ubpa::UECS { SystemMngr systemMngr; EntityMngr entityMngr; + RTDCmptTraits cmptTraits; // 1. schedule: run registered System's static OnUpdate(Schedule&) // 2. gen job graph: schedule -> graph diff --git a/include/UECS/detail/Archetype.h b/include/UECS/detail/Archetype.h index b8fe4f2..607a18c 100644 --- a/include/UECS/detail/Archetype.h +++ b/include/UECS/detail/Archetype.h @@ -25,6 +25,9 @@ namespace Ubpa::UECS { template Archetype(EntityMngr*, TypeList); + // copy + Archetype(EntityMngr*, const Archetype&); + ~Archetype(); // auto add Entity, use RTDCmptTraits diff --git a/src/core/Archetype.cpp b/src/core/Archetype.cpp index 370a8db..f27769a 100644 --- a/src/core/Archetype.cpp +++ b/src/core/Archetype.cpp @@ -1,5 +1,7 @@ #include +#include + #include using namespace Ubpa::UECS; @@ -27,6 +29,39 @@ Archetype::~Archetype() { entityMngr->sharedChunkPool.Recycle(chunk); } +Archetype::Archetype(EntityMngr* em, const Archetype& src) + : entityMngr{ em } +{ + types = src.types; + cmptTraits = src.cmptTraits; + type2offset = src.type2offset; + entityNum = src.entityNum; + chunkCapacity = src.chunkCapacity; + + chunks.resize(src.chunks.size(), nullptr); + for (size_t i = 0; i < src.chunks.size(); i++) { + auto srcChunk = src.chunks[i]; + auto dstChunk = chunks[i] = entityMngr->sharedChunkPool.Request(); + size_t num = src.EntityNumOfChunk(i); + for (auto type : types.data) { + auto offset = Offsetof(type); + auto srcBegin = srcChunk->Data() + offset; + auto dstBegin = dstChunk->Data() + offset; + auto size = cmptTraits.Sizeof(type); + auto target = cmptTraits.copy_constructors.find(type); + if (target != cmptTraits.copy_constructors.end()) { + const auto& copy_ctor = target->second; + for (size_t j = 0; j < num; j++) { + auto offset_j = j * size; + copy_ctor(dstBegin + offset_j, srcBegin + offset_j); + } + } + else + memcpy(dstBegin, srcBegin, num * size); + } + } +} + void Archetype::SetLayout() { vector alignments; vector sizes; @@ -58,7 +93,7 @@ Archetype* Archetype::New(EntityMngr* entityMngr, const CmptType* types, size_t rst->types.data.insert(CmptType::Of); rst->cmptTraits.Register(); for (size_t i = 0; i < num; i++) - rst->cmptTraits.Register(entityMngr->cmptTraits, types[i]); + rst->cmptTraits.Register(entityMngr->world->cmptTraits, types[i]); rst->SetLayout(); return rst; } @@ -73,7 +108,7 @@ Archetype* Archetype::Add(const Archetype* from, const CmptType* types, size_t n rst->cmptTraits = from->cmptTraits; rst->types.Insert(types, num); for (size_t i = 0; i < num; i++) - rst->cmptTraits.Register(rst->entityMngr->cmptTraits, types[i]); + rst->cmptTraits.Register(rst->entityMngr->world->cmptTraits, types[i]); rst->SetLayout(); @@ -102,7 +137,7 @@ size_t Archetype::Create(Entity e) { size_t idxInChunk = idx % chunkCapacity; byte* buffer = chunks[idx / chunkCapacity]->Data(); - const auto& rtdct = entityMngr->cmptTraits; + const auto& rtdct = entityMngr->world->cmptTraits; for (const auto& type : types.data) { if (type.Is()) { constexpr size_t size = sizeof(Entity); diff --git a/src/core/EntityMngr.cpp b/src/core/EntityMngr.cpp index 3a7c3d2..e2b49f4 100644 --- a/src/core/EntityMngr.cpp +++ b/src/core/EntityMngr.cpp @@ -1,5 +1,6 @@ #include +#include #include using namespace Ubpa::UECS; @@ -17,6 +18,48 @@ size_t EntityMngr::RequestEntityFreeEntry() { return entry; } +EntityMngr::EntityMngr(const EntityMngr& em) + : world{ em.world } +{ + ts2a.reserve(em.ts2a.size()); + for (const auto& [ts, a] : em.ts2a) { + auto [iter, success] = ts2a.try_emplace(ts, std::make_unique(this, *a)); + assert(success); + } + entityTableFreeEntry = em.entityTableFreeEntry; + entityTable.resize(em.entityTable.size()); + for (size_t i = 0; i < em.entityTable.size(); i++) { + auto& dst = entityTable[i]; + const auto& src = em.entityTable[i]; + dst.idxInArchetype = src.idxInArchetype; + dst.version = src.version; + dst.archetype = ts2a.find(src.archetype->types)->second.get(); + } + queryCache.reserve(em.queryCache.size()); + for (const auto& [query, srcArchetypes] : em.queryCache) { + auto& dstArchetypes = queryCache[query]; + for (auto archetype : srcArchetypes) + dstArchetypes.insert(ts2a.find(archetype->types)->second.get()); + } +} + +void EntityMngr::Swap(EntityMngr& rhs) noexcept { + assert(world == rhs.world); + + using std::swap; + + swap(ts2a, rhs.ts2a); + swap(entityTableFreeEntry, rhs.entityTableFreeEntry); + swap(entityTable, rhs.entityTable); + swap(queryCache, rhs.queryCache); + + auto pool = std::move(sharedChunkPool); + sharedChunkPool.~Pool(); + new(&sharedChunkPool)Pool(std::move(rhs.sharedChunkPool)); + rhs.sharedChunkPool.~Pool(); + new(&rhs.sharedChunkPool)Pool(std::move(pool)); +} + void EntityMngr::RecycleEntityEntry(Entity e) { assert(Exist(e)); @@ -115,8 +158,8 @@ void EntityMngr::Attach(Entity e, const CmptType* types, size_t num) { if (origArchetype->GetCmptTypeSet().Contains(type)) continue; - auto target = cmptTraits.default_constructors.find(type); - if (target == cmptTraits.default_constructors.end()) + auto target = world->cmptTraits.default_constructors.find(type); + if (target == world->cmptTraits.default_constructors.end()) continue; target->second(info.archetype->At(type, info.idxInArchetype)); @@ -354,13 +397,12 @@ void EntityMngr::GenChunkJob(World* w, Job* job, SystemFunc* sys) const { assert(job != nullptr); for (Archetype* archetype : QueryArchetypes(sys->entityQuery)) { size_t chunkNum = archetype->ChunkNum(); - SingletonsView singletonsView{ singletons.data(), singletons.size() }; for (size_t i = 0; i < chunkNum; i++) { job->emplace([=, singletons = singletons]() { (*sys)( w, - singletonsView, + SingletonsView{ singletons.data(), singletons.size() }, ChunkView{ archetype, i } ); }); diff --git a/src/core/World.cpp b/src/core/World.cpp index be78adc..d39cc01 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -6,7 +6,7 @@ using namespace Ubpa::UECS; using namespace Ubpa; using namespace std; -World::World() : systemMngr{ this } {} +World::World() : systemMngr{ this }, entityMngr{ this } {} void World::Update() { schedule.Clear(); @@ -118,7 +118,7 @@ UGraphviz::Graph World::GenUpdateFrameGraph() const { unordered_map sysFuncHashcode2idx; auto queryCmptName = [this](CmptType type) -> string { - auto cmptName = entityMngr.cmptTraits.Nameof(type); + auto cmptName = cmptTraits.Nameof(type); return cmptName.empty() ? std::to_string(type.HashCode()) : string{ cmptName }; }; diff --git a/src/test/02_order/main.cpp b/src/test/02_order/main.cpp index b8946c3..e8ff2c6 100644 --- a/src/test/02_order/main.cpp +++ b/src/test/02_order/main.cpp @@ -28,7 +28,7 @@ int main() { World w; w.systemMngr.Register(); - w.entityMngr.cmptTraits.Register< + w.cmptTraits.Register< Data1, Data2 >(); diff --git a/src/test/11_runtime_cmpt/main.cpp b/src/test/11_runtime_cmpt/main.cpp index 51e4b95..efe4195 100644 --- a/src/test/11_runtime_cmpt/main.cpp +++ b/src/test/11_runtime_cmpt/main.cpp @@ -47,7 +47,7 @@ int main() { World w; w.systemMngr.Register(); - w.entityMngr.cmptTraits + w.cmptTraits .RegisterSize(type, 8) .RegisterDefaultConstructor(type, [](void*) { cout << "construct" << endl; }) .RegisterDestructor(type, [](void*) { cout << "destruct" << endl; }); diff --git a/src/test/12_framegraph/main.cpp b/src/test/12_framegraph/main.cpp index 8952c3b..85da3c1 100644 --- a/src/test/12_framegraph/main.cpp +++ b/src/test/12_framegraph/main.cpp @@ -37,7 +37,7 @@ int main() { World w; w.systemMngr.Register(); - w.entityMngr.cmptTraits + w.cmptTraits .RegisterName(CmptType::Of, "A") .RegisterName(CmptType::Of, "B") .RegisterName(CmptType::Of, "C") diff --git a/src/test/14_serialize/main.cpp b/src/test/14_serialize/main.cpp index 24d3541..aae5e70 100644 --- a/src/test/14_serialize/main.cpp +++ b/src/test/14_serialize/main.cpp @@ -130,7 +130,7 @@ class Dumper : public IListener { cout << "{" << endl; indent++; PrintIndent(); - cout << "\"type\" : \"" << w->entityMngr.cmptTraits.Nameof(cmpt->Type()) << "\""; + cout << "\"type\" : \"" << w->cmptTraits.Nameof(cmpt->Type()) << "\""; if (cmpt->Type().Is()) { auto v = cmpt->As(); cout << "," << endl; @@ -167,7 +167,7 @@ class MoverSystem : public System { int main() { World w; - w.entityMngr.cmptTraits.Register(); + w.cmptTraits.Register(); w.systemMngr.Register(); w.entityMngr.Create(); w.entityMngr.Create(); diff --git a/src/test/15_chunk_job/main.cpp b/src/test/15_chunk_job/main.cpp index af971fc..dc3485e 100644 --- a/src/test/15_chunk_job/main.cpp +++ b/src/test/15_chunk_job/main.cpp @@ -55,7 +55,7 @@ int main() { World w; w.systemMngr.Register(); - w.entityMngr.cmptTraits.Register(); + w.cmptTraits.Register(); w.entityMngr.Create(); w.entityMngr.Create(); diff --git a/src/test/16_singleton/main.cpp b/src/test/16_singleton/main.cpp index 95e3420..6fc530d 100644 --- a/src/test/16_singleton/main.cpp +++ b/src/test/16_singleton/main.cpp @@ -33,7 +33,7 @@ int main() { w.systemMngr.Register(); w.entityMngr.Create(); w.entityMngr.Create(); - w.entityMngr.cmptTraits.Register + w.cmptTraits.Register (); w.Update(); diff --git a/src/test/17_serial/main.cpp b/src/test/17_serial/main.cpp index e3d99b8..f70767a 100644 --- a/src/test/17_serial/main.cpp +++ b/src/test/17_serial/main.cpp @@ -34,7 +34,7 @@ int main() { w.entityMngr.Create(); w.entityMngr.Create(); w.entityMngr.Create(); - w.entityMngr.cmptTraits.Register + w.cmptTraits.Register (); for (size_t i = 0; i < 5; i++) { diff --git a/src/test/18_copy/CMakeLists.txt b/src/test/18_copy/CMakeLists.txt new file mode 100644 index 0000000..ec4a795 --- /dev/null +++ b/src/test/18_copy/CMakeLists.txt @@ -0,0 +1,6 @@ +Ubpa_GetTargetName(core "${PROJECT_SOURCE_DIR}/src/core") +Ubpa_AddTarget( + TEST + MODE EXE + LIB ${core} +) diff --git a/src/test/18_copy/main.cpp b/src/test/18_copy/main.cpp new file mode 100644 index 0000000..4cb7d43 --- /dev/null +++ b/src/test/18_copy/main.cpp @@ -0,0 +1,45 @@ +#include + +#include + +using namespace Ubpa::UECS; + +struct Position { float val{ 0.f }; }; +struct Velocity { float val{ 1.f }; }; + +class MoverSystem : public System { +public: + using System::System; + + virtual void OnUpdate(Schedule& schedule) override { + schedule.RegisterEntityJob( + [](const Velocity* v, Position* p) { + p->val += v->val; + }, + "Mover" + ); + schedule.RegisterEntityJob( + [](const Velocity* v, const Position* p) { + std::cout << "v:" << v->val << std::endl; + std::cout << "p:" << p->val << std::endl; + }, + "Print" + ); + } +}; + +int main() { + World w; + w.systemMngr.Register(); + w.entityMngr.Create(); + + auto copy_e = w.entityMngr; + + w.entityMngr.Swap(copy_e); + w.Update(); + w.entityMngr.Create(); + w.Update(); + std::cout << "swap" << std::endl; + w.entityMngr.Swap(copy_e); + w.Update(); +}