feat: expand editor scripting asset and viewport flow
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <XCEngine/Components/Component.h>
|
||||
#include <XCEngine/Core/Asset/AssetRef.h>
|
||||
#include <XCEngine/Core/Asset/ResourceHandle.h>
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
#include <XCEngine/Resources/Mesh/Mesh.h>
|
||||
|
||||
#include <memory>
|
||||
@@ -32,12 +33,14 @@ private:
|
||||
struct PendingMeshLoadState;
|
||||
|
||||
void BeginAsyncMeshLoad(const std::string& meshPath);
|
||||
void EnsureDeferredAsyncMeshLoadStarted();
|
||||
void ResolvePendingMesh();
|
||||
|
||||
Resources::ResourceHandle<Resources::Mesh> m_mesh;
|
||||
std::string m_meshPath;
|
||||
Resources::AssetRef m_meshRef;
|
||||
std::shared_ptr<PendingMeshLoadState> m_pendingMeshLoad;
|
||||
bool m_asyncMeshLoadRequested = false;
|
||||
};
|
||||
|
||||
} // namespace Components
|
||||
|
||||
@@ -46,6 +46,7 @@ private:
|
||||
struct PendingMaterialLoadState;
|
||||
|
||||
void BeginAsyncMaterialLoad(size_t index, const std::string& materialPath);
|
||||
void EnsureDeferredAsyncMaterialLoadStarted(size_t index);
|
||||
void ResolvePendingMaterials();
|
||||
void EnsureMaterialSlot(size_t index);
|
||||
static std::string MaterialPathFromHandle(const Resources::ResourceHandle<Resources::Material>& material);
|
||||
@@ -54,6 +55,7 @@ private:
|
||||
std::vector<std::string> m_materialPaths;
|
||||
std::vector<Resources::AssetRef> m_materialRefs;
|
||||
std::vector<std::shared_ptr<PendingMaterialLoadState>> m_pendingMaterialLoads;
|
||||
std::vector<bool> m_asyncMaterialLoadRequested;
|
||||
bool m_castShadows = true;
|
||||
bool m_receiveShadows = true;
|
||||
uint32_t m_renderLayer = 0;
|
||||
|
||||
@@ -6,12 +6,23 @@
|
||||
|
||||
#include <filesystem>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
class Mesh;
|
||||
class Material;
|
||||
|
||||
class AssetDatabase {
|
||||
public:
|
||||
struct ArtifactDependencyRecord {
|
||||
Containers::String path;
|
||||
Containers::String hash;
|
||||
Core::uint64 fileSize = 0;
|
||||
Core::uint64 writeTime = 0;
|
||||
};
|
||||
|
||||
struct SourceAssetRecord {
|
||||
AssetGUID guid;
|
||||
Containers::String relativePath;
|
||||
@@ -39,6 +50,7 @@ public:
|
||||
Core::uint64 sourceFileSize = 0;
|
||||
Core::uint64 sourceWriteTime = 0;
|
||||
LocalID mainLocalID = kMainAssetLocalID;
|
||||
std::vector<ArtifactDependencyRecord> dependencies;
|
||||
};
|
||||
|
||||
struct ResolvedAsset {
|
||||
@@ -66,13 +78,15 @@ public:
|
||||
ResourceType requestedType,
|
||||
ResolvedAsset& outAsset);
|
||||
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;
|
||||
|
||||
const Containers::String& GetProjectRoot() const { return m_projectRoot; }
|
||||
const Containers::String& GetAssetsRoot() const { return m_assetsRoot; }
|
||||
const Containers::String& GetLibraryRoot() const { return m_libraryRoot; }
|
||||
|
||||
private:
|
||||
static constexpr Core::uint32 kCurrentImporterVersion = 2;
|
||||
static constexpr Core::uint32 kCurrentImporterVersion = 3;
|
||||
|
||||
void EnsureProjectLayout();
|
||||
void LoadSourceAssetDB();
|
||||
@@ -110,12 +124,24 @@ private:
|
||||
bool ImportModelAsset(const SourceAssetRecord& sourceRecord,
|
||||
ArtifactRecord& outRecord);
|
||||
|
||||
Containers::String BuildArtifactKey(const SourceAssetRecord& sourceRecord) const;
|
||||
Containers::String BuildArtifactKey(
|
||||
const SourceAssetRecord& sourceRecord,
|
||||
const std::vector<ArtifactDependencyRecord>& dependencies = {}) const;
|
||||
Containers::String BuildArtifactDirectory(const Containers::String& artifactKey) const;
|
||||
static Containers::String ReadWholeFileText(const std::filesystem::path& path);
|
||||
static Containers::String ComputeFileHash(const std::filesystem::path& path);
|
||||
static Core::uint64 GetFileSizeValue(const std::filesystem::path& path);
|
||||
static Core::uint64 GetFileWriteTimeValue(const std::filesystem::path& path);
|
||||
Containers::String NormalizeDependencyPath(const std::filesystem::path& path) const;
|
||||
std::filesystem::path ResolveDependencyPath(const Containers::String& path) const;
|
||||
bool CaptureDependencyRecord(const std::filesystem::path& path,
|
||||
ArtifactDependencyRecord& outRecord) const;
|
||||
bool AreDependenciesCurrent(const std::vector<ArtifactDependencyRecord>& dependencies) const;
|
||||
bool CollectModelDependencies(const SourceAssetRecord& sourceRecord,
|
||||
const Mesh& mesh,
|
||||
std::vector<ArtifactDependencyRecord>& outDependencies) const;
|
||||
bool CollectMaterialDependencies(const Material& material,
|
||||
std::vector<ArtifactDependencyRecord>& outDependencies) const;
|
||||
|
||||
Containers::String m_projectRoot;
|
||||
Containers::String m_assetsRoot;
|
||||
|
||||
38
engine/include/XCEngine/Core/Asset/AssetImportService.h
Normal file
38
engine/include/XCEngine/Core/Asset/AssetImportService.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "AssetDatabase.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
class AssetImportService {
|
||||
public:
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
void SetProjectRoot(const Containers::String& projectRoot);
|
||||
Containers::String GetProjectRoot() const;
|
||||
|
||||
void Refresh();
|
||||
|
||||
bool EnsureArtifact(const Containers::String& requestPath,
|
||||
ResourceType requestedType,
|
||||
AssetDatabase::ResolvedAsset& 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;
|
||||
|
||||
private:
|
||||
mutable std::recursive_mutex m_mutex;
|
||||
Containers::String m_projectRoot;
|
||||
AssetDatabase m_assetDatabase;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
37
engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h
Normal file
37
engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/Core/Asset/AssetRef.h>
|
||||
#include <XCEngine/Core/Asset/ResourceTypes.h>
|
||||
#include <XCEngine/Core/Containers/String.h>
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Resources {
|
||||
|
||||
class AssetImportService;
|
||||
|
||||
class ProjectAssetIndex {
|
||||
public:
|
||||
void ResetProjectRoot(const Containers::String& projectRoot = Containers::String());
|
||||
void RefreshFrom(const AssetImportService& importService);
|
||||
|
||||
bool TryGetAssetRef(AssetImportService& importService,
|
||||
const Containers::String& path,
|
||||
ResourceType resourceType,
|
||||
AssetRef& outRef) const;
|
||||
bool TryResolveAssetPath(const AssetImportService& importService,
|
||||
const AssetRef& assetRef,
|
||||
Containers::String& outPath) const;
|
||||
void RememberResolvedPath(const AssetGUID& assetGuid, const Containers::String& relativePath);
|
||||
|
||||
private:
|
||||
mutable std::shared_mutex m_mutex;
|
||||
Containers::String m_projectRoot;
|
||||
std::unordered_map<std::string, AssetGUID> m_assetGuidByPathKey;
|
||||
std::unordered_map<AssetGUID, Containers::String> m_assetPathByGuid;
|
||||
};
|
||||
|
||||
} // namespace Resources
|
||||
} // namespace XCEngine
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEngine/Core/IO/IResourceLoader.h>
|
||||
#include "AssetDatabase.h"
|
||||
#include "AssetImportService.h"
|
||||
#include "ProjectAssetIndex.h"
|
||||
#include "ResourceCache.h"
|
||||
#include "AsyncLoader.h"
|
||||
#include "ResourceHandle.h"
|
||||
@@ -165,12 +166,12 @@ private:
|
||||
size_t m_memoryUsage = 0;
|
||||
size_t m_memoryBudget = 512 * 1024 * 1024;
|
||||
|
||||
AssetDatabase m_assetDatabase;
|
||||
mutable AssetImportService m_assetImportService;
|
||||
mutable ProjectAssetIndex m_projectAssetIndex;
|
||||
ResourceCache m_cache;
|
||||
Core::UniqueRef<AsyncLoader> m_asyncLoader;
|
||||
Threading::Mutex m_mutex;
|
||||
std::mutex m_initializeMutex;
|
||||
mutable std::recursive_mutex m_ioMutex;
|
||||
std::mutex m_inFlightLoadsMutex;
|
||||
std::unordered_map<InFlightLoadKey, std::shared_ptr<InFlightLoadState>, InFlightLoadKeyHasher> m_inFlightLoads;
|
||||
std::atomic<Core::uint32> m_deferredSceneLoadDepth{0};
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
bool IsKeyDown(KeyCode key) const;
|
||||
bool IsKeyUp(KeyCode key) const;
|
||||
bool IsKeyPressed(KeyCode key) const;
|
||||
bool IsKeyReleased(KeyCode key) const;
|
||||
|
||||
Math::Vector2 GetMousePosition() const;
|
||||
Math::Vector2 GetMouseDelta() const;
|
||||
@@ -28,6 +29,7 @@ public:
|
||||
bool IsMouseButtonDown(MouseButton button) const;
|
||||
bool IsMouseButtonUp(MouseButton button) const;
|
||||
bool IsMouseButtonClicked(MouseButton button) const;
|
||||
bool IsMouseButtonReleased(MouseButton button) const;
|
||||
|
||||
int GetTouchCount() const;
|
||||
TouchState GetTouch(int index) const;
|
||||
@@ -38,6 +40,8 @@ public:
|
||||
bool GetButton(const Containers::String& buttonName) const;
|
||||
bool GetButtonDown(const Containers::String& buttonName) const;
|
||||
bool GetButtonUp(const Containers::String& buttonName) const;
|
||||
bool IsAnyKeyDown() const;
|
||||
bool IsAnyKeyPressed() const;
|
||||
|
||||
void RegisterAxis(const InputAxis& axis);
|
||||
void RegisterButton(const Containers::String& name, KeyCode key);
|
||||
@@ -68,6 +72,7 @@ private:
|
||||
|
||||
std::vector<bool> m_keyDownThisFrame;
|
||||
std::vector<bool> m_keyDownLastFrame;
|
||||
std::vector<bool> m_keyUpThisFrame;
|
||||
std::vector<bool> m_keyDown;
|
||||
|
||||
Math::Vector2 m_mousePosition;
|
||||
@@ -75,6 +80,7 @@ private:
|
||||
float m_mouseScrollDelta = 0.0f;
|
||||
std::vector<bool> m_mouseButtonDownThisFrame;
|
||||
std::vector<bool> m_mouseButtonDownLastFrame;
|
||||
std::vector<bool> m_mouseButtonUpThisFrame;
|
||||
std::vector<bool> m_mouseButtonDown;
|
||||
|
||||
std::vector<TouchState> m_touches;
|
||||
|
||||
@@ -57,6 +57,7 @@ struct CameraRenderRequest {
|
||||
Math::Color clearColorOverride = Math::Color::Black();
|
||||
RenderPassSequence* preScenePasses = nullptr;
|
||||
RenderPassSequence* postScenePasses = nullptr;
|
||||
RenderPassSequence* overlayPasses = nullptr;
|
||||
|
||||
bool IsValid() const {
|
||||
return scene != nullptr &&
|
||||
|
||||
@@ -28,6 +28,26 @@ enum class ScriptLifecycleMethod {
|
||||
OnDestroy
|
||||
};
|
||||
|
||||
struct ScriptClassDescriptor {
|
||||
std::string assemblyName;
|
||||
std::string namespaceName;
|
||||
std::string className;
|
||||
|
||||
std::string GetFullName() const {
|
||||
return namespaceName.empty() ? className : namespaceName + "." + className;
|
||||
}
|
||||
|
||||
bool operator==(const ScriptClassDescriptor& other) const {
|
||||
return assemblyName == other.assemblyName
|
||||
&& namespaceName == other.namespaceName
|
||||
&& className == other.className;
|
||||
}
|
||||
|
||||
bool operator!=(const ScriptClassDescriptor& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
struct ScriptRuntimeContext {
|
||||
Components::Scene* scene = nullptr;
|
||||
Components::GameObject* gameObject = nullptr;
|
||||
@@ -43,6 +63,9 @@ public:
|
||||
virtual void OnRuntimeStart(Components::Scene* scene) = 0;
|
||||
virtual void OnRuntimeStop(Components::Scene* scene) = 0;
|
||||
|
||||
virtual bool TryGetAvailableScriptClasses(
|
||||
std::vector<ScriptClassDescriptor>& outClasses) const = 0;
|
||||
|
||||
virtual bool TryGetClassFieldMetadata(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
|
||||
@@ -50,6 +50,8 @@ public:
|
||||
const std::string& namespaceName,
|
||||
const std::string& className) const;
|
||||
std::vector<std::string> GetScriptClassNames(const std::string& assemblyName = std::string()) const;
|
||||
bool TryGetAvailableScriptClasses(
|
||||
std::vector<ScriptClassDescriptor>& outClasses) const override;
|
||||
bool TryGetClassFieldMetadata(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
|
||||
@@ -9,6 +9,8 @@ class NullScriptRuntime : public IScriptRuntime {
|
||||
public:
|
||||
void OnRuntimeStart(Components::Scene* scene) override;
|
||||
void OnRuntimeStop(Components::Scene* scene) override;
|
||||
bool TryGetAvailableScriptClasses(
|
||||
std::vector<ScriptClassDescriptor>& outClasses) const override;
|
||||
bool TryGetClassFieldMetadata(
|
||||
const std::string& assemblyName,
|
||||
const std::string& namespaceName,
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
|
||||
void SetScriptClass(const std::string& namespaceName, const std::string& className);
|
||||
void SetScriptClass(const std::string& assemblyName, const std::string& namespaceName, const std::string& className);
|
||||
void ClearScriptClass();
|
||||
|
||||
bool HasScriptClass() const { return !m_className.empty(); }
|
||||
std::string GetFullClassName() const;
|
||||
|
||||
@@ -19,9 +19,12 @@ class ScriptComponent;
|
||||
class ScriptEngine {
|
||||
public:
|
||||
static ScriptEngine& Get();
|
||||
static constexpr float DefaultFixedDeltaTime = 1.0f / 50.0f;
|
||||
|
||||
void SetRuntime(IScriptRuntime* runtime);
|
||||
IScriptRuntime* GetRuntime() const { return m_runtime; }
|
||||
void SetRuntimeFixedDeltaTime(float fixedDeltaTime);
|
||||
float GetRuntimeFixedDeltaTime() const { return m_runtimeFixedDeltaTime; }
|
||||
|
||||
void OnRuntimeStart(Components::Scene* scene);
|
||||
void OnRuntimeStop();
|
||||
@@ -33,6 +36,7 @@ public:
|
||||
void OnScriptComponentEnabled(ScriptComponent* component);
|
||||
void OnScriptComponentDisabled(ScriptComponent* component);
|
||||
void OnScriptComponentDestroyed(ScriptComponent* component);
|
||||
void OnScriptComponentClassChanged(ScriptComponent* component);
|
||||
|
||||
bool IsRuntimeRunning() const { return m_runtimeRunning; }
|
||||
Components::Scene* GetRuntimeScene() const { return m_runtimeScene; }
|
||||
@@ -40,6 +44,9 @@ public:
|
||||
bool HasTrackedScriptComponent(const ScriptComponent* component) const;
|
||||
bool HasRuntimeInstance(const ScriptComponent* component) const;
|
||||
size_t GetTrackedScriptCount() const { return m_scriptOrder.size(); }
|
||||
bool TryGetAvailableScriptClasses(
|
||||
std::vector<ScriptClassDescriptor>& outClasses,
|
||||
const std::string& assemblyName = std::string()) const;
|
||||
bool TrySetScriptFieldValue(
|
||||
ScriptComponent* component,
|
||||
const std::string& fieldName,
|
||||
@@ -138,6 +145,7 @@ private:
|
||||
IScriptRuntime* m_runtime = &m_nullRuntime;
|
||||
Components::Scene* m_runtimeScene = nullptr;
|
||||
bool m_runtimeRunning = false;
|
||||
float m_runtimeFixedDeltaTime = DefaultFixedDeltaTime;
|
||||
uint64_t m_runtimeSceneCreatedSubscription = 0;
|
||||
|
||||
std::unordered_map<ScriptInstanceKey, ScriptInstanceState, ScriptInstanceKeyHasher> m_scriptStates;
|
||||
|
||||
Reference in New Issue
Block a user