refactor(assets): 重构资产目录系统以支持多种资源类型

- 将 AbstractAssetCatalogSystem 从 GFramework.Godot 移动到 GFramework.Game
- 引入 GameUnitId、TemplateId 和 AssetId 替代原有的 SceneId 和 ResourceId
- 更新注册与查询接口以区分不同类型资源
- 修改相关系统类以适配新的资产标识符类型
- 调整项目引用依赖关系,确保正确的程序集链接
- 扩展资源工厂系统以处理新增的资源类别
- [no tag]
This commit is contained in:
GeWuYou 2025-12-20 13:45:49 +08:00
parent 2baa29aed6
commit 2db09e72d7
14 changed files with 374 additions and 238 deletions

View File

@ -10,5 +10,7 @@
<ItemGroup>
<Folder Include="entities\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,166 @@
using GFramework.Core.system;
namespace GFramework.Game.assets;
/// <summary>
/// 资源目录系统抽象基类,用于管理和注册游戏中的场景和资源。
/// 提供了统一的接口来注册和查询不同类型的资产(如游戏单元、模板、普通资源)。
/// 子类需要实现 <see cref="RegisterAssets"/> 方法以完成具体资产的注册逻辑。
/// </summary>
public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalogSystem
{
private readonly Dictionary<string, AssetCatalog.GameUnitId> _gameUnits = new();
private readonly Dictionary<string, AssetCatalog.TemplateId> _templates = new();
private readonly Dictionary<string, AssetCatalog.AssetId> _assets = new();
/// <summary>
/// 系统初始化时调用,用于触发资产注册流程。
/// 此方法会调用抽象方法 <see cref="RegisterAssets"/>,由子类提供实际注册逻辑。
/// </summary>
protected override void OnInit()
{
RegisterAssets();
}
/// <summary>
/// 抽象方法,必须在子类中重写。用于定义具体的资产注册逻辑。
/// 在此方法中应通过调用各种 Register 方法将资产信息添加到系统中。
/// </summary>
protected abstract void RegisterAssets();
#region Register or Module 使
/// <summary>
/// 注册一个游戏单元GameUnit使用指定的键和路径。
/// </summary>
/// <param name="key">唯一标识该游戏单元的字符串键。</param>
/// <param name="path">该游戏单元对应的资源路径。</param>
/// <exception cref="InvalidOperationException">当键已存在时抛出异常。</exception>
public void RegisterGameUnit(string key, string path)
{
if (!_gameUnits.TryAdd(key, new AssetCatalog.GameUnitId(path)))
throw new InvalidOperationException($"GameUnit key duplicated: {key}");
}
/// <summary>
/// 根据映射对象注册一个游戏单元GameUnit
/// </summary>
/// <param name="mapping">包含键与ID映射关系的对象。</param>
/// <exception cref="InvalidOperationException">
/// 当映射ID不是 <see cref="AssetCatalog.GameUnitId"/> 类型或键重复时抛出异常。
/// </exception>
public void RegisterGameUnit(AssetCatalog.AssetCatalogMapping mapping)
{
if (mapping.Id is not AssetCatalog.GameUnitId sceneId)
throw new InvalidOperationException("Mapping ID is not a GameUnitId");
if (!_gameUnits.TryAdd(mapping.Key, sceneId))
throw new InvalidOperationException($"Scene key duplicated: {mapping.Key}");
}
/// <summary>
/// 注册一个模板资源Template使用指定的键和路径。
/// </summary>
/// <param name="key">唯一标识该模板的字符串键。</param>
/// <param name="path">该模板对应的资源路径。</param>
/// <exception cref="InvalidOperationException">当键已存在时抛出异常。</exception>
public void RegisterTemplate(string key, string path)
{
if (!_templates.TryAdd(key, new AssetCatalog.TemplateId(path)))
throw new InvalidOperationException($"Template key duplicated: {key}");
}
/// <summary>
/// 根据映射对象注册一个模板资源Template
/// </summary>
/// <param name="mapping">包含键与ID映射关系的对象。</param>
/// <exception cref="InvalidOperationException">
/// 当映射ID不是 <see cref="AssetCatalog.TemplateId"/> 类型或键重复时抛出异常。
/// </exception>
public void RegisterTemplate(AssetCatalog.AssetCatalogMapping mapping)
{
if (mapping.Id is not AssetCatalog.TemplateId templateId)
throw new InvalidOperationException("Mapping ID is not a TemplateId");
if (!_templates.TryAdd(mapping.Key, templateId))
throw new InvalidOperationException($"Template key duplicated: {mapping.Key}");
}
/// <summary>
/// 注册一个通用资源Asset使用指定的键和路径。
/// </summary>
/// <param name="key">唯一标识该资源的字符串键。</param>
/// <param name="path">该资源对应的资源路径。</param>
/// <exception cref="InvalidOperationException">当键已存在时抛出异常。</exception>
public void RegisterAsset(string key, string path)
{
if (!_assets.TryAdd(key, new AssetCatalog.AssetId(path)))
throw new InvalidOperationException($"Asset key duplicated: {key}");
}
/// <summary>
/// 根据映射对象注册一个通用资源Asset
/// </summary>
/// <param name="mapping">包含键与ID映射关系的对象。</param>
/// <exception cref="InvalidOperationException">
/// 当映射ID不是 <see cref="AssetCatalog.AssetId"/> 类型或键重复时抛出异常。
/// </exception>
public void RegisterAsset(AssetCatalog.AssetCatalogMapping mapping)
{
if (mapping.Id is not AssetCatalog.AssetId assetId)
throw new InvalidOperationException("Mapping ID is not a AssetId");
if (!_assets.TryAdd(mapping.Key, assetId))
throw new InvalidOperationException($"Asset key duplicated: {mapping.Key}");
}
#endregion
#region Query
/// <summary>
/// 获取指定键对应的游戏单元ID。
/// </summary>
/// <param name="key">要查找的游戏单元键。</param>
/// <returns>对应的游戏单元ID。</returns>
/// <exception cref="KeyNotFoundException">如果未找到指定键则抛出异常。</exception>
public AssetCatalog.GameUnitId GetGameUnit(string key) => _gameUnits[key];
/// <summary>
/// 获取指定键对应的模板资源ID。
/// </summary>
/// <param name="key">要查找的模板资源键。</param>
/// <returns>对应的模板资源ID。</returns>
/// <exception cref="KeyNotFoundException">如果未找到指定键则抛出异常。</exception>
public AssetCatalog.TemplateId GetTemplate(string key) => _templates[key];
/// <summary>
/// 获取指定键对应的通用资源ID。
/// </summary>
/// <param name="key">要查找的通用资源键。</param>
/// <returns>对应的通用资源ID。</returns>
/// <exception cref="KeyNotFoundException">如果未找到指定键则抛出异常。</exception>
public AssetCatalog.AssetId GetAsset(string key) => _assets[key];
/// <summary>
/// 判断是否存在指定键的游戏单元。
/// </summary>
/// <param name="key">要检查的游戏单元键。</param>
/// <returns>若存在返回 true否则返回 false。</returns>
public bool HasGameUnit(string key) => _gameUnits.ContainsKey(key);
/// <summary>
/// 判断是否存在指定键的模板资源。
/// </summary>
/// <param name="key">要检查的模板资源键。</param>
/// <returns>若存在返回 true否则返回 false。</returns>
public bool HasTemplate(string key) => _templates.ContainsKey(key);
/// <summary>
/// 判断是否存在指定键的通用资源。
/// </summary>
/// <param name="key">要检查的通用资源键。</param>
/// <returns>若存在返回 true否则返回 false。</returns>
public bool HasAsset(string key) => _assets.ContainsKey(key);
#endregion
}

View File

@ -1,5 +1,5 @@

namespace GFramework.Godot.system;
namespace GFramework.Game.assets;
/// <summary>
/// 资源目录类,用于定义和管理游戏中的场景和资源标识符
@ -23,17 +23,23 @@ public static class AssetCatalog
/// <param name="Key">资源目录的键</param>
/// <param name="Id">资源标识符</param>
public readonly record struct AssetCatalogMapping(string Key, IAssetId Id);
/// <summary>
/// 场景标识符结构体,用于唯一标识一个场景资源
/// 模板资源标识符结构体实现IAssetId接口
/// </summary>
/// <param name="Path">场景资源路径</param>
public readonly record struct SceneId(string Path) : IAssetId;
/// <param name="Path">资源路径</param>
public readonly record struct TemplateId(string Path) : IAssetId;
/// <summary>
/// 资源标识符结构体,用于唯一标识一个游戏资源
/// 游戏单位资源标识符结构体实现IAssetId接口
/// </summary>
/// <param name="Path">游戏资源的路径</param>
public readonly record struct ResourceId(string Path) : IAssetId;
/// <param name="Path">资源路径</param>
public readonly record struct GameUnitId(string Path) : IAssetId;
/// <summary>
/// 通用资源标识符结构体实现IAssetId接口
/// </summary>
/// <param name="Path">资源路径</param>
public readonly record struct AssetId(string Path) : IAssetId;
}

View File

@ -0,0 +1,91 @@
using GFramework.Core.system;
namespace GFramework.Game.assets;
/// <summary>
/// 资源目录系统接口,用于管理场景和资源的获取与查询
/// </summary>
public interface IAssetCatalogSystem : ISystem
{
/// <summary>
/// 根据指定的键获取游戏单位ID
/// </summary>
/// <param name="key">用于查找游戏单位的键值</param>
/// <returns>返回对应的游戏单位ID如果未找到则返回默认值</returns>
AssetCatalog.GameUnitId GetGameUnit(string key);
/// <summary>
/// 根据指定的键获取模板ID
/// </summary>
/// <param name="key">用于查找模板的键值</param>
/// <returns>返回对应的模板ID如果未找到则返回默认值</returns>
AssetCatalog.TemplateId GetTemplate(string key);
/// <summary>
/// 根据指定的键获取资源ID
/// </summary>
/// <param name="key">用于查找资源的键值</param>
/// <returns>返回对应的资源ID如果未找到则返回默认值</returns>
AssetCatalog.AssetId GetAsset(string key);
/// <summary>
/// 注册游戏单位资源到资产目录中
/// </summary>
/// <param name="key">游戏单位的唯一标识键值</param>
/// <param name="path">游戏单位资源的路径</param>
void RegisterGameUnit(string key, string path);
/// <summary>
/// 根据映射配置注册游戏单位资源到资产目录中
/// </summary>
/// <param name="mapping">包含键值和路径映射关系的配置对象</param>
void RegisterGameUnit(AssetCatalog.AssetCatalogMapping mapping);
/// <summary>
/// 注册模板资源到资产目录中
/// </summary>
/// <param name="key">模板的唯一标识键值</param>
/// <param name="path">模板资源的路径</param>
void RegisterTemplate(string key, string path);
/// <summary>
/// 根据映射配置注册模板资源到资产目录中
/// </summary>
/// <param name="mapping">包含键值和路径映射关系的配置对象</param>
void RegisterTemplate(AssetCatalog.AssetCatalogMapping mapping);
/// <summary>
/// 注册普通资产资源到资产目录中
/// </summary>
/// <param name="key">资产的唯一标识键值</param>
/// <param name="path">资产资源的路径</param>
void RegisterAsset(string key, string path);
/// <summary>
/// 根据映射配置注册普通资产资源到资产目录中
/// </summary>
/// <param name="mapping">包含键值和路径映射关系的配置对象</param>
void RegisterAsset(AssetCatalog.AssetCatalogMapping mapping);
/// <summary>
/// 检查是否存在指定键的游戏单位
/// </summary>
/// <param name="key">用于查找游戏单位的键值</param>
/// <returns>存在返回true否则返回false</returns>
bool HasGameUnit(string key);
/// <summary>
/// 检查是否存在指定键的模板
/// </summary>
/// <param name="key">用于查找模板的键值</param>
/// <returns>存在返回true否则返回false</returns>
bool HasTemplate(string key);
/// <summary>
/// 检查是否存在指定键的资源
/// </summary>
/// <param name="key">用于查找资源的键值</param>
/// <returns>存在返回true否则返回false</returns>
bool HasAsset(string key);
}

View File

@ -1,6 +1,6 @@
using GFramework.Core.system;
namespace GFramework.Godot.system;
namespace GFramework.Game.assets;
/// <summary>
/// 资源工厂系统接口,用于获取指定类型的资源创建函数

View File

@ -1,4 +1,4 @@
namespace GFramework.Godot.system;
namespace GFramework.Game.assets;
/// <summary>
/// 资源工厂类,用于注册和解析各种资源的创建工厂
@ -68,7 +68,7 @@ public static class ResourceFactory
/// <summary>
/// 工厂注册表,管理所有已注册的资源工厂
/// </summary>
internal sealed class Registry
public sealed class Registry
{
/// <summary>
/// 存储所有已注册的工厂函数,键为资源类型,值为对应的工厂条目对象

View File

@ -14,7 +14,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj" />
<ProjectReference Include="..\GFramework.Game\GFramework.Game.csproj" />
</ItemGroup>

View File

@ -1,117 +0,0 @@
using GFramework.Core.system;
namespace GFramework.Godot.system;
/// <summary>
/// 资源目录系统抽象基类,用于管理和注册游戏中的场景和资源
/// </summary>
public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalogSystem
{
private readonly Dictionary<string, AssetCatalog.SceneId> _scenes = new();
private readonly Dictionary<string, AssetCatalog.ResourceId> _resources = new();
/// <summary>
/// 系统初始化时调用,用于注册所有资产
/// </summary>
protected override void OnInit()
{
RegisterAssets();
}
/// <summary>
/// 抽象方法,由子类实现具体的资产注册逻辑
/// </summary>
protected abstract void RegisterAssets();
#region Register or Module 使
/// <summary>
/// 注册场景资源
/// </summary>
/// <param name="key">场景的唯一标识键</param>
/// <param name="path">场景资源的路径</param>
/// <exception cref="InvalidOperationException">当场景键已存在时抛出异常</exception>
public void RegisterScene(string key, string path)
{
if (_scenes.ContainsKey(key))
throw new InvalidOperationException($"Scene key duplicated: {key}");
_scenes[key] = new AssetCatalog.SceneId(path);
}
/// <summary>
/// 注册场景资源
/// </summary>
/// <param name="mapping">包含键和场景标识符的映射对象</param>
/// <exception cref="InvalidOperationException">当场景键已存在时抛出异常</exception>
public void RegisterScene(AssetCatalog.AssetCatalogMapping mapping)
{
if (mapping.Id is not AssetCatalog.SceneId sceneId)
throw new InvalidOperationException("Mapping ID is not a SceneId");
if (!_scenes.TryAdd(mapping.Key, sceneId))
throw new InvalidOperationException($"Scene key duplicated: {mapping.Key}");
}
/// <summary>
/// 注册普通资源
/// </summary>
/// <param name="key">资源的唯一标识键</param>
/// <param name="path">资源的路径</param>
/// <exception cref="InvalidOperationException">当资源键已存在时抛出异常</exception>
public void RegisterResource(string key, string path)
{
if (_resources.ContainsKey(key))
throw new InvalidOperationException($"Resource key duplicated: {key}");
_resources[key] = new AssetCatalog.ResourceId(path);
}
/// <summary>
/// 注册普通资源
/// </summary>
/// <param name="mapping">包含键和资源标识符的映射对象</param>
/// <exception cref="InvalidOperationException">当资源键已存在时抛出异常</exception>
public void RegisterResource(AssetCatalog.AssetCatalogMapping mapping)
{
if (mapping.Id is not AssetCatalog.ResourceId resourceId)
throw new InvalidOperationException("Mapping ID is not a ResourceId");
if (!_resources.TryAdd(mapping.Key, resourceId))
throw new InvalidOperationException($"Resource key duplicated: {mapping.Key}");
}
#endregion
#region Query
/// <summary>
/// 根据键获取场景ID
/// </summary>
/// <param name="key">场景的唯一标识键</param>
/// <returns>对应的场景ID</returns>
public AssetCatalog.SceneId GetScene(string key) => _scenes[key];
/// <summary>
/// 根据键获取资源ID
/// </summary>
/// <param name="key">资源的唯一标识键</param>
/// <returns>对应的资源ID</returns>
public AssetCatalog.ResourceId GetResource(string key) => _resources[key];
/// <summary>
/// 检查是否存在指定键的场景
/// </summary>
/// <param name="key">场景的唯一标识键</param>
/// <returns>如果存在返回true否则返回false</returns>
public bool HasScene(string key) => _scenes.ContainsKey(key);
/// <summary>
/// 检查是否存在指定键的资源
/// </summary>
/// <param name="key">资源的唯一标识键</param>
/// <returns>如果存在返回true否则返回false</returns>
public bool HasResource(string key) => _resources.ContainsKey(key);
#endregion
}

View File

@ -1,5 +1,6 @@
using GFramework.Core.extensions;
using GFramework.Core.system;
using GFramework.Game.assets;
using Godot;
namespace GFramework.Godot.system;
@ -179,7 +180,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
/// <param name="musicId">音乐资源ID</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="loop">是否循环播放</param>
public virtual void PlayMusic(AssetCatalog.ResourceId musicId, float volume = 1.0f, bool loop = true)
public virtual void PlayMusic(AssetCatalog.AssetId musicId, float volume = 1.0f, bool loop = true)
{
PlayMusic(musicId.Path, volume, loop);
}
@ -266,7 +267,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
/// <param name="soundId">音效资源ID</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlaySound(AssetCatalog.ResourceId soundId, float volume = 1.0f, float pitch = 1.0f)
public virtual void PlaySound(AssetCatalog.AssetId soundId, float volume = 1.0f, float pitch = 1.0f)
{
PlaySound(soundId.Path, volume, pitch);
}

View File

@ -1,3 +1,5 @@
using GFramework.Game.assets;
namespace GFramework.Godot.system;
/// <summary>

View File

@ -1,11 +1,11 @@
using GFramework.Core.events;
using GFramework.Core.extensions;
using GFramework.Core.system;
using GFramework.Game.assets;
using Godot;
namespace GFramework.Godot.system;
/// <summary>
/// 资源工厂系统抽象基类,用于统一管理各类资源的创建与预加载逻辑。
/// 提供注册场景和资源的方法,并通过依赖的资源加载系统和资产目录系统完成实际资源的获取与构造。
@ -15,7 +15,7 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
private ResourceFactory.Registry? _registry;
private IResourceLoadSystem? _resourceLoadSystem;
private IAssetCatalogSystem? _assetCatalogSystem;
/// <summary>
/// 系统初始化方法,在系统启动时执行一次。
/// 初始化资源注册表,并获取依赖的资源加载系统和资产目录系统。
@ -35,11 +35,12 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
_registry.PreloadAll();
});
}
/// <summary>
/// 注册系统所需的各种资源类型。由子类实现具体注册逻辑。
/// </summary>
protected abstract void RegisterResources();
/// <summary>
/// 根据指定的键获取资源工厂函数。
@ -47,8 +48,8 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
/// <typeparam name="T">资源类型</typeparam>
/// <param name="key">资源键</param>
/// <returns>返回创建指定类型资源的工厂函数</returns>
public Func<T> GetFactory<T>(string key)=>_registry!.ResolveFactory<T>(key);
public Func<T> GetFactory<T>(string key) => _registry!.ResolveFactory<T>(key);
/// <summary>
/// 根据资产目录映射信息获取资源工厂函数。
/// </summary>
@ -58,52 +59,67 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
public Func<T> GetFactory<T>(AssetCatalog.AssetCatalogMapping mapping) => _registry!.ResolveFactory<T>(mapping.Key);
#region Register Helpers
/// <summary>
/// 注册场景资源工厂。
/// 根据场景键名获取场景ID并将场景加载工厂注册到注册表中。
/// 注册游戏单位资源到资源管理系统中
/// </summary>
/// <typeparam name="T">场景节点类型必须继承自Node</typeparam>
/// <param name="sceneKey">场景在资产目录中的键名</param>
/// <param name="preload">是否需要预加载该场景资源</param>
protected void RegisterScene<T>(
/// <typeparam name="T">游戏单位类型必须继承自Node</typeparam>
/// <param name="sceneKey">场景键值,用于标识特定的游戏单位资源</param>
/// <param name="preload">是否预加载该资源默认为false</param>
public void RegisterGameUnit<T>(
string sceneKey,
bool preload = false)
where T : Node
{
var id = _assetCatalogSystem!.GetScene(sceneKey);
var id = _assetCatalogSystem!.GetGameUnit(sceneKey);
_registry!.Register(
sceneKey,
_resourceLoadSystem!.GetOrRegisterSceneFactory<T>(id),
_resourceLoadSystem!.GetOrRegisterGameUnitFactory<T>(id),
preload
);
}
/// <summary>
/// 注册普通资源工厂。
/// 根据资源键名获取资源ID并将资源加载工厂注册到注册表中。
/// 注册模板资源到资源管理系统中
/// </summary>
/// <typeparam name="T">资源类型必须继承自Resource</typeparam>
/// <param name="resourceKey">资源在资产目录中的键名</param>
/// <param name="duplicate">是否需要复制资源实例</param>
/// <param name="preload">是否需要预加载该资源</param>
protected void RegisterResource<T>(
string resourceKey,
bool duplicate = false,
/// <typeparam name="T">模板类型必须继承自Node</typeparam>
/// <param name="templateKey">模板键值,用于标识特定的模板资源</param>
/// <param name="preload">是否预加载该资源默认为false</param>
public void RegisterTemplate<T>(
string templateKey,
bool preload = false)
where T : Node
{
var id = _assetCatalogSystem!.GetTemplate(templateKey);
_registry!.Register(
templateKey,
_resourceLoadSystem!.GetOrRegisterTemplateFactory<T>(id),
preload
);
}
/// <summary>
/// 注册通用资产资源到资源管理系统中
/// </summary>
/// <typeparam name="T">资产类型必须继承自Resource</typeparam>
/// <param name="assetKey">资产键值,用于标识特定的资产资源</param>
/// <param name="preload">是否预加载该资源默认为false</param>
public void RegisterAsset<T>(
string assetKey,
bool preload = false)
where T : Resource
{
var id = _assetCatalogSystem!.GetResource(resourceKey);
var id = _assetCatalogSystem!.GetAsset(assetKey);
_registry!.Register(
resourceKey,
_resourceLoadSystem!.GetOrRegisterResourceFactory<T>(id, duplicate),
assetKey,
_resourceLoadSystem!.GetOrRegisterAssetFactory<T>(id),
preload
);
}
#endregion
}
}

View File

@ -1,37 +0,0 @@
using GFramework.Core.system;
namespace GFramework.Godot.system;
/// <summary>
/// 资源目录系统接口,用于管理场景和资源的获取与查询
/// </summary>
public interface IAssetCatalogSystem : ISystem
{
/// <summary>
/// 根据键名获取场景标识符
/// </summary>
/// <param name="key">场景的唯一键名</param>
/// <returns>返回对应的场景ID</returns>
AssetCatalog.SceneId GetScene(string key);
/// <summary>
/// 根据键名获取资源标识符
/// </summary>
/// <param name="key">资源的唯一键名</param>
/// <returns>返回对应的资源ID</returns>
AssetCatalog.ResourceId GetResource(string key);
/// <summary>
/// 检查是否存在指定键名的场景
/// </summary>
/// <param name="key">要检查的场景键名</param>
/// <returns>如果存在返回true否则返回false</returns>
bool HasScene(string key);
/// <summary>
/// 检查是否存在指定键名的资源
/// </summary>
/// <param name="key">要检查的资源键名</param>
/// <returns>如果存在返回true否则返回false</returns>
bool HasResource(string key);
}

View File

@ -1,4 +1,5 @@
using GFramework.Core.system;
using GFramework.Game.assets;
using Godot;
namespace GFramework.Godot.system;
@ -22,6 +23,7 @@ public interface IResourceLoadSystem : ISystem
/// <param name="path">场景路径</param>
/// <returns>场景的延迟加载包装器</returns>
public Lazy<PackedScene> GetSceneLoader(string path);
/// <summary>
/// 创建指定路径场景的实例
/// </summary>
@ -30,24 +32,37 @@ public interface IResourceLoadSystem : ISystem
/// <returns>场景实例化的节点对象</returns>
public T? CreateInstance<T>(string path) where T : Node;
/// <summary>
/// 获取或注册场景工厂函数
/// 获取或注册游戏单位工厂函数
/// </summary>
/// <typeparam name="T">节点类型必须继承自Node</typeparam>
/// <param name="id">场景资源标识符</param>
/// <returns>创建场景实例的工厂函数</returns>
public Func<T> GetOrRegisterSceneFactory<T>(AssetCatalog.SceneId id) where T : Node;
Func<T> GetOrRegisterGameUnitFactory<T>(
AssetCatalog.GameUnitId id
) where T : Node;
/// <summary>
/// 获取或注册资源工厂函数
/// 获取或注册模板资源工厂函数
/// </summary>
/// <typeparam name="T">资源类型必须继承自Node</typeparam>
/// <param name="id">资源标识符</param>
/// <param name="duplicate">是否创建副本默认为false</param>
/// <returns>创建资源实例的工厂函数</returns>
public Func<T> GetOrRegisterResourceFactory<T>(AssetCatalog.ResourceId id, bool duplicate = false)
where T : Resource;
/// <typeparam name="T">节点类型必须继承自Node</typeparam>
/// <param name="id">模板资源标识符</param>
/// <returns>创建模板实例的工厂函数</returns>
Func<T> GetOrRegisterTemplateFactory<T>(
AssetCatalog.TemplateId id
) where T : Node;
/// <summary>
/// 获取或注册通用资产工厂函数
/// </summary>
/// <typeparam name="T">资源类型必须继承自Resource</typeparam>
/// <param name="id">资产资源标识符</param>
/// <param name="duplicate">是否对原始资源进行复制操作默认为false</param>
/// <returns>创建资产实例的工厂函数</returns>
Func<T> GetOrRegisterAssetFactory<T>(
AssetCatalog.AssetId id,
bool duplicate = false
) where T : Resource;
/// <summary>
/// 预加载指定路径的多个资源

View File

@ -1,4 +1,5 @@
using GFramework.Core.system;
using GFramework.Game.assets;
using Godot;
namespace GFramework.Godot.system;
@ -85,9 +86,7 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
}
#endregion
#region
/// <summary>
/// 根据给定路径加载场景,并创建其节点实例。
/// </summary>
@ -100,16 +99,7 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
return scene.Instantiate<T>();
}
/// <summary>
/// 注册或获取一个用于创建特定场景实例的工厂函数。
/// 如果已存在相同路径的工厂函数,则尝试转换后复用。
/// </summary>
/// <typeparam name="T">目标场景根节点的类型。</typeparam>
/// <param name="id">场景文件的id。</param>
/// <returns>用于创建该场景实例的Func委托。</returns>
/// <exception cref="InvalidCastException">当已有工厂不是Func&lt;T&gt;类型时抛出。</exception>
/// <exception cref="InvalidOperationException">当无法加载场景或实例化失败时抛出。</exception>
public Func<T> GetOrRegisterSceneFactory<T>(AssetCatalog.SceneId id) where T : Node
public Func<T> GetOrRegisterGameUnitFactory<T>(AssetCatalog.GameUnitId id) where T : Node
{
var path = id.Path;
if (_sceneFactories.TryGetValue(path, out var d))
@ -129,22 +119,27 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
return factory;
}
#endregion
public Func<T> GetOrRegisterTemplateFactory<T>(AssetCatalog.TemplateId id) where T : Node
{
var path = id.Path;
if (_sceneFactories.TryGetValue(path, out var d))
return d as Func<T> ??
throw new InvalidCastException($"Factory for path '{path}' is not of type Func<{typeof(T)}>");
#region
var factory = () =>
{
var scene = GetSceneLoader(path).Value
?? throw new InvalidOperationException($"Scene not loaded: {path}");
/// <summary>
/// 注册或获取一个用于加载或复制资源的工厂函数。
/// 可选择是否每次调用都返回副本Duplicate适用于需要独立状态的资源。
/// </summary>
/// <typeparam name="T">资源的具体类型。</typeparam>
/// <param name="id">资源文件的id。</param>
/// <param name="duplicate">是否每次都返回资源的一个副本默认为false。</param>
/// <returns>用于加载或复制资源的Func委托。</returns>
/// <exception cref="InvalidCastException">当已有工厂不是Func&lt;T&gt;类型时抛出。</exception>
/// <exception cref="InvalidOperationException">当资源加载失败时抛出。</exception>
public Func<T> GetOrRegisterResourceFactory<T>(AssetCatalog.ResourceId id, bool duplicate = false)
where T : Resource
return scene.Instantiate<T>()
?? throw new InvalidOperationException($"Instantiate failed: {path}");
};
_sceneFactories[path] = factory;
return factory;
}
public Func<T> GetOrRegisterAssetFactory<T>(AssetCatalog.AssetId id, bool duplicate = false) where T : Resource
{
var path = id.Path;
if (_resourceFactories.TryGetValue(path, out var d))
@ -164,9 +159,6 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
_resourceFactories[path] = factory;
return factory;
}
#endregion
#region
/// <summary>