style(csharp): 统一代码格式化规范并优化方法实现

- 调整注释格式统一使用4个空格缩进
- 重新排列字段声明顺序提升代码可读性
- 将简单属性访问器改为表达式主体语法
- 优化AudioManagerSystem中音量设置逻辑
- 移除AbstractAssetCatalogSystem中多余空行
- 重构日志类中方法实现为表达式主体形式
- 统一空行分隔符保持代码结构一致性
- 优化方法内部逻辑表达式简化代码
- [no tag]
This commit is contained in:
GeWuYou 2025-12-26 13:50:14 +08:00
parent 378690a42c
commit 017870421e
74 changed files with 1519 additions and 1404 deletions

View File

@ -8,9 +8,9 @@ using GFramework.Core.utility;
namespace GFramework.Core.architecture;
/// <summary>
/// 架构基类,提供系统、模型、工具等组件的注册与管理功能。
/// 专注于生命周期管理、初始化流程控制和架构阶段转换。
/// 不直接提供业务操作方法,业务操作通过 ArchitectureRuntime 提供。
/// 架构基类,提供系统、模型、工具等组件的注册与管理功能。
/// 专注于生命周期管理、初始化流程控制和架构阶段转换。
/// 不直接提供业务操作方法,业务操作通过 ArchitectureRuntime 提供。
/// </summary>
public abstract class Architecture(
IArchitectureConfiguration? configuration = null,
@ -20,49 +20,49 @@ public abstract class Architecture(
: IArchitecture, IArchitectureLifecycle
{
/// <summary>
/// 获取架构配置对象
/// 获取架构配置对象
/// </summary>
/// <value>
/// 返回一个IArchitectureConfiguration接口的实例默认为DefaultArchitectureConfiguration类型
/// 返回一个IArchitectureConfiguration接口的实例默认为DefaultArchitectureConfiguration类型
/// </value>
private IArchitectureConfiguration Configuration { get; } = configuration ?? new ArchitectureConfiguration();
/// <summary>
/// 获取架构服务对象
/// 获取架构服务对象
/// </summary>
/// <value>
/// 返回一个IArchitectureServices接口的实例默认为DefaultArchitectureServices类型
/// 返回一个IArchitectureServices接口的实例默认为DefaultArchitectureServices类型
/// </value>
private IArchitectureServices Services { get; } = services ?? new ArchitectureServices();
/// <summary>
/// 获取依赖注入容器
/// 获取依赖注入容器
/// </summary>
/// <value>
/// 通过Services属性获取的IArchitectureServices中的Container属性
/// 通过Services属性获取的IArchitectureServices中的Container属性
/// </value>
private IIocContainer Container => Services.Container;
/// <summary>
/// 获取类型事件系统
/// 获取类型事件系统
/// </summary>
/// <value>
/// 通过Services属性获取的IArchitectureServices中的TypeEventSystem属性
/// 通过Services属性获取的IArchitectureServices中的TypeEventSystem属性
/// </value>
private ITypeEventSystem TypeEventSystem => Services.TypeEventSystem;
/// <summary>
/// 获取架构运行时实例
/// 获取架构运行时实例
/// </summary>
/// <value>
/// 统一的操作入口,负责命令、查询、事件的执行
/// 统一的操作入口,负责命令、查询、事件的执行
/// </value>
public IArchitectureRuntime Runtime { get; private set; } = null!;
#region Module Management
/// <summary>
/// 安装架构模块
/// 安装架构模块
/// </summary>
/// <param name="module">要安装的模块</param>
public void InstallModule(IArchitectureModule module)
@ -80,7 +80,7 @@ public abstract class Architecture(
#region IArchitectureLifecycle Implementation
/// <summary>
/// 处理架构阶段变更通知
/// 处理架构阶段变更通知
/// </summary>
/// <param name="phase">当前架构阶段</param>
/// <param name="architecture">架构实例</param>
@ -123,7 +123,7 @@ public abstract class Architecture(
private ArchitecturePhase CurrentPhase { get; set; }
/// <summary>
/// 日志记录器实例,用于记录应用程序的运行日志
/// 日志记录器实例,用于记录应用程序的运行日志
/// </summary>
private ILogger _logger = null!;
@ -136,7 +136,7 @@ public abstract class Architecture(
#region Lifecycle Management
/// <summary>
/// 进入指定的架构阶段,并执行相应的生命周期管理操作
/// 进入指定的架构阶段,并执行相应的生命周期管理操作
/// </summary>
/// <param name="next">要进入的下一个架构阶段</param>
/// <exception cref="InvalidOperationException">当阶段转换不被允许时抛出异常</exception>
@ -156,10 +156,7 @@ public abstract class Architecture(
var previousPhase = CurrentPhase;
CurrentPhase = next;
if (previousPhase != next)
{
logger.Info($"Architecture phase changed: {previousPhase} -> {next}");
}
if (previousPhase != next) logger.Info($"Architecture phase changed: {previousPhase} -> {next}");
NotifyPhase(next);
@ -172,7 +169,7 @@ public abstract class Architecture(
}
/// <summary>
/// 通知所有生命周期钩子当前阶段变更
/// 通知所有生命周期钩子当前阶段变更
/// </summary>
/// <param name="phase">当前架构阶段</param>
private void NotifyPhase(ArchitecturePhase phase)
@ -182,7 +179,7 @@ public abstract class Architecture(
}
/// <summary>
/// 注册生命周期钩子
/// 注册生命周期钩子
/// </summary>
/// <param name="hook">生命周期钩子实例</param>
public void RegisterLifecycleHook(IArchitectureLifecycle hook)
@ -200,11 +197,11 @@ public abstract class Architecture(
protected abstract void Init();
/// <summary>
/// 销毁架构并清理所有系统资源
/// 销毁架构并清理所有系统资源
/// </summary>
/// <remarks>
/// 此函数负责有序地销毁架构中的所有系统组件,并发送相应的生命周期事件。
/// 函数会确保只执行一次销毁操作,避免重复销毁。
/// 此函数负责有序地销毁架构中的所有系统组件,并发送相应的生命周期事件。
/// 函数会确保只执行一次销毁操作,避免重复销毁。
/// </remarks>
public virtual void Destroy()
{
@ -368,7 +365,9 @@ public abstract class Architecture(
Container.RegisterPlurality(system);
_allSystems.Add(system);
if (!_mInited)
{
_mSystems.Add(system);
}
else
{
_logger.Debug($"Immediately initializing system: {typeof(TSystem).Name}");
@ -400,7 +399,9 @@ public abstract class Architecture(
Container.RegisterPlurality(model);
if (!_mInited)
{
_mModels.Add(model);
}
else
{
_logger.Debug($"Immediately initializing model: {typeof(TModel).Name}");

View File

@ -3,26 +3,26 @@
namespace GFramework.Core.architecture;
/// <summary>
/// 默认架构配置类实现IArchitectureConfiguration接口
/// 提供日志工厂、日志级别和架构选项的默认配置
/// 默认架构配置类实现IArchitectureConfiguration接口
/// 提供日志工厂、日志级别和架构选项的默认配置
/// </summary>
public class ArchitectureConfiguration: IArchitectureConfiguration
public class ArchitectureConfiguration : IArchitectureConfiguration
{
/// <summary>
/// 获取或设置日志工厂实例
/// 默认使用控制台日志工厂
/// </summary>
public ILoggerFactory LoggerFactory { get; set; } = new ConsoleLoggerFactory();
/// <summary>
/// 获取或设置日志级别
/// 默认设置为Info级别
/// 获取或设置日志级别
/// 默认设置为Info级别
/// </summary>
public LogLevel LogLevel { get; set; } = LogLevel.Info;
/// <summary>
/// 获取或设置架构选项
/// 默认创建新的ArchitectureOptions实例
/// 获取或设置日志工厂实例
/// 默认使用控制台日志工厂
/// </summary>
public ILoggerFactory LoggerFactory { get; set; } = new ConsoleLoggerFactory();
/// <summary>
/// 获取或设置架构选项
/// 默认创建新的ArchitectureOptions实例
/// </summary>
public ArchitectureOptions Options { get; set; } = new();
}
}

View File

@ -1,5 +1,4 @@

using System.Collections.Immutable;
using System.Collections.Immutable;
namespace GFramework.Core.architecture;

View File

@ -10,7 +10,7 @@ using GFramework.Core.utility;
namespace GFramework.Core.architecture;
/// <summary>
/// 架构上下文类,提供对系统、模型、工具等组件的访问以及命令、查询、事件的执行管理
/// 架构上下文类,提供对系统、模型、工具等组件的访问以及命令、查询、事件的执行管理
/// </summary>
public class ArchitectureContext(
IIocContainer container,

View File

@ -1,7 +1,7 @@
namespace GFramework.Core.architecture;
/// <summary>
/// 架构选项配置类,用于定义架构行为的相关配置选项
/// 架构选项配置类,用于定义架构行为的相关配置选项
/// </summary>
public sealed class ArchitectureOptions(
bool strictPhaseValidation = true,
@ -9,12 +9,12 @@ public sealed class ArchitectureOptions(
)
{
/// <summary>
/// 严格阶段验证开关当设置为true时启用严格的阶段验证机制
/// </summary>
public bool StrictPhaseValidation = strictPhaseValidation;
/// <summary>
/// 允许延迟注册开关当设置为true时允许在初始化完成后进行组件注册
/// 允许延迟注册开关当设置为true时允许在初始化完成后进行组件注册
/// </summary>
public bool AllowLateRegistration = allowLateRegistration;
/// <summary>
/// 严格阶段验证开关当设置为true时启用严格的阶段验证机制
/// </summary>
public bool StrictPhaseValidation = strictPhaseValidation;
}

View File

@ -1,49 +1,51 @@
namespace GFramework.Core.architecture;
/// <summary>
/// 架构阶段枚举,定义了系统架构初始化和运行过程中的各个关键阶段
/// 架构阶段枚举,定义了系统架构初始化和运行过程中的各个关键阶段
/// </summary>
/// <remarks>
/// 该枚举用于标记和控制系统架构组件的生命周期,确保在正确的时机执行相应的初始化和处理逻辑。
/// 各个阶段按照时间顺序排列,从创建到准备就绪的完整流程。
/// 该枚举用于标记和控制系统架构组件的生命周期,确保在正确的时机执行相应的初始化和处理逻辑。
/// 各个阶段按照时间顺序排列,从创建到准备就绪的完整流程。
/// </remarks>
public enum ArchitecturePhase
{
/// <summary>
/// 无效阶段,表示未定义的阶段
/// 无效阶段,表示未定义的阶段
/// </summary>
None = 0,
/// <summary>
/// 模型初始化之前阶段
/// 模型初始化之前阶段
/// </summary>
BeforeModelInit,
/// <summary>
/// 模型初始化之后阶段
/// 模型初始化之后阶段
/// </summary>
AfterModelInit,
/// <summary>
/// 系统初始化之前阶段
/// 系统初始化之前阶段
/// </summary>
BeforeSystemInit,
/// <summary>
/// 系统初始化之后阶段
/// 系统初始化之后阶段
/// </summary>
AfterSystemInit,
/// <summary>
/// 就绪阶段,完成冻结和事件处理后的最终状态
/// 就绪阶段,完成冻结和事件处理后的最终状态
/// </summary>
Ready,
/// <summary>
/// 正在销毁中 暂时不使用
/// 正在销毁中 暂时不使用
/// </summary>
Destroying,
/// <summary>
/// 已销毁 暂时不使用
/// 已销毁 暂时不使用
/// </summary>
Destroyed
}
}

View File

@ -5,12 +5,27 @@ using GFramework.Core.query;
namespace GFramework.Core.architecture;
/// <summary>
/// 架构运行时默认实现,委托 ArchitectureContext 执行具体操作
/// 架构运行时默认实现,委托 ArchitectureContext 执行具体操作
/// </summary>
public class ArchitectureRuntime(IArchitectureContext context) : IArchitectureRuntime
{
private readonly IArchitectureContext _context = context ?? throw new ArgumentNullException(nameof(context));
#region Query Execution
/// <summary>
/// 发起一次查询请求并获得其结果
/// </summary>
/// <typeparam name="TResult">查询结果的数据类型</typeparam>
/// <param name="query">要发起的查询对象</param>
/// <returns>查询得到的结果数据</returns>
public TResult SendQuery<TResult>(IQuery<TResult> query)
{
return _context.SendQuery(query);
}
#endregion
#region Command Execution
/// <summary>
@ -36,21 +51,6 @@ public class ArchitectureRuntime(IArchitectureContext context) : IArchitectureRu
#endregion
#region Query Execution
/// <summary>
/// 发起一次查询请求并获得其结果
/// </summary>
/// <typeparam name="TResult">查询结果的数据类型</typeparam>
/// <param name="query">要发起的查询对象</param>
/// <returns>查询得到的结果数据</returns>
public TResult SendQuery<TResult>(IQuery<TResult> query)
{
return _context.SendQuery(query);
}
#endregion
#region Event Management
/// <summary>

View File

@ -1,10 +1,9 @@

using GFramework.Core.events;
using GFramework.Core.events;
using GFramework.Core.ioc;
namespace GFramework.Core.architecture;
public class ArchitectureServices: IArchitectureServices
public class ArchitectureServices : IArchitectureServices
{
public IIocContainer Container { get; } = new IocContainer();
public ITypeEventSystem TypeEventSystem { get; } = new TypeEventSystem();

View File

@ -1,8 +1,4 @@
using GFramework.Core.architecture;
using GFramework.Core.command;
using GFramework.Core.events;
using GFramework.Core.model;
using GFramework.Core.query;
using GFramework.Core.model;
using GFramework.Core.system;
using GFramework.Core.utility;
@ -12,64 +8,64 @@ namespace GFramework.Core.architecture;
/// 架构接口,专注于生命周期管理,包括系统、模型、工具的注册和获取
/// 业务操作通过 ArchitectureRuntime 提供
/// </summary>
public interface IArchitecture: IAsyncInitializable
public interface IArchitecture : IAsyncInitializable
{
/// <summary>
/// 初始化方法,用于执行对象的初始化操作
/// 获取架构上下文
/// </summary>
IArchitectureContext Context { get; }
/// <summary>
/// 获取架构运行时实例
/// </summary>
IArchitectureRuntime Runtime { get; }
/// <summary>
/// 初始化方法,用于执行对象的初始化操作
/// </summary>
/// <remarks>
/// 该方法通常用于设置初始状态、初始化成员变量或执行必要的预处理操作
/// 该方法通常用于设置初始状态、初始化成员变量或执行必要的预处理操作
/// </remarks>
void Initialize();
/// <summary>
/// 销毁方法,用于执行对象的清理和销毁操作
/// 销毁方法,用于执行对象的清理和销毁操作
/// </summary>
/// <remarks>
/// 该方法通常用于释放资源、清理内存或执行必要的清理操作
/// 该方法通常用于释放资源、清理内存或执行必要的清理操作
/// </remarks>
void Destroy();
/// <summary>
/// 注册系统实例到架构中
/// 注册系统实例到架构中
/// </summary>
/// <typeparam name="T">系统类型必须实现ISystem接口</typeparam>
/// <param name="system">要注册的系统实例</param>
void RegisterSystem<T>(T system) where T : ISystem;
/// <summary>
/// 注册模型实例到架构中
/// 注册模型实例到架构中
/// </summary>
/// <typeparam name="T">模型类型必须实现IModel接口</typeparam>
/// <param name="model">要注册的模型实例</param>
void RegisterModel<T>(T model) where T : IModel;
/// <summary>
/// 注册工具实例到架构中
/// 注册工具实例到架构中
/// </summary>
/// <typeparam name="T">工具类型必须实现IUtility接口</typeparam>
/// <param name="utility">要注册的工具实例</param>
void RegisterUtility<T>(T utility) where T : IUtility;
/// <summary>
/// 安装架构模块
/// 安装架构模块
/// </summary>
/// <param name="module">要安装的模块</param>
void InstallModule(IArchitectureModule module);
/// <summary>
/// 注册生命周期钩子
/// 注册生命周期钩子
/// </summary>
/// <param name="hook">生命周期钩子实例</param>
void RegisterLifecycleHook(IArchitectureLifecycle hook);
/// <summary>
/// 获取架构上下文
/// </summary>
IArchitectureContext Context { get; }
/// <summary>
/// 获取架构运行时实例
/// </summary>
IArchitectureRuntime Runtime { get; }
}

View File

@ -3,17 +3,17 @@
namespace GFramework.Core.architecture;
/// <summary>
/// 定义架构配置的接口,提供日志工厂、日志级别和架构选项的配置功能
/// 定义架构配置的接口,提供日志工厂、日志级别和架构选项的配置功能
/// </summary>
public interface IArchitectureConfiguration
{
/// <summary>
/// 获取或设置日志工厂,用于创建日志记录器实例
/// 获取或设置日志工厂,用于创建日志记录器实例
/// </summary>
ILoggerFactory LoggerFactory { get; set; }
/// <summary>
/// 获取或设置架构选项,包含架构相关的配置参数
/// 获取或设置架构选项,包含架构相关的配置参数
/// </summary>
ArchitectureOptions Options { get; set; }
}
}

View File

@ -9,44 +9,44 @@ using GFramework.Core.utility;
namespace GFramework.Core.architecture;
/// <summary>
/// 架构上下文接口,提供对系统、模型、工具类的访问以及命令、查询、事件的发送和注册功能
/// 架构上下文接口,提供对系统、模型、工具类的访问以及命令、查询、事件的发送和注册功能
/// </summary>
public interface IArchitectureContext
{
/// <summary>
/// 获取日志工厂
/// 获取日志工厂
/// </summary>
ILoggerFactory LoggerFactory { get; }
/// <summary>
/// 获取指定类型的系统实例
/// 获取指定类型的系统实例
/// </summary>
/// <typeparam name="TSystem">系统类型必须继承自ISystem接口</typeparam>
/// <returns>系统实例如果不存在则返回null</returns>
TSystem? GetSystem<TSystem>() where TSystem : class, ISystem;
/// <summary>
/// 获取指定类型的模型实例
/// 获取指定类型的模型实例
/// </summary>
/// <typeparam name="TModel">模型类型必须继承自IModel接口</typeparam>
/// <returns>模型实例如果不存在则返回null</returns>
TModel? GetModel<TModel>() where TModel : class, IModel;
/// <summary>
/// 获取指定类型的工具类实例
/// 获取指定类型的工具类实例
/// </summary>
/// <typeparam name="TUtility">工具类类型必须继承自IUtility接口</typeparam>
/// <returns>工具类实例如果不存在则返回null</returns>
TUtility? GetUtility<TUtility>() where TUtility : class, IUtility;
/// <summary>
/// 发送一个命令
/// 发送一个命令
/// </summary>
/// <param name="command">要发送的命令</param>
void SendCommand(ICommand command);
/// <summary>
/// 发送一个带返回值的命令
/// 发送一个带返回值的命令
/// </summary>
/// <typeparam name="TResult">命令执行结果类型</typeparam>
/// <param name="command">要发送的命令</param>
@ -54,7 +54,7 @@ public interface IArchitectureContext
TResult SendCommand<TResult>(ICommand<TResult> command);
/// <summary>
/// 发送一个查询请求
/// 发送一个查询请求
/// </summary>
/// <typeparam name="TResult">查询结果类型</typeparam>
/// <param name="query">要发送的查询</param>
@ -62,20 +62,20 @@ public interface IArchitectureContext
TResult SendQuery<TResult>(IQuery<TResult> query);
/// <summary>
/// 发送一个事件
/// 发送一个事件
/// </summary>
/// <typeparam name="TEvent">事件类型,必须具有无参构造函数</typeparam>
void SendEvent<TEvent>() where TEvent : new();
/// <summary>
/// 发送一个带参数的事件
/// 发送一个带参数的事件
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="e">事件参数</param>
void SendEvent<TEvent>(TEvent e) where TEvent : class;
/// <summary>
/// 注册事件处理器
/// 注册事件处理器
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="handler">事件处理委托</param>
@ -83,7 +83,7 @@ public interface IArchitectureContext
IUnRegister RegisterEvent<TEvent>(Action<TEvent> handler);
/// <summary>
/// 取消注册事件监听器
/// 取消注册事件监听器
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="onEvent">要取消注册的事件回调方法</param>

View File

@ -1,20 +1,19 @@
namespace GFramework.Core.architecture;
/// <summary>
/// 可扩展架构接口继承自IArchitecture接口提供模块安装和生命周期钩子注册功能
/// 可扩展架构接口继承自IArchitecture接口提供模块安装和生命周期钩子注册功能
/// </summary>
public interface IArchitectureExtensible : IArchitecture
{
/// <summary>
/// 安装架构模块
/// 安装架构模块
/// </summary>
/// <param name="module">要安装的架构模块实例</param>
void InstallModule(IArchitectureModule module);
/// <summary>
/// 注册架构生命周期钩子
/// 注册架构生命周期钩子
/// </summary>
/// <param name="hook">要注册的架构生命周期钩子实例</param>
void RegisterLifecycleHook(IArchitectureLifecycle hook);
}
}

View File

@ -1,15 +1,14 @@
namespace GFramework.Core.architecture;
/// <summary>
/// 架构生命周期接口,定义了架构在不同阶段的回调方法
/// 架构生命周期接口,定义了架构在不同阶段的回调方法
/// </summary>
public interface IArchitectureLifecycle
{
/// <summary>
/// 当架构进入指定阶段时触发的回调方法
/// 当架构进入指定阶段时触发的回调方法
/// </summary>
/// <param name="phase">当前的架构阶段</param>
/// <param name="architecture">相关的架构实例</param>
void OnPhase(ArchitecturePhase phase, IArchitecture architecture);
}
}

View File

@ -1,15 +1,14 @@

namespace GFramework.Core.architecture;
namespace GFramework.Core.architecture;
/// <summary>
/// 架构模块接口,继承自架构生命周期接口。
/// 定义了模块安装到架构中的标准方法。
/// 架构模块接口,继承自架构生命周期接口。
/// 定义了模块安装到架构中的标准方法。
/// </summary>
public interface IArchitectureModule : IArchitectureLifecycle, IArchitecturePhaseAware
{
/// <summary>
/// 将当前模块安装到指定的架构中。
/// 将当前模块安装到指定的架构中。
/// </summary>
/// <param name="architecture">要安装模块的目标架构实例。</param>
void Install(IArchitecture architecture);
}
}

View File

@ -1,14 +1,13 @@
namespace GFramework.Core.architecture;
/// <summary>
/// 定义架构阶段感知接口,用于在架构的不同阶段执行相应的逻辑
/// 定义架构阶段感知接口,用于在架构的不同阶段执行相应的逻辑
/// </summary>
public interface IArchitecturePhaseAware
{
/// <summary>
/// 当架构进入指定阶段时触发的回调方法
/// 当架构进入指定阶段时触发的回调方法
/// </summary>
/// <param name="phase">架构阶段枚举值,表示当前所处的架构阶段</param>
void OnArchitecturePhase(ArchitecturePhase phase);
}
}

View File

@ -5,20 +5,20 @@ using GFramework.Core.query;
namespace GFramework.Core.architecture;
/// <summary>
/// 架构运行时接口,提供统一的命令、查询、事件操作入口
/// 负责委托 ArchitectureContext 的能力执行具体操作
/// 架构运行时接口,提供统一的命令、查询、事件操作入口
/// 负责委托 ArchitectureContext 的能力执行具体操作
/// </summary>
public interface IArchitectureRuntime
{
/// <summary>
/// 发送并执行指定的命令
/// 发送并执行指定的命令
/// </summary>
/// <typeparam name="T">命令类型必须实现ICommand接口</typeparam>
/// <param name="command">要执行的命令实例</param>
void SendCommand<T>(T command) where T : ICommand;
/// <summary>
/// 发送并执行带有返回值的命令
/// 发送并执行带有返回值的命令
/// </summary>
/// <typeparam name="TResult">命令执行结果的类型</typeparam>
/// <param name="command">要执行的命令实例</param>
@ -26,7 +26,7 @@ public interface IArchitectureRuntime
TResult SendCommand<TResult>(ICommand<TResult> command);
/// <summary>
/// 发送并执行查询操作
/// 发送并执行查询操作
/// </summary>
/// <typeparam name="TResult">查询结果的类型</typeparam>
/// <param name="query">要执行的查询实例</param>
@ -34,20 +34,20 @@ public interface IArchitectureRuntime
TResult SendQuery<TResult>(IQuery<TResult> query);
/// <summary>
/// 发送无参事件
/// 发送无参事件
/// </summary>
/// <typeparam name="TEvent">事件类型,必须具有无参构造函数</typeparam>
void SendEvent<TEvent>() where TEvent : new();
/// <summary>
/// 发送指定的事件实例
/// 发送指定的事件实例
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="e">要发送的事件实例</param>
void SendEvent<TEvent>(TEvent e) where TEvent : class;
/// <summary>
/// 注册事件监听器
/// 注册事件监听器
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="onEvent">事件触发时的回调方法</param>
@ -55,7 +55,7 @@ public interface IArchitectureRuntime
IUnRegister RegisterEvent<TEvent>(Action<TEvent> onEvent);
/// <summary>
/// 取消注册事件监听器
/// 取消注册事件监听器
/// </summary>
/// <typeparam name="TEvent">事件类型</typeparam>
/// <param name="onEvent">要取消注册的事件回调方法</param>

View File

@ -4,19 +4,19 @@ using GFramework.Core.ioc;
namespace GFramework.Core.architecture;
/// <summary>
/// 架构服务接口,定义了框架核心架构所需的服务组件
/// 架构服务接口,定义了框架核心架构所需的服务组件
/// </summary>
public interface IArchitectureServices
{
/// <summary>
/// 获取依赖注入容器
/// 获取依赖注入容器
/// </summary>
/// <returns>IIocContainer类型的依赖注入容器实例</returns>
IIocContainer Container { get; }
/// <summary>
/// 获取类型事件系统
/// 获取类型事件系统
/// </summary>
/// <returns>ITypeEventSystem类型的事件系统实例</returns>
ITypeEventSystem TypeEventSystem { get; }
}
}

View File

@ -1,13 +1,13 @@
namespace GFramework.Core.architecture;
/// <summary>
/// 定义异步初始化接口,用于需要异步初始化的组件或服务
/// 定义异步初始化接口,用于需要异步初始化的组件或服务
/// </summary>
public interface IAsyncInitializable
{
/// <summary>
/// 异步初始化方法,用于执行组件或服务的异步初始化逻辑
/// 异步初始化方法,用于执行组件或服务的异步初始化逻辑
/// </summary>
/// <returns>表示异步初始化操作的Task</returns>
Task InitializeAsync();
}
}

View File

@ -6,7 +6,7 @@ namespace GFramework.Core.command;
/// 命令接口,定义了无返回值命令的基本契约
/// 该接口继承了多个框架能力接口,使命令可以访问架构、系统、模型、工具,并能够发送事件、命令和查询
/// </summary>
public interface ICommand: IContextAware
public interface ICommand : IContextAware
{
/// <summary>
/// 执行命令的核心方法
@ -20,7 +20,7 @@ public interface ICommand: IContextAware
/// 该接口继承了多个框架能力接口,使命令可以访问架构、系统、模型、工具,并能够发送事件、命令和查询
/// </summary>
/// <typeparam name="TResult">命令执行后返回的结果类型</typeparam>
public interface ICommand<out TResult>: IContextAware
public interface ICommand<out TResult> : IContextAware
{
/// <summary>
/// 执行命令的核心方法

View File

@ -1,12 +1,12 @@
namespace GFramework.Core.constants;
/// <summary>
/// GFramework框架常量定义类
/// GFramework框架常量定义类
/// </summary>
public static class GFrameworkConstants
{
/// <summary>
/// 框架名称常量
/// 框架名称常量
/// </summary>
public const string FrameworkName = "GFramework";
}
}

View File

@ -1,25 +1,25 @@
namespace GFramework.Core.events;
/// <summary>
/// 架构事件定义类,包含应用程序架构生命周期相关的事件结构体
/// 架构事件定义类,包含应用程序架构生命周期相关的事件结构体
/// </summary>
public static class ArchitectureEvents
{
/// <summary>
/// 架构生命周期准备就绪事件
/// 当架构完成初始化并准备就绪时触发此事件
/// 架构生命周期准备就绪事件
/// 当架构完成初始化并准备就绪时触发此事件
/// </summary>
public readonly struct ArchitectureLifecycleReadyEvent;
/// <summary>
/// 架构销毁中事件
/// 当架构开始销毁过程时触发此事件,表示系统正在关闭
/// 架构销毁中事件
/// 当架构开始销毁过程时触发此事件,表示系统正在关闭
/// </summary>
public readonly struct ArchitectureDestroyingEvent;
/// <summary>
/// 架构已销毁事件
/// 当架构完全销毁完成后触发此事件,表示系统已关闭
/// 架构已销毁事件
/// 当架构完全销毁完成后触发此事件,表示系统已关闭
/// </summary>
public readonly struct ArchitectureDestroyedEvent;
}
}

View File

@ -1,25 +1,25 @@
namespace GFramework.Core.events;
/// <summary>
/// 类型事件系统接口,定义基于类型的事件发送、注册和注销功能
/// 类型事件系统接口,定义基于类型的事件发送、注册和注销功能
/// </summary>
public interface ITypeEventSystem
{
/// <summary>
/// 发送事件,自动创建事件实例
/// 发送事件,自动创建事件实例
/// </summary>
/// <typeparam name="T">事件类型,必须具有无参构造函数</typeparam>
void Send<T>() where T : new();
/// <summary>
/// 发送指定的事件实例
/// 发送指定的事件实例
/// </summary>
/// <typeparam name="T">事件类型</typeparam>
/// <param name="e">事件实例</param>
void Send<T>(T e);
/// <summary>
/// 注册事件监听器
/// 注册事件监听器
/// </summary>
/// <typeparam name="T">事件类型</typeparam>
/// <param name="onEvent">事件处理回调函数</param>
@ -27,9 +27,9 @@ public interface ITypeEventSystem
IUnRegister Register<T>(Action<T> onEvent);
/// <summary>
/// 注销事件监听器
/// 注销事件监听器
/// </summary>
/// <typeparam name="T">事件类型</typeparam>
/// <param name="onEvent">要注销的事件处理回调函数</param>
void UnRegister<T>(Action<T> onEvent);
}
}

View File

@ -1,20 +1,23 @@
namespace GFramework.Core.events;
/// <summary>
/// 类型事件系统,提供基于类型的事件发送、注册和注销功能
/// 类型事件系统,提供基于类型的事件发送、注册和注销功能
/// </summary>
public class TypeEventSystem : ITypeEventSystem
{
private readonly EasyEvents _mEvents = new();
/// <summary>
/// 发送事件,自动创建事件实例
/// 发送事件,自动创建事件实例
/// </summary>
/// <typeparam name="T">事件类型,必须具有无参构造函数</typeparam>
public void Send<T>() where T : new() => _mEvents.GetEvent<EasyEvent<T>>().Trigger(new T());
public void Send<T>() where T : new()
{
_mEvents.GetEvent<EasyEvent<T>>().Trigger(new T());
}
/// <summary>
/// 发送指定的事件实例
/// 发送指定的事件实例
/// </summary>
/// <typeparam name="T">事件类型</typeparam>
/// <param name="e">事件实例</param>
@ -24,17 +27,23 @@ public class TypeEventSystem : ITypeEventSystem
}
/// <summary>
/// 注册事件监听器
/// 注册事件监听器
/// </summary>
/// <typeparam name="T">事件类型</typeparam>
/// <param name="onEvent">事件处理回调函数</param>
/// <returns>反注册接口,用于注销事件监听</returns>
public IUnRegister Register<T>(Action<T> onEvent) => _mEvents.GetOrAddEvent<EasyEvent<T>>().Register(onEvent);
public IUnRegister Register<T>(Action<T> onEvent)
{
return _mEvents.GetOrAddEvent<EasyEvent<T>>().Register(onEvent);
}
/// <summary>
/// 注销事件监听器
/// 注销事件监听器
/// </summary>
/// <typeparam name="T">事件类型</typeparam>
/// <param name="onEvent">要注销的事件处理回调函数</param>
public void UnRegister<T>(Action<T> onEvent) => _mEvents.GetEvent<EasyEvent<T>>().UnRegister(onEvent);
public void UnRegister<T>(Action<T> onEvent)
{
_mEvents.GetEvent<EasyEvent<T>>().UnRegister(onEvent);
}
}

View File

@ -4,15 +4,15 @@ using GFramework.Core.system;
namespace GFramework.Core.ioc;
/// <summary>
/// 依赖注入容器接口,定义了服务注册、解析和管理的基本操作
/// 依赖注入容器接口,定义了服务注册、解析和管理的基本操作
/// </summary>
public interface IIocContainer : IContextAware
{
#region Register Methods
/// <summary>
/// 注册单例
/// 一个类型只允许一个实例
/// 注册单例
/// 一个类型只允许一个实例
/// </summary>
/// <typeparam name="T">要注册为单例的类型</typeparam>
/// <param name="instance">要注册的单例实例</param>
@ -21,27 +21,27 @@ public interface IIocContainer : IContextAware
/// <summary>
/// 注册一个实例及其所有可赋值的接口类型到容器中
/// 注册一个实例及其所有可赋值的接口类型到容器中
/// </summary>
/// <typeparam name="T">实例的类型</typeparam>
/// <param name="instance">要注册的实例对象不能为null</param>
void RegisterPlurality<T>(T instance);
/// <summary>
/// 注册系统实例,将其绑定到其所有实现的接口上
/// 注册系统实例,将其绑定到其所有实现的接口上
/// </summary>
/// <param name="system">系统实例对象</param>
void RegisterSystem(ISystem system);
/// <summary>
/// 注册指定类型的实例到容器中
/// 注册指定类型的实例到容器中
/// </summary>
/// <typeparam name="T">要注册的实例类型</typeparam>
/// <param name="instance">要注册的实例对象不能为null</param>
void Register<T>(T instance);
/// <summary>
/// 注册指定类型的实例到容器中
/// 注册指定类型的实例到容器中
/// </summary>
/// <param name="type">要注册的实例类型</param>
/// <param name="instance">要注册的实例对象</param>
@ -52,15 +52,15 @@ public interface IIocContainer : IContextAware
#region Get Methods
/// <summary>
/// 获取单个实例(通常用于具体类型)
/// 如果存在多个,只返回第一个
/// 获取单个实例(通常用于具体类型)
/// 如果存在多个,只返回第一个
/// </summary>
/// <typeparam name="T">期望获取的实例类型</typeparam>
/// <returns>找到的第一个实例;如果未找到则返回 null</returns>
T? Get<T>() where T : class;
/// <summary>
/// 获取指定类型的必需实例
/// 获取指定类型的必需实例
/// </summary>
/// <typeparam name="T">期望获取的实例类型</typeparam>
/// <returns>找到的唯一实例</returns>
@ -68,14 +68,14 @@ public interface IIocContainer : IContextAware
T GetRequired<T>() where T : class;
/// <summary>
/// 获取指定类型的所有实例(接口 / 抽象类推荐使用)
/// 获取指定类型的所有实例(接口 / 抽象类推荐使用)
/// </summary>
/// <typeparam name="T">期望获取的实例类型</typeparam>
/// <returns>所有符合条件的实例列表;如果没有则返回空数组</returns>
IReadOnlyList<T> GetAll<T>() where T : class;
/// <summary>
/// 获取并排序(系统调度专用)
/// 获取并排序(系统调度专用)
/// </summary>
/// <typeparam name="T">期望获取的实例类型</typeparam>
/// <param name="comparison">比较器委托,定义排序规则</param>
@ -87,26 +87,26 @@ public interface IIocContainer : IContextAware
#region Utility Methods
/// <summary>
/// 检查容器中是否包含指定类型的实例
/// 检查容器中是否包含指定类型的实例
/// </summary>
/// <typeparam name="T">要检查的类型</typeparam>
/// <returns>如果容器中包含指定类型的实例则返回true否则返回false</returns>
bool Contains<T>();
/// <summary>
/// 判断容器中是否包含某个具体的实例对象
/// 判断容器中是否包含某个具体的实例对象
/// </summary>
/// <param name="instance">待查询的实例对象</param>
/// <returns>若容器中包含该实例则返回true否则返回false</returns>
bool ContainsInstance(object instance);
/// <summary>
/// 清空容器中的所有实例
/// 清空容器中的所有实例
/// </summary>
void Clear();
/// <summary>
/// 冻结容器,防止后续修改
/// 冻结容器,防止后续修改
/// </summary>
void Freeze();

View File

@ -12,9 +12,9 @@ public class IocContainer : ContextAwareBase, IIocContainer
#region Lock
/// <summary>
/// 读写锁对象,用于控制多线程环境下对共享资源的访问
/// 使用ReaderWriterLockSlim提供高效的读写锁定机制
/// 配置为不支持递归锁,避免死锁风险
/// 读写锁对象,用于控制多线程环境下对共享资源的访问
/// 使用ReaderWriterLockSlim提供高效的读写锁定机制
/// 配置为不支持递归锁,避免死锁风险
/// </summary>
private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.NoRecursion);
@ -23,8 +23,8 @@ public class IocContainer : ContextAwareBase, IIocContainer
#region Flag
/// <summary>
/// 冻结标志位,用于标识对象是否已被冻结
/// true表示对象已冻结不可修改false表示对象可正常修改
/// 冻结标志位,用于标识对象是否已被冻结
/// true表示对象已冻结不可修改false表示对象可正常修改
/// </summary>
private volatile bool _frozen;
@ -33,14 +33,14 @@ public class IocContainer : ContextAwareBase, IIocContainer
#region Core
/// <summary>
/// 存储所有已注册对象实例的集合,用于跟踪和管理容器中的所有对象
/// 使用HashSet确保对象唯一性避免重复注册同一实例
/// 存储所有已注册对象实例的集合,用于跟踪和管理容器中的所有对象
/// 使用HashSet确保对象唯一性避免重复注册同一实例
/// </summary>
private readonly HashSet<object> _objects = [];
/// <summary>
/// 类型索引字典,用于快速查找指定类型的所有实例
/// 键为类型对象,值为该类型对应的所有实例集合
/// 类型索引字典,用于快速查找指定类型的所有实例
/// 键为类型对象,值为该类型对应的所有实例集合
/// </summary>
private readonly Dictionary<Type, HashSet<object>> _typeIndex = new();
@ -57,8 +57,8 @@ public class IocContainer : ContextAwareBase, IIocContainer
}
/// <summary>
/// 注册单例
/// 一个类型只允许一个实例
/// 注册单例
/// 一个类型只允许一个实例
/// </summary>
/// <typeparam name="T">要注册为单例的类型</typeparam>
/// <param name="instance">要注册的单例实例</param>
@ -94,7 +94,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
/// <summary>
/// 注册一个实例及其所有可赋值的接口类型到容器中
/// 注册一个实例及其所有可赋值的接口类型到容器中
/// </summary>
/// <typeparam name="T">实例的类型</typeparam>
/// <param name="instance">要注册的实例对象不能为null</param>
@ -126,7 +126,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
}
/// <summary>
/// 在内部字典中注册指定类型和实例的映射关系
/// 在内部字典中注册指定类型和实例的映射关系
/// </summary>
/// <param name="type">要注册的类型</param>
/// <param name="instance">要注册的实例</param>
@ -152,7 +152,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
/// <summary>
/// 注册系统实例,将其绑定到其所有实现的接口上
/// 注册系统实例,将其绑定到其所有实现的接口上
/// </summary>
/// <param name="system">系统实例对象</param>
public void RegisterSystem(ISystem system)
@ -162,7 +162,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
/// <summary>
/// 注册指定类型的实例到容器中
/// 注册指定类型的实例到容器中
/// </summary>
/// <typeparam name="T">要注册的实例类型</typeparam>
/// <param name="instance">要注册的实例对象不能为null</param>
@ -182,7 +182,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
}
/// <summary>
/// 注册指定类型的实例到容器中
/// 注册指定类型的实例到容器中
/// </summary>
/// <param name="type">要注册的实例类型</param>
/// <param name="instance">要注册的实例对象</param>
@ -206,8 +206,8 @@ public class IocContainer : ContextAwareBase, IIocContainer
#region Get
/// <summary>
/// 获取单个实例(通常用于具体类型)
/// 如果存在多个,只返回第一个
/// 获取单个实例(通常用于具体类型)
/// 如果存在多个,只返回第一个
/// </summary>
/// <typeparam name="T">期望获取的实例类型</typeparam>
/// <returns>找到的第一个实例;如果未找到则返回 null</returns>
@ -234,7 +234,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
/// <summary>
/// 获取指定类型的必需实例
/// 获取指定类型的必需实例
/// </summary>
/// <typeparam name="T">期望获取的实例类型</typeparam>
/// <returns>找到的唯一实例</returns>
@ -262,7 +262,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
}
/// <summary>
/// 获取指定类型的所有实例(接口 / 抽象类推荐使用)
/// 获取指定类型的所有实例(接口 / 抽象类推荐使用)
/// </summary>
/// <typeparam name="T">期望获取的实例类型</typeparam>
/// <returns>所有符合条件的实例列表;如果没有则返回空数组</returns>
@ -283,7 +283,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
/// <summary>
/// 获取并排序(系统调度专用)
/// 获取并排序(系统调度专用)
/// </summary>
/// <typeparam name="T">期望获取的实例类型</typeparam>
/// <param name="comparison">比较器委托,定义排序规则</param>
@ -301,7 +301,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
#region Utility
/// <summary>
/// 检查容器中是否包含指定类型的实例
/// 检查容器中是否包含指定类型的实例
/// </summary>
/// <typeparam name="T">要检查的类型</typeparam>
/// <returns>如果容器中包含指定类型的实例则返回true否则返回false</returns>
@ -319,7 +319,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
}
/// <summary>
/// 清空容器中的所有实例
/// 清空容器中的所有实例
/// </summary>
public void Clear()
{
@ -336,7 +336,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
}
/// <summary>
/// 判断容器中是否包含某个具体的实例对象
/// 判断容器中是否包含某个具体的实例对象
/// </summary>
/// <param name="instance">待查询的实例对象</param>
/// <returns>若容器中包含该实例则返回true否则返回false</returns>
@ -355,7 +355,7 @@ public class IocContainer : ContextAwareBase, IIocContainer
/// <summary>
/// 冻结容器,防止后续修改
/// 冻结容器,防止后续修改
/// </summary>
public void Freeze()
{

View File

@ -1,8 +1,8 @@
namespace GFramework.Core.logging;
/// <summary>
/// 日志抽象基类,封装日志级别判断、格式化与异常处理逻辑。
/// 平台日志器只需实现 Write 方法即可。
/// 日志抽象基类,封装日志级别判断、格式化与异常处理逻辑。
/// 平台日志器只需实现 Write 方法即可。
/// </summary>
public abstract class AbstractLogger(
string? name = null,
@ -13,298 +13,420 @@ public abstract class AbstractLogger(
#region Metadata
/// <summary>
/// 获取日志器的名称
/// 获取日志器的名称
/// </summary>
/// <returns>日志器名称</returns>
public string Name() => _name;
public string Name()
{
return _name;
}
#endregion
/// <summary>
/// 平台输出入口,由具体实现负责真正的日志写入。
/// </summary>
/// <param name="level">日志级别</param>
/// <param name="message">日志消息</param>
/// <param name="exception">异常对象可为null</param>
protected abstract void Write(LogLevel level, string message, Exception? exception);
#region Level Checks
/// <summary>
/// 判断指定日志级别是否启用
/// 判断指定日志级别是否启用
/// </summary>
/// <param name="level">要检查的日志级别</param>
/// <returns>如果指定级别大于等于最小级别则返回true否则返回false</returns>
protected bool IsEnabled(LogLevel level) => level >= minLevel;
protected bool IsEnabled(LogLevel level)
{
return level >= minLevel;
}
/// <summary>
/// 检查Trace级别日志是否启用
/// 检查Trace级别日志是否启用
/// </summary>
/// <returns>如果Trace级别启用返回true否则返回false</returns>
public bool IsTraceEnabled() => IsEnabled(LogLevel.Trace);
public bool IsTraceEnabled()
{
return IsEnabled(LogLevel.Trace);
}
/// <summary>
/// 检查Debug级别日志是否启用
/// 检查Debug级别日志是否启用
/// </summary>
/// <returns>如果Debug级别启用返回true否则返回false</returns>
public bool IsDebugEnabled() => IsEnabled(LogLevel.Debug);
public bool IsDebugEnabled()
{
return IsEnabled(LogLevel.Debug);
}
/// <summary>
/// 检查Info级别日志是否启用
/// 检查Info级别日志是否启用
/// </summary>
/// <returns>如果Info级别启用返回true否则返回false</returns>
public bool IsInfoEnabled() => IsEnabled(LogLevel.Info);
public bool IsInfoEnabled()
{
return IsEnabled(LogLevel.Info);
}
/// <summary>
/// 检查Warning级别日志是否启用
/// 检查Warning级别日志是否启用
/// </summary>
/// <returns>如果Warning级别启用返回true否则返回false</returns>
public bool IsWarnEnabled() => IsEnabled(LogLevel.Warning);
public bool IsWarnEnabled()
{
return IsEnabled(LogLevel.Warning);
}
/// <summary>
/// 检查Error级别日志是否启用
/// 检查Error级别日志是否启用
/// </summary>
/// <returns>如果Error级别启用返回true否则返回false</returns>
public bool IsErrorEnabled() => IsEnabled(LogLevel.Error);
public bool IsErrorEnabled()
{
return IsEnabled(LogLevel.Error);
}
/// <summary>
/// 检查Fatal级别日志是否启用
/// 检查Fatal级别日志是否启用
/// </summary>
/// <returns>如果Fatal级别启用返回true否则返回false</returns>
public bool IsFatalEnabled() => IsEnabled(LogLevel.Fatal);
public bool IsFatalEnabled()
{
return IsEnabled(LogLevel.Fatal);
}
#endregion
#region Trace
/// <summary>
/// 记录Trace级别日志
/// 记录Trace级别日志
/// </summary>
/// <param name="msg">日志消息</param>
public void Trace(string msg) => Log(LogLevel.Trace, msg);
public void Trace(string msg)
{
Log(LogLevel.Trace, msg);
}
/// <summary>
/// 记录Trace级别日志带格式化参数
/// 记录Trace级别日志带格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</param>
public void Trace(string format, object arg) => Log(LogLevel.Trace, format, arg);
public void Trace(string format, object arg)
{
Log(LogLevel.Trace, format, arg);
}
/// <summary>
/// 记录Trace级别日志带两个格式化参数
/// 记录Trace级别日志带两个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</param>
public void Trace(string format, object arg1, object arg2) => Log(LogLevel.Trace, format, arg1, arg2);
public void Trace(string format, object arg1, object arg2)
{
Log(LogLevel.Trace, format, arg1, arg2);
}
/// <summary>
/// 记录Trace级别日志带多个格式化参数
/// 记录Trace级别日志带多个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</param>
public void Trace(string format, params object[] arguments) => Log(LogLevel.Trace, format, arguments);
public void Trace(string format, params object[] arguments)
{
Log(LogLevel.Trace, format, arguments);
}
/// <summary>
/// 记录Trace级别日志带异常信息
/// 记录Trace级别日志带异常信息
/// </summary>
/// <param name="msg">日志消息</param>
/// <param name="t">异常对象</param>
public void Trace(string msg, Exception t) => Log(LogLevel.Trace, msg, t);
public void Trace(string msg, Exception t)
{
Log(LogLevel.Trace, msg, t);
}
#endregion
#region Debug
/// <summary>
/// 记录Debug级别日志
/// 记录Debug级别日志
/// </summary>
/// <param name="msg">日志消息</param>
public void Debug(string msg) => Log(LogLevel.Debug, msg);
public void Debug(string msg)
{
Log(LogLevel.Debug, msg);
}
/// <summary>
/// 记录Debug级别日志带格式化参数
/// 记录Debug级别日志带格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</param>
public void Debug(string format, object arg) => Log(LogLevel.Debug, format, arg);
public void Debug(string format, object arg)
{
Log(LogLevel.Debug, format, arg);
}
/// <summary>
/// 记录Debug级别日志带两个格式化参数
/// 记录Debug级别日志带两个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</param>
public void Debug(string format, object arg1, object arg2) => Log(LogLevel.Debug, format, arg1, arg2);
public void Debug(string format, object arg1, object arg2)
{
Log(LogLevel.Debug, format, arg1, arg2);
}
/// <summary>
/// 记录Debug级别日志带多个格式化参数
/// 记录Debug级别日志带多个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</param>
public void Debug(string format, params object[] arguments) => Log(LogLevel.Debug, format, arguments);
public void Debug(string format, params object[] arguments)
{
Log(LogLevel.Debug, format, arguments);
}
/// <summary>
/// 记录Debug级别日志带异常信息
/// 记录Debug级别日志带异常信息
/// </summary>
/// <param name="msg">日志消息</param>
/// <param name="t">异常对象</param>
public void Debug(string msg, Exception t) => Log(LogLevel.Debug, msg, t);
public void Debug(string msg, Exception t)
{
Log(LogLevel.Debug, msg, t);
}
#endregion
#region Info
/// <summary>
/// 记录Info级别日志
/// 记录Info级别日志
/// </summary>
/// <param name="msg">日志消息</param>
public void Info(string msg) => Log(LogLevel.Info, msg);
public void Info(string msg)
{
Log(LogLevel.Info, msg);
}
/// <summary>
/// 记录Info级别日志带格式化参数
/// 记录Info级别日志带格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</param>
public void Info(string format, object arg) => Log(LogLevel.Info, format, arg);
public void Info(string format, object arg)
{
Log(LogLevel.Info, format, arg);
}
/// <summary>
/// 记录Info级别日志带两个格式化参数
/// 记录Info级别日志带两个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</param>
public void Info(string format, object arg1, object arg2) => Log(LogLevel.Info, format, arg1, arg2);
public void Info(string format, object arg1, object arg2)
{
Log(LogLevel.Info, format, arg1, arg2);
}
/// <summary>
/// 记录Info级别日志带多个格式化参数
/// 记录Info级别日志带多个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</param>
public void Info(string format, params object[] arguments) => Log(LogLevel.Info, format, arguments);
public void Info(string format, params object[] arguments)
{
Log(LogLevel.Info, format, arguments);
}
/// <summary>
/// 记录Info级别日志带异常信息
/// 记录Info级别日志带异常信息
/// </summary>
/// <param name="msg">日志消息</param>
/// <param name="t">异常对象</param>
public void Info(string msg, Exception t) => Log(LogLevel.Info, msg, t);
public void Info(string msg, Exception t)
{
Log(LogLevel.Info, msg, t);
}
#endregion
#region Warn
/// <summary>
/// 记录Warning级别日志
/// 记录Warning级别日志
/// </summary>
/// <param name="msg">日志消息</param>
public void Warn(string msg) => Log(LogLevel.Warning, msg);
public void Warn(string msg)
{
Log(LogLevel.Warning, msg);
}
/// <summary>
/// 记录Warning级别日志带格式化参数
/// 记录Warning级别日志带格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</param>
public void Warn(string format, object arg) => Log(LogLevel.Warning, format, arg);
public void Warn(string format, object arg)
{
Log(LogLevel.Warning, format, arg);
}
/// <summary>
/// 记录Warning级别日志带两个格式化参数
/// 记录Warning级别日志带两个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</param>
public void Warn(string format, object arg1, object arg2) => Log(LogLevel.Warning, format, arg1, arg2);
public void Warn(string format, object arg1, object arg2)
{
Log(LogLevel.Warning, format, arg1, arg2);
}
/// <summary>
/// 记录Warning级别日志带多个格式化参数
/// 记录Warning级别日志带多个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</param>
public void Warn(string format, params object[] arguments) => Log(LogLevel.Warning, format, arguments);
public void Warn(string format, params object[] arguments)
{
Log(LogLevel.Warning, format, arguments);
}
/// <summary>
/// 记录Warning级别日志带异常信息
/// 记录Warning级别日志带异常信息
/// </summary>
/// <param name="msg">日志消息</param>
/// <param name="t">异常对象</param>
public void Warn(string msg, Exception t) => Log(LogLevel.Warning, msg, t);
public void Warn(string msg, Exception t)
{
Log(LogLevel.Warning, msg, t);
}
#endregion
#region Error
/// <summary>
/// 记录Error级别日志
/// 记录Error级别日志
/// </summary>
/// <param name="msg">日志消息</param>
public void Error(string msg) => Log(LogLevel.Error, msg);
public void Error(string msg)
{
Log(LogLevel.Error, msg);
}
/// <summary>
/// 记录Error级别日志带格式化参数
/// 记录Error级别日志带格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</param>
public void Error(string format, object arg) => Log(LogLevel.Error, format, arg);
public void Error(string format, object arg)
{
Log(LogLevel.Error, format, arg);
}
/// <summary>
/// 记录Error级别日志带两个格式化参数
/// 记录Error级别日志带两个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</param>
public void Error(string format, object arg1, object arg2) => Log(LogLevel.Error, format, arg1, arg2);
public void Error(string format, object arg1, object arg2)
{
Log(LogLevel.Error, format, arg1, arg2);
}
/// <summary>
/// 记录Error级别日志带多个格式化参数
/// 记录Error级别日志带多个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</param>
public void Error(string format, params object[] arguments) => Log(LogLevel.Error, format, arguments);
public void Error(string format, params object[] arguments)
{
Log(LogLevel.Error, format, arguments);
}
/// <summary>
/// 记录Error级别日志带异常信息
/// 记录Error级别日志带异常信息
/// </summary>
/// <param name="msg">日志消息</param>
/// <param name="t">异常对象</param>
public void Error(string msg, Exception t) => Log(LogLevel.Error, msg, t);
public void Error(string msg, Exception t)
{
Log(LogLevel.Error, msg, t);
}
#endregion
#region Fatal
/// <summary>
/// 记录Fatal级别日志
/// 记录Fatal级别日志
/// </summary>
/// <param name="msg">日志消息</param>
public void Fatal(string msg) => Log(LogLevel.Fatal, msg);
public void Fatal(string msg)
{
Log(LogLevel.Fatal, msg);
}
/// <summary>
/// 记录Fatal级别日志带格式化参数
/// 记录Fatal级别日志带格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</param>
public void Fatal(string format, object arg) => Log(LogLevel.Fatal, format, arg);
public void Fatal(string format, object arg)
{
Log(LogLevel.Fatal, format, arg);
}
/// <summary>
/// 记录Fatal级别日志带两个格式化参数
/// 记录Fatal级别日志带两个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</param>
public void Fatal(string format, object arg1, object arg2) => Log(LogLevel.Fatal, format, arg1, arg2);
public void Fatal(string format, object arg1, object arg2)
{
Log(LogLevel.Fatal, format, arg1, arg2);
}
/// <summary>
/// 记录Fatal级别日志带多个格式化参数
/// 记录Fatal级别日志带多个格式化参数
/// </summary>
/// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</param>
public void Fatal(string format, params object[] arguments) => Log(LogLevel.Fatal, format, arguments);
public void Fatal(string format, params object[] arguments)
{
Log(LogLevel.Fatal, format, arguments);
}
/// <summary>
/// 记录Fatal级别日志带异常信息
/// 记录Fatal级别日志带异常信息
/// </summary>
/// <param name="msg">日志消息</param>
/// <param name="t">异常对象</param>
public void Fatal(string msg, Exception t) => Log(LogLevel.Fatal, msg, t);
public void Fatal(string msg, Exception t)
{
Log(LogLevel.Fatal, msg, t);
}
#endregion
#region Core Pipeline
/// <summary>
/// 核心日志记录方法(无参数)
/// 核心日志记录方法(无参数)
/// </summary>
/// <param name="level">日志级别</param>
/// <param name="message">日志消息</param>
@ -315,7 +437,7 @@ public abstract class AbstractLogger(
}
/// <summary>
/// 核心日志记录方法(带参数格式化)
/// 核心日志记录方法(带参数格式化)
/// </summary>
/// <param name="level">日志级别</param>
/// <param name="format">格式化字符串</param>
@ -327,7 +449,7 @@ public abstract class AbstractLogger(
}
/// <summary>
/// 核心日志记录方法(带异常)
/// 核心日志记录方法(带异常)
/// </summary>
/// <param name="level">日志级别</param>
/// <param name="message">日志消息</param>
@ -339,12 +461,4 @@ public abstract class AbstractLogger(
}
#endregion
/// <summary>
/// 平台输出入口,由具体实现负责真正的日志写入。
/// </summary>
/// <param name="level">日志级别</param>
/// <param name="message">日志消息</param>
/// <param name="exception">异常对象可为null</param>
protected abstract void Write(LogLevel level, string message, Exception? exception);
}
}

View File

@ -1,7 +1,7 @@
namespace GFramework.Core.logging;
/// <summary>
/// 控制台日志记录器
/// 控制台日志记录器
/// </summary>
public sealed class ConsoleLogger(
string? name = null,
@ -9,11 +9,11 @@ public sealed class ConsoleLogger(
TextWriter? writer = null,
bool useColors = true) : AbstractLogger(name ?? ILogger.RootLoggerName, minLevel)
{
private readonly TextWriter _writer = writer ?? Console.Out;
private readonly bool _useColors = useColors && writer == Console.Out;
private readonly TextWriter _writer = writer ?? Console.Out;
/// <summary>
/// 写入日志消息到控制台
/// 写入日志消息到控制台
/// </summary>
/// <param name="level">日志级别</param>
/// <param name="message">日志消息</param>
@ -25,24 +25,18 @@ public sealed class ConsoleLogger(
var log = $"[{timestamp}] {levelStr} [{Name()}] {message}";
// 添加异常信息到日志
if (exception != null)
{
log += Environment.NewLine + exception;
}
if (exception != null) log += Environment.NewLine + exception;
if (_useColors)
{
WriteColored(level, log);
}
else
{
_writer.WriteLine(log);
}
}
#region Internal Core
/// <summary>
/// 以指定颜色写入日志消息
/// 以指定颜色写入日志消息
/// </summary>
/// <param name="level">日志级别</param>
/// <param name="message">日志消息</param>
@ -61,20 +55,23 @@ public sealed class ConsoleLogger(
}
/// <summary>
/// 根据日志级别获取对应的颜色
/// 根据日志级别获取对应的颜色
/// </summary>
/// <param name="level">日志级别</param>
/// <returns>控制台颜色</returns>
private static ConsoleColor GetColor(LogLevel level) => level switch
private static ConsoleColor GetColor(LogLevel level)
{
LogLevel.Trace => ConsoleColor.DarkGray,
LogLevel.Debug => ConsoleColor.Cyan,
LogLevel.Info => ConsoleColor.White,
LogLevel.Warning => ConsoleColor.Yellow,
LogLevel.Error => ConsoleColor.Red,
LogLevel.Fatal => ConsoleColor.Magenta,
_ => ConsoleColor.White
};
return level switch
{
LogLevel.Trace => ConsoleColor.DarkGray,
LogLevel.Debug => ConsoleColor.Cyan,
LogLevel.Info => ConsoleColor.White,
LogLevel.Warning => ConsoleColor.Yellow,
LogLevel.Error => ConsoleColor.Red,
LogLevel.Fatal => ConsoleColor.Magenta,
_ => ConsoleColor.White
};
}
#endregion
}
}

View File

@ -1,12 +1,12 @@
namespace GFramework.Core.logging;
/// <summary>
/// 控制台日志提供程序,用于创建控制台日志记录器实例
/// 控制台日志提供程序,用于创建控制台日志记录器实例
/// </summary>
public class ConsoleLoggerFactory : ILoggerFactory
{
/// <summary>
/// 获取指定名称的控制台日志记录器实例
/// 获取指定名称的控制台日志记录器实例
/// </summary>
/// <param name="name">日志记录器的名称</param>
/// <returns>控制台日志记录器实例</returns>
@ -14,4 +14,4 @@ public class ConsoleLoggerFactory : ILoggerFactory
{
return new ConsoleLogger(name);
}
}
}

View File

@ -1,61 +1,61 @@
namespace GFramework.Core.logging;
/// <summary>
/// 定义日志记录接口,提供日志记录和级别检查功能
/// 定义日志记录接口,提供日志记录和级别检查功能
/// </summary>
public interface ILogger
{
/// <summary>
/// 根日志记录器的名称常量
/// 根日志记录器的名称常量
/// </summary>
public const string RootLoggerName = "ROOT";
/// <summary>
/// 获取日志记录器的名称
/// 获取日志记录器的名称
/// </summary>
/// <returns>日志记录器的名称</returns>
string Name();
#region Level Enabled Check
/// <summary>
/// 检查是否启用了Trace级别日志
/// 检查是否启用了Trace级别日志
/// </summary>
/// <returns>如果启用了Trace级别日志则返回true否则返回false</returns>
bool IsTraceEnabled();
/// <summary>
/// 检查是否启用了Debug级别日志
/// 检查是否启用了Debug级别日志
/// </summary>
/// <returns>如果启用了Debug级别日志则返回true否则返回false</returns>
bool IsDebugEnabled();
/// <summary>
/// 检查是否启用了Info级别日志
/// 检查是否启用了Info级别日志
/// </summary>
/// <returns>如果启用了Info级别日志则返回true否则返回false</returns>
bool IsInfoEnabled();
/// <summary>
/// 检查是否启用了Warn级别日志
/// 检查是否启用了Warn级别日志
/// </summary>
/// <returns>如果启用了Warn级别日志则返回true否则返回false</returns>
bool IsWarnEnabled();
/// <summary>
/// 检查是否启用了Error级别日志
/// 检查是否启用了Error级别日志
/// </summary>
/// <returns>如果启用了Error级别日志则返回true否则返回false</returns>
bool IsErrorEnabled();
/// <summary>
/// 检查是否启用了Fatal级别日志
/// 检查是否启用了Fatal级别日志
/// </summary>
/// <returns>如果启用了Fatal级别日志则返回true否则返回false</returns>
bool IsFatalEnabled();
/// <summary>
/// 检查指定的日志级别是否已启用
/// 检查指定的日志级别是否已启用
/// </summary>
/// <param name="level">要检查的日志级别</param>
/// <returns>如果指定的日志级别已启用则返回true否则返回false</returns>
@ -74,26 +74,26 @@ public interface ILogger
}
#endregion
#region Trace Logging Methods
/// <summary>
/// 记录 TRACE 级别的消息
/// 记录 TRACE 级别的消息
/// </summary>
/// <param name="msg">要记录的消息字符串</param>
void Trace(string msg);
/// <summary>
/// 根据指定格式和参数记录 TRACE 级别的消息
/// 当日志记录器对 TRACE 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 TRACE 级别的消息
/// 当日志记录器对 TRACE 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg">参数</param>
void Trace(string format, object arg);
/// <summary>
/// 根据指定格式和参数记录 TRACE 级别的消息
/// 当日志记录器对 TRACE 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 TRACE 级别的消息
/// 当日志记录器对 TRACE 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg1">第一个参数</param>
@ -101,15 +101,15 @@ public interface ILogger
void Trace(string format, object arg1, object arg2);
/// <summary>
/// 根据指定格式和参数数组记录 TRACE 级别的消息
/// 当日志记录器对 TRACE 级别禁用时,此方法可避免不必要的字符串连接
/// 根据指定格式和参数数组记录 TRACE 级别的消息
/// 当日志记录器对 TRACE 级别禁用时,此方法可避免不必要的字符串连接
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arguments">参数数组</param>
void Trace(string format, params object[] arguments);
/// <summary>
/// 使用伴随消息在 TRACE 级别记录异常
/// 使用伴随消息在 TRACE 级别记录异常
/// </summary>
/// <param name="msg">伴随异常的消息</param>
/// <param name="t">要记录的异常</param>
@ -120,22 +120,22 @@ public interface ILogger
#region Debug Logging Methods
/// <summary>
/// 记录 DEBUG 级别的消息
/// 记录 DEBUG 级别的消息
/// </summary>
/// <param name="msg">要记录的消息字符串</param>
void Debug(string msg);
/// <summary>
/// 根据指定格式和参数记录 DEBUG 级别的消息
/// 当日志记录器对 DEBUG 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 DEBUG 级别的消息
/// 当日志记录器对 DEBUG 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg">参数</param>
void Debug(string format, object arg);
/// <summary>
/// 根据指定格式和参数记录 DEBUG 级别的消息
/// 当日志记录器对 DEBUG 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 DEBUG 级别的消息
/// 当日志记录器对 DEBUG 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg1">第一个参数</param>
@ -143,15 +143,15 @@ public interface ILogger
void Debug(string format, object arg1, object arg2);
/// <summary>
/// 根据指定格式和参数数组记录 DEBUG 级别的消息
/// 当日志记录器对 DEBUG 级别禁用时,此方法可避免不必要的字符串连接
/// 根据指定格式和参数数组记录 DEBUG 级别的消息
/// 当日志记录器对 DEBUG 级别禁用时,此方法可避免不必要的字符串连接
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arguments">参数数组</param>
void Debug(string format, params object[] arguments);
/// <summary>
/// 使用伴随消息在 DEBUG 级别记录异常
/// 使用伴随消息在 DEBUG 级别记录异常
/// </summary>
/// <param name="msg">伴随异常的消息</param>
/// <param name="t">要记录的异常</param>
@ -162,22 +162,22 @@ public interface ILogger
#region Info Logging Methods
/// <summary>
/// 记录 INFO 级别的消息
/// 记录 INFO 级别的消息
/// </summary>
/// <param name="msg">要记录的消息字符串</param>
void Info(string msg);
/// <summary>
/// 根据指定格式和参数记录 INFO 级别的消息
/// 当日志记录器对 INFO 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 INFO 级别的消息
/// 当日志记录器对 INFO 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg">参数</param>
void Info(string format, object arg);
/// <summary>
/// 根据指定格式和参数记录 INFO 级别的消息
/// 当日志记录器对 INFO 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 INFO 级别的消息
/// 当日志记录器对 INFO 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg1">第一个参数</param>
@ -185,15 +185,15 @@ public interface ILogger
void Info(string format, object arg1, object arg2);
/// <summary>
/// 根据指定格式和参数数组记录 INFO 级别的消息
/// 当日志记录器对 INFO 级别禁用时,此方法可避免不必要的字符串连接
/// 根据指定格式和参数数组记录 INFO 级别的消息
/// 当日志记录器对 INFO 级别禁用时,此方法可避免不必要的字符串连接
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arguments">参数数组</param>
void Info(string format, params object[] arguments);
/// <summary>
/// 使用伴随消息在 INFO 级别记录异常
/// 使用伴随消息在 INFO 级别记录异常
/// </summary>
/// <param name="msg">伴随异常的消息</param>
/// <param name="t">要记录的异常</param>
@ -204,22 +204,22 @@ public interface ILogger
#region Warn Logging Methods
/// <summary>
/// 记录 WARN 级别的消息
/// 记录 WARN 级别的消息
/// </summary>
/// <param name="msg">要记录的消息字符串</param>
void Warn(string msg);
/// <summary>
/// 根据指定格式和参数记录 WARN 级别的消息
/// 当日志记录器对 WARN 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 WARN 级别的消息
/// 当日志记录器对 WARN 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg">参数</param>
void Warn(string format, object arg);
/// <summary>
/// 根据指定格式和参数记录 WARN 级别的消息
/// 当日志记录器对 WARN 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 WARN 级别的消息
/// 当日志记录器对 WARN 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg1">第一个参数</param>
@ -227,15 +227,15 @@ public interface ILogger
void Warn(string format, object arg1, object arg2);
/// <summary>
/// 根据指定格式和参数数组记录 WARN 级别的消息
/// 当日志记录器对 WARN 级别禁用时,此方法可避免不必要的字符串连接
/// 根据指定格式和参数数组记录 WARN 级别的消息
/// 当日志记录器对 WARN 级别禁用时,此方法可避免不必要的字符串连接
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arguments">参数数组</param>
void Warn(string format, params object[] arguments);
/// <summary>
/// 使用伴随消息在 WARN 级别记录异常
/// 使用伴随消息在 WARN 级别记录异常
/// </summary>
/// <param name="msg">伴随异常的消息</param>
/// <param name="t">要记录的异常</param>
@ -246,22 +246,22 @@ public interface ILogger
#region Error Logging Methods
/// <summary>
/// 记录 ERROR 级别的消息
/// 记录 ERROR 级别的消息
/// </summary>
/// <param name="msg">要记录的消息字符串</param>
void Error(string msg);
/// <summary>
/// 根据指定格式和参数记录 ERROR 级别的消息
/// 当日志记录器对 ERROR 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 ERROR 级别的消息
/// 当日志记录器对 ERROR 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg">参数</param>
void Error(string format, object arg);
/// <summary>
/// 根据指定格式和参数记录 ERROR 级别的消息
/// 当日志记录器对 ERROR 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 ERROR 级别的消息
/// 当日志记录器对 ERROR 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg1">第一个参数</param>
@ -269,15 +269,15 @@ public interface ILogger
void Error(string format, object arg1, object arg2);
/// <summary>
/// 根据指定格式和参数数组记录 ERROR 级别的消息
/// 当日志记录器对 ERROR 级别禁用时,此方法可避免不必要的字符串连接
/// 根据指定格式和参数数组记录 ERROR 级别的消息
/// 当日志记录器对 ERROR 级别禁用时,此方法可避免不必要的字符串连接
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arguments">参数数组</param>
void Error(string format, params object[] arguments);
/// <summary>
/// 使用伴随消息在 ERROR 级别记录异常
/// 使用伴随消息在 ERROR 级别记录异常
/// </summary>
/// <param name="msg">伴随异常的消息</param>
/// <param name="t">要记录的异常</param>
@ -288,22 +288,22 @@ public interface ILogger
#region Fatal Logging Methods
/// <summary>
/// 记录 FATAL 级别的消息
/// 记录 FATAL 级别的消息
/// </summary>
/// <param name="msg">要记录的消息字符串</param>
void Fatal(string msg);
/// <summary>
/// 根据指定格式和参数记录 FATAL 级别的消息
/// 当日志记录器对 FATAL 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 FATAL 级别的消息
/// 当日志记录器对 FATAL 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg">参数</param>
void Fatal(string format, object arg);
/// <summary>
/// 根据指定格式和参数记录 FATAL 级别的消息
/// 当日志记录器对 FATAL 级别禁用时,此方法可避免不必要的对象创建
/// 根据指定格式和参数记录 FATAL 级别的消息
/// 当日志记录器对 FATAL 级别禁用时,此方法可避免不必要的对象创建
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arg1">第一个参数</param>
@ -311,19 +311,19 @@ public interface ILogger
void Fatal(string format, object arg1, object arg2);
/// <summary>
/// 根据指定格式和参数数组记录 FATAL 级别的消息
/// 当日志记录器对 FATAL 级别禁用时,此方法可避免不必要的字符串连接
/// 根据指定格式和参数数组记录 FATAL 级别的消息
/// 当日志记录器对 FATAL 级别禁用时,此方法可避免不必要的字符串连接
/// </summary>
/// <param name="format">格式字符串</param>
/// <param name="arguments">参数数组</param>
void Fatal(string format, params object[] arguments);
/// <summary>
/// 使用伴随消息在 FATAL 级别记录异常
/// 使用伴随消息在 FATAL 级别记录异常
/// </summary>
/// <param name="msg">伴随异常的消息</param>
/// <param name="t">要记录的异常</param>
void Fatal(string msg, Exception t);
#endregion
}
}

View File

@ -1,12 +1,12 @@
namespace GFramework.Core.logging;
/// <summary>
/// 定义日志工厂接口,用于创建日志记录器实例
/// 定义日志工厂接口,用于创建日志记录器实例
/// </summary>
public interface ILoggerFactory
{
/// <summary>
/// 根据指定的名称获取日志记录器实例
/// 根据指定的名称获取日志记录器实例
/// </summary>
/// <param name="name">日志记录器的名称</param>
/// <returns>指定名称的日志记录器实例</returns>

View File

@ -1,32 +1,37 @@
namespace GFramework.Core.logging;
/// <summary>
/// 定义日志级别的枚举,用于标识不同严重程度的日志消息
/// 定义日志级别的枚举,用于标识不同严重程度的日志消息
/// </summary>
public enum LogLevel
{
/// <summary>
/// 跟踪级别,用于详细的程序执行流程信息
/// 跟踪级别,用于详细的程序执行流程信息
/// </summary>
Trace,
/// <summary>
/// 调试级别,用于调试过程中的详细信息
/// 调试级别,用于调试过程中的详细信息
/// </summary>
Debug,
/// <summary>
/// 信息级别,用于一般性的程序运行信息
/// 信息级别,用于一般性的程序运行信息
/// </summary>
Info,
/// <summary>
/// 警告级别,用于表示可能的问题或异常情况
/// 警告级别,用于表示可能的问题或异常情况
/// </summary>
Warning,
/// <summary>
/// 错误级别,用于表示错误但程序仍可继续运行的情况
/// 错误级别,用于表示错误但程序仍可继续运行的情况
/// </summary>
Error,
/// <summary>
/// 致命级别,用于表示严重的错误导致程序无法继续运行
/// 致命级别,用于表示严重的错误导致程序无法继续运行
/// </summary>
Fatal
}
}

View File

@ -1,7 +1,7 @@
namespace GFramework.Core.logging;
/// <summary>
/// 空操作日志记录器实现,不执行任何实际的日志记录操作
/// 空操作日志记录器实现,不执行任何实际的日志记录操作
/// </summary>
/// <param name="name">日志记录器名称默认为null</param>
/// <param name="minLevel">最小日志级别默认为Info</param>
@ -10,13 +10,12 @@ internal sealed class NoopLogger(
LogLevel minLevel = LogLevel.Info) : AbstractLogger(name ?? ILogger.RootLoggerName, minLevel)
{
/// <summary>
/// 重写写入方法,空操作实现,不执行任何实际的日志记录操作
/// 重写写入方法,空操作实现,不执行任何实际的日志记录操作
/// </summary>
/// <param name="level">日志级别</param>
/// <param name="message">日志消息</param>
/// <param name="exception">异常信息</param>
protected override void Write(LogLevel level, string message, Exception? exception)
{
}
}
}

View File

@ -1,12 +1,12 @@
namespace GFramework.Core.logging;
/// <summary>
/// 无操作日志工厂实现,用于提供空的日志记录功能
/// 无操作日志工厂实现,用于提供空的日志记录功能
/// </summary>
public class NoopLoggerFactory: ILoggerFactory
public class NoopLoggerFactory : ILoggerFactory
{
/// <summary>
/// 获取指定名称的无操作日志记录器
/// 获取指定名称的无操作日志记录器
/// </summary>
/// <param name="name">日志记录器的名称</param>
/// <returns>返回一个NoopLogger实例该实例不执行任何实际的日志记录操作</returns>

View File

@ -2,7 +2,8 @@
## 概述
GFramework.Core 提供了一个灵活、可配置的日志系统,支持多级别、多类别和多种输出方式的日志记录。默认日志级别为 `Info`,确保框架的关键操作都能被记录下来。
GFramework.Core 提供了一个灵活、可配置的日志系统,支持多级别、多类别和多种输出方式的日志记录。默认日志级别为 `Info`
,确保框架的关键操作都能被记录下来。
## 主要特性
@ -241,27 +242,32 @@ paymentLogger.Info("支付成功", new { OrderId = "ORD_789", TransactionId = "t
GFramework.Core 在以下关键位置自动添加了日志记录:
### 架构模块 (Architecture)
- 架构初始化流程
- 组件注册和初始化
- 生命周期阶段变更
- 模块安装和卸载
### IOC容器 (IOC)
- 对象注册和获取
- 容器冻结操作
- 重复注册检测
### 事件系统 (Event)
- 事件发送和接收
- 事件处理器注册和注销
### 系统模块 (System)
- 系统初始化和销毁
- 组件生命周期管理
## 输出格式
### 控制台输出示例
```
[2025-12-23 12:34:56.789] INFO Architecture Architecture initialized
[2025-12-23 12:34:56.790] INFO Architecture Initializing 3 systems
@ -271,6 +277,7 @@ GFramework.Core 在以下关键位置自动添加了日志记录:
```
### 日志输出级别颜色
- **Trace**: 灰色
- **Debug**: 青色
- **Info**: 白色
@ -281,11 +288,11 @@ GFramework.Core 在以下关键位置自动添加了日志记录:
## 最佳实践
1. **使用合适的日志级别**:
- 使用 `Info` 记录重要业务流程
- 使用 `Debug` 记录调试信息
- 使用 `Warning` 记录异常情况
- 使用 `Error` 记录错误但不影响程序运行
- 使用 `Fatal` 记录严重错误
- 使用 `Info` 记录重要业务流程
- 使用 `Debug` 记录调试信息
- 使用 `Warning` 记录异常情况
- 使用 `Error` 记录错误但不影响程序运行
- 使用 `Fatal` 记录严重错误
2. **提供上下文信息**:
```csharp
@ -331,6 +338,7 @@ GFramework.Core 在以下关键位置自动添加了日志记录:
## 配置建议
### 开发环境
```csharp
Log.Configure(
minLevel: LogLevel.Debug,
@ -341,6 +349,7 @@ Log.Configure(
```
### 生产环境
```csharp
var config = new LogConfig
{

View File

@ -12,6 +12,14 @@ public abstract class AbstractModel : IModel
/// </summary>
protected IArchitecture Architecture;
/// <summary>
/// 初始化模型调用抽象方法OnInit执行具体初始化逻辑
/// </summary>
void IModel.Init()
{
OnInit();
}
/// <summary>
/// 获取模型所属的架构实例
/// </summary>
@ -30,14 +38,6 @@ public abstract class AbstractModel : IModel
Architecture = architecture;
}
/// <summary>
/// 初始化模型调用抽象方法OnInit执行具体初始化逻辑
/// </summary>
void IModel.Init()
{
OnInit();
}
/// <summary>
/// 抽象初始化方法,由子类实现具体的初始化逻辑
/// </summary>

View File

@ -1,8 +1,4 @@
using GFramework.Core.events;
using GFramework.Core.rule;
using GFramework.Core.utility;
namespace GFramework.Core.model;
namespace GFramework.Core.model;
/// <summary>
/// 模型接口,定义了模型的基本行为和功能

View File

@ -6,7 +6,7 @@ namespace GFramework.Core.query;
/// 抽象查询类,提供查询操作的基础实现
/// </summary>
/// <typeparam name="T">查询结果的类型</typeparam>
public abstract class AbstractQuery<T> :ContextAwareBase, IQuery<T>
public abstract class AbstractQuery<T> : ContextAwareBase, IQuery<T>
{
/// <summary>
/// 执行查询操作
@ -16,7 +16,7 @@ public abstract class AbstractQuery<T> :ContextAwareBase, IQuery<T>
{
return OnDo();
}
/// <summary>
/// 抽象方法,由子类实现具体的查询逻辑
/// </summary>

View File

@ -6,7 +6,7 @@ namespace GFramework.Core.query;
/// 查询接口,定义了执行查询操作的契约
/// </summary>
/// <typeparam name="TResult">查询结果的类型</typeparam>
public interface IQuery<out TResult>:IContextAware
public interface IQuery<out TResult> : IContextAware
{
/// <summary>
/// 执行查询操作并返回结果

View File

@ -3,17 +3,17 @@
namespace GFramework.Core.rule;
/// <summary>
/// 上下文感知基类实现了IContextAware接口为需要感知架构上下文的类提供基础实现
/// 上下文感知基类实现了IContextAware接口为需要感知架构上下文的类提供基础实现
/// </summary>
public abstract class ContextAwareBase : IContextAware
{
/// <summary>
/// 获取当前实例的架构上下文
/// 获取当前实例的架构上下文
/// </summary>
protected IArchitectureContext Context { get; private set; } = null!;
/// <summary>
/// 设置架构上下文的实现方法,由框架调用
/// 设置架构上下文的实现方法,由框架调用
/// </summary>
/// <param name="context">要设置的架构上下文实例</param>
void IContextAware.SetContext(IArchitectureContext context)
@ -23,7 +23,9 @@ public abstract class ContextAwareBase : IContextAware
}
/// <summary>
/// 当上下文准备就绪时调用的虚方法,子类可以重写此方法来执行上下文相关的初始化逻辑
/// 当上下文准备就绪时调用的虚方法,子类可以重写此方法来执行上下文相关的初始化逻辑
/// </summary>
protected virtual void OnContextReady() { }
}
protected virtual void OnContextReady()
{
}
}

View File

@ -3,13 +3,13 @@
namespace GFramework.Core.rule;
/// <summary>
/// 上下文感知接口,用于为实现该接口的类提供设置架构上下文的能力
/// 上下文感知接口,用于为实现该接口的类提供设置架构上下文的能力
/// </summary>
public interface IContextAware
{
/// <summary>
/// 设置架构上下文
/// 设置架构上下文
/// </summary>
/// <param name="context">架构上下文对象,用于提供架构级别的服务和功能访问</param>
void SetContext(IArchitectureContext context);
}
}

View File

@ -3,13 +3,13 @@
namespace GFramework.Core.rule;
/// <summary>
/// 定义一个支持日志记录的接口,允许实现类设置和使用日志记录器
/// 定义一个支持日志记录的接口,允许实现类设置和使用日志记录器
/// </summary>
public interface ILogAware
{
/// <summary>
/// 设置日志记录器
/// 设置日志记录器
/// </summary>
/// <param name="logger">要设置的ILogger实例</param>
void SetLogger(ILogger logger);
}
}

View File

@ -13,7 +13,7 @@ public interface ISystem : IContextAware
/// 在系统被创建后调用,用于执行系统的初始化逻辑
/// </summary>
void Init();
/// <summary>
/// 销毁系统
/// 在系统被销毁前调用,用于执行系统的资源清理逻辑

View File

@ -4,15 +4,15 @@ using GFramework.Core.rule;
namespace GFramework.Core.utility;
/// <summary>
/// 抽象上下文工具类,提供上下文相关的通用功能实现
/// 继承自ContextAwareBase并实现IContextUtility接口
/// 抽象上下文工具类,提供上下文相关的通用功能实现
/// 继承自ContextAwareBase并实现IContextUtility接口
/// </summary>
public abstract class AbstractContextUtility : ContextAwareBase, IContextUtility
{
protected ILogger Logger = null !;
/// <summary>
/// 初始化上下文工具类
/// 初始化上下文工具类
/// </summary>
void IContextUtility.Init()
{

View File

@ -3,14 +3,13 @@
namespace GFramework.Core.utility;
/// <summary>
/// 上下文工具接口继承自IUtility和IContextAware接口
/// 提供具有上下文感知能力的工具功能
/// 上下文工具接口继承自IUtility和IContextAware接口
/// 提供具有上下文感知能力的工具功能
/// </summary>
public interface IContextUtility:IUtility,IContextAware
public interface IContextUtility : IUtility, IContextAware
{
/// <summary>
/// 初始化上下文工具
/// 初始化上下文工具
/// </summary>
void Init();
}
}

View File

@ -7,6 +7,6 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj" />
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj"/>
</ItemGroup>
</Project>

View File

@ -3,20 +3,20 @@ using GFramework.Core.system;
namespace GFramework.Game.assets;
/// <summary>
/// 资源目录系统抽象基类,用于管理和注册游戏中的场景和资源。
/// 提供了统一的接口来注册和查询不同类型的资产(如游戏单元、模板、普通资源)。
/// 子类需要实现 <see cref="RegisterAssets"/> 方法以完成具体资产的注册逻辑。
/// 资源目录系统抽象基类,用于管理和注册游戏中的场景和资源。
/// 提供了统一的接口来注册和查询不同类型的资产(如游戏单元、模板、普通资源)。
/// 子类需要实现 <see cref="RegisterAssets" /> 方法以完成具体资产的注册逻辑。
/// </summary>
public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalogSystem
{
private readonly Dictionary<string, AssetCatalog.SceneUnitId> _sceneUnits = new();
private readonly Dictionary<string, AssetCatalog.ScenePageId> _scenePages = new();
private readonly Dictionary<string, AssetCatalog.AssetId> _assets = new();
private readonly Dictionary<string, AssetCatalog.ScenePageId> _scenePages = new();
private readonly Dictionary<string, AssetCatalog.SceneUnitId> _sceneUnits = new();
/// <summary>
/// 系统初始化时调用,用于触发资产注册流程。
/// 此方法会调用抽象方法 <see cref="RegisterAssets"/>,由子类提供实际注册逻辑。
/// 系统初始化时调用,用于触发资产注册流程。
/// 此方法会调用抽象方法 <see cref="RegisterAssets" />,由子类提供实际注册逻辑。
/// </summary>
protected override void OnInit()
{
@ -24,16 +24,15 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
}
/// <summary>
/// 抽象方法,必须在子类中重写。用于定义具体的资产注册逻辑。
/// 在此方法中应通过调用各种 Register 方法将资产信息添加到系统中。
/// 抽象方法,必须在子类中重写。用于定义具体的资产注册逻辑。
/// 在此方法中应通过调用各种 Register 方法将资产信息添加到系统中。
/// </summary>
protected abstract void RegisterAssets();
#region Register or Module 使
/// <summary>
/// 注册场景单元到资产目录中
/// 注册场景单元到资产目录中
/// </summary>
/// <param name="key">场景单元的唯一标识键</param>
/// <param name="path">场景单元资源的路径</param>
@ -46,7 +45,7 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
}
/// <summary>
/// 通过资产目录映射注册场景单元
/// 通过资产目录映射注册场景单元
/// </summary>
/// <param name="mapping">包含场景单元信息的资产目录映射对象</param>
/// <exception cref="InvalidOperationException">当映射ID不是SceneUnitId类型或键已存在时抛出异常</exception>
@ -62,7 +61,7 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
}
/// <summary>
/// 注册场景页面模板
/// 注册场景页面模板
/// </summary>
/// <param name="key">场景页面的唯一标识键</param>
/// <param name="path">场景页面资源路径</param>
@ -72,9 +71,9 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
if (!_scenePages.TryAdd(key, new AssetCatalog.ScenePageId(path)))
throw new InvalidOperationException($"Template key duplicated: {key}");
}
/// <summary>
/// 通过资产目录映射注册场景页面
/// 通过资产目录映射注册场景页面
/// </summary>
/// <param name="mapping">包含场景页面信息的资产目录映射对象</param>
/// <exception cref="InvalidOperationException">当映射ID不是ScenePageId类型或键已存在时抛出异常</exception>
@ -91,7 +90,7 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
/// <summary>
/// 注册一个通用资源Asset使用指定的键和路径。
/// 注册一个通用资源Asset使用指定的键和路径。
/// </summary>
/// <param name="key">唯一标识该资源的字符串键。</param>
/// <param name="path">该资源对应的资源路径。</param>
@ -103,11 +102,11 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
}
/// <summary>
/// 根据映射对象注册一个通用资源Asset
/// 根据映射对象注册一个通用资源Asset
/// </summary>
/// <param name="mapping">包含键与ID映射关系的对象。</param>
/// <exception cref="InvalidOperationException">
/// 当映射ID不是 <see cref="AssetCatalog.AssetId"/> 类型或键重复时抛出异常。
/// 当映射ID不是 <see cref="AssetCatalog.AssetId" /> 类型或键重复时抛出异常。
/// </exception>
public void RegisterAsset(AssetCatalog.AssetCatalogMapping mapping)
{
@ -117,51 +116,71 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
if (!_assets.TryAdd(mapping.Key, assetId))
throw new InvalidOperationException($"Asset key duplicated: {mapping.Key}");
}
#endregion
#region Query
/// <summary>
/// 根据指定的键获取场景单元标识符
/// 根据指定的键获取场景单元标识符
/// </summary>
/// <param name="key">用于查找场景单元的键值</param>
/// <returns>返回与指定键对应的场景单元标识符</returns>
public AssetCatalog.SceneUnitId GetSceneUnit(string key) => _sceneUnits[key];
public AssetCatalog.SceneUnitId GetSceneUnit(string key)
{
return _sceneUnits[key];
}
/// <summary>
/// 根据指定的键获取场景页面标识符
/// 根据指定的键获取场景页面标识符
/// </summary>
/// <param name="key">用于查找场景页面的键值</param>
/// <returns>返回与指定键对应的场景页面标识符</returns>
public AssetCatalog.ScenePageId GetScenePage(string key) => _scenePages[key];
public AssetCatalog.ScenePageId GetScenePage(string key)
{
return _scenePages[key];
}
/// <summary>
/// 获取指定键对应的通用资源ID。
/// 获取指定键对应的通用资源ID。
/// </summary>
/// <param name="key">要查找的通用资源键。</param>
/// <returns>对应的通用资源ID。</returns>
/// <exception cref="KeyNotFoundException">如果未找到指定键则抛出异常。</exception>
public AssetCatalog.AssetId GetAsset(string key) => _assets[key];
public AssetCatalog.AssetId GetAsset(string key)
{
return _assets[key];
}
/// <summary>
/// 检查是否存在指定键的场景单元
/// 检查是否存在指定键的场景单元
/// </summary>
/// <param name="key">用于查找场景单元的键值</param>
/// <returns>存在返回true否则返回false</returns>
public bool HasSceneUnit(string key) => _sceneUnits.ContainsKey(key);
public bool HasSceneUnit(string key)
{
return _sceneUnits.ContainsKey(key);
}
/// <summary>
/// 检查是否存在指定键的场景页面
/// 检查是否存在指定键的场景页面
/// </summary>
/// <param name="key">用于查找场景页面的键值</param>
/// <returns>存在返回true否则返回false</returns>
public bool HasScenePage(string key) => _scenePages.ContainsKey(key);
public bool HasScenePage(string key)
{
return _scenePages.ContainsKey(key);
}
/// <summary>
/// 判断是否存在指定键的通用资源。
/// 判断是否存在指定键的通用资源。
/// </summary>
/// <param name="key">要检查的通用资源键。</param>
/// <returns>若存在返回 true否则返回 false。</returns>
public bool HasAsset(string key) => _assets.ContainsKey(key);
public bool HasAsset(string key)
{
return _assets.ContainsKey(key);
}
#endregion
}
}

View File

@ -1,47 +1,45 @@
namespace GFramework.Game.assets;
/// <summary>
/// 资源目录类,用于定义和管理游戏中的场景和资源标识符
/// 资源目录类,用于定义和管理游戏中的场景和资源标识符
/// </summary>
public static class AssetCatalog
{
/// <summary>
/// 资源标识符接口,定义了资源路径的访问接口
/// 资源标识符接口,定义了资源路径的访问接口
/// </summary>
public interface IAssetId
{
/// <summary>
/// 获取资源的路径
/// 获取资源的路径
/// </summary>
string Path { get; }
}
/// <summary>
/// 资源目录映射结构体,用于存储资源目录的键值对映射关系
/// 资源目录映射结构体,用于存储资源目录的键值对映射关系
/// </summary>
/// <param name="Key">资源目录的键</param>
/// <param name="Id">资源标识符</param>
public readonly record struct AssetCatalogMapping(string Key, IAssetId Id);
/// <summary>
/// 场景页面资源标识符结构体,用于标识场景页面资源
/// 场景页面资源标识符结构体,用于标识场景页面资源
/// </summary>
/// <param name="Path">场景页面资源路径</param>
public readonly record struct ScenePageId(string Path) : IAssetId;
/// <summary>
/// 场景单元资源标识符结构体,用于标识场景单元资源
/// 场景单元资源标识符结构体,用于标识场景单元资源
/// </summary>
/// <param name="Path">场景单元资源路径</param>
public readonly record struct SceneUnitId(string Path) : IAssetId;
/// <summary>
/// 通用资源标识符结构体实现IAssetId接口
/// 通用资源标识符结构体实现IAssetId接口
/// </summary>
/// <param name="Path">资源路径</param>
public readonly record struct AssetId(string Path) : IAssetId;
}
}

View File

@ -3,19 +3,19 @@
namespace GFramework.Game.assets;
/// <summary>
/// 资源目录系统接口,用于管理场景和资源的获取与查询
/// 资源目录系统接口,用于管理场景和资源的获取与查询
/// </summary>
public interface IAssetCatalogSystem : ISystem
{
/// <summary>
/// 根据指定的键获取场景单元标识符
/// 根据指定的键获取场景单元标识符
/// </summary>
/// <param name="key">用于查找场景单元的键值</param>
/// <returns>返回与指定键对应的场景单元标识符</returns>
AssetCatalog.SceneUnitId GetSceneUnit(string key);
/// <summary>
/// 根据指定的键获取场景页面标识符
/// 根据指定的键获取场景页面标识符
/// </summary>
/// <param name="key">用于查找场景页面的键值</param>
/// <returns>返回与指定键对应的场景页面标识符</returns>
@ -23,14 +23,14 @@ public interface IAssetCatalogSystem : ISystem
/// <summary>
/// 根据指定的键获取资源ID
/// 根据指定的键获取资源ID
/// </summary>
/// <param name="key">用于查找资源的键值</param>
/// <returns>返回对应的资源ID如果未找到则返回默认值</returns>
AssetCatalog.AssetId GetAsset(string key);
/// <summary>
/// 注册场景单元到资产目录中
/// 注册场景单元到资产目录中
/// </summary>
/// <param name="key">场景单元的唯一标识键</param>
/// <param name="path">场景单元资源的路径</param>
@ -38,14 +38,14 @@ public interface IAssetCatalogSystem : ISystem
public void RegisterSceneUnit(string key, string path);
/// <summary>
/// 通过资产目录映射注册场景单元
/// 通过资产目录映射注册场景单元
/// </summary>
/// <param name="mapping">包含场景单元信息的资产目录映射对象</param>
/// <exception cref="InvalidOperationException">当映射ID不是SceneUnitId类型或键已存在时抛出异常</exception>
public void RegisterSceneUnit(AssetCatalog.AssetCatalogMapping mapping);
/// <summary>
/// 注册场景页面模板
/// 注册场景页面模板
/// </summary>
/// <param name="key">场景页面的唯一标识键</param>
/// <param name="path">场景页面资源路径</param>
@ -53,28 +53,28 @@ public interface IAssetCatalogSystem : ISystem
void RegisterScenePage(string key, string path);
/// <summary>
/// 通过资产目录映射注册场景页面
/// 通过资产目录映射注册场景页面
/// </summary>
/// <param name="mapping">包含场景页面信息的资产目录映射对象</param>
/// <exception cref="InvalidOperationException">当映射ID不是ScenePageId类型或键已存在时抛出异常</exception>
void RegisterScenePage(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>
@ -82,17 +82,16 @@ public interface IAssetCatalogSystem : ISystem
/// <summary>
/// 检查是否存在指定键的场景页面
/// 检查是否存在指定键的场景页面
/// </summary>
/// <param name="key">用于查找场景页面的键值</param>
/// <returns>存在返回true否则返回false</returns>
bool HasScenePage(string key);
/// <summary>
/// 检查是否存在指定键的资源
/// 检查是否存在指定键的资源
/// </summary>
/// <param name="key">用于查找资源的键值</param>
/// <returns>存在返回true否则返回false</returns>
bool HasAsset(string key);
}

View File

@ -3,24 +3,23 @@
namespace GFramework.Game.assets;
/// <summary>
/// 资源工厂系统接口,用于获取指定类型的资源创建函数
/// 资源工厂系统接口,用于获取指定类型的资源创建函数
/// </summary>
public interface IResourceFactorySystem : ISystem
{
/// <summary>
/// 根据指定键名获取指定类型T的资源创建函数
/// 根据指定键名获取指定类型T的资源创建函数
/// </summary>
/// <typeparam name="T">要获取创建函数的资源类型</typeparam>
/// <param name="key">用于标识资源的键名</param>
/// <returns>返回一个创建T类型实例的函数委托</returns>
Func<T> GetFactory<T>(string key);
/// <summary>
/// 根据资产目录映射获取指定类型T的资源创建函数
/// 根据资产目录映射获取指定类型T的资源创建函数
/// </summary>
/// <typeparam name="T">要获取创建函数的资源类型</typeparam>
/// <param name="mapping">资产目录映射信息</param>
/// <returns>返回一个创建T类型实例的函数委托</returns>
Func<T> GetFactory<T>(AssetCatalog.AssetCatalogMapping mapping);
}
}

View File

@ -1,82 +1,85 @@
namespace GFramework.Game.assets;
/// <summary>
/// 资源工厂类,用于注册和解析各种资源的创建工厂
/// 资源工厂类,用于注册和解析各种资源的创建工厂
/// </summary>
public static class ResourceFactory
{
/// <summary>
/// 可预加载条目接口,定义了是否需要预加载以及执行工厂的方法
/// 可预加载条目接口,定义了是否需要预加载以及执行工厂的方法
/// </summary>
private interface IPreloadableEntry
{
/// <summary>
/// 获取一个值,表示该资源是否需要预加载
/// 获取一个值,表示该资源是否需要预加载
/// </summary>
bool Preload { get; }
/// <summary>
/// 执行与该条目关联的工厂方法
/// </summary>
void ExecuteFactory();
/// <summary>
/// 获取资源类型
/// 获取资源类型
/// </summary>
Type ResourceType { get; }
/// <summary>
/// 获取资源键值
/// 获取资源键值
/// </summary>
string Key { get; }
/// <summary>
/// 执行与该条目关联的工厂方法
/// </summary>
void ExecuteFactory();
}
/// <summary>
/// 表示一个具体的资源工厂条目,实现 IPreloadableEntry 接口
/// 表示一个具体的资源工厂条目,实现 IPreloadableEntry 接口
/// </summary>
/// <typeparam name="T">资源类型</typeparam>
private sealed class Entry<T>(string key, Func<T> factory, bool preload) : IPreloadableEntry
{
/// <summary>
/// 获取用于创建资源的工厂函数
/// 获取用于创建资源的工厂函数
/// </summary>
public Func<T> Factory { get; } = factory;
/// <summary>
/// 获取一个值,表示该资源是否需要预加载
/// 获取一个值,表示该资源是否需要预加载
/// </summary>
public bool Preload { get; } = preload;
/// <summary>
/// 执行工厂函数以创建资源实例
/// 执行工厂函数以创建资源实例
/// </summary>
public void ExecuteFactory() => Factory();
public void ExecuteFactory()
{
Factory();
}
/// <summary>
/// 获取资源的类型
/// 获取资源的类型
/// </summary>
public Type ResourceType => typeof(T);
/// <summary>
/// 获取资源的键值
/// 获取资源的键值
/// </summary>
public string Key { get; } = key;
}
/// <summary>
/// 工厂注册表,管理所有已注册的资源工厂
/// 工厂注册表,管理所有已注册的资源工厂
/// </summary>
public sealed class Registry
{
/// <summary>
/// 存储所有已注册的工厂函数,键为资源类型,值为对应的工厂条目对象
/// 存储所有已注册的工厂函数,键为资源类型,值为对应的工厂条目对象
/// </summary>
private readonly Dictionary<(Type type, string key), IPreloadableEntry> _factories = new();
/// <summary>
/// 注册指定类型的资源工厂
/// 注册指定类型的资源工厂
/// </summary>
/// <typeparam name="T">要注册的资源类型</typeparam>
/// <param name="key">键</param>
@ -93,7 +96,7 @@ public static class ResourceFactory
}
/// <summary>
/// 解析并获取指定类型的工厂函数
/// 解析并获取指定类型的工厂函数
/// </summary>
/// <typeparam name="T">要获取工厂函数的资源类型</typeparam>
/// <param name="key">资源键</param>
@ -105,26 +108,21 @@ public static class ResourceFactory
if (_factories.TryGetValue(dictKey, out var entry)
&& entry is Entry<T> typed)
{
return typed.Factory;
}
throw new InvalidOperationException(
$"Factory not registered: {typeof(T).Name} with key '{key}'");
}
/// <summary>
/// 预加载所有标记为需要预加载的资源
/// 预加载所有标记为需要预加载的资源
/// </summary>
public void PreloadAll()
{
// 遍历所有已注册的工厂
foreach (var entry in _factories.Values.Where(entry => entry.Preload))
{
// 执行其工厂方法进行预加载
entry.ExecuteFactory();
}
}
}
}
}

View File

@ -4,20 +4,20 @@ using System;
namespace GFramework.Godot.SourceGenerators.Attributes.logging;
/// <summary>
/// Godot日志特性用于在类上标记以自动生成日志字段
/// Godot日志特性用于在类上标记以自动生成日志字段
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class GodotLogAttribute : Attribute
{
/// <summary>
/// 初始化 GodotLogAttribute 类的新实例
/// 初始化 GodotLogAttribute 类的新实例
/// </summary>
public GodotLogAttribute()
{
}
/// <summary>
/// 初始化 GodotLogAttribute 类的新实例
/// 初始化 GodotLogAttribute 类的新实例
/// </summary>
/// <param name="name">日志分类名</param>
public GodotLogAttribute(string? name)

View File

@ -1,44 +0,0 @@
using Microsoft.CodeAnalysis;
namespace GFramework.Godot.SourceGenerators.logging;
/// <summary>
/// 提供诊断描述符的静态类用于GFramework日志生成器的编译时检查
/// </summary>
internal static class GodotLoggerDiagnostics
{
/// <summary>
/// 诊断描述符:标识使用[GodotLog]特性的类必须声明为partial
/// </summary>
/// <remarks>
/// ID: GFLOG001
/// 严重性: Error
/// 分类: GFramework.Godot.Logging
/// </remarks>
public static readonly DiagnosticDescriptor MustBePartial =
new(
id: "GFLOG001",
title: "Class must be partial",
messageFormat: "Class '{0}' must be declared as partial to use [GodotLog]",
category: "GFramework.Godot.Logging",
DiagnosticSeverity.Error,
isEnabledByDefault: true
);
/// <summary>
/// 诊断描述符标识GodotLogAttribute无法在指定类上生成Logger
/// </summary>
/// <remarks>
/// ID: GFW_LOG001
/// 严重性: Warning
/// 分类: GFramework.Godot.Logging
/// </remarks>
public static readonly DiagnosticDescriptor LogAttributeInvalid = new(
id: "GFW_LOG001",
title: "GodotLogAttribute cannot generate Logger",
messageFormat: "GodotLogAttribute on class '{0}' is ineffective: {1}",
category: "GFramework.Godot.Logging",
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
}

View File

@ -0,0 +1,44 @@
using Microsoft.CodeAnalysis;
namespace GFramework.Godot.SourceGenerators.logging;
/// <summary>
/// 提供诊断描述符的静态类用于GFramework日志生成器的编译时检查
/// </summary>
internal static class GodotLoggerDiagnostics
{
/// <summary>
/// 诊断描述符:标识使用[GodotLog]特性的类必须声明为partial
/// </summary>
/// <remarks>
/// ID: GFLOG001
/// 严重性: Error
/// 分类: GFramework.Godot.Logging
/// </remarks>
public static readonly DiagnosticDescriptor MustBePartial =
new(
"GFLOG001",
"Class must be partial",
"Class '{0}' must be declared as partial to use [GodotLog]",
"GFramework.Godot.Logging",
DiagnosticSeverity.Error,
true
);
/// <summary>
/// 诊断描述符标识GodotLogAttribute无法在指定类上生成Logger
/// </summary>
/// <remarks>
/// ID: GFW_LOG001
/// 严重性: Warning
/// 分类: GFramework.Godot.Logging
/// </remarks>
public static readonly DiagnosticDescriptor LogAttributeInvalid = new(
"GFW_LOG001",
"GodotLogAttribute cannot generate Logger",
"GodotLogAttribute on class '{0}' is ineffective: {1}",
"GFramework.Godot.Logging",
DiagnosticSeverity.Warning,
true);
}

View File

@ -9,7 +9,7 @@ using Microsoft.CodeAnalysis.Text;
namespace GFramework.Godot.SourceGenerators.logging;
/// <summary>
/// 日志生成器用于为标记了LogAttribute的类自动生成日志字段
/// 日志生成器用于为标记了LogAttribute的类自动生成日志字段
/// </summary>
[Generator]
public sealed class GodotLoggerGenerator : IIncrementalGenerator
@ -21,7 +21,7 @@ public sealed class GodotLoggerGenerator : IIncrementalGenerator
private const string AttributeShortNameWithoutSuffix = "GodotLog";
/// <summary>
/// 初始化生成器,设置语法过滤和代码生成逻辑
/// 初始化生成器,设置语法过滤和代码生成逻辑
/// </summary>
/// <param name="context">增量生成器初始化上下文</param>
public void Initialize(IncrementalGeneratorInitializationContext context)
@ -86,7 +86,7 @@ public sealed class GodotLoggerGenerator : IIncrementalGenerator
}
/// <summary>
/// 获取类符号上的LogAttribute特性
/// 获取类符号上的LogAttribute特性
/// </summary>
/// <param name="classSymbol">类符号</param>
/// <returns>LogAttribute特性数据如果不存在则返回null</returns>
@ -104,7 +104,7 @@ public sealed class GodotLoggerGenerator : IIncrementalGenerator
}
/// <summary>
/// 生成日志字段代码
/// 生成日志字段代码
/// </summary>
/// <param name="classSymbol">类符号</param>
/// <param name="attr">LogAttribute特性数据</param>
@ -173,7 +173,7 @@ public sealed class GodotLoggerGenerator : IIncrementalGenerator
}
/// <summary>
/// 从特性数据中获取命名参数的值
/// 从特性数据中获取命名参数的值
/// </summary>
/// <param name="attr">特性数据</param>
/// <param name="name">参数名称</param>

View File

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

View File

@ -6,46 +6,45 @@ using Godot;
namespace GFramework.Godot.architecture;
/// <summary>
/// 抽象架构类,为特定类型的架构提供基础实现框架。
/// 此类负责管理架构的初始化、生命周期绑定以及扩展模块的安装与销毁。
/// 抽象架构类,为特定类型的架构提供基础实现框架。
/// 此类负责管理架构的初始化、生命周期绑定以及扩展模块的安装与销毁。
/// </summary>
public abstract class AbstractArchitecture: Architecture
public abstract class AbstractArchitecture : Architecture
{
/// <summary>
/// 架构锚点节点的唯一标识名称
/// 用于在Godot场景树中创建和查找架构锚点节点
/// 架构锚点节点的唯一标识名称
/// 用于在Godot场景树中创建和查找架构锚点节点
/// </summary>
private const string ArchitectureAnchorName = $"__{GFrameworkConstants.FrameworkName}__ArchitectureAnchor__";
/// <summary>
/// 存储所有已安装的Godot架构扩展组件列表
/// 用于在架构销毁时正确清理所有扩展资源
/// 存储所有已安装的Godot架构扩展组件列表
/// 用于在架构销毁时正确清理所有扩展资源
/// </summary>
private readonly List<IGodotModule> _extensions = [];
/// <summary>
/// 架构锚点节点引用
/// 用于将架构绑定到Godot生命周期并作为扩展节点的父节点
/// 架构锚点节点引用
/// 用于将架构绑定到Godot生命周期并作为扩展节点的父节点
/// </summary>
private ArchitectureAnchor? _anchor;
/// <summary>
/// 获取架构根节点。如果尚未初始化或已被销毁,则抛出异常。
/// 标记架构是否已被销毁的状态标志
/// 用于防止架构被重复销毁,确保资源清理只执行一次
/// </summary>
private bool _destroyed;
/// <summary>
/// 获取架构根节点。如果尚未初始化或已被销毁,则抛出异常。
/// </summary>
/// <exception cref="InvalidOperationException">当架构未准备就绪时抛出。</exception>
protected Node ArchitectureRoot => _anchor ?? throw new InvalidOperationException("Architecture root not ready");
/// <summary>
/// 标记架构是否已被销毁的状态标志
/// 用于防止架构被重复销毁,确保资源清理只执行一次
/// </summary>
private bool _destroyed;
/// <summary>
/// 初始化架构,按顺序注册模型、系统和工具。
/// 包括将架构绑定到Godot生命周期并调用模块安装逻辑。
/// 初始化架构,按顺序注册模型、系统和工具。
/// 包括将架构绑定到Godot生命周期并调用模块安装逻辑。
/// </summary>
protected override void Init()
{
@ -54,14 +53,14 @@ public abstract class AbstractArchitecture: Architecture
}
/// <summary>
/// 安装模块抽象方法,由子类实现具体的模块注册逻辑。
/// 子类应在此方法中完成所有模型、系统及工具的注册工作。
/// 安装模块抽象方法,由子类实现具体的模块注册逻辑。
/// 子类应在此方法中完成所有模型、系统及工具的注册工作。
/// </summary>
protected abstract void InstallModules();
/// <summary>
/// 将架构绑定到Godot生命周期中确保在场景树销毁时能够正确清理资源。
/// 通过创建一个锚节点来监听场景树的销毁事件。
/// 将架构绑定到Godot生命周期中确保在场景树销毁时能够正确清理资源。
/// 通过创建一个锚节点来监听场景树的销毁事件。
/// </summary>
private void AttachToGodotLifecycle()
{
@ -82,9 +81,9 @@ public abstract class AbstractArchitecture: Architecture
tree.Root.CallDeferred(Node.MethodName.AddChild, _anchor);
}
/// <summary>
/// 安装Godot模块扩展
/// 安装Godot模块扩展
/// </summary>
/// <typeparam name="TModule">模块类型必须实现IGodotModule接口</typeparam>
/// <param name="module">要安装的模块实例</param>
@ -92,30 +91,29 @@ public abstract class AbstractArchitecture: Architecture
protected async Task InstallGodotModule<TModule>(TModule module) where TModule : IGodotModule
{
module.Install(this);
// 检查锚点是否已初始化,未初始化则抛出异常
if (_anchor == null)
throw new InvalidOperationException("Anchor not initialized");
// 等待锚点准备就绪
await _anchor.WaitUntilReady();
// 延迟调用将扩展节点添加为锚点的子节点
_anchor.CallDeferred(Node.MethodName.AddChild, module.Node);
// 调用扩展的附加回调方法
module.OnAttach(this);
// 将扩展添加到扩展集合中
_extensions.Add(module);
}
/// <summary>
/// 销毁架构及其相关资源。
/// 调用所有已安装扩展的OnDetach方法并清空扩展列表。
/// 若已被销毁则直接返回。
/// 销毁架构及其相关资源。
/// 调用所有已安装扩展的OnDetach方法并清空扩展列表。
/// 若已被销毁则直接返回。
/// </summary>
public override void Destroy()
{

View File

@ -4,54 +4,50 @@ using Godot;
namespace GFramework.Godot.architecture;
/// <summary>
/// 抽象的Godot模块基类用于定义Godot框架中的模块行为
/// 抽象的Godot模块基类用于定义Godot框架中的模块行为
/// </summary>
public abstract class AbstractGodotModule: IGodotModule
public abstract class AbstractGodotModule : IGodotModule
{
/// <summary>
/// 当架构阶段发生变化时调用此方法
/// 当架构阶段发生变化时调用此方法
/// </summary>
/// <param name="phase">当前的架构阶段</param>
/// <param name="arch">架构实例</param>
public virtual void OnPhase(ArchitecturePhase phase, IArchitecture arch)
{
}
/// <summary>
/// 当架构阶段发生变化时调用此方法
/// 当架构阶段发生变化时调用此方法
/// </summary>
/// <param name="phase">当前的架构阶段</param>
public virtual void OnArchitecturePhase(ArchitecturePhase phase)
{
}
/// <summary>
/// 安装模块到指定架构中
/// 安装模块到指定架构中
/// </summary>
/// <param name="architecture">要安装到的架构实例</param>
public abstract void Install(IArchitecture architecture);
/// <summary>
/// 获取模块关联的Godot节点
/// 获取模块关联的Godot节点
/// </summary>
public abstract Node Node { get; }
/// <summary>
/// 当模块被附加到架构时调用此方法
/// 当模块被附加到架构时调用此方法
/// </summary>
/// <param name="architecture">被附加到的架构实例</param>
public virtual void OnAttach(Architecture architecture)
{
}
/// <summary>
/// 当模块从架构中分离时调用此方法
/// 当模块从架构中分离时调用此方法
/// </summary>
public virtual void OnDetach()
{
}
}
}

View File

@ -3,29 +3,28 @@
namespace GFramework.Godot.architecture;
/// <summary>
/// 架构锚点节点类用于在Godot场景树中作为架构组件的根节点
/// 该类提供了退出时的回调绑定功能,可以在节点从场景树中移除时执行清理操作
/// 架构锚点节点类用于在Godot场景树中作为架构组件的根节点
/// 该类提供了退出时的回调绑定功能,可以在节点从场景树中移除时执行清理操作
/// </summary>
public partial class ArchitectureAnchor : Node
{
private Action? _onExit;
/// <summary>
/// 绑定节点退出时的回调动作
/// 绑定节点退出时的回调动作
/// </summary>
/// <param name="onExit">当节点从场景树退出时要执行的动作</param>
public void Bind(Action onExit)
{
if (_onExit != null)
{
GD.PushWarning(
$"{nameof(ArchitectureAnchor)} already bound. Rebinding will override previous callback.");
}
_onExit = onExit;
}
/// <summary>
/// 当节点从场景树中移除时调用此方法
/// 执行绑定的退出回调并清理引用
/// 当节点从场景树中移除时调用此方法
/// 执行绑定的退出回调并清理引用
/// </summary>
public override void _ExitTree()
{
@ -33,5 +32,4 @@ public partial class ArchitectureAnchor : Node
_onExit = null;
callback?.Invoke();
}
}
}

View File

@ -4,23 +4,23 @@ using Godot;
namespace GFramework.Godot.architecture;
/// <summary>
/// Godot模块接口定义了Godot引擎中模块的基本行为和属性
/// Godot模块接口定义了Godot引擎中模块的基本行为和属性
/// </summary>
public interface IGodotModule : IArchitectureModule
{
/// <summary>
/// 获取模块关联的Godot节点
/// 获取模块关联的Godot节点
/// </summary>
Node Node { get; }
/// <summary>
/// 当模块被附加到架构时调用
/// 当模块被附加到架构时调用
/// </summary>
/// <param name="architecture">要附加到的架构实例</param>
void OnAttach(Architecture architecture);
/// <summary>
/// 当模块从架构分离时调用
/// 当模块从架构分离时调用
/// </summary>
void OnDetach();
}

View File

@ -7,29 +7,17 @@ using Godot;
namespace GFramework.Godot.assets;
/// <summary>
/// 资源工厂系统抽象基类,用于统一管理各类资源的创建与预加载逻辑。
/// 提供注册场景和资源的方法,并通过依赖的资源加载系统和资产目录系统完成实际资源的获取与构造。
/// 资源工厂系统抽象基类,用于统一管理各类资源的创建与预加载逻辑。
/// 提供注册场景和资源的方法,并通过依赖的资源加载系统和资产目录系统完成实际资源的获取与构造。
/// </summary>
public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceFactorySystem, IArchitectureLifecycle
{
private IAssetCatalogSystem? _assetCatalogSystem;
private ResourceFactory.Registry? _registry;
private IResourceLoadSystem? _resourceLoadSystem;
private IAssetCatalogSystem? _assetCatalogSystem;
/// <summary>
/// 系统初始化方法,在系统启动时执行一次。
/// 初始化资源注册表,并获取依赖的资源加载系统和资产目录系统。
/// 最后执行所有已注册资源的预加载操作。
/// </summary>
protected override void OnInit()
{
_registry = new ResourceFactory.Registry();
_resourceLoadSystem = Context.GetSystem<IResourceLoadSystem>();
_assetCatalogSystem = Context.GetSystem<IAssetCatalogSystem>();
}
/// <summary>
/// 架构阶段回调,在架构就绪时注册和预加载资源
/// 架构阶段回调,在架构就绪时注册和预加载资源
/// </summary>
/// <param name="phase">当前架构阶段</param>
/// <param name="architecture">架构实例</param>
@ -44,34 +32,51 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
}
}
/// <summary>
/// 注册系统所需的各种资源类型。由子类实现具体注册逻辑。
/// </summary>
protected abstract void RegisterResources();
/// <summary>
/// 根据指定的键获取资源工厂函数。
/// 根据指定的键获取资源工厂函数。
/// </summary>
/// <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)
{
return _registry!.ResolveFactory<T>(key);
}
/// <summary>
/// 根据资产目录映射信息获取资源工厂函数。
/// 根据资产目录映射信息获取资源工厂函数。
/// </summary>
/// <typeparam name="T">资源类型</typeparam>
/// <param name="mapping">资产目录映射信息</param>
/// <returns>返回创建指定类型资源的工厂函数</returns>
public Func<T> GetFactory<T>(AssetCatalog.AssetCatalogMapping mapping) => _registry!.ResolveFactory<T>(mapping.Key);
public Func<T> GetFactory<T>(AssetCatalog.AssetCatalogMapping mapping)
{
return _registry!.ResolveFactory<T>(mapping.Key);
}
/// <summary>
/// 系统初始化方法,在系统启动时执行一次。
/// 初始化资源注册表,并获取依赖的资源加载系统和资产目录系统。
/// 最后执行所有已注册资源的预加载操作。
/// </summary>
protected override void OnInit()
{
_registry = new ResourceFactory.Registry();
_resourceLoadSystem = Context.GetSystem<IResourceLoadSystem>();
_assetCatalogSystem = Context.GetSystem<IAssetCatalogSystem>();
}
/// <summary>
/// 注册系统所需的各种资源类型。由子类实现具体注册逻辑。
/// </summary>
protected abstract void RegisterResources();
#region Register Helpers
/// <summary>
/// 注册场景单元到资源管理系统中
/// 注册场景单元到资源管理系统中
/// </summary>
/// <typeparam name="T">场景单元类型必须继承自Node</typeparam>
/// <param name="sceneUnitKey">场景单元键值,用于标识特定的场景单元资源</param>
@ -92,7 +97,7 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
/// <summary>
/// 注册场景页面到资源管理系统中
/// 注册场景页面到资源管理系统中
/// </summary>
/// <typeparam name="T">场景页面类型必须继承自Node</typeparam>
/// <param name="scenePageKey">场景页面键值,用于标识特定的场景页面资源</param>
@ -112,7 +117,7 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
}
/// <summary>
/// 注册通用资产资源到资源管理系统中
/// 注册通用资产资源到资源管理系统中
/// </summary>
/// <typeparam name="T">资产类型必须继承自Resource</typeparam>
/// <param name="assetKey">资产键值,用于标识特定的资产资源</param>
@ -131,6 +136,5 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
);
}
#endregion
}

View File

@ -5,35 +5,35 @@ using Godot;
namespace GFramework.Godot.system;
/// <summary>
/// 资源加载系统接口,提供资源和场景的加载、实例化、预加载等功能
/// 资源加载系统接口,提供资源和场景的加载、实例化、预加载等功能
/// </summary>
public interface IResourceLoadSystem : ISystem
{
/// <summary>
/// 加载指定路径的资源
/// 加载指定路径的资源
/// </summary>
/// <typeparam name="T">资源类型必须继承自Resource</typeparam>
/// <param name="path">资源路径</param>
/// <returns>加载的资源实例</returns>
public T? LoadResource<T>(string path) where T : Resource;
/// <summary>
/// 获取场景加载器,用于延迟加载场景
/// 获取场景加载器,用于延迟加载场景
/// </summary>
/// <param name="path">场景路径</param>
/// <returns>场景的延迟加载包装器</returns>
public Lazy<PackedScene> GetSceneLoader(string path);
/// <summary>
/// 创建指定路径场景的实例
/// 创建指定路径场景的实例
/// </summary>
/// <typeparam name="T">节点类型必须继承自Node</typeparam>
/// <param name="path">场景路径</param>
/// <returns>场景实例化的节点对象</returns>
public T? CreateInstance<T>(string path) where T : Node;
/// <summary>
/// 获取或注册游戏单位工厂函数
/// 获取或注册游戏单位工厂函数
/// </summary>
/// <typeparam name="T">节点类型必须继承自Node</typeparam>
/// <param name="id">场景资源标识符</param>
@ -43,7 +43,7 @@ public interface IResourceLoadSystem : ISystem
) where T : Node;
/// <summary>
/// 获取或注册模板资源工厂函数
/// 获取或注册模板资源工厂函数
/// </summary>
/// <typeparam name="T">节点类型必须继承自Node</typeparam>
/// <param name="id">模板资源标识符</param>
@ -53,7 +53,7 @@ public interface IResourceLoadSystem : ISystem
) where T : Node;
/// <summary>
/// 获取或注册通用资产工厂函数
/// 获取或注册通用资产工厂函数
/// </summary>
/// <typeparam name="T">资源类型必须继承自Resource</typeparam>
/// <param name="id">资产资源标识符</param>
@ -65,19 +65,19 @@ public interface IResourceLoadSystem : ISystem
) where T : Resource;
/// <summary>
/// 预加载指定路径的多个资源
/// 预加载指定路径的多个资源
/// </summary>
/// <param name="paths">需要预加载的资源路径集合</param>
public void Preload(IEnumerable<string> paths);
/// <summary>
/// 卸载指定路径的资源
/// 卸载指定路径的资源
/// </summary>
/// <param name="path">需要卸载的资源路径</param>
public void Unload(string path);
/// <summary>
/// 清除所有已加载的资源
/// 清除所有已加载的资源
/// </summary>
public void ClearAll();
}
}

View File

@ -5,90 +5,33 @@ using Godot;
namespace GFramework.Godot.system;
/// <summary>
/// 资源加载系统用于统一管理和缓存Godot资源如场景、纹理等的加载与实例化。
/// 提供基础加载、场景实例化、资源工厂注册以及缓存管理功能。
/// 资源加载系统用于统一管理和缓存Godot资源如场景、纹理等的加载与实例化。
/// 提供基础加载、场景实例化、资源工厂注册以及缓存管理功能。
/// </summary>
public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
{
/// <summary>
/// 已加载的资源缓存字典键为资源路径值为已加载的Resource对象。
/// 已加载的资源缓存字典键为资源路径值为已加载的Resource对象。
/// </summary>
private readonly Dictionary<string, Resource> _loadedResources = new();
/// <summary>
/// 场景懒加载器缓存键为场景路径值为延迟加载的PackedScene对象。
/// </summary>
private readonly Dictionary<string, Lazy<PackedScene>> _sceneLoaders = new();
/// <summary>
/// 场景实例化工厂委托缓存键为场景路径值为创建该场景实例的Func委托。
/// </summary>
private readonly Dictionary<string, Delegate> _sceneFactories = new();
/// <summary>
/// 资源获取/复制工厂委托缓存键为资源路径值为获取或复制资源的Func委托。
/// 资源获取/复制工厂委托缓存键为资源路径值为获取或复制资源的Func委托。
/// </summary>
private readonly Dictionary<string, Delegate> _resourceFactories = new();
/// <summary>
/// 初始化方法,在系统初始化时打印日志信息
/// 场景实例化工厂委托缓存键为场景路径值为创建该场景实例的Func委托。
/// </summary>
protected override void OnInit()
{
}
#region
private readonly Dictionary<string, Delegate> _sceneFactories = new();
/// <summary>
/// 加载指定类型的资源并进行缓存。如果资源已经加载过则直接从缓存中返回
/// 场景懒加载器缓存键为场景路径值为延迟加载的PackedScene对象。
/// </summary>
/// <typeparam name="T">要加载的资源类型必须继承自Resource。</typeparam>
/// <param name="path">资源在项目中的相对路径。</param>
/// <returns>成功加载的资源对象若路径无效或加载失败则返回null。</returns>
public T? LoadResource<T>(string path) where T : Resource
{
if (string.IsNullOrEmpty(path))
return null;
if (_loadedResources.TryGetValue(path, out var cached))
return cached as T;
var res = GD.Load<T>(path);
if (res == null)
{
GD.PrintErr($"[ResourceLoadSystem] Load failed: {path}");
return null;
}
_loadedResources[path] = res;
return res;
}
private readonly Dictionary<string, Lazy<PackedScene>> _sceneLoaders = new();
/// <summary>
/// 获取一个场景的懒加载器用于按需加载PackedScene资源。
/// 若对应路径尚未注册加载器则会自动创建一个新的Lazy实例。
/// </summary>
/// <param name="path">场景文件的相对路径。</param>
/// <returns>表示该场景懒加载逻辑的Lazy&lt;PackedScene&gt;对象。</returns>
public Lazy<PackedScene> GetSceneLoader(string path)
{
if (_sceneLoaders.TryGetValue(path, out var loader))
return loader;
loader = new Lazy<PackedScene>(() =>
{
var scene = LoadResource<PackedScene>(path);
return scene ?? throw new InvalidOperationException($"Failed to load scene: {path}");
});
_sceneLoaders[path] = loader;
return loader;
}
#endregion
/// <summary>
/// 根据给定路径加载场景,并创建其节点实例。
/// 根据给定路径加载场景,并创建其节点实例。
/// </summary>
/// <typeparam name="T">期望返回的节点类型必须是Node的子类。</typeparam>
/// <param name="path">场景文件的相对路径。</param>
@ -159,10 +102,68 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
_resourceFactories[path] = factory;
return factory;
}
/// <summary>
/// 初始化方法,在系统初始化时打印日志信息。
/// </summary>
protected override void OnInit()
{
}
#region
/// <summary>
/// 加载指定类型的资源并进行缓存。如果资源已经加载过则直接从缓存中返回。
/// </summary>
/// <typeparam name="T">要加载的资源类型必须继承自Resource。</typeparam>
/// <param name="path">资源在项目中的相对路径。</param>
/// <returns>成功加载的资源对象若路径无效或加载失败则返回null。</returns>
public T? LoadResource<T>(string path) where T : Resource
{
if (string.IsNullOrEmpty(path))
return null;
if (_loadedResources.TryGetValue(path, out var cached))
return cached as T;
var res = GD.Load<T>(path);
if (res == null)
{
GD.PrintErr($"[ResourceLoadSystem] Load failed: {path}");
return null;
}
_loadedResources[path] = res;
return res;
}
/// <summary>
/// 获取一个场景的懒加载器用于按需加载PackedScene资源。
/// 若对应路径尚未注册加载器则会自动创建一个新的Lazy实例。
/// </summary>
/// <param name="path">场景文件的相对路径。</param>
/// <returns>表示该场景懒加载逻辑的Lazy&lt;PackedScene&gt;对象。</returns>
public Lazy<PackedScene> GetSceneLoader(string path)
{
if (_sceneLoaders.TryGetValue(path, out var loader))
return loader;
loader = new Lazy<PackedScene>(() =>
{
var scene = LoadResource<PackedScene>(path);
return scene ?? throw new InvalidOperationException($"Failed to load scene: {path}");
});
_sceneLoaders[path] = loader;
return loader;
}
#endregion
#region
/// <summary>
/// 预加载一组资源和场景到内存中以提升后续访问速度。
/// 预加载一组资源和场景到内存中以提升后续访问速度。
/// </summary>
/// <param name="paths">待预加载的资源路径集合。</param>
public void Preload(IEnumerable<string> paths)
@ -175,7 +176,7 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
}
/// <summary>
/// 清除指定路径的所有相关缓存数据,包括资源、场景加载器及各类工厂。
/// 清除指定路径的所有相关缓存数据,包括资源、场景加载器及各类工厂。
/// </summary>
/// <param name="path">要卸载的资源路径。</param>
public void Unload(string path)
@ -187,7 +188,7 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
}
/// <summary>
/// 清空所有当前系统的资源缓存、加载器和工厂列表。
/// 清空所有当前系统的资源缓存、加载器和工厂列表。
/// </summary>
public void ClearAll()
{
@ -198,4 +199,4 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
}
#endregion
}
}

View File

@ -243,7 +243,7 @@ public static class NodeExtensions
/// <summary>
/// 将指定节点转换为目标类型T
/// 将指定节点转换为目标类型T
/// </summary>
/// <typeparam name="T">目标节点类型必须继承自Node</typeparam>
/// <param name="node">要转换的节点对象可以为null</param>
@ -252,10 +252,8 @@ public static class NodeExtensions
public static T OfType<T>(this Node? node) where T : Node
{
// 检查节点是否有效且类型匹配
if (node.IsValidNode()&& node is T t)
if (node.IsValidNode() && node is T t)
return t;
throw new InvalidCastException($"Cannot cast {node} to {typeof(T)}");
}
}

View File

@ -4,21 +4,18 @@ using Godot;
namespace GFramework.Godot.logging;
/// <summary>
/// Godot平台的日志记录器实现
/// Godot平台的日志记录器实现
/// </summary>
public sealed class GodotLogger(
string? name = null,
LogLevel minLevel = LogLevel.Info) : AbstractLogger(name??ILogger.RootLoggerName, minLevel)
LogLevel minLevel = LogLevel.Info) : AbstractLogger(name ?? ILogger.RootLoggerName, minLevel)
{
protected override void Write(LogLevel level, string message, Exception? exception)
{
var prefix = $"[{level.ToString().ToUpper()}][{Name()}]";
// 将异常信息追加到日志消息中
if (exception != null)
{
message += "\n" + exception;
}
if (exception != null) message += "\n" + exception;
// 根据日志级别选择不同的输出方法
switch (level)

View File

@ -3,12 +3,12 @@
namespace GFramework.Godot.logging;
/// <summary>
/// Godot日志工厂类用于创建Godot平台专用的日志记录器实例
/// Godot日志工厂类用于创建Godot平台专用的日志记录器实例
/// </summary>
public class GodotLoggerFactory: ILoggerFactory
public class GodotLoggerFactory : ILoggerFactory
{
/// <summary>
/// 获取指定名称的日志记录器实例
/// 获取指定名称的日志记录器实例
/// </summary>
/// <param name="name">日志记录器的名称</param>
/// <returns>返回GodotLogger类型的日志记录器实例</returns>
@ -16,4 +16,4 @@ public class GodotLoggerFactory: ILoggerFactory
{
return new GodotLogger(name);
}
}
}

View File

@ -5,102 +5,427 @@ using Godot;
namespace GFramework.Godot.system;
/// <summary>
/// 音频管理器抽象基类,提供音频播放的基础实现
/// 音频管理器抽象基类,提供音频播放的基础实现
/// </summary>
public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManagerSystem
{
/// <summary>
/// 音频资源加载系统依赖
/// </summary>
protected IResourceLoadSystem? ResourceLoadSystem;
/// <summary>
/// 资源目录系统依赖
/// </summary>
protected IAssetCatalogSystem? AssetCatalogSystem;
/// <summary>
/// 背景音乐播放器
/// </summary>
protected AudioStreamPlayer? MusicPlayer;
/// <summary>
/// 音效播放器列表
/// </summary>
protected readonly List<AudioStreamPlayer> SoundPlayers = [];
/// <summary>
/// 可用音效播放器队列
/// </summary>
protected readonly Queue<AudioStreamPlayer> AvailableSoundPlayers = new();
/// <summary>
/// 3D音效播放器列表
/// </summary>
protected readonly List<AudioStreamPlayer3D> Sound3DPlayers = [];
/// <summary>
/// 可用3D音效播放器队列
/// </summary>
protected readonly Queue<AudioStreamPlayer3D> AvailableSound3DPlayers = new();
/// <summary>
/// 资源工厂系统依赖
/// </summary>
protected IResourceFactorySystem? ResourceFactorySystem;
/// <summary>
/// 背景音乐音量
/// </summary>
protected float MusicVolume = 1.0f;
/// <summary>
/// 音效音量
/// </summary>
protected float SoundVolume = 1.0f;
/// <summary>
/// 主音量
/// </summary>
protected float MasterVolume = 1.0f;
/// <summary>
/// 特效音量
/// </summary>
protected float SfxVolume = 1.0f;
/// <summary>
/// 语音音量
/// </summary>
protected float VoiceVolume = 1.0f;
/// <summary>
/// 环境音量
/// </summary>
protected float AmbientVolume = 1.0f;
/// <summary>
/// 音乐淡入淡出动画
/// </summary>
protected Tween? MusicFadeTween;
/// <summary>
/// 最大同时播放的音效数量
/// 最大同时播放的音效数量
/// </summary>
protected const int MaxSoundPlayers = 10;
/// <summary>
/// 最大同时播放的3D音效数量
/// 最大同时播放的3D音效数量
/// </summary>
protected const int MaxSound3DPlayers = 5;
/// <summary>
/// 所有者节点的抽象属性
/// 可用3D音效播放器队列
/// </summary>
protected readonly Queue<AudioStreamPlayer3D> AvailableSound3DPlayers = new();
/// <summary>
/// 可用音效播放器队列
/// </summary>
protected readonly Queue<AudioStreamPlayer> AvailableSoundPlayers = new();
/// <summary>
/// 3D音效播放器列表
/// </summary>
protected readonly List<AudioStreamPlayer3D> Sound3DPlayers = [];
/// <summary>
/// 音效播放器列表
/// </summary>
protected readonly List<AudioStreamPlayer> SoundPlayers = [];
/// <summary>
/// 环境音量
/// </summary>
protected float AmbientVolume = 1.0f;
/// <summary>
/// 资源目录系统依赖
/// </summary>
protected IAssetCatalogSystem? AssetCatalogSystem;
/// <summary>
/// 主音量
/// </summary>
protected float MasterVolume = 1.0f;
/// <summary>
/// 音乐淡入淡出动画
/// </summary>
protected Tween? MusicFadeTween;
/// <summary>
/// 背景音乐播放器
/// </summary>
protected AudioStreamPlayer? MusicPlayer;
/// <summary>
/// 背景音乐音量
/// </summary>
protected float MusicVolume = 1.0f;
/// <summary>
/// 资源工厂系统依赖
/// </summary>
protected IResourceFactorySystem? ResourceFactorySystem;
/// <summary>
/// 音频资源加载系统依赖
/// </summary>
protected IResourceLoadSystem? ResourceLoadSystem;
/// <summary>
/// 特效音量
/// </summary>
protected float SfxVolume = 1.0f;
/// <summary>
/// 音效音量
/// </summary>
protected float SoundVolume = 1.0f;
/// <summary>
/// 语音音量
/// </summary>
protected float VoiceVolume = 1.0f;
/// <summary>
/// 所有者节点的抽象属性
/// </summary>
protected abstract Node Owner { get; }
/// <summary>
/// 系统初始化方法
/// 播放背景音乐
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="loop">是否循环播放</param>
public virtual void PlayMusic(string audioPath, float volume = 1.0f, bool loop = true)
{
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null || MusicPlayer == null) return;
// 停止当前正在进行的淡入淡出效果
MusicFadeTween?.Kill();
MusicPlayer.Stream = audioStream;
MusicPlayer.VolumeDb = LinearToDb(volume * MusicVolume * MasterVolume);
MusicPlayer.Play();
}
/// <summary>
/// 播放音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlaySound(string audioPath, float volume = 1.0f, float pitch = 1.0f)
{
if (AvailableSoundPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSoundPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * SoundVolume * MasterVolume);
player.Play();
}
/// <summary>
/// 播放特效音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlaySfx(string audioPath, float volume = 1.0f, float pitch = 1.0f)
{
if (AvailableSoundPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSoundPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * SfxVolume * MasterVolume);
player.Play();
}
/// <summary>
/// 播放语音
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlayVoice(string audioPath, float volume = 1.0f, float pitch = 1.0f)
{
if (AvailableSoundPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSoundPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * VoiceVolume * MasterVolume);
player.Play();
}
/// <summary>
/// 播放环境音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlayAmbient(string audioPath, float volume = 1.0f, float pitch = 1.0f)
{
if (AvailableSoundPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSoundPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * AmbientVolume * MasterVolume);
player.Play();
}
/// <summary>
/// 播放3D音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="position">3D空间中的位置</param>
/// <param name="volume">音量大小范围0-1</param>
public virtual void PlaySound3D(string audioPath, Vector3 position, float volume = 1.0f)
{
if (AvailableSound3DPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSound3DPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * SoundVolume * MasterVolume);
player.Position = position;
player.Play();
}
/// <summary>
/// 停止背景音乐
/// </summary>
public virtual void StopMusic()
{
MusicFadeTween?.Kill();
MusicPlayer?.Stop();
}
/// <summary>
/// 暂停背景音乐
/// </summary>
public virtual void PauseMusic()
{
MusicFadeTween?.Kill();
// todo 需要记录音乐播放位置,以便恢复播放时从正确位置开始
}
/// <summary>
/// 恢复背景音乐播放
/// </summary>
public virtual void ResumeMusic()
{
MusicPlayer?.Play();
}
/// <summary>
/// 设置背景音乐音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetMusicVolume(float volume)
{
MusicVolume = volume;
if (MusicPlayer != null) MusicPlayer.VolumeDb = LinearToDb(MusicVolume * MasterVolume);
}
/// <summary>
/// 获取背景音乐音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetMusicVolume()
{
return MusicVolume;
}
/// <summary>
/// 设置音效音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetSoundVolume(float volume)
{
SoundVolume = volume;
}
/// <summary>
/// 获取音效音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetSoundVolume()
{
return SoundVolume;
}
/// <summary>
/// 设置主音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetMasterVolume(float volume)
{
MasterVolume = volume;
// 更新音乐音量
if (MusicPlayer != null) MusicPlayer.VolumeDb = LinearToDb(MusicVolume * MasterVolume);
}
/// <summary>
/// 获取主音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetMasterVolume()
{
return MasterVolume;
}
/// <summary>
/// 设置SFX音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetSfxVolume(float volume)
{
SfxVolume = volume;
}
/// <summary>
/// 获取SFX音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetSfxVolume()
{
return SfxVolume;
}
/// <summary>
/// 设置语音音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetVoiceVolume(float volume)
{
VoiceVolume = volume;
}
/// <summary>
/// 获取语音音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetVoiceVolume()
{
return VoiceVolume;
}
/// <summary>
/// 设置环境音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetAmbientVolume(float volume)
{
AmbientVolume = volume;
}
/// <summary>
/// 获取环境音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetAmbientVolume()
{
return AmbientVolume;
}
/// <summary>
/// 检查背景音乐是否正在播放
/// </summary>
/// <returns>正在播放返回true否则返回false</returns>
public virtual bool IsMusicPlaying()
{
return MusicPlayer?.Playing ?? false;
}
/// <summary>
/// 淡入背景音乐
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="duration">淡入持续时间(秒)</param>
/// <param name="volume">目标音量</param>
public virtual void FadeInMusic(string audioPath, float duration, float volume = 1.0f)
{
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null || MusicPlayer == null) return;
// 停止当前正在进行的淡入淡出效果
MusicFadeTween?.Kill();
MusicPlayer.Stream = audioStream;
MusicPlayer.VolumeDb = LinearToDb(0.0f); // 初始音量为0
MusicPlayer.Play();
// 创建淡入动画
MusicFadeTween = Owner.CreateTween();
MusicFadeTween.TweenProperty(MusicPlayer, "volume_db", LinearToDb(volume * MusicVolume * MasterVolume),
duration);
}
/// <summary>
/// 淡出背景音乐
/// </summary>
/// <param name="duration">淡出持续时间(秒)</param>
public virtual void FadeOutMusic(float duration)
{
if (MusicPlayer == null) return;
// 停止当前正在进行的淡入淡出效果
MusicFadeTween?.Kill();
// 创建淡出动画
MusicFadeTween = Owner.CreateTween();
MusicFadeTween.TweenProperty(MusicPlayer, "volume_db", LinearToDb(0.0f), duration);
MusicFadeTween.TweenCallback(Callable.From(() => MusicPlayer.Stop()));
}
/// <summary>
/// 设置低通滤波器强度
/// </summary>
/// <param name="amount">滤波器强度范围0-1</param>
public virtual void SetLowPassFilter(float amount)
{
// TODO: 实现低通滤波器效果
// 可以通过AudioEffectLowPassFilter实现
}
/// <summary>
/// 设置音频混响效果
/// </summary>
/// <param name="roomSize">房间大小</param>
/// <param name="damping">阻尼</param>
/// <param name="wetLevel">湿声级别</param>
public virtual void SetReverb(float roomSize, float damping, float wetLevel)
{
// TODO: 实现音频混响效果
// 可以通过AudioEffectReverb实现
}
/// <summary>
/// 系统初始化方法
/// </summary>
protected override void OnInit()
{
@ -135,7 +460,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
}
/// <summary>
/// 当音效播放完成时的回调
/// 当音效播放完成时的回调
/// </summary>
/// <param name="player">完成播放的音频播放器</param>
private void OnSoundFinished(AudioStreamPlayer player)
@ -145,7 +470,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
}
/// <summary>
/// 当3D音效播放完成时的回调
/// 当3D音效播放完成时的回调
/// </summary>
/// <param name="player">完成播放的3D音频播放器</param>
private void OnSound3DFinished(AudioStreamPlayer3D player)
@ -155,26 +480,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
}
/// <summary>
/// 播放背景音乐
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="loop">是否循环播放</param>
public virtual void PlayMusic(string audioPath, float volume = 1.0f, bool loop = true)
{
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null || MusicPlayer == null) return;
// 停止当前正在进行的淡入淡出效果
MusicFadeTween?.Kill();
MusicPlayer.Stream = audioStream;
MusicPlayer.VolumeDb = LinearToDb(volume * MusicVolume * MasterVolume);
MusicPlayer.Play();
}
/// <summary>
/// 通过资源ID播放背景音乐
/// 通过资源ID播放背景音乐
/// </summary>
/// <param name="musicId">音乐资源ID</param>
/// <param name="volume">音量大小范围0-1</param>
@ -185,83 +491,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
}
/// <summary>
/// 播放音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlaySound(string audioPath, float volume = 1.0f, float pitch = 1.0f)
{
if (AvailableSoundPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSoundPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * SoundVolume * MasterVolume);
player.Play();
}
/// <summary>
/// 播放特效音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlaySfx(string audioPath, float volume = 1.0f, float pitch = 1.0f)
{
if (AvailableSoundPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSoundPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * SfxVolume * MasterVolume);
player.Play();
}
/// <summary>
/// 播放语音
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlayVoice(string audioPath, float volume = 1.0f, float pitch = 1.0f)
{
if (AvailableSoundPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSoundPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * VoiceVolume * MasterVolume);
player.Play();
}
/// <summary>
/// 播放环境音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlayAmbient(string audioPath, float volume = 1.0f, float pitch = 1.0f)
{
if (AvailableSoundPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSoundPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * AmbientVolume * MasterVolume);
player.Play();
}
/// <summary>
/// 通过资源ID播放音效
/// 通过资源ID播放音效
/// </summary>
/// <param name="soundId">音效资源ID</param>
/// <param name="volume">音量大小范围0-1</param>
@ -272,243 +502,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
}
/// <summary>
/// 播放3D音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="position">3D空间中的位置</param>
/// <param name="volume">音量大小范围0-1</param>
public virtual void PlaySound3D(string audioPath, Vector3 position, float volume = 1.0f)
{
if (AvailableSound3DPlayers.Count == 0) return;
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null) return;
var player = AvailableSound3DPlayers.Dequeue();
player.Stream = audioStream;
player.VolumeDb = LinearToDb(volume * SoundVolume * MasterVolume);
player.Position = position;
player.Play();
}
/// <summary>
/// 停止背景音乐
/// </summary>
public virtual void StopMusic()
{
MusicFadeTween?.Kill();
MusicPlayer?.Stop();
}
/// <summary>
/// 暂停背景音乐
/// </summary>
public virtual void PauseMusic()
{
MusicFadeTween?.Kill();
// todo 需要记录音乐播放位置,以便恢复播放时从正确位置开始
}
/// <summary>
/// 恢复背景音乐播放
/// </summary>
public virtual void ResumeMusic()
{
MusicPlayer?.Play();
}
/// <summary>
/// 设置背景音乐音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetMusicVolume(float volume)
{
MusicVolume = volume;
if (MusicPlayer != null)
{
MusicPlayer.VolumeDb = LinearToDb(MusicVolume * MasterVolume);
}
}
/// <summary>
/// 获取背景音乐音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetMusicVolume()
{
return MusicVolume;
}
/// <summary>
/// 设置音效音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetSoundVolume(float volume)
{
SoundVolume = volume;
}
/// <summary>
/// 获取音效音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetSoundVolume()
{
return SoundVolume;
}
/// <summary>
/// 设置主音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetMasterVolume(float volume)
{
MasterVolume = volume;
// 更新音乐音量
if (MusicPlayer != null)
{
MusicPlayer.VolumeDb = LinearToDb(MusicVolume * MasterVolume);
}
}
/// <summary>
/// 获取主音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetMasterVolume()
{
return MasterVolume;
}
/// <summary>
/// 设置SFX音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetSfxVolume(float volume)
{
SfxVolume = volume;
}
/// <summary>
/// 获取SFX音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetSfxVolume()
{
return SfxVolume;
}
/// <summary>
/// 设置语音音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetVoiceVolume(float volume)
{
VoiceVolume = volume;
}
/// <summary>
/// 获取语音音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetVoiceVolume()
{
return VoiceVolume;
}
/// <summary>
/// 设置环境音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
public virtual void SetAmbientVolume(float volume)
{
AmbientVolume = volume;
}
/// <summary>
/// 获取环境音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
public virtual float GetAmbientVolume()
{
return AmbientVolume;
}
/// <summary>
/// 检查背景音乐是否正在播放
/// </summary>
/// <returns>正在播放返回true否则返回false</returns>
public virtual bool IsMusicPlaying()
{
return MusicPlayer?.Playing ?? false;
}
/// <summary>
/// 淡入背景音乐
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="duration">淡入持续时间(秒)</param>
/// <param name="volume">目标音量</param>
public virtual void FadeInMusic(string audioPath, float duration, float volume = 1.0f)
{
var audioStream = ResourceLoadSystem?.LoadResource<AudioStream>(audioPath);
if (audioStream == null || MusicPlayer == null) return;
// 停止当前正在进行的淡入淡出效果
MusicFadeTween?.Kill();
MusicPlayer.Stream = audioStream;
MusicPlayer.VolumeDb = LinearToDb(0.0f); // 初始音量为0
MusicPlayer.Play();
// 创建淡入动画
MusicFadeTween = Owner.CreateTween();
MusicFadeTween.TweenProperty(MusicPlayer, "volume_db", LinearToDb(volume * MusicVolume * MasterVolume),
duration);
}
/// <summary>
/// 淡出背景音乐
/// </summary>
/// <param name="duration">淡出持续时间(秒)</param>
public virtual void FadeOutMusic(float duration)
{
if (MusicPlayer == null) return;
// 停止当前正在进行的淡入淡出效果
MusicFadeTween?.Kill();
// 创建淡出动画
MusicFadeTween = Owner.CreateTween();
MusicFadeTween.TweenProperty(MusicPlayer, "volume_db", LinearToDb(0.0f), duration);
MusicFadeTween.TweenCallback(Callable.From(() => MusicPlayer.Stop()));
}
/// <summary>
/// 设置低通滤波器强度
/// </summary>
/// <param name="amount">滤波器强度范围0-1</param>
public virtual void SetLowPassFilter(float amount)
{
// TODO: 实现低通滤波器效果
// 可以通过AudioEffectLowPassFilter实现
}
/// <summary>
/// 设置音频混响效果
/// </summary>
/// <param name="roomSize">房间大小</param>
/// <param name="damping">阻尼</param>
/// <param name="wetLevel">湿声级别</param>
public virtual void SetReverb(float roomSize, float damping, float wetLevel)
{
// TODO: 实现音频混响效果
// 可以通过AudioEffectReverb实现
}
/// <summary>
/// 将线性音量值转换为分贝值
/// 将线性音量值转换为分贝值
/// </summary>
/// <param name="linear">线性音量值0-1</param>
/// <returns>分贝值</returns>
@ -518,7 +512,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
}
/// <summary>
/// 将分贝值转换为线性音量值
/// 将分贝值转换为线性音量值
/// </summary>
/// <param name="db">分贝值</param>
/// <returns>线性音量值0-1</returns>
@ -528,7 +522,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
}
/// <summary>
/// 系统销毁时清理资源
/// 系统销毁时清理资源
/// </summary>
protected override void OnDestroy()
{
@ -539,16 +533,10 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
MusicPlayer?.QueueFree();
// 清理音效播放器池
foreach (var player in SoundPlayers)
{
player.QueueFree();
}
foreach (var player in SoundPlayers) player.QueueFree();
// 清理3D音效播放器池
foreach (var player in Sound3DPlayers)
{
player.QueueFree();
}
foreach (var player in Sound3DPlayers) player.QueueFree();
SoundPlayers.Clear();
AvailableSoundPlayers.Clear();

View File

@ -4,173 +4,173 @@ using Godot;
namespace GFramework.Godot.system;
/// <summary>
/// 音频管理器系统接口,用于统一管理背景音乐和音效的播放
/// 音频管理器系统接口,用于统一管理背景音乐和音效的播放
/// </summary>
public interface IAudioManagerSystem : ISystem
{
/// <summary>
/// 播放背景音乐
/// 播放背景音乐
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="loop">是否循环播放</param>
void PlayMusic(string audioPath, float volume = 1.0f, bool loop = true);
/// <summary>
/// 播放音效
/// 播放音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
void PlaySound(string audioPath, float volume = 1.0f, float pitch = 1.0f);
/// <summary>
/// 播放特效音效
/// 播放特效音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
void PlaySfx(string audioPath, float volume = 1.0f, float pitch = 1.0f);
/// <summary>
/// 播放语音
/// 播放语音
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
void PlayVoice(string audioPath, float volume = 1.0f, float pitch = 1.0f);
/// <summary>
/// 播放环境音效
/// 播放环境音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
void PlayAmbient(string audioPath, float volume = 1.0f, float pitch = 1.0f);
/// <summary>
/// 停止背景音乐
/// 停止背景音乐
/// </summary>
void StopMusic();
/// <summary>
/// 暂停背景音乐
/// 暂停背景音乐
/// </summary>
void PauseMusic();
/// <summary>
/// 恢复背景音乐播放
/// 恢复背景音乐播放
/// </summary>
void ResumeMusic();
/// <summary>
/// 设置背景音乐音量
/// 设置背景音乐音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
void SetMusicVolume(float volume);
/// <summary>
/// 获取背景音乐音量
/// 获取背景音乐音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
float GetMusicVolume();
/// <summary>
/// 设置音效音量
/// 设置音效音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
void SetSoundVolume(float volume);
/// <summary>
/// 获取音效音量
/// 获取音效音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
float GetSoundVolume();
/// <summary>
/// 设置特效音量
/// 设置特效音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
void SetSfxVolume(float volume);
/// <summary>
/// 获取特效音量
/// 获取特效音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
float GetSfxVolume();
/// <summary>
/// 设置语音音量
/// 设置语音音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
void SetVoiceVolume(float volume);
/// <summary>
/// 获取语音音量
/// 获取语音音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
float GetVoiceVolume();
/// <summary>
/// 设置环境音量
/// 设置环境音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
void SetAmbientVolume(float volume);
/// <summary>
/// 获取环境音量
/// 获取环境音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
float GetAmbientVolume();
/// <summary>
/// 设置主音量
/// 设置主音量
/// </summary>
/// <param name="volume">音量大小范围0-1</param>
void SetMasterVolume(float volume);
/// <summary>
/// 获取主音量
/// 获取主音量
/// </summary>
/// <returns>音量大小范围0-1</returns>
float GetMasterVolume();
/// <summary>
/// 检查背景音乐是否正在播放
/// 检查背景音乐是否正在播放
/// </summary>
/// <returns>正在播放返回true否则返回false</returns>
bool IsMusicPlaying();
/// <summary>
/// 淡入背景音乐
/// 淡入背景音乐
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="duration">淡入持续时间(秒)</param>
/// <param name="volume">目标音量</param>
void FadeInMusic(string audioPath, float duration, float volume = 1.0f);
/// <summary>
/// 淡出背景音乐
/// 淡出背景音乐
/// </summary>
/// <param name="duration">淡出持续时间(秒)</param>
void FadeOutMusic(float duration);
/// <summary>
/// 播放3D音效
/// 播放3D音效
/// </summary>
/// <param name="audioPath">音频文件路径</param>
/// <param name="position">3D空间中的位置</param>
/// <param name="volume">音量大小范围0-1</param>
void PlaySound3D(string audioPath, Vector3 position, float volume = 1.0f);
/// <summary>
/// 设置低通滤波器强度
/// 设置低通滤波器强度
/// </summary>
/// <param name="amount">滤波器强度范围0-1</param>
void SetLowPassFilter(float amount);
/// <summary>
/// 设置音频混响效果
/// 设置音频混响效果
/// </summary>
/// <param name="roomSize">房间大小</param>
/// <param name="damping">阻尼</param>

View File

@ -6,6 +6,6 @@
<LangVersion>10</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.14.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.14.0"/>
</ItemGroup>
</Project>

View File

@ -1,21 +1,20 @@
using System;
namespace GFramework.SourceGenerators.Attributes.enums
namespace GFramework.SourceGenerators.Attributes.enums;
/// <summary>
/// 标注在 enum 上Source Generator 会为该 enum 生成扩展方法。
/// </summary>
[AttributeUsage(AttributeTargets.Enum)]
public sealed class GenerateEnumExtensionsAttribute : Attribute
{
/// <summary>
/// 标注在 enum 上Source Generator 会为该 enum 生成扩展方法。
/// 是否为每个枚举项生成单独的 IsXXX 方法(默认 true
/// </summary>
[AttributeUsage(AttributeTargets.Enum)]
public sealed class GenerateEnumExtensionsAttribute : Attribute
{
/// <summary>
/// 是否为每个枚举项生成单独的 IsXXX 方法(默认 true
/// </summary>
public bool GenerateIsMethods { get; set; } = true;
public bool GenerateIsMethods { get; set; } = true;
/// <summary>
/// 是否生成一个 IsIn(params T[]) 方法以简化多值判断(默认 true
/// </summary>
public bool GenerateIsInMethod { get; set; } = true;
}
/// <summary>
/// 是否生成一个 IsIn(params T[]) 方法以简化多值判断(默认 true
/// </summary>
public bool GenerateIsInMethod { get; set; } = true;
}

View File

@ -4,7 +4,7 @@ using System;
namespace GFramework.SourceGenerators.Attributes.logging;
/// <summary>
/// 标注在类上Source Generator 会为该类自动生成一个日志记录器字段。
/// 标注在类上Source Generator 会为该类自动生成一个日志记录器字段。
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class LogAttribute : Attribute
@ -14,7 +14,7 @@ public sealed class LogAttribute : Attribute
}
/// <summary>
/// 初始化 GodotLogAttribute 类的新实例
/// 初始化 GodotLogAttribute 类的新实例
/// </summary>
/// <param name="name">日志分类名,默认使用类名</param>
public LogAttribute(string? name)

View File

@ -1,37 +0,0 @@
using Microsoft.CodeAnalysis;
namespace GFramework.SourceGenerators.logging;
/// <summary>
/// 提供诊断描述符的静态类用于GFramework日志生成器的编译时检查
/// </summary>
internal static class LoggerDiagnostics
{
/// <summary>
/// 定义诊断描述符:要求使用[Log]特性的类必须声明为partial
/// </summary>
/// <remarks>
/// 当类使用[Log]特性但未声明为partial时编译器将报告此错误
/// </remarks>
public static readonly DiagnosticDescriptor MustBePartial =
new(
id: "GFLOG001",
title: "Class must be partial",
messageFormat: "Class '{0}' must be declared partial to use [Log]",
category: "GFramework.Logging",
DiagnosticSeverity.Error,
isEnabledByDefault: true
);
/// <summary>
/// 定义诊断描述符LogAttribute无法生成Logger的错误情况
/// </summary>
public static readonly DiagnosticDescriptor LogAttributeInvalid =
new(
id: "GFW_LOG001",
title: "LogAttribute cannot generate Logger",
messageFormat: "LogAttribute on class '{0}' is ineffective: {1}",
category: "GFramework.Godot.Logging",
DiagnosticSeverity.Warning,
isEnabledByDefault: true);
}

View File

@ -0,0 +1,37 @@
using Microsoft.CodeAnalysis;
namespace GFramework.SourceGenerators.logging;
/// <summary>
/// 提供诊断描述符的静态类用于GFramework日志生成器的编译时检查
/// </summary>
internal static class LoggerDiagnostics
{
/// <summary>
/// 定义诊断描述符:要求使用[Log]特性的类必须声明为partial
/// </summary>
/// <remarks>
/// 当类使用[Log]特性但未声明为partial时编译器将报告此错误
/// </remarks>
public static readonly DiagnosticDescriptor MustBePartial =
new(
"GFLOG001",
"Class must be partial",
"Class '{0}' must be declared partial to use [Log]",
"GFramework.Logging",
DiagnosticSeverity.Error,
true
);
/// <summary>
/// 定义诊断描述符LogAttribute无法生成Logger的错误情况
/// </summary>
public static readonly DiagnosticDescriptor LogAttributeInvalid =
new(
"GFW_LOG001",
"LogAttribute cannot generate Logger",
"LogAttribute on class '{0}' is ineffective: {1}",
"GFramework.Godot.Logging",
DiagnosticSeverity.Warning,
true);
}

View File

@ -12,7 +12,7 @@ using Microsoft.CodeAnalysis.Text;
namespace GFramework.SourceGenerators.logging;
/// <summary>
/// 日志生成器用于为标记了LogAttribute的类自动生成日志字段
/// 日志生成器用于为标记了LogAttribute的类自动生成日志字段
/// </summary>
[Generator]
public sealed class LoggerGenerator : IIncrementalGenerator
@ -22,7 +22,7 @@ public sealed class LoggerGenerator : IIncrementalGenerator
private const string AttributeShortNameWithoutSuffix = "Log";
/// <summary>
/// 初始化生成器,设置语法过滤和代码生成逻辑
/// 初始化生成器,设置语法过滤和代码生成逻辑
/// </summary>
/// <param name="context">增量生成器初始化上下文</param>
public void Initialize(IncrementalGeneratorInitializationContext context)
@ -87,7 +87,7 @@ public sealed class LoggerGenerator : IIncrementalGenerator
}
/// <summary>
/// 获取类符号上的LogAttribute特性
/// 获取类符号上的LogAttribute特性
/// </summary>
/// <param name="classSymbol">类符号</param>
/// <returns>LogAttribute特性数据如果不存在则返回null</returns>
@ -105,7 +105,7 @@ public sealed class LoggerGenerator : IIncrementalGenerator
}
/// <summary>
/// 生成日志字段代码
/// 生成日志字段代码
/// </summary>
/// <param name="classSymbol">类符号</param>
/// <param name="attr">LogAttribute特性数据</param>
@ -160,7 +160,7 @@ public sealed class LoggerGenerator : IIncrementalGenerator
sb.AppendLine($" public partial class {className}");
sb.AppendLine(" {");
sb.AppendLine($" /// <summary>Auto-generated logger</summary>");
sb.AppendLine(" /// <summary>Auto-generated logger</summary>");
sb.AppendLine(
$" {access} {staticKeyword}readonly ILogger {fieldName} = " +
$"new ConsoleLoggerFactory().GetLogger(\"{name}\");");
@ -173,7 +173,7 @@ public sealed class LoggerGenerator : IIncrementalGenerator
}
/// <summary>
/// 从特性数据中获取命名参数的值
/// 从特性数据中获取命名参数的值
/// </summary>
/// <param name="attr">特性数据</param>
/// <param name="name">参数名称</param>

View File

@ -20,10 +20,10 @@
<!-- 排除不需要参与打包/编译的目录 -->
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="" />
<None Remove="GFramework.Core\**" />
<None Remove="GFramework.Game\**" />
<None Remove="GFramework.Godot\**" />
<None Include="README.md" Pack="true" PackagePath=""/>
<None Remove="GFramework.Core\**"/>
<None Remove="GFramework.Game\**"/>
<None Remove="GFramework.Godot\**"/>
<None Update="GFramework.SourceGenerators\bin\Debug\netstandard2.0\GFramework.Generator.Attributes.dll">
<Link>GFramework.SorceGenerators\bin\Debug\netstandard2.0\GFramework.Generator.Attributes.dll</Link>
</None>
@ -47,13 +47,13 @@
</ItemGroup>
<!-- 聚合核心模块 -->
<ItemGroup>
<ProjectReference Include="GFramework.Core\GFramework.Core.csproj" />
<ProjectReference Include="GFramework.Game\GFramework.Game.csproj" />
<ProjectReference Include="GFramework.Core\GFramework.Core.csproj"/>
<ProjectReference Include="GFramework.Game\GFramework.Game.csproj"/>
</ItemGroup>
<ItemGroup>
<Compile Remove="GFramework.Core\**" />
<Compile Remove="GFramework.Game\**" />
<Compile Remove="GFramework.Godot\**" />
<Compile Remove="GFramework.Core\**"/>
<Compile Remove="GFramework.Game\**"/>
<Compile Remove="GFramework.Godot\**"/>
<Compile Update="GFramework.SourceGenerators\enums\EnumExtensionsGenerator.cs">
<Link>GFramework.SorceGenerators\enums\EnumExtensionsGenerator.cs</Link>
</Compile>
@ -70,9 +70,9 @@
<Compile Remove="GFramework.SourceGenerators.Attributes\**"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="GFramework.Core\**" />
<EmbeddedResource Remove="GFramework.Game\**" />
<EmbeddedResource Remove="GFramework.Godot\**" />
<EmbeddedResource Remove="GFramework.Core\**"/>
<EmbeddedResource Remove="GFramework.Game\**"/>
<EmbeddedResource Remove="GFramework.Godot\**"/>
<EmbeddedResource Remove="GFramework.Godot.SourceGenerators\**"/>
<EmbeddedResource Remove="GFramework.Godot.SourceGenerators.Attributes\**"/>
<EmbeddedResource Remove="GFramework.SorceGenerators\**"/>