feat(asset): modern asset system with SQLite catalog

Refactored asset management to use a persistent, thread-safe SQLite-backed AssetCatalog, replacing in-memory dictionaries.
Added AssetHandlerRegistry for O(1) handler lookup, ImportCoordinator for async background importing, and robust AssetMeta/AssetMetaIO for JSON-based metadata and settings.
Refactored AssetRegistry to integrate these components and support auto-import via file system watcher.
Updated IImportableAssetHandler for handler-specific settings and polymorphic serialization.
Added comprehensive unit tests for all new systems.
Removed obsolete code and legacy integration tests.

BREAKING CHANGE: Asset system APIs and storage format have changed; migration required for existing projects.
This commit is contained in:
2026-04-14 20:18:38 +09:00
parent d9bfa43663
commit 6615fe794e
28 changed files with 1188 additions and 1130 deletions

View File

@@ -62,7 +62,6 @@ internal static class ActivationHandler
};
AllocationManager.Initialize(opts);
TypeCache.Initialize();
//App.GetService<EngineCore>();

View File

@@ -2,6 +2,7 @@ using Ghost.Core;
using Ghost.Editor.Core;
using Ghost.Editor.Core.Contracts;
using Ghost.Editor.Core.Services;
using Ghost.Editor.Core.Utilities;
using Ghost.Editor.View.Pages.EngineEditor;
using Ghost.Editor.View.Windows;
using Ghost.Editor.ViewModels.Controls;
@@ -52,6 +53,8 @@ public partial class App : Application
{
InitializeComponent();
TypeCache.Initialize();
Host = Microsoft.Extensions.Hosting.Host.
CreateDefaultBuilder().
UseContentRoot(AppContext.BaseDirectory).
@@ -69,6 +72,31 @@ public partial class App : Application
services.AddTransient<ProjectBrowserViewModel>();
foreach (var type in TypeCache.GetTypes())
{
var data = type.GetCustomAttributesData().FirstOrDefault(a => a.AttributeType == typeof(EditorInjectionAttribute));
if (data is null)
{
continue;
}
var lifeTime = (EditorInjectionAttribute.ServiceLifetime)data.ConstructorArguments[0].Value!;
var implementationType = (Type)data.ConstructorArguments[1].Value!;
var serviceType = type.IsInterface ? type.AsType() : implementationType;
switch (lifeTime)
{
case EditorInjectionAttribute.ServiceLifetime.Singleton:
services.AddSingleton(serviceType, implementationType);
break;
case EditorInjectionAttribute.ServiceLifetime.Transient:
services.AddTransient(serviceType, implementationType);
break;
default:
break;
}
}
#region Should be deleted
services.AddTransient<ScenePage>();
@@ -119,7 +147,6 @@ public partial class App : Application
try
{
EditorApplication.Initialize(Host.Services, arguments.ProjectPath, arguments.ProjectName);
// NOTE: We must call DispatcherQueue.GetForCurrentThread() on the UI thread before any await.
EditorApplication.SetDispatcherQueue(DispatcherQueue.GetForCurrentThread());