Finalize library bootstrap status and stabilize async asset regressions
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
38
engine/include/XCEngine/Resources/UI/UIDocumentCompiler.h
Normal file
38
engine/include/XCEngine/Resources/UI/UIDocumentCompiler.h
Normal 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
|
||||
44
engine/include/XCEngine/Resources/UI/UIDocumentLoaders.h
Normal file
44
engine/include/XCEngine/Resources/UI/UIDocumentLoaders.h
Normal 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
|
||||
76
engine/include/XCEngine/Resources/UI/UIDocumentTypes.h
Normal file
76
engine/include/XCEngine/Resources/UI/UIDocumentTypes.h
Normal 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
|
||||
49
engine/include/XCEngine/Resources/UI/UIDocuments.h
Normal file
49
engine/include/XCEngine/Resources/UI/UIDocuments.h
Normal 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
|
||||
Reference in New Issue
Block a user