Finalize library bootstrap status and stabilize async asset regressions

This commit is contained in:
2026-04-04 19:44:59 +08:00
parent 013e5a73b9
commit bcef1f145b
25 changed files with 3415 additions and 81 deletions

View File

@@ -10,28 +10,91 @@ namespace Resources {
class AssetImportService {
public:
struct ImportStatusSnapshot {
Core::uint64 revision = 0;
bool inProgress = false;
bool success = false;
Containers::String operation;
Containers::String targetPath;
Containers::String message;
Core::uint64 startedAtMs = 0;
Core::uint64 completedAtMs = 0;
Core::uint64 durationMs = 0;
Core::uint32 importedAssetCount = 0;
Core::uint32 removedArtifactCount = 0;
bool HasValue() const {
return revision != 0;
}
};
struct LookupSnapshot {
std::unordered_map<std::string, AssetGUID> assetGuidByPathKey;
std::unordered_map<AssetGUID, Containers::String> assetPathByGuid;
void Clear() {
assetGuidByPathKey.clear();
assetPathByGuid.clear();
}
};
struct ImportedAsset {
bool exists = false;
bool artifactReady = false;
bool imported = false;
Containers::String absolutePath;
Containers::String relativePath;
AssetGUID assetGuid;
ResourceType resourceType = ResourceType::Unknown;
Containers::String runtimeLoadPath;
Containers::String artifactDirectory;
LocalID mainLocalID = kMainAssetLocalID;
};
void Initialize();
void Shutdown();
void SetProjectRoot(const Containers::String& projectRoot);
Containers::String GetProjectRoot() const;
Containers::String GetLibraryRoot() const;
bool BootstrapProject();
void Refresh();
bool ClearLibraryCache();
bool RebuildLibraryCache();
bool ReimportAllAssets();
bool ReimportAsset(const Containers::String& requestPath,
ImportedAsset& outAsset);
ImportStatusSnapshot GetLastImportStatus() const;
bool TryGetImportableResourceType(const Containers::String& requestPath,
ResourceType& outType) const;
bool EnsureArtifact(const Containers::String& requestPath,
ResourceType requestedType,
AssetDatabase::ResolvedAsset& outAsset);
ImportedAsset& outAsset);
bool TryGetAssetRef(const Containers::String& requestPath,
ResourceType resourceType,
AssetRef& outRef) const;
bool TryGetPrimaryAssetPath(const AssetGUID& guid, Containers::String& outRelativePath) const;
void BuildLookupSnapshot(std::unordered_map<std::string, AssetGUID>& outPathToGuid,
std::unordered_map<AssetGUID, Containers::String>& outGuidToPath) const;
void BuildLookupSnapshot(LookupSnapshot& outSnapshot) const;
private:
static ImportedAsset ConvertResolvedAsset(const AssetDatabase::ResolvedAsset& resolvedAsset);
void ResetImportStatusLocked();
void BeginImportStatusLocked(const Containers::String& operation,
const Containers::String& targetPath,
const Containers::String& message);
void FinishImportStatusLocked(const Containers::String& operation,
const Containers::String& targetPath,
bool success,
const Containers::String& message,
const AssetDatabase::MaintenanceStats& stats);
mutable std::recursive_mutex m_mutex;
Containers::String m_projectRoot;
AssetDatabase m_assetDatabase;
ImportStatusSnapshot m_lastImportStatus;
Core::uint64 m_nextImportStatusRevision = 1;
};
} // namespace Resources

View File

@@ -18,22 +18,26 @@ public:
ResourceHandle() = default;
explicit ResourceHandle(T* resource)
: m_resource(resource) {
if (m_resource) {
ResourceManager::Get().AddRef(m_resource->GetGUID());
: m_resource(resource),
m_guid(resource != nullptr ? resource->GetGUID() : ResourceGUID()) {
if (m_guid.IsValid()) {
ResourceManager::Get().AddRef(m_guid);
}
}
ResourceHandle(const ResourceHandle& other)
: m_resource(other.m_resource) {
if (m_resource) {
ResourceManager::Get().AddRef(m_resource->GetGUID());
: m_resource(other.m_resource),
m_guid(other.m_guid) {
if (m_guid.IsValid()) {
ResourceManager::Get().AddRef(m_guid);
}
}
ResourceHandle(ResourceHandle&& other) noexcept
: m_resource(other.m_resource) {
: m_resource(other.m_resource),
m_guid(other.m_guid) {
other.m_resource = nullptr;
other.m_guid = ResourceGUID();
}
~ResourceHandle() {
@@ -44,8 +48,9 @@ public:
if (this != &other) {
Reset();
m_resource = other.m_resource;
if (m_resource) {
ResourceManager::Get().AddRef(m_resource->GetGUID());
m_guid = other.m_guid;
if (m_guid.IsValid()) {
ResourceManager::Get().AddRef(m_guid);
}
}
return *this;
@@ -55,7 +60,9 @@ public:
if (this != &other) {
Reset();
m_resource = other.m_resource;
m_guid = other.m_guid;
other.m_resource = nullptr;
other.m_guid = ResourceGUID();
}
return *this;
}
@@ -64,11 +71,11 @@ public:
T* operator->() const { return m_resource; }
T& operator*() const { return *m_resource; }
bool IsValid() const { return m_resource != nullptr && m_resource->IsValid(); }
bool IsValid() const { return m_resource != nullptr && m_guid.IsValid() && m_resource->IsValid(); }
explicit operator bool() const { return IsValid(); }
ResourceGUID GetGUID() const {
return m_resource ? m_resource->GetGUID() : ResourceGUID(0);
return m_guid;
}
ResourceType GetResourceType() const {
@@ -76,18 +83,21 @@ public:
}
void Reset() {
if (m_resource) {
ResourceManager::Get().Release(m_resource->GetGUID());
if (m_guid.IsValid()) {
ResourceManager::Get().Release(m_guid);
m_resource = nullptr;
m_guid = ResourceGUID();
}
}
void Swap(ResourceHandle& other) {
std::swap(m_resource, other.m_resource);
std::swap(m_guid, other.m_guid);
}
private:
T* m_resource = nullptr;
ResourceGUID m_guid;
};
template<typename T>

View File

@@ -42,6 +42,7 @@ public:
void SetResourceRoot(const Containers::String& rootPath);
const Containers::String& GetResourceRoot() const;
bool BootstrapProjectAssets();
template<typename T>
ResourceHandle<T> Load(const Containers::String& path, ImportSettings* settings = nullptr) {
@@ -116,7 +117,13 @@ public:
Containers::Array<Containers::String> GetResourcePaths() const;
void UnloadGroup(const Containers::Array<ResourceGUID>& guids);
void RefreshAssetDatabase();
void RefreshProjectAssets();
bool CanReimportProjectAsset(const Containers::String& path) const;
bool ReimportProjectAsset(const Containers::String& path);
bool ClearProjectLibraryCache();
bool RebuildProjectAssetCache();
Containers::String GetProjectLibraryRoot() const;
AssetImportService::ImportStatusSnapshot GetProjectAssetImportStatus() const;
bool TryGetAssetRef(const Containers::String& path, ResourceType resourceType, AssetRef& outRef) const;
bool TryResolveAssetPath(const AssetRef& assetRef, Containers::String& outPath) const;
void BeginDeferredSceneLoad();

View File

@@ -0,0 +1,38 @@
#pragma once
#include <XCEngine/Core/Containers/String.h>
#include <XCEngine/Resources/UI/UIDocumentTypes.h>
namespace XCEngine {
namespace Resources {
struct UIDocumentCompileRequest {
UIDocumentKind kind = UIDocumentKind::View;
Containers::String path;
Containers::String expectedRootTag;
};
struct UIDocumentCompileResult {
UIDocumentModel document = {};
Containers::String errorMessage;
bool succeeded = false;
};
bool CompileUIDocument(
const UIDocumentCompileRequest& request,
UIDocumentCompileResult& outResult);
bool WriteUIDocumentArtifact(
const Containers::String& artifactPath,
const UIDocumentCompileResult& compileResult,
Containers::String* outErrorMessage = nullptr);
bool LoadUIDocumentArtifact(
const Containers::String& artifactPath,
UIDocumentKind expectedKind,
UIDocumentCompileResult& outResult);
Containers::String GetUIDocumentDefaultRootTag(UIDocumentKind kind);
} // namespace Resources
} // namespace XCEngine

View File

@@ -0,0 +1,44 @@
#pragma once
#include <XCEngine/Core/IO/IResourceLoader.h>
#include <XCEngine/Resources/UI/UIDocumentCompiler.h>
#include <XCEngine/Resources/UI/UIDocuments.h>
namespace XCEngine {
namespace Resources {
class UIViewLoader : public IResourceLoader {
public:
ResourceType GetResourceType() const override { return ResourceType::UIView; }
Containers::Array<Containers::String> GetSupportedExtensions() const override;
bool CanLoad(const Containers::String& path) const override;
LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override;
ImportSettings* GetDefaultSettings() const override { return nullptr; }
bool CompileDocument(const Containers::String& path, UIDocumentCompileResult& outResult) const;
};
class UIThemeLoader : public IResourceLoader {
public:
ResourceType GetResourceType() const override { return ResourceType::UITheme; }
Containers::Array<Containers::String> GetSupportedExtensions() const override;
bool CanLoad(const Containers::String& path) const override;
LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override;
ImportSettings* GetDefaultSettings() const override { return nullptr; }
bool CompileDocument(const Containers::String& path, UIDocumentCompileResult& outResult) const;
};
class UISchemaLoader : public IResourceLoader {
public:
ResourceType GetResourceType() const override { return ResourceType::UISchema; }
Containers::Array<Containers::String> GetSupportedExtensions() const override;
bool CanLoad(const Containers::String& path) const override;
LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override;
ImportSettings* GetDefaultSettings() const override { return nullptr; }
bool CompileDocument(const Containers::String& path, UIDocumentCompileResult& outResult) const;
};
} // namespace Resources
} // namespace XCEngine

View File

@@ -0,0 +1,76 @@
#pragma once
#include <XCEngine/Core/Containers/Array.h>
#include <XCEngine/Core/Containers/String.h>
#include <XCEngine/Core/Types.h>
namespace XCEngine {
namespace Resources {
enum class UIDocumentKind : Core::uint8 {
View = 0,
Theme,
Schema
};
enum class UIDocumentDiagnosticSeverity : Core::uint8 {
Info = 0,
Warning,
Error
};
struct UIDocumentSourceLocation {
Core::uint32 line = 1;
Core::uint32 column = 1;
};
struct UIDocumentAttribute {
Containers::String name;
Containers::String value;
};
struct UIDocumentDiagnostic {
UIDocumentDiagnosticSeverity severity = UIDocumentDiagnosticSeverity::Error;
UIDocumentSourceLocation location = {};
Containers::String message;
};
struct UIDocumentNode {
Containers::String tagName;
Containers::Array<UIDocumentAttribute> attributes;
Containers::Array<UIDocumentNode> children;
UIDocumentSourceLocation location = {};
bool selfClosing = false;
const UIDocumentAttribute* FindAttribute(const Containers::String& name) const {
for (const UIDocumentAttribute& attribute : attributes) {
if (attribute.name == name) {
return &attribute;
}
}
return nullptr;
}
};
struct UIDocumentModel {
UIDocumentKind kind = UIDocumentKind::View;
Containers::String sourcePath;
Containers::String displayName;
UIDocumentNode rootNode;
Containers::Array<Containers::String> dependencies;
Containers::Array<UIDocumentDiagnostic> diagnostics;
bool valid = false;
void Clear() {
sourcePath.Clear();
displayName.Clear();
rootNode = UIDocumentNode();
dependencies.Clear();
diagnostics.Clear();
valid = false;
}
};
} // namespace Resources
} // namespace XCEngine

View File

@@ -0,0 +1,49 @@
#pragma once
#include <XCEngine/Core/Asset/IResource.h>
#include <XCEngine/Resources/UI/UIDocumentTypes.h>
namespace XCEngine {
namespace Resources {
class UIDocumentResource : public IResource {
public:
const Containers::String& GetName() const override { return m_name; }
const Containers::String& GetPath() const override { return m_path; }
ResourceGUID GetGUID() const override { return m_guid; }
bool IsValid() const override { return m_isValid; }
size_t GetMemorySize() const override { return m_memorySize; }
void Release() override;
const UIDocumentModel& GetDocument() const { return m_document; }
const UIDocumentNode& GetRootNode() const { return m_document.rootNode; }
const Containers::Array<Containers::String>& GetDependencies() const { return m_document.dependencies; }
const Containers::Array<UIDocumentDiagnostic>& GetDiagnostics() const { return m_document.diagnostics; }
const Containers::String& GetSourcePath() const { return m_document.sourcePath; }
void SetDocumentModel(const UIDocumentModel& document);
void SetDocumentModel(UIDocumentModel&& document);
protected:
void RecalculateMemorySize();
UIDocumentModel m_document = {};
};
class UIView : public UIDocumentResource {
public:
ResourceType GetType() const override { return ResourceType::UIView; }
};
class UITheme : public UIDocumentResource {
public:
ResourceType GetType() const override { return ResourceType::UITheme; }
};
class UISchema : public UIDocumentResource {
public:
ResourceType GetType() const override { return ResourceType::UISchema; }
};
} // namespace Resources
} // namespace XCEngine