From 4e54728cc7712c70f98ff21ded915e67cf2ce7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pereira?= Date: Sat, 28 Sep 2024 20:46:47 +0100 Subject: [PATCH 1/3] Still works fine with uuids(sometimes), debbuging the ids as paths --- engine/include/cubos/engine/assets/asset.hpp | 18 ++- engine/include/cubos/engine/assets/assets.hpp | 6 +- engine/samples/games/cubosurfers/main.cpp | 1 + engine/src/assets/asset.cpp | 48 +++++--- engine/src/assets/assets.cpp | 110 ++++++++++++++++-- engine/src/render/mesh/plugin.cpp | 18 +-- engine/src/scene/bridge.cpp | 2 +- .../src/tesseratos/scene_editor/plugin.cpp | 2 +- 8 files changed, 161 insertions(+), 44 deletions(-) diff --git a/engine/include/cubos/engine/assets/asset.hpp b/engine/include/cubos/engine/assets/asset.hpp index 1424f6106..7b27b20d7 100644 --- a/engine/include/cubos/engine/assets/asset.hpp +++ b/engine/include/cubos/engine/assets/asset.hpp @@ -30,7 +30,7 @@ namespace cubos::engine /// @brief Avoid using this field, use @ref getId() instead. /// @todo This was added as a dirty fix for #692, should be removed once the issue is fixed. - uuids::uuid reflectedId; + std::string idOrPath; ~AnyAsset(); @@ -73,7 +73,11 @@ namespace cubos::engine /// @brief Gets the UUID of the asset. /// @return Asset UUID. - uuids::uuid getId() const; + std::string getId() const; + + /// @brief Gets the path of the asset. + /// @return Asset path. + std::string getPath() const; /// @brief Checks if the handle is null. /// @return Whether the handle is null. @@ -111,9 +115,10 @@ namespace cubos::engine /// @brief Decrements the reference count of the asset. void decRef() const; - uuids::uuid mId; ///< UUID of the asset. - void* mRefCount; ///< Void pointer to avoid including `` in the header. - int mVersion; ///< Last known version of the asset. + uuids::uuid mId; ///< UUID of the asset. + void* mRefCount; ///< Void pointer to avoid including `` in the header. + int mVersion; ///< Last known version of the asset. + std::string path; ///< Path of the asset. }; /// @brief Handle to an asset of a specific type. @@ -160,10 +165,11 @@ namespace cubos::engine inline AnyAsset::operator Asset() const { Asset asset; - asset.reflectedId = reflectedId; + asset.idOrPath = idOrPath; asset.mId = mId; asset.mRefCount = mRefCount; asset.mVersion = mVersion; + asset.path = path; asset.incRef(); return asset; } diff --git a/engine/include/cubos/engine/assets/assets.hpp b/engine/include/cubos/engine/assets/assets.hpp index 6cfcb38ef..f217480f8 100644 --- a/engine/include/cubos/engine/assets/assets.hpp +++ b/engine/include/cubos/engine/assets/assets.hpp @@ -247,7 +247,6 @@ namespace cubos::engine struct Entry { Entry(); - Status status{Status::Unloaded}; ///< The status of the asset. AssetMeta meta; ///< The metadata associated with the asset. @@ -308,6 +307,11 @@ namespace cubos::engine /// @return Lock guard. std::unique_lock lockWrite(const AnyAsset& handle) const; + /// @brief Checks if the given ID is of the correct type. + /// @param id ID to check. + /// @return The ID as a string. + std::string checkIdType(const std::string& id) const; + /// @brief Gets a pointer to the entry associated with the given handle. /// @param handle Handle to get the entry for. /// @return Entry for the given handle, or nullptr if there is no such entry. diff --git a/engine/samples/games/cubosurfers/main.cpp b/engine/samples/games/cubosurfers/main.cpp index 1e3ba1caf..ecd2d9976 100644 --- a/engine/samples/games/cubosurfers/main.cpp +++ b/engine/samples/games/cubosurfers/main.cpp @@ -14,6 +14,7 @@ using namespace cubos::engine; +// static const Asset SceneAsset = AnyAsset("/assets/scenes/main.cubos"); static const Asset SceneAsset = AnyAsset("ee5bb451-05b7-430f-a641-a746f7009eef"); static const Asset PaletteAsset = AnyAsset("101da567-3d23-46ae-a391-c10ec00e8718"); static const Asset InputBindingsAsset = AnyAsset("b20900a4-20ee-4caa-8830-14585050bead"); diff --git a/engine/src/assets/asset.cpp b/engine/src/assets/asset.cpp index ea2cdac07..0c5f8352c 100644 --- a/engine/src/assets/asset.cpp +++ b/engine/src/assets/asset.cpp @@ -27,7 +27,7 @@ AnyAsset::AnyAsset(std::nullptr_t) } AnyAsset::AnyAsset(uuids::uuid id) - : reflectedId(id) + : idOrPath(uuids::to_string(id)) , mId(id) , mRefCount(nullptr) , mVersion(-1) @@ -38,31 +38,42 @@ AnyAsset::AnyAsset(std::string_view str) : mRefCount(nullptr) , mVersion(-1) { + if (auto id = uuids::uuid::from_string(str)) { - reflectedId = id.value(); + idOrPath = str; mId = id.value(); } else { - CUBOS_ERROR("Could not create asset handle, invalid UUID: \"{}\"", str); + if (str.find('/') != std::string::npos || str.find('\\') != std::string::npos) + { + idOrPath = str; + path = str; + } + else + { + CUBOS_ERROR("Could not create asset handle, invalid UUID or Path: \"{}\"", str); + } } } AnyAsset::AnyAsset(const AnyAsset& other) - : reflectedId(other.reflectedId) + : idOrPath(other.idOrPath) , mId(other.mId) , mRefCount(other.mRefCount) , mVersion(other.mVersion) + , path(other.path) { this->incRef(); } AnyAsset::AnyAsset(AnyAsset&& other) noexcept - : reflectedId(other.reflectedId) + : idOrPath(other.idOrPath) , mId(other.mId) , mRefCount(other.mRefCount) , mVersion(other.mVersion) + , path(other.path) { other.mRefCount = nullptr; } @@ -70,10 +81,11 @@ AnyAsset::AnyAsset(AnyAsset&& other) noexcept AnyAsset& AnyAsset::operator=(const AnyAsset& other) { this->decRef(); - reflectedId = other.reflectedId; + idOrPath = other.idOrPath; mId = other.mId; mRefCount = other.mRefCount; mVersion = other.mVersion; + path = other.path; this->incRef(); return *this; } @@ -81,11 +93,12 @@ AnyAsset& AnyAsset::operator=(const AnyAsset& other) AnyAsset& AnyAsset::operator=(AnyAsset&& other) noexcept { this->decRef(); - reflectedId = other.reflectedId; + idOrPath = other.idOrPath; mId = other.mId; mRefCount = other.mRefCount; mVersion = other.mVersion; other.mRefCount = nullptr; + path = other.path; return *this; } @@ -96,22 +109,27 @@ bool AnyAsset::operator==(const AnyAsset& other) const int AnyAsset::getVersion() const { - return reflectedId == mId ? mVersion : 0; + return uuids::uuid::from_string(idOrPath) == mId ? mVersion : 0; +} + +std::string AnyAsset::getId() const +{ + return idOrPath; } -uuids::uuid AnyAsset::getId() const +std::string AnyAsset::getPath() const { - return reflectedId; + return path; } bool AnyAsset::isNull() const { - return reflectedId.is_nil(); + return idOrPath.empty(); } bool AnyAsset::isStrong() const { - return reflectedId == mId && mRefCount != nullptr; + return uuids::uuid::from_string(idOrPath) == mId && mRefCount != nullptr; } void AnyAsset::makeWeak() @@ -126,12 +144,12 @@ cubos::core::reflection::Type& AnyAsset::makeType(std::string name) return Type::create(std::move(name)) .with(ConstructibleTrait::typed().withBasicConstructors().build()) - .with(FieldsTrait().withField("id", &AnyAsset::reflectedId)); + .with(FieldsTrait().withField("id", &AnyAsset::idOrPath)); } void AnyAsset::incRef() const { - if (reflectedId == mId && mRefCount != nullptr) + if (uuids::uuid::from_string(idOrPath) == mId && mRefCount != nullptr) { static_cast*>(mRefCount)->fetch_add(1); } @@ -139,7 +157,7 @@ void AnyAsset::incRef() const void AnyAsset::decRef() const { - if (reflectedId == mId && mRefCount != nullptr) + if (uuids::uuid::from_string(idOrPath) == mId && mRefCount != nullptr) { static_cast*>(mRefCount)->fetch_sub(1); } diff --git a/engine/src/assets/assets.cpp b/engine/src/assets/assets.cpp index fa3412c12..0463a1f00 100644 --- a/engine/src/assets/assets.cpp +++ b/engine/src/assets/assets.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -11,6 +12,8 @@ #include +using cubos::core::data::File; +using cubos::core::data::FileSystem; using cubos::core::reflection::ConstructibleTrait; using cubos::core::reflection::Type; @@ -221,6 +224,7 @@ AnyAsset Assets::load(AnyAsset handle) const // Return a strong handle to the asset. assetEntry->refCount += 1; handle.mRefCount = &assetEntry->refCount; + handle.mId = uuids::uuid::from_string(assetEntry->meta.get("id").value_or("")).value_or(uuids::uuid()); return handle; } @@ -288,7 +292,7 @@ Assets::Status Assets::status(const AnyAsset& handle) const std::shared_lock lock(mMutex); // Do not use .entry() here because we don't want to log errors if the asset is unknown. - auto it = mEntries.find(handle.getId()); + auto it = mEntries.find(uuids::uuid::from_string(handle.idOrPath).value_or(uuids::uuid())); if (it == mEntries.end()) { return Status::Unknown; @@ -306,9 +310,9 @@ bool Assets::update(AnyAsset& handle) const return false; } - if (handle.mId != handle.reflectedId) + if (handle.mId != uuids::uuid::from_string(handle.idOrPath).value_or(uuids::uuid())) { - handle = AnyAsset{handle.reflectedId}; + handle = AnyAsset{handle.idOrPath}; handle.mVersion = assetEntry->version; return true; } @@ -503,6 +507,23 @@ std::unique_lock Assets::lockWrite(const AnyAsset& handle) co abort(); } +std::string Assets::checkIdType(const std::string& id) const +{ + if (uuids::uuid::from_string(id).has_value()) + { + return "UUID"; + } + else if (id.find('/') != std::string::npos || id.find('\\') != std::string::npos) + { + return "Path"; + } + else + { + return "Unknown"; + } +} + +// TODO: Implement this function, too much sus std::shared_ptr Assets::entry(const AnyAsset& handle) const { // If the handle is null, we can't access the asset. @@ -516,14 +537,48 @@ std::shared_ptr Assets::entry(const AnyAsset& handle) const auto sharedLock = std::shared_lock(mMutex); // Search for the entry in the map. - auto it = mEntries.find(handle.getId()); - if (it == mEntries.end()) + std::string id = handle.getId(); + + CUBOS_ERROR("Assets::entry 1 Current ID: {}", id); + if (Assets::checkIdType(id) == "Path") + { + std::vector assets = this->listAll(); + for (auto& asset : assets) + { + auto meta = this->readMeta(asset); + auto path = meta->get("path"); + CUBOS_ERROR("Assets::entry 1 Current path: {}", path.value()); + if (path.has_value() && path.value() == id) + { + auto it = mEntries.find(uuids::uuid::from_string(asset.getId()).value()); + CUBOS_ERROR("Assets::entry 1 Current ID: {}", asset.getId()); + if (it == mEntries.end()) + { + CUBOS_ERROR("No such asset {}", handle); + return nullptr; + } + return it->second; + } + } + + CUBOS_ERROR("No such asset {}", handle); + return nullptr; + } + else if (Assets::checkIdType(id) == "UUID") + { + auto it = mEntries.find(uuids::uuid::from_string(handle.getId()).value()); + if (it == mEntries.end()) + { + CUBOS_ERROR("No such asset {}", handle); + return nullptr; + } + return it->second; + } + else { CUBOS_ERROR("No such asset {}", handle); return nullptr; } - - return it->second; } std::shared_ptr Assets::entry(const AnyAsset& handle, bool create) @@ -549,7 +604,41 @@ std::shared_ptr Assets::entry(const AnyAsset& handle, bool create } // Search for an existing entry for the asset. - auto it = mEntries.find(handle.getId()); + + std::string id = handle.getId(); + uuids::uuid uuid = uuids::uuid{}; + if (Assets::checkIdType(id) == "Path") + { + std::vector assets = this->listAll(); + for (auto& asset : assets) + { + auto meta = this->readMeta(asset); + auto path = meta->get("path"); + if (path.has_value() && path.value() == id) + { + auto tid = meta->get("id"); + if (tid.has_value()) + { + uuid = uuids::uuid::from_string(tid.value()).value(); + } + else + { + CUBOS_ERROR("No such asset {}", handle); + return nullptr; + } + } + } + } + else if (Assets::checkIdType(id) == "UUID") + { + uuid = uuids::uuid::from_string(id).value(); + } + else + { + CUBOS_ERROR("Id type missmatch", id); + return nullptr; + } + auto it = mEntries.find(uuids::uuid::from_string(id).value()); if (it == mEntries.end()) { // If we're creating the asset, create a new entry for it. @@ -557,8 +646,8 @@ std::shared_ptr Assets::entry(const AnyAsset& handle, bool create if (create) { auto entry = std::make_shared(); - entry->meta.set("id", uuids::to_string(handle.getId())); - it = mEntries.emplace(handle.getId(), std::move(entry)).first; + entry->meta.set("id", uuids::to_string(uuid)); + it = mEntries.emplace(uuid, std::move(entry)).first; CUBOS_TRACE("Created new asset entry for {}", handle); } else @@ -567,7 +656,6 @@ std::shared_ptr Assets::entry(const AnyAsset& handle, bool create return nullptr; } } - return it->second; } diff --git a/engine/src/render/mesh/plugin.cpp b/engine/src/render/mesh/plugin.cpp index 2e9ac8dbe..508fb1666 100644 --- a/engine/src/render/mesh/plugin.cpp +++ b/engine/src/render/mesh/plugin.cpp @@ -89,7 +89,7 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) // If the asset has never been loaded, or it has been updated since the last meshing, update the entry // and queue a meshing task. Otherwise, just reuse the existing mesh. - auto& entry = state.entries[grid.asset.getId()]; + auto& entry = state.entries[uuids::uuid::from_string(grid.asset.getId()).value()]; entry.referenceCount += 1; if (entry.asset.isNull() || assets.update(entry.asset)) { @@ -111,7 +111,7 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) task.finish(std::move(vertices)); }); - state.meshing.insert(grid.asset.getId()); + state.meshing.insert(uuids::uuid::from_string(grid.asset.getId()).value()); } else if (entry.firstBucketId != RenderMeshPool::BucketId::Invalid) { @@ -131,8 +131,8 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) continue; } - auto& entry = state.entries[grid.asset.getId()]; - if (!state.meshing.contains(grid.asset.getId())) + auto& entry = state.entries[uuids::uuid::from_string(grid.asset.getId()).value()]; + if (!state.meshing.contains(uuids::uuid::from_string(grid.asset.getId()).value())) { if (entry.asset.isNull() || assets.update(entry.asset)) { @@ -154,7 +154,7 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) task.finish(std::move(vertices)); }); - state.meshing.insert(grid.asset.getId()); + state.meshing.insert(uuids::uuid::from_string(grid.asset.getId()).value()); } else { @@ -172,14 +172,14 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) CUBOS_INFO("Finished meshing voxel grid asset {} ({} vertices), allocated new render bucket", grid.asset.getId(), vertices.size()); - auto& entry = state.entries[grid.asset.getId()]; + auto& entry = state.entries[uuids::uuid::from_string(grid.asset.getId()).value()]; if (entry.firstBucketId != RenderMeshPool::BucketId::Invalid) { pool.deallocate(entry.firstBucketId); CUBOS_INFO("Deallocated old render mesh bucket of asset {}", grid.asset.getId()); } entry.firstBucketId = firstBucketId; - state.meshing.erase(grid.asset.getId()); + state.meshing.erase(uuids::uuid::from_string(grid.asset.getId()).value()); } } }); @@ -189,12 +189,12 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) .call([](Query query, RenderMeshPool& pool, State& state) { for (auto [ent, grid] : query) { - auto& entry = state.entries[grid.asset.getId()]; + auto& entry = state.entries[uuids::uuid::from_string(grid.asset.getId()).value()]; entry.referenceCount -= 1; if (entry.referenceCount == 0) { pool.deallocate(entry.firstBucketId); - state.entries.erase(grid.asset.getId()); + state.entries.erase(uuids::uuid::from_string(grid.asset.getId()).value()); CUBOS_INFO("Deallocated render mesh bucket of asset {} (no more references)", grid.asset.getId()); } } diff --git a/engine/src/scene/bridge.cpp b/engine/src/scene/bridge.cpp index 1cdac3d5b..e8896984a 100644 --- a/engine/src/scene/bridge.cpp +++ b/engine/src/scene/bridge.cpp @@ -320,7 +320,7 @@ bool SceneBridge::saveToFile(const Assets& assets, const AnyAsset& handle, Strea auto importJson = nlohmann::json::object(); for (const auto& [name, subHandle] : scene->imports) { - importJson.emplace(name.c_str(), uuids::to_string(subHandle.getId())); + importJson.emplace(name.c_str(), subHandle.getId()); } json.push_back({"imports", importJson}); diff --git a/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp b/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp index 10ea4153e..0b5775d98 100644 --- a/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp +++ b/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp @@ -471,7 +471,7 @@ void tesseratos::sceneEditorPlugin(Cubos& cubos) } else { - auto id = uuids::to_string(state.asset.getId()); + auto id = state.asset.getId(); ImGui::Text("Editing scene %s", id.c_str()); if (ImGui::Button("Save")) From 38414b34f1e854af855207c9ded7eaff6bb3f944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pereira?= Date: Sun, 29 Sep 2024 16:29:03 +0100 Subject: [PATCH 2/3] Needs some review, stuck on a mutex --- engine/src/assets/assets.cpp | 77 ++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/engine/src/assets/assets.cpp b/engine/src/assets/assets.cpp index 0463a1f00..315d31d61 100644 --- a/engine/src/assets/assets.cpp +++ b/engine/src/assets/assets.cpp @@ -187,6 +187,8 @@ void Assets::loadMeta(std::string_view path) AnyAsset Assets::load(AnyAsset handle) const { auto assetEntry = this->entry(handle); + CUBOS_INFO("Asset::load Loading asset with ID: {} and Path: {}", assetEntry->meta.get("id").value_or(""), + assetEntry->meta.get("path").value_or("")); if (assetEntry == nullptr) { CUBOS_ERROR("Could not load asset"); @@ -225,6 +227,8 @@ AnyAsset Assets::load(AnyAsset handle) const assetEntry->refCount += 1; handle.mRefCount = &assetEntry->refCount; handle.mId = uuids::uuid::from_string(assetEntry->meta.get("id").value_or("")).value_or(uuids::uuid()); + CUBOS_INFO("New Handle ID: {} and Path: {}", uuids::to_string(handle.mId), + assetEntry->meta.get("path").value_or("")); return handle; } @@ -359,6 +363,7 @@ void Assets::invalidate(const AnyAsset& handle, bool shouldLock) AssetMetaRead Assets::readMeta(const AnyAsset& handle) const { + CUBOS_WARN("Reading metadata for asset {}", handle); auto assetEntry = this->entry(handle); CUBOS_ASSERT(assetEntry != nullptr, "Could not access metadata"); @@ -523,7 +528,6 @@ std::string Assets::checkIdType(const std::string& id) const } } -// TODO: Implement this function, too much sus std::shared_ptr Assets::entry(const AnyAsset& handle) const { // If the handle is null, we can't access the asset. @@ -535,50 +539,48 @@ std::shared_ptr Assets::entry(const AnyAsset& handle) const // Lock the entries map for reading. auto sharedLock = std::shared_lock(mMutex); - // Search for the entry in the map. std::string id = handle.getId(); - + uuids::uuid uuid = uuids::uuid{}; CUBOS_ERROR("Assets::entry 1 Current ID: {}", id); + CUBOS_INFO("Assets::entry 1 Current ID type: {}", checkIdType(id)); if (Assets::checkIdType(id) == "Path") { - std::vector assets = this->listAll(); - for (auto& asset : assets) + for (auto asset : mEntries) { - auto meta = this->readMeta(asset); - auto path = meta->get("path"); - CUBOS_ERROR("Assets::entry 1 Current path: {}", path.value()); + auto meta = asset.second->meta; + auto path = meta.get("path"); + auto idd = meta.get("id"); + CUBOS_ERROR("Assets::entry Path Current path: {}", path.value()); + CUBOS_WARN("Assets::entry Path Current ID: {}", idd.value()); if (path.has_value() && path.value() == id) { - auto it = mEntries.find(uuids::uuid::from_string(asset.getId()).value()); - CUBOS_ERROR("Assets::entry 1 Current ID: {}", asset.getId()); - if (it == mEntries.end()) - { - CUBOS_ERROR("No such asset {}", handle); - return nullptr; - } - return it->second; + CUBOS_INFO("Assets::entry Path Found asset with path: {}", id); + uuid = uuids::uuid::from_string(meta.get("id").value()).value(); + CUBOS_INFO("Assets::entry Path Found asset with id: {}", uuids::to_string(uuid)); + break; } } - - CUBOS_ERROR("No such asset {}", handle); - return nullptr; } else if (Assets::checkIdType(id) == "UUID") { - auto it = mEntries.find(uuids::uuid::from_string(handle.getId()).value()); - if (it == mEntries.end()) - { - CUBOS_ERROR("No such asset {}", handle); - return nullptr; - } - return it->second; + uuid = uuids::uuid::from_string(id).value(); } else { - CUBOS_ERROR("No such asset {}", handle); + CUBOS_ERROR("Type mismatch {}", handle); return nullptr; } + auto it = mEntries.find(uuid); + // CUBOS_INFO("Assets::entry 1 Found asset with id: {}, and Path: {}", uuids::to_string(it->first), + // it->second->meta.get("path").value()); + CUBOS_INFO("Assets::entry 1 UUID to find id: {}", uuids::to_string(uuid)); + if (it == mEntries.end()) + { + CUBOS_ERROR("No such asset found with the uuid: {}", handle); + return nullptr; + } + return it->second; } std::shared_ptr Assets::entry(const AnyAsset& handle, bool create) @@ -609,23 +611,14 @@ std::shared_ptr Assets::entry(const AnyAsset& handle, bool create uuids::uuid uuid = uuids::uuid{}; if (Assets::checkIdType(id) == "Path") { - std::vector assets = this->listAll(); - for (auto& asset : assets) + for (auto asset : mEntries) { - auto meta = this->readMeta(asset); - auto path = meta->get("path"); + auto meta = asset.second->meta; + auto path = meta.get("path"); if (path.has_value() && path.value() == id) { - auto tid = meta->get("id"); - if (tid.has_value()) - { - uuid = uuids::uuid::from_string(tid.value()).value(); - } - else - { - CUBOS_ERROR("No such asset {}", handle); - return nullptr; - } + uuid = uuids::uuid::from_string(meta.get("id").value()).value(); + break; } } } @@ -638,7 +631,7 @@ std::shared_ptr Assets::entry(const AnyAsset& handle, bool create CUBOS_ERROR("Id type missmatch", id); return nullptr; } - auto it = mEntries.find(uuids::uuid::from_string(id).value()); + auto it = mEntries.find(uuid); if (it == mEntries.end()) { // If we're creating the asset, create a new entry for it. From b2d8aafbb1aef812ed4fb0b338d4b117c79624da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pereira?= Date: Sat, 28 Sep 2024 20:46:47 +0100 Subject: [PATCH 3/3] feat(assets): add use paths instead of UUIDs to identifying assets --- engine/include/cubos/engine/assets/asset.hpp | 18 ++- engine/include/cubos/engine/assets/assets.hpp | 6 +- engine/samples/games/cubosurfers/main.cpp | 1 + engine/src/assets/asset.cpp | 48 +++++--- engine/src/assets/assets.cpp | 103 ++++++++++++++++-- engine/src/render/mesh/plugin.cpp | 18 +-- engine/src/scene/bridge.cpp | 2 +- .../src/tesseratos/scene_editor/plugin.cpp | 2 +- 8 files changed, 154 insertions(+), 44 deletions(-) diff --git a/engine/include/cubos/engine/assets/asset.hpp b/engine/include/cubos/engine/assets/asset.hpp index 1424f6106..7b27b20d7 100644 --- a/engine/include/cubos/engine/assets/asset.hpp +++ b/engine/include/cubos/engine/assets/asset.hpp @@ -30,7 +30,7 @@ namespace cubos::engine /// @brief Avoid using this field, use @ref getId() instead. /// @todo This was added as a dirty fix for #692, should be removed once the issue is fixed. - uuids::uuid reflectedId; + std::string idOrPath; ~AnyAsset(); @@ -73,7 +73,11 @@ namespace cubos::engine /// @brief Gets the UUID of the asset. /// @return Asset UUID. - uuids::uuid getId() const; + std::string getId() const; + + /// @brief Gets the path of the asset. + /// @return Asset path. + std::string getPath() const; /// @brief Checks if the handle is null. /// @return Whether the handle is null. @@ -111,9 +115,10 @@ namespace cubos::engine /// @brief Decrements the reference count of the asset. void decRef() const; - uuids::uuid mId; ///< UUID of the asset. - void* mRefCount; ///< Void pointer to avoid including `` in the header. - int mVersion; ///< Last known version of the asset. + uuids::uuid mId; ///< UUID of the asset. + void* mRefCount; ///< Void pointer to avoid including `` in the header. + int mVersion; ///< Last known version of the asset. + std::string path; ///< Path of the asset. }; /// @brief Handle to an asset of a specific type. @@ -160,10 +165,11 @@ namespace cubos::engine inline AnyAsset::operator Asset() const { Asset asset; - asset.reflectedId = reflectedId; + asset.idOrPath = idOrPath; asset.mId = mId; asset.mRefCount = mRefCount; asset.mVersion = mVersion; + asset.path = path; asset.incRef(); return asset; } diff --git a/engine/include/cubos/engine/assets/assets.hpp b/engine/include/cubos/engine/assets/assets.hpp index 6cfcb38ef..f217480f8 100644 --- a/engine/include/cubos/engine/assets/assets.hpp +++ b/engine/include/cubos/engine/assets/assets.hpp @@ -247,7 +247,6 @@ namespace cubos::engine struct Entry { Entry(); - Status status{Status::Unloaded}; ///< The status of the asset. AssetMeta meta; ///< The metadata associated with the asset. @@ -308,6 +307,11 @@ namespace cubos::engine /// @return Lock guard. std::unique_lock lockWrite(const AnyAsset& handle) const; + /// @brief Checks if the given ID is of the correct type. + /// @param id ID to check. + /// @return The ID as a string. + std::string checkIdType(const std::string& id) const; + /// @brief Gets a pointer to the entry associated with the given handle. /// @param handle Handle to get the entry for. /// @return Entry for the given handle, or nullptr if there is no such entry. diff --git a/engine/samples/games/cubosurfers/main.cpp b/engine/samples/games/cubosurfers/main.cpp index 1e3ba1caf..ecd2d9976 100644 --- a/engine/samples/games/cubosurfers/main.cpp +++ b/engine/samples/games/cubosurfers/main.cpp @@ -14,6 +14,7 @@ using namespace cubos::engine; +// static const Asset SceneAsset = AnyAsset("/assets/scenes/main.cubos"); static const Asset SceneAsset = AnyAsset("ee5bb451-05b7-430f-a641-a746f7009eef"); static const Asset PaletteAsset = AnyAsset("101da567-3d23-46ae-a391-c10ec00e8718"); static const Asset InputBindingsAsset = AnyAsset("b20900a4-20ee-4caa-8830-14585050bead"); diff --git a/engine/src/assets/asset.cpp b/engine/src/assets/asset.cpp index ea2cdac07..0c5f8352c 100644 --- a/engine/src/assets/asset.cpp +++ b/engine/src/assets/asset.cpp @@ -27,7 +27,7 @@ AnyAsset::AnyAsset(std::nullptr_t) } AnyAsset::AnyAsset(uuids::uuid id) - : reflectedId(id) + : idOrPath(uuids::to_string(id)) , mId(id) , mRefCount(nullptr) , mVersion(-1) @@ -38,31 +38,42 @@ AnyAsset::AnyAsset(std::string_view str) : mRefCount(nullptr) , mVersion(-1) { + if (auto id = uuids::uuid::from_string(str)) { - reflectedId = id.value(); + idOrPath = str; mId = id.value(); } else { - CUBOS_ERROR("Could not create asset handle, invalid UUID: \"{}\"", str); + if (str.find('/') != std::string::npos || str.find('\\') != std::string::npos) + { + idOrPath = str; + path = str; + } + else + { + CUBOS_ERROR("Could not create asset handle, invalid UUID or Path: \"{}\"", str); + } } } AnyAsset::AnyAsset(const AnyAsset& other) - : reflectedId(other.reflectedId) + : idOrPath(other.idOrPath) , mId(other.mId) , mRefCount(other.mRefCount) , mVersion(other.mVersion) + , path(other.path) { this->incRef(); } AnyAsset::AnyAsset(AnyAsset&& other) noexcept - : reflectedId(other.reflectedId) + : idOrPath(other.idOrPath) , mId(other.mId) , mRefCount(other.mRefCount) , mVersion(other.mVersion) + , path(other.path) { other.mRefCount = nullptr; } @@ -70,10 +81,11 @@ AnyAsset::AnyAsset(AnyAsset&& other) noexcept AnyAsset& AnyAsset::operator=(const AnyAsset& other) { this->decRef(); - reflectedId = other.reflectedId; + idOrPath = other.idOrPath; mId = other.mId; mRefCount = other.mRefCount; mVersion = other.mVersion; + path = other.path; this->incRef(); return *this; } @@ -81,11 +93,12 @@ AnyAsset& AnyAsset::operator=(const AnyAsset& other) AnyAsset& AnyAsset::operator=(AnyAsset&& other) noexcept { this->decRef(); - reflectedId = other.reflectedId; + idOrPath = other.idOrPath; mId = other.mId; mRefCount = other.mRefCount; mVersion = other.mVersion; other.mRefCount = nullptr; + path = other.path; return *this; } @@ -96,22 +109,27 @@ bool AnyAsset::operator==(const AnyAsset& other) const int AnyAsset::getVersion() const { - return reflectedId == mId ? mVersion : 0; + return uuids::uuid::from_string(idOrPath) == mId ? mVersion : 0; +} + +std::string AnyAsset::getId() const +{ + return idOrPath; } -uuids::uuid AnyAsset::getId() const +std::string AnyAsset::getPath() const { - return reflectedId; + return path; } bool AnyAsset::isNull() const { - return reflectedId.is_nil(); + return idOrPath.empty(); } bool AnyAsset::isStrong() const { - return reflectedId == mId && mRefCount != nullptr; + return uuids::uuid::from_string(idOrPath) == mId && mRefCount != nullptr; } void AnyAsset::makeWeak() @@ -126,12 +144,12 @@ cubos::core::reflection::Type& AnyAsset::makeType(std::string name) return Type::create(std::move(name)) .with(ConstructibleTrait::typed().withBasicConstructors().build()) - .with(FieldsTrait().withField("id", &AnyAsset::reflectedId)); + .with(FieldsTrait().withField("id", &AnyAsset::idOrPath)); } void AnyAsset::incRef() const { - if (reflectedId == mId && mRefCount != nullptr) + if (uuids::uuid::from_string(idOrPath) == mId && mRefCount != nullptr) { static_cast*>(mRefCount)->fetch_add(1); } @@ -139,7 +157,7 @@ void AnyAsset::incRef() const void AnyAsset::decRef() const { - if (reflectedId == mId && mRefCount != nullptr) + if (uuids::uuid::from_string(idOrPath) == mId && mRefCount != nullptr) { static_cast*>(mRefCount)->fetch_sub(1); } diff --git a/engine/src/assets/assets.cpp b/engine/src/assets/assets.cpp index fa3412c12..315d31d61 100644 --- a/engine/src/assets/assets.cpp +++ b/engine/src/assets/assets.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -11,6 +12,8 @@ #include +using cubos::core::data::File; +using cubos::core::data::FileSystem; using cubos::core::reflection::ConstructibleTrait; using cubos::core::reflection::Type; @@ -184,6 +187,8 @@ void Assets::loadMeta(std::string_view path) AnyAsset Assets::load(AnyAsset handle) const { auto assetEntry = this->entry(handle); + CUBOS_INFO("Asset::load Loading asset with ID: {} and Path: {}", assetEntry->meta.get("id").value_or(""), + assetEntry->meta.get("path").value_or("")); if (assetEntry == nullptr) { CUBOS_ERROR("Could not load asset"); @@ -221,6 +226,9 @@ AnyAsset Assets::load(AnyAsset handle) const // Return a strong handle to the asset. assetEntry->refCount += 1; handle.mRefCount = &assetEntry->refCount; + handle.mId = uuids::uuid::from_string(assetEntry->meta.get("id").value_or("")).value_or(uuids::uuid()); + CUBOS_INFO("New Handle ID: {} and Path: {}", uuids::to_string(handle.mId), + assetEntry->meta.get("path").value_or("")); return handle; } @@ -288,7 +296,7 @@ Assets::Status Assets::status(const AnyAsset& handle) const std::shared_lock lock(mMutex); // Do not use .entry() here because we don't want to log errors if the asset is unknown. - auto it = mEntries.find(handle.getId()); + auto it = mEntries.find(uuids::uuid::from_string(handle.idOrPath).value_or(uuids::uuid())); if (it == mEntries.end()) { return Status::Unknown; @@ -306,9 +314,9 @@ bool Assets::update(AnyAsset& handle) const return false; } - if (handle.mId != handle.reflectedId) + if (handle.mId != uuids::uuid::from_string(handle.idOrPath).value_or(uuids::uuid())) { - handle = AnyAsset{handle.reflectedId}; + handle = AnyAsset{handle.idOrPath}; handle.mVersion = assetEntry->version; return true; } @@ -355,6 +363,7 @@ void Assets::invalidate(const AnyAsset& handle, bool shouldLock) AssetMetaRead Assets::readMeta(const AnyAsset& handle) const { + CUBOS_WARN("Reading metadata for asset {}", handle); auto assetEntry = this->entry(handle); CUBOS_ASSERT(assetEntry != nullptr, "Could not access metadata"); @@ -503,6 +512,22 @@ std::unique_lock Assets::lockWrite(const AnyAsset& handle) co abort(); } +std::string Assets::checkIdType(const std::string& id) const +{ + if (uuids::uuid::from_string(id).has_value()) + { + return "UUID"; + } + else if (id.find('/') != std::string::npos || id.find('\\') != std::string::npos) + { + return "Path"; + } + else + { + return "Unknown"; + } +} + std::shared_ptr Assets::entry(const AnyAsset& handle) const { // If the handle is null, we can't access the asset. @@ -514,15 +539,47 @@ std::shared_ptr Assets::entry(const AnyAsset& handle) const // Lock the entries map for reading. auto sharedLock = std::shared_lock(mMutex); - // Search for the entry in the map. - auto it = mEntries.find(handle.getId()); + std::string id = handle.getId(); + uuids::uuid uuid = uuids::uuid{}; + CUBOS_ERROR("Assets::entry 1 Current ID: {}", id); + CUBOS_INFO("Assets::entry 1 Current ID type: {}", checkIdType(id)); + if (Assets::checkIdType(id) == "Path") + { + for (auto asset : mEntries) + { + auto meta = asset.second->meta; + auto path = meta.get("path"); + auto idd = meta.get("id"); + CUBOS_ERROR("Assets::entry Path Current path: {}", path.value()); + CUBOS_WARN("Assets::entry Path Current ID: {}", idd.value()); + if (path.has_value() && path.value() == id) + { + CUBOS_INFO("Assets::entry Path Found asset with path: {}", id); + uuid = uuids::uuid::from_string(meta.get("id").value()).value(); + CUBOS_INFO("Assets::entry Path Found asset with id: {}", uuids::to_string(uuid)); + break; + } + } + } + else if (Assets::checkIdType(id) == "UUID") + { + uuid = uuids::uuid::from_string(id).value(); + } + else + { + CUBOS_ERROR("Type mismatch {}", handle); + return nullptr; + } + auto it = mEntries.find(uuid); + // CUBOS_INFO("Assets::entry 1 Found asset with id: {}, and Path: {}", uuids::to_string(it->first), + // it->second->meta.get("path").value()); + CUBOS_INFO("Assets::entry 1 UUID to find id: {}", uuids::to_string(uuid)); if (it == mEntries.end()) { - CUBOS_ERROR("No such asset {}", handle); + CUBOS_ERROR("No such asset found with the uuid: {}", handle); return nullptr; } - return it->second; } @@ -549,7 +606,32 @@ std::shared_ptr Assets::entry(const AnyAsset& handle, bool create } // Search for an existing entry for the asset. - auto it = mEntries.find(handle.getId()); + + std::string id = handle.getId(); + uuids::uuid uuid = uuids::uuid{}; + if (Assets::checkIdType(id) == "Path") + { + for (auto asset : mEntries) + { + auto meta = asset.second->meta; + auto path = meta.get("path"); + if (path.has_value() && path.value() == id) + { + uuid = uuids::uuid::from_string(meta.get("id").value()).value(); + break; + } + } + } + else if (Assets::checkIdType(id) == "UUID") + { + uuid = uuids::uuid::from_string(id).value(); + } + else + { + CUBOS_ERROR("Id type missmatch", id); + return nullptr; + } + auto it = mEntries.find(uuid); if (it == mEntries.end()) { // If we're creating the asset, create a new entry for it. @@ -557,8 +639,8 @@ std::shared_ptr Assets::entry(const AnyAsset& handle, bool create if (create) { auto entry = std::make_shared(); - entry->meta.set("id", uuids::to_string(handle.getId())); - it = mEntries.emplace(handle.getId(), std::move(entry)).first; + entry->meta.set("id", uuids::to_string(uuid)); + it = mEntries.emplace(uuid, std::move(entry)).first; CUBOS_TRACE("Created new asset entry for {}", handle); } else @@ -567,7 +649,6 @@ std::shared_ptr Assets::entry(const AnyAsset& handle, bool create return nullptr; } } - return it->second; } diff --git a/engine/src/render/mesh/plugin.cpp b/engine/src/render/mesh/plugin.cpp index 2e9ac8dbe..508fb1666 100644 --- a/engine/src/render/mesh/plugin.cpp +++ b/engine/src/render/mesh/plugin.cpp @@ -89,7 +89,7 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) // If the asset has never been loaded, or it has been updated since the last meshing, update the entry // and queue a meshing task. Otherwise, just reuse the existing mesh. - auto& entry = state.entries[grid.asset.getId()]; + auto& entry = state.entries[uuids::uuid::from_string(grid.asset.getId()).value()]; entry.referenceCount += 1; if (entry.asset.isNull() || assets.update(entry.asset)) { @@ -111,7 +111,7 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) task.finish(std::move(vertices)); }); - state.meshing.insert(grid.asset.getId()); + state.meshing.insert(uuids::uuid::from_string(grid.asset.getId()).value()); } else if (entry.firstBucketId != RenderMeshPool::BucketId::Invalid) { @@ -131,8 +131,8 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) continue; } - auto& entry = state.entries[grid.asset.getId()]; - if (!state.meshing.contains(grid.asset.getId())) + auto& entry = state.entries[uuids::uuid::from_string(grid.asset.getId()).value()]; + if (!state.meshing.contains(uuids::uuid::from_string(grid.asset.getId()).value())) { if (entry.asset.isNull() || assets.update(entry.asset)) { @@ -154,7 +154,7 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) task.finish(std::move(vertices)); }); - state.meshing.insert(grid.asset.getId()); + state.meshing.insert(uuids::uuid::from_string(grid.asset.getId()).value()); } else { @@ -172,14 +172,14 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) CUBOS_INFO("Finished meshing voxel grid asset {} ({} vertices), allocated new render bucket", grid.asset.getId(), vertices.size()); - auto& entry = state.entries[grid.asset.getId()]; + auto& entry = state.entries[uuids::uuid::from_string(grid.asset.getId()).value()]; if (entry.firstBucketId != RenderMeshPool::BucketId::Invalid) { pool.deallocate(entry.firstBucketId); CUBOS_INFO("Deallocated old render mesh bucket of asset {}", grid.asset.getId()); } entry.firstBucketId = firstBucketId; - state.meshing.erase(grid.asset.getId()); + state.meshing.erase(uuids::uuid::from_string(grid.asset.getId()).value()); } } }); @@ -189,12 +189,12 @@ void cubos::engine::renderMeshPlugin(Cubos& cubos) .call([](Query query, RenderMeshPool& pool, State& state) { for (auto [ent, grid] : query) { - auto& entry = state.entries[grid.asset.getId()]; + auto& entry = state.entries[uuids::uuid::from_string(grid.asset.getId()).value()]; entry.referenceCount -= 1; if (entry.referenceCount == 0) { pool.deallocate(entry.firstBucketId); - state.entries.erase(grid.asset.getId()); + state.entries.erase(uuids::uuid::from_string(grid.asset.getId()).value()); CUBOS_INFO("Deallocated render mesh bucket of asset {} (no more references)", grid.asset.getId()); } } diff --git a/engine/src/scene/bridge.cpp b/engine/src/scene/bridge.cpp index 1cdac3d5b..e8896984a 100644 --- a/engine/src/scene/bridge.cpp +++ b/engine/src/scene/bridge.cpp @@ -320,7 +320,7 @@ bool SceneBridge::saveToFile(const Assets& assets, const AnyAsset& handle, Strea auto importJson = nlohmann::json::object(); for (const auto& [name, subHandle] : scene->imports) { - importJson.emplace(name.c_str(), uuids::to_string(subHandle.getId())); + importJson.emplace(name.c_str(), subHandle.getId()); } json.push_back({"imports", importJson}); diff --git a/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp b/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp index 10ea4153e..0b5775d98 100644 --- a/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp +++ b/tools/tesseratos/src/tesseratos/scene_editor/plugin.cpp @@ -471,7 +471,7 @@ void tesseratos::sceneEditorPlugin(Cubos& cubos) } else { - auto id = uuids::to_string(state.asset.getId()); + auto id = state.asset.getId(); ImGui::Text("Editing scene %s", id.c_str()); if (ImGui::Button("Save"))