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

@ -156,10 +156,7 @@ public abstract class Architecture(
var previousPhase = CurrentPhase; var previousPhase = CurrentPhase;
CurrentPhase = next; CurrentPhase = next;
if (previousPhase != next) if (previousPhase != next) logger.Info($"Architecture phase changed: {previousPhase} -> {next}");
{
logger.Info($"Architecture phase changed: {previousPhase} -> {next}");
}
NotifyPhase(next); NotifyPhase(next);
@ -368,7 +365,9 @@ public abstract class Architecture(
Container.RegisterPlurality(system); Container.RegisterPlurality(system);
_allSystems.Add(system); _allSystems.Add(system);
if (!_mInited) if (!_mInited)
{
_mSystems.Add(system); _mSystems.Add(system);
}
else else
{ {
_logger.Debug($"Immediately initializing system: {typeof(TSystem).Name}"); _logger.Debug($"Immediately initializing system: {typeof(TSystem).Name}");
@ -400,7 +399,9 @@ public abstract class Architecture(
Container.RegisterPlurality(model); Container.RegisterPlurality(model);
if (!_mInited) if (!_mInited)
{
_mModels.Add(model); _mModels.Add(model);
}
else else
{ {
_logger.Debug($"Immediately initializing model: {typeof(TModel).Name}"); _logger.Debug($"Immediately initializing model: {typeof(TModel).Name}");

View File

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

View File

@ -1,5 +1,4 @@
 using System.Collections.Immutable;
using System.Collections.Immutable;
namespace GFramework.Core.architecture; namespace GFramework.Core.architecture;

View File

@ -8,13 +8,13 @@ public sealed class ArchitectureOptions(
bool allowLateRegistration = false bool allowLateRegistration = false
) )
{ {
/// <summary>
/// 严格阶段验证开关当设置为true时启用严格的阶段验证机制
/// </summary>
public bool StrictPhaseValidation = strictPhaseValidation;
/// <summary> /// <summary>
/// 允许延迟注册开关当设置为true时允许在初始化完成后进行组件注册 /// 允许延迟注册开关当设置为true时允许在初始化完成后进行组件注册
/// </summary> /// </summary>
public bool AllowLateRegistration = allowLateRegistration; public bool AllowLateRegistration = allowLateRegistration;
/// <summary>
/// 严格阶段验证开关当设置为true时启用严格的阶段验证机制
/// </summary>
public bool StrictPhaseValidation = strictPhaseValidation;
} }

View File

@ -13,6 +13,7 @@ public enum ArchitecturePhase
/// 无效阶段,表示未定义的阶段 /// 无效阶段,表示未定义的阶段
/// </summary> /// </summary>
None = 0, None = 0,
/// <summary> /// <summary>
/// 模型初始化之前阶段 /// 模型初始化之前阶段
/// </summary> /// </summary>
@ -37,13 +38,14 @@ public enum ArchitecturePhase
/// 就绪阶段,完成冻结和事件处理后的最终状态 /// 就绪阶段,完成冻结和事件处理后的最终状态
/// </summary> /// </summary>
Ready, Ready,
/// <summary> /// <summary>
/// 正在销毁中 暂时不使用 /// 正在销毁中 暂时不使用
/// </summary> /// </summary>
Destroying, Destroying,
/// <summary> /// <summary>
/// 已销毁 暂时不使用 /// 已销毁 暂时不使用
/// </summary> /// </summary>
Destroyed Destroyed
} }

View File

@ -11,6 +11,21 @@ public class ArchitectureRuntime(IArchitectureContext context) : IArchitectureRu
{ {
private readonly IArchitectureContext _context = context ?? throw new ArgumentNullException(nameof(context)); 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 #region Command Execution
/// <summary> /// <summary>
@ -36,21 +51,6 @@ public class ArchitectureRuntime(IArchitectureContext context) : IArchitectureRu
#endregion #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 #region Event Management
/// <summary> /// <summary>

View File

@ -1,10 +1,9 @@
 using GFramework.Core.events;
using GFramework.Core.events;
using GFramework.Core.ioc; using GFramework.Core.ioc;
namespace GFramework.Core.architecture; namespace GFramework.Core.architecture;
public class ArchitectureServices: IArchitectureServices public class ArchitectureServices : IArchitectureServices
{ {
public IIocContainer Container { get; } = new IocContainer(); public IIocContainer Container { get; } = new IocContainer();
public ITypeEventSystem TypeEventSystem { get; } = new TypeEventSystem(); public ITypeEventSystem TypeEventSystem { get; } = new TypeEventSystem();

View File

@ -1,8 +1,4 @@
using GFramework.Core.architecture; using GFramework.Core.model;
using GFramework.Core.command;
using GFramework.Core.events;
using GFramework.Core.model;
using GFramework.Core.query;
using GFramework.Core.system; using GFramework.Core.system;
using GFramework.Core.utility; using GFramework.Core.utility;
@ -12,8 +8,18 @@ namespace GFramework.Core.architecture;
/// 架构接口,专注于生命周期管理,包括系统、模型、工具的注册和获取 /// 架构接口,专注于生命周期管理,包括系统、模型、工具的注册和获取
/// 业务操作通过 ArchitectureRuntime 提供 /// 业务操作通过 ArchitectureRuntime 提供
/// </summary> /// </summary>
public interface IArchitecture: IAsyncInitializable public interface IArchitecture : IAsyncInitializable
{ {
/// <summary>
/// 获取架构上下文
/// </summary>
IArchitectureContext Context { get; }
/// <summary>
/// 获取架构运行时实例
/// </summary>
IArchitectureRuntime Runtime { get; }
/// <summary> /// <summary>
/// 初始化方法,用于执行对象的初始化操作 /// 初始化方法,用于执行对象的初始化操作
/// </summary> /// </summary>
@ -62,14 +68,4 @@ public interface IArchitecture: IAsyncInitializable
/// </summary> /// </summary>
/// <param name="hook">生命周期钩子实例</param> /// <param name="hook">生命周期钩子实例</param>
void RegisterLifecycleHook(IArchitectureLifecycle hook); void RegisterLifecycleHook(IArchitectureLifecycle hook);
/// <summary>
/// 获取架构上下文
/// </summary>
IArchitectureContext Context { get; }
/// <summary>
/// 获取架构运行时实例
/// </summary>
IArchitectureRuntime Runtime { get; }
} }

View File

@ -17,4 +17,3 @@ public interface IArchitectureExtensible : IArchitecture
/// <param name="hook">要注册的架构生命周期钩子实例</param> /// <param name="hook">要注册的架构生命周期钩子实例</param>
void RegisterLifecycleHook(IArchitectureLifecycle hook); void RegisterLifecycleHook(IArchitectureLifecycle hook);
} }

View File

@ -12,4 +12,3 @@ public interface IArchitectureLifecycle
/// <param name="architecture">相关的架构实例</param> /// <param name="architecture">相关的架构实例</param>
void OnPhase(ArchitecturePhase phase, IArchitecture architecture); void OnPhase(ArchitecturePhase phase, IArchitecture architecture);
} }

View File

@ -1,5 +1,4 @@
 namespace GFramework.Core.architecture;
namespace GFramework.Core.architecture;
/// <summary> /// <summary>
/// 架构模块接口,继承自架构生命周期接口。 /// 架构模块接口,继承自架构生命周期接口。

View File

@ -11,4 +11,3 @@ public interface IArchitecturePhaseAware
/// <param name="phase">架构阶段枚举值,表示当前所处的架构阶段</param> /// <param name="phase">架构阶段枚举值,表示当前所处的架构阶段</param>
void OnArchitecturePhase(ArchitecturePhase phase); void OnArchitecturePhase(ArchitecturePhase phase);
} }

View File

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

View File

@ -11,7 +11,10 @@ public class TypeEventSystem : ITypeEventSystem
/// 发送事件,自动创建事件实例 /// 发送事件,自动创建事件实例
/// </summary> /// </summary>
/// <typeparam name="T">事件类型,必须具有无参构造函数</typeparam> /// <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>
/// 发送指定的事件实例 /// 发送指定的事件实例
@ -29,12 +32,18 @@ public class TypeEventSystem : ITypeEventSystem
/// <typeparam name="T">事件类型</typeparam> /// <typeparam name="T">事件类型</typeparam>
/// <param name="onEvent">事件处理回调函数</param> /// <param name="onEvent">事件处理回调函数</param>
/// <returns>反注册接口,用于注销事件监听</returns> /// <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>
/// 注销事件监听器 /// 注销事件监听器
/// </summary> /// </summary>
/// <typeparam name="T">事件类型</typeparam> /// <typeparam name="T">事件类型</typeparam>
/// <param name="onEvent">要注销的事件处理回调函数</param> /// <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

@ -16,10 +16,21 @@ public abstract class AbstractLogger(
/// 获取日志器的名称 /// 获取日志器的名称
/// </summary> /// </summary>
/// <returns>日志器名称</returns> /// <returns>日志器名称</returns>
public string Name() => _name; public string Name()
{
return _name;
}
#endregion #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 #region Level Checks
/// <summary> /// <summary>
@ -27,43 +38,64 @@ public abstract class AbstractLogger(
/// </summary> /// </summary>
/// <param name="level">要检查的日志级别</param> /// <param name="level">要检查的日志级别</param>
/// <returns>如果指定级别大于等于最小级别则返回true否则返回false</returns> /// <returns>如果指定级别大于等于最小级别则返回true否则返回false</returns>
protected bool IsEnabled(LogLevel level) => level >= minLevel; protected bool IsEnabled(LogLevel level)
{
return level >= minLevel;
}
/// <summary> /// <summary>
/// 检查Trace级别日志是否启用 /// 检查Trace级别日志是否启用
/// </summary> /// </summary>
/// <returns>如果Trace级别启用返回true否则返回false</returns> /// <returns>如果Trace级别启用返回true否则返回false</returns>
public bool IsTraceEnabled() => IsEnabled(LogLevel.Trace); public bool IsTraceEnabled()
{
return IsEnabled(LogLevel.Trace);
}
/// <summary> /// <summary>
/// 检查Debug级别日志是否启用 /// 检查Debug级别日志是否启用
/// </summary> /// </summary>
/// <returns>如果Debug级别启用返回true否则返回false</returns> /// <returns>如果Debug级别启用返回true否则返回false</returns>
public bool IsDebugEnabled() => IsEnabled(LogLevel.Debug); public bool IsDebugEnabled()
{
return IsEnabled(LogLevel.Debug);
}
/// <summary> /// <summary>
/// 检查Info级别日志是否启用 /// 检查Info级别日志是否启用
/// </summary> /// </summary>
/// <returns>如果Info级别启用返回true否则返回false</returns> /// <returns>如果Info级别启用返回true否则返回false</returns>
public bool IsInfoEnabled() => IsEnabled(LogLevel.Info); public bool IsInfoEnabled()
{
return IsEnabled(LogLevel.Info);
}
/// <summary> /// <summary>
/// 检查Warning级别日志是否启用 /// 检查Warning级别日志是否启用
/// </summary> /// </summary>
/// <returns>如果Warning级别启用返回true否则返回false</returns> /// <returns>如果Warning级别启用返回true否则返回false</returns>
public bool IsWarnEnabled() => IsEnabled(LogLevel.Warning); public bool IsWarnEnabled()
{
return IsEnabled(LogLevel.Warning);
}
/// <summary> /// <summary>
/// 检查Error级别日志是否启用 /// 检查Error级别日志是否启用
/// </summary> /// </summary>
/// <returns>如果Error级别启用返回true否则返回false</returns> /// <returns>如果Error级别启用返回true否则返回false</returns>
public bool IsErrorEnabled() => IsEnabled(LogLevel.Error); public bool IsErrorEnabled()
{
return IsEnabled(LogLevel.Error);
}
/// <summary> /// <summary>
/// 检查Fatal级别日志是否启用 /// 检查Fatal级别日志是否启用
/// </summary> /// </summary>
/// <returns>如果Fatal级别启用返回true否则返回false</returns> /// <returns>如果Fatal级别启用返回true否则返回false</returns>
public bool IsFatalEnabled() => IsEnabled(LogLevel.Fatal); public bool IsFatalEnabled()
{
return IsEnabled(LogLevel.Fatal);
}
#endregion #endregion
@ -73,14 +105,20 @@ public abstract class AbstractLogger(
/// 记录Trace级别日志 /// 记录Trace级别日志
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
public void Trace(string msg) => Log(LogLevel.Trace, msg); public void Trace(string msg)
{
Log(LogLevel.Trace, msg);
}
/// <summary> /// <summary>
/// 记录Trace级别日志带格式化参数 /// 记录Trace级别日志带格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</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> /// <summary>
/// 记录Trace级别日志带两个格式化参数 /// 记录Trace级别日志带两个格式化参数
@ -88,21 +126,30 @@ public abstract class AbstractLogger(
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param> /// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</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> /// <summary>
/// 记录Trace级别日志带多个格式化参数 /// 记录Trace级别日志带多个格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</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> /// <summary>
/// 记录Trace级别日志带异常信息 /// 记录Trace级别日志带异常信息
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
/// <param name="t">异常对象</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 #endregion
@ -112,14 +159,20 @@ public abstract class AbstractLogger(
/// 记录Debug级别日志 /// 记录Debug级别日志
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
public void Debug(string msg) => Log(LogLevel.Debug, msg); public void Debug(string msg)
{
Log(LogLevel.Debug, msg);
}
/// <summary> /// <summary>
/// 记录Debug级别日志带格式化参数 /// 记录Debug级别日志带格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</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> /// <summary>
/// 记录Debug级别日志带两个格式化参数 /// 记录Debug级别日志带两个格式化参数
@ -127,21 +180,30 @@ public abstract class AbstractLogger(
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param> /// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</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> /// <summary>
/// 记录Debug级别日志带多个格式化参数 /// 记录Debug级别日志带多个格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</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> /// <summary>
/// 记录Debug级别日志带异常信息 /// 记录Debug级别日志带异常信息
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
/// <param name="t">异常对象</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 #endregion
@ -151,14 +213,20 @@ public abstract class AbstractLogger(
/// 记录Info级别日志 /// 记录Info级别日志
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
public void Info(string msg) => Log(LogLevel.Info, msg); public void Info(string msg)
{
Log(LogLevel.Info, msg);
}
/// <summary> /// <summary>
/// 记录Info级别日志带格式化参数 /// 记录Info级别日志带格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</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> /// <summary>
/// 记录Info级别日志带两个格式化参数 /// 记录Info级别日志带两个格式化参数
@ -166,21 +234,30 @@ public abstract class AbstractLogger(
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param> /// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</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> /// <summary>
/// 记录Info级别日志带多个格式化参数 /// 记录Info级别日志带多个格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</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> /// <summary>
/// 记录Info级别日志带异常信息 /// 记录Info级别日志带异常信息
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
/// <param name="t">异常对象</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 #endregion
@ -190,14 +267,20 @@ public abstract class AbstractLogger(
/// 记录Warning级别日志 /// 记录Warning级别日志
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
public void Warn(string msg) => Log(LogLevel.Warning, msg); public void Warn(string msg)
{
Log(LogLevel.Warning, msg);
}
/// <summary> /// <summary>
/// 记录Warning级别日志带格式化参数 /// 记录Warning级别日志带格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</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> /// <summary>
/// 记录Warning级别日志带两个格式化参数 /// 记录Warning级别日志带两个格式化参数
@ -205,21 +288,30 @@ public abstract class AbstractLogger(
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param> /// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</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> /// <summary>
/// 记录Warning级别日志带多个格式化参数 /// 记录Warning级别日志带多个格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</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> /// <summary>
/// 记录Warning级别日志带异常信息 /// 记录Warning级别日志带异常信息
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
/// <param name="t">异常对象</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 #endregion
@ -229,14 +321,20 @@ public abstract class AbstractLogger(
/// 记录Error级别日志 /// 记录Error级别日志
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
public void Error(string msg) => Log(LogLevel.Error, msg); public void Error(string msg)
{
Log(LogLevel.Error, msg);
}
/// <summary> /// <summary>
/// 记录Error级别日志带格式化参数 /// 记录Error级别日志带格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</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> /// <summary>
/// 记录Error级别日志带两个格式化参数 /// 记录Error级别日志带两个格式化参数
@ -244,21 +342,30 @@ public abstract class AbstractLogger(
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param> /// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</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> /// <summary>
/// 记录Error级别日志带多个格式化参数 /// 记录Error级别日志带多个格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</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> /// <summary>
/// 记录Error级别日志带异常信息 /// 记录Error级别日志带异常信息
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
/// <param name="t">异常对象</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 #endregion
@ -268,14 +375,20 @@ public abstract class AbstractLogger(
/// 记录Fatal级别日志 /// 记录Fatal级别日志
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
public void Fatal(string msg) => Log(LogLevel.Fatal, msg); public void Fatal(string msg)
{
Log(LogLevel.Fatal, msg);
}
/// <summary> /// <summary>
/// 记录Fatal级别日志带格式化参数 /// 记录Fatal级别日志带格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg">格式化参数</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> /// <summary>
/// 记录Fatal级别日志带两个格式化参数 /// 记录Fatal级别日志带两个格式化参数
@ -283,21 +396,30 @@ public abstract class AbstractLogger(
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arg1">第一个格式化参数</param> /// <param name="arg1">第一个格式化参数</param>
/// <param name="arg2">第二个格式化参数</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> /// <summary>
/// 记录Fatal级别日志带多个格式化参数 /// 记录Fatal级别日志带多个格式化参数
/// </summary> /// </summary>
/// <param name="format">格式化字符串</param> /// <param name="format">格式化字符串</param>
/// <param name="arguments">格式化参数数组</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> /// <summary>
/// 记录Fatal级别日志带异常信息 /// 记录Fatal级别日志带异常信息
/// </summary> /// </summary>
/// <param name="msg">日志消息</param> /// <param name="msg">日志消息</param>
/// <param name="t">异常对象</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 #endregion
@ -339,12 +461,4 @@ public abstract class AbstractLogger(
} }
#endregion #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

@ -9,8 +9,8 @@ public sealed class ConsoleLogger(
TextWriter? writer = null, TextWriter? writer = null,
bool useColors = true) : AbstractLogger(name ?? ILogger.RootLoggerName, minLevel) 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 bool _useColors = useColors && writer == Console.Out;
private readonly TextWriter _writer = writer ?? Console.Out;
/// <summary> /// <summary>
/// 写入日志消息到控制台 /// 写入日志消息到控制台
@ -25,22 +25,16 @@ public sealed class ConsoleLogger(
var log = $"[{timestamp}] {levelStr} [{Name()}] {message}"; var log = $"[{timestamp}] {levelStr} [{Name()}] {message}";
// 添加异常信息到日志 // 添加异常信息到日志
if (exception != null) if (exception != null) log += Environment.NewLine + exception;
{
log += Environment.NewLine + exception;
}
if (_useColors) if (_useColors)
{
WriteColored(level, log); WriteColored(level, log);
}
else else
{
_writer.WriteLine(log); _writer.WriteLine(log);
} }
}
#region Internal Core #region Internal Core
/// <summary> /// <summary>
/// 以指定颜色写入日志消息 /// 以指定颜色写入日志消息
/// </summary> /// </summary>
@ -65,7 +59,9 @@ public sealed class ConsoleLogger(
/// </summary> /// </summary>
/// <param name="level">日志级别</param> /// <param name="level">日志级别</param>
/// <returns>控制台颜色</returns> /// <returns>控制台颜色</returns>
private static ConsoleColor GetColor(LogLevel level) => level switch private static ConsoleColor GetColor(LogLevel level)
{
return level switch
{ {
LogLevel.Trace => ConsoleColor.DarkGray, LogLevel.Trace => ConsoleColor.DarkGray,
LogLevel.Debug => ConsoleColor.Cyan, LogLevel.Debug => ConsoleColor.Cyan,
@ -75,6 +71,7 @@ public sealed class ConsoleLogger(
LogLevel.Fatal => ConsoleColor.Magenta, LogLevel.Fatal => ConsoleColor.Magenta,
_ => ConsoleColor.White _ => ConsoleColor.White
}; };
}
#endregion #endregion
} }

View File

@ -9,22 +9,27 @@ public enum LogLevel
/// 跟踪级别,用于详细的程序执行流程信息 /// 跟踪级别,用于详细的程序执行流程信息
/// </summary> /// </summary>
Trace, Trace,
/// <summary> /// <summary>
/// 调试级别,用于调试过程中的详细信息 /// 调试级别,用于调试过程中的详细信息
/// </summary> /// </summary>
Debug, Debug,
/// <summary> /// <summary>
/// 信息级别,用于一般性的程序运行信息 /// 信息级别,用于一般性的程序运行信息
/// </summary> /// </summary>
Info, Info,
/// <summary> /// <summary>
/// 警告级别,用于表示可能的问题或异常情况 /// 警告级别,用于表示可能的问题或异常情况
/// </summary> /// </summary>
Warning, Warning,
/// <summary> /// <summary>
/// 错误级别,用于表示错误但程序仍可继续运行的情况 /// 错误级别,用于表示错误但程序仍可继续运行的情况
/// </summary> /// </summary>
Error, Error,
/// <summary> /// <summary>
/// 致命级别,用于表示严重的错误导致程序无法继续运行 /// 致命级别,用于表示严重的错误导致程序无法继续运行
/// </summary> /// </summary>

View File

@ -17,6 +17,5 @@ internal sealed class NoopLogger(
/// <param name="exception">异常信息</param> /// <param name="exception">异常信息</param>
protected override void Write(LogLevel level, string message, Exception? exception) protected override void Write(LogLevel level, string message, Exception? exception)
{ {
} }
} }

View File

@ -3,7 +3,7 @@
/// <summary> /// <summary>
/// 无操作日志工厂实现,用于提供空的日志记录功能 /// 无操作日志工厂实现,用于提供空的日志记录功能
/// </summary> /// </summary>
public class NoopLoggerFactory: ILoggerFactory public class NoopLoggerFactory : ILoggerFactory
{ {
/// <summary> /// <summary>
/// 获取指定名称的无操作日志记录器 /// 获取指定名称的无操作日志记录器

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 在以下关键位置自动添加了日志记录: GFramework.Core 在以下关键位置自动添加了日志记录:
### 架构模块 (Architecture) ### 架构模块 (Architecture)
- 架构初始化流程 - 架构初始化流程
- 组件注册和初始化 - 组件注册和初始化
- 生命周期阶段变更 - 生命周期阶段变更
- 模块安装和卸载 - 模块安装和卸载
### IOC容器 (IOC) ### IOC容器 (IOC)
- 对象注册和获取 - 对象注册和获取
- 容器冻结操作 - 容器冻结操作
- 重复注册检测 - 重复注册检测
### 事件系统 (Event) ### 事件系统 (Event)
- 事件发送和接收 - 事件发送和接收
- 事件处理器注册和注销 - 事件处理器注册和注销
### 系统模块 (System) ### 系统模块 (System)
- 系统初始化和销毁 - 系统初始化和销毁
- 组件生命周期管理 - 组件生命周期管理
## 输出格式 ## 输出格式
### 控制台输出示例 ### 控制台输出示例
``` ```
[2025-12-23 12:34:56.789] INFO Architecture Architecture initialized [2025-12-23 12:34:56.789] INFO Architecture Architecture initialized
[2025-12-23 12:34:56.790] INFO Architecture Initializing 3 systems [2025-12-23 12:34:56.790] INFO Architecture Initializing 3 systems
@ -271,6 +277,7 @@ GFramework.Core 在以下关键位置自动添加了日志记录:
``` ```
### 日志输出级别颜色 ### 日志输出级别颜色
- **Trace**: 灰色 - **Trace**: 灰色
- **Debug**: 青色 - **Debug**: 青色
- **Info**: 白色 - **Info**: 白色
@ -331,6 +338,7 @@ GFramework.Core 在以下关键位置自动添加了日志记录:
## 配置建议 ## 配置建议
### 开发环境 ### 开发环境
```csharp ```csharp
Log.Configure( Log.Configure(
minLevel: LogLevel.Debug, minLevel: LogLevel.Debug,
@ -341,6 +349,7 @@ Log.Configure(
``` ```
### 生产环境 ### 生产环境
```csharp ```csharp
var config = new LogConfig var config = new LogConfig
{ {

View File

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

View File

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

View File

@ -6,7 +6,7 @@ namespace GFramework.Core.query;
/// 抽象查询类,提供查询操作的基础实现 /// 抽象查询类,提供查询操作的基础实现
/// </summary> /// </summary>
/// <typeparam name="T">查询结果的类型</typeparam> /// <typeparam name="T">查询结果的类型</typeparam>
public abstract class AbstractQuery<T> :ContextAwareBase, IQuery<T> public abstract class AbstractQuery<T> : ContextAwareBase, IQuery<T>
{ {
/// <summary> /// <summary>
/// 执行查询操作 /// 执行查询操作

View File

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

View File

@ -25,5 +25,7 @@ public abstract class ContextAwareBase : IContextAware
/// <summary> /// <summary>
/// 当上下文准备就绪时调用的虚方法,子类可以重写此方法来执行上下文相关的初始化逻辑 /// 当上下文准备就绪时调用的虚方法,子类可以重写此方法来执行上下文相关的初始化逻辑
/// </summary> /// </summary>
protected virtual void OnContextReady() { } protected virtual void OnContextReady()
{
}
} }

View File

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

View File

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

View File

@ -5,18 +5,18 @@ namespace GFramework.Game.assets;
/// <summary> /// <summary>
/// 资源目录系统抽象基类,用于管理和注册游戏中的场景和资源。 /// 资源目录系统抽象基类,用于管理和注册游戏中的场景和资源。
/// 提供了统一的接口来注册和查询不同类型的资产(如游戏单元、模板、普通资源)。 /// 提供了统一的接口来注册和查询不同类型的资产(如游戏单元、模板、普通资源)。
/// 子类需要实现 <see cref="RegisterAssets"/> 方法以完成具体资产的注册逻辑。 /// 子类需要实现 <see cref="RegisterAssets" /> 方法以完成具体资产的注册逻辑。
/// </summary> /// </summary>
public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalogSystem 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.AssetId> _assets = new();
private readonly Dictionary<string, AssetCatalog.ScenePageId> _scenePages = new();
private readonly Dictionary<string, AssetCatalog.SceneUnitId> _sceneUnits = new();
/// <summary> /// <summary>
/// 系统初始化时调用,用于触发资产注册流程。 /// 系统初始化时调用,用于触发资产注册流程。
/// 此方法会调用抽象方法 <see cref="RegisterAssets"/>,由子类提供实际注册逻辑。 /// 此方法会调用抽象方法 <see cref="RegisterAssets" />,由子类提供实际注册逻辑。
/// </summary> /// </summary>
protected override void OnInit() protected override void OnInit()
{ {
@ -31,7 +31,6 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
#region Register or Module 使 #region Register or Module 使
/// <summary> /// <summary>
/// 注册场景单元到资产目录中 /// 注册场景单元到资产目录中
/// </summary> /// </summary>
@ -107,7 +106,7 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
/// </summary> /// </summary>
/// <param name="mapping">包含键与ID映射关系的对象。</param> /// <param name="mapping">包含键与ID映射关系的对象。</param>
/// <exception cref="InvalidOperationException"> /// <exception cref="InvalidOperationException">
/// 当映射ID不是 <see cref="AssetCatalog.AssetId"/> 类型或键重复时抛出异常。 /// 当映射ID不是 <see cref="AssetCatalog.AssetId" /> 类型或键重复时抛出异常。
/// </exception> /// </exception>
public void RegisterAsset(AssetCatalog.AssetCatalogMapping mapping) public void RegisterAsset(AssetCatalog.AssetCatalogMapping mapping)
{ {
@ -117,6 +116,7 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
if (!_assets.TryAdd(mapping.Key, assetId)) if (!_assets.TryAdd(mapping.Key, assetId))
throw new InvalidOperationException($"Asset key duplicated: {mapping.Key}"); throw new InvalidOperationException($"Asset key duplicated: {mapping.Key}");
} }
#endregion #endregion
#region Query #region Query
@ -126,14 +126,20 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
/// </summary> /// </summary>
/// <param name="key">用于查找场景单元的键值</param> /// <param name="key">用于查找场景单元的键值</param>
/// <returns>返回与指定键对应的场景单元标识符</returns> /// <returns>返回与指定键对应的场景单元标识符</returns>
public AssetCatalog.SceneUnitId GetSceneUnit(string key) => _sceneUnits[key]; public AssetCatalog.SceneUnitId GetSceneUnit(string key)
{
return _sceneUnits[key];
}
/// <summary> /// <summary>
/// 根据指定的键获取场景页面标识符 /// 根据指定的键获取场景页面标识符
/// </summary> /// </summary>
/// <param name="key">用于查找场景页面的键值</param> /// <param name="key">用于查找场景页面的键值</param>
/// <returns>返回与指定键对应的场景页面标识符</returns> /// <returns>返回与指定键对应的场景页面标识符</returns>
public AssetCatalog.ScenePageId GetScenePage(string key) => _scenePages[key]; public AssetCatalog.ScenePageId GetScenePage(string key)
{
return _scenePages[key];
}
/// <summary> /// <summary>
/// 获取指定键对应的通用资源ID。 /// 获取指定键对应的通用资源ID。
@ -141,27 +147,40 @@ public abstract class AbstractAssetCatalogSystem : AbstractSystem, IAssetCatalog
/// <param name="key">要查找的通用资源键。</param> /// <param name="key">要查找的通用资源键。</param>
/// <returns>对应的通用资源ID。</returns> /// <returns>对应的通用资源ID。</returns>
/// <exception cref="KeyNotFoundException">如果未找到指定键则抛出异常。</exception> /// <exception cref="KeyNotFoundException">如果未找到指定键则抛出异常。</exception>
public AssetCatalog.AssetId GetAsset(string key) => _assets[key]; public AssetCatalog.AssetId GetAsset(string key)
{
return _assets[key];
}
/// <summary> /// <summary>
/// 检查是否存在指定键的场景单元 /// 检查是否存在指定键的场景单元
/// </summary> /// </summary>
/// <param name="key">用于查找场景单元的键值</param> /// <param name="key">用于查找场景单元的键值</param>
/// <returns>存在返回true否则返回false</returns> /// <returns>存在返回true否则返回false</returns>
public bool HasSceneUnit(string key) => _sceneUnits.ContainsKey(key); public bool HasSceneUnit(string key)
{
return _sceneUnits.ContainsKey(key);
}
/// <summary> /// <summary>
/// 检查是否存在指定键的场景页面 /// 检查是否存在指定键的场景页面
/// </summary> /// </summary>
/// <param name="key">用于查找场景页面的键值</param> /// <param name="key">用于查找场景页面的键值</param>
/// <returns>存在返回true否则返回false</returns> /// <returns>存在返回true否则返回false</returns>
public bool HasScenePage(string key) => _scenePages.ContainsKey(key); public bool HasScenePage(string key)
{
return _scenePages.ContainsKey(key);
}
/// <summary> /// <summary>
/// 判断是否存在指定键的通用资源。 /// 判断是否存在指定键的通用资源。
/// </summary> /// </summary>
/// <param name="key">要检查的通用资源键。</param> /// <param name="key">要检查的通用资源键。</param>
/// <returns>若存在返回 true否则返回 false。</returns> /// <returns>若存在返回 true否则返回 false。</returns>
public bool HasAsset(string key) => _assets.ContainsKey(key); public bool HasAsset(string key)
{
return _assets.ContainsKey(key);
}
#endregion #endregion
} }

View File

@ -42,6 +42,4 @@ public static class AssetCatalog
/// </summary> /// </summary>
/// <param name="Path">资源路径</param> /// <param name="Path">资源路径</param>
public readonly record struct AssetId(string Path) : IAssetId; public readonly record struct AssetId(string Path) : IAssetId;
} }

View File

@ -94,5 +94,4 @@ public interface IAssetCatalogSystem : ISystem
/// <param name="key">用于查找资源的键值</param> /// <param name="key">用于查找资源的键值</param>
/// <returns>存在返回true否则返回false</returns> /// <returns>存在返回true否则返回false</returns>
bool HasAsset(string key); bool HasAsset(string key);
} }

View File

@ -23,4 +23,3 @@ public interface IResourceFactorySystem : ISystem
/// <returns>返回一个创建T类型实例的函数委托</returns> /// <returns>返回一个创建T类型实例的函数委托</returns>
Func<T> GetFactory<T>(AssetCatalog.AssetCatalogMapping mapping); Func<T> GetFactory<T>(AssetCatalog.AssetCatalogMapping mapping);
} }

View File

@ -15,11 +15,6 @@ public static class ResourceFactory
/// </summary> /// </summary>
bool Preload { get; } bool Preload { get; }
/// <summary>
/// 执行与该条目关联的工厂方法
/// </summary>
void ExecuteFactory();
/// <summary> /// <summary>
/// 获取资源类型 /// 获取资源类型
/// </summary> /// </summary>
@ -29,6 +24,11 @@ public static class ResourceFactory
/// 获取资源键值 /// 获取资源键值
/// </summary> /// </summary>
string Key { get; } string Key { get; }
/// <summary>
/// 执行与该条目关联的工厂方法
/// </summary>
void ExecuteFactory();
} }
@ -51,7 +51,10 @@ public static class ResourceFactory
/// <summary> /// <summary>
/// 执行工厂函数以创建资源实例 /// 执行工厂函数以创建资源实例
/// </summary> /// </summary>
public void ExecuteFactory() => Factory(); public void ExecuteFactory()
{
Factory();
}
/// <summary> /// <summary>
/// 获取资源的类型 /// 获取资源的类型
@ -105,9 +108,7 @@ public static class ResourceFactory
if (_factories.TryGetValue(dictKey, out var entry) if (_factories.TryGetValue(dictKey, out var entry)
&& entry is Entry<T> typed) && entry is Entry<T> typed)
{
return typed.Factory; return typed.Factory;
}
throw new InvalidOperationException( throw new InvalidOperationException(
$"Factory not registered: {typeof(T).Name} with key '{key}'"); $"Factory not registered: {typeof(T).Name} with key '{key}'");
@ -120,11 +121,8 @@ public static class ResourceFactory
{ {
// 遍历所有已注册的工厂 // 遍历所有已注册的工厂
foreach (var entry in _factories.Values.Where(entry => entry.Preload)) foreach (var entry in _factories.Values.Where(entry => entry.Preload))
{
// 执行其工厂方法进行预加载 // 执行其工厂方法进行预加载
entry.ExecuteFactory(); entry.ExecuteFactory();
} }
} }
}
} }

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

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

View File

@ -9,9 +9,8 @@ namespace GFramework.Godot.architecture;
/// 抽象架构类,为特定类型的架构提供基础实现框架。 /// 抽象架构类,为特定类型的架构提供基础实现框架。
/// 此类负责管理架构的初始化、生命周期绑定以及扩展模块的安装与销毁。 /// 此类负责管理架构的初始化、生命周期绑定以及扩展模块的安装与销毁。
/// </summary> /// </summary>
public abstract class AbstractArchitecture: Architecture public abstract class AbstractArchitecture : Architecture
{ {
/// <summary> /// <summary>
/// 架构锚点节点的唯一标识名称 /// 架构锚点节点的唯一标识名称
/// 用于在Godot场景树中创建和查找架构锚点节点 /// 用于在Godot场景树中创建和查找架构锚点节点
@ -30,18 +29,18 @@ public abstract class AbstractArchitecture: Architecture
/// </summary> /// </summary>
private ArchitectureAnchor? _anchor; private ArchitectureAnchor? _anchor;
/// <summary>
/// 获取架构根节点。如果尚未初始化或已被销毁,则抛出异常。
/// </summary>
/// <exception cref="InvalidOperationException">当架构未准备就绪时抛出。</exception>
protected Node ArchitectureRoot => _anchor ?? throw new InvalidOperationException("Architecture root not ready");
/// <summary> /// <summary>
/// 标记架构是否已被销毁的状态标志 /// 标记架构是否已被销毁的状态标志
/// 用于防止架构被重复销毁,确保资源清理只执行一次 /// 用于防止架构被重复销毁,确保资源清理只执行一次
/// </summary> /// </summary>
private bool _destroyed; private bool _destroyed;
/// <summary>
/// 获取架构根节点。如果尚未初始化或已被销毁,则抛出异常。
/// </summary>
/// <exception cref="InvalidOperationException">当架构未准备就绪时抛出。</exception>
protected Node ArchitectureRoot => _anchor ?? throw new InvalidOperationException("Architecture root not ready");
/// <summary> /// <summary>
/// 初始化架构,按顺序注册模型、系统和工具。 /// 初始化架构,按顺序注册模型、系统和工具。
@ -111,7 +110,6 @@ public abstract class AbstractArchitecture: Architecture
} }
/// <summary> /// <summary>
/// 销毁架构及其相关资源。 /// 销毁架构及其相关资源。
/// 调用所有已安装扩展的OnDetach方法并清空扩展列表。 /// 调用所有已安装扩展的OnDetach方法并清空扩展列表。

View File

@ -6,7 +6,7 @@ namespace GFramework.Godot.architecture;
/// <summary> /// <summary>
/// 抽象的Godot模块基类用于定义Godot框架中的模块行为 /// 抽象的Godot模块基类用于定义Godot框架中的模块行为
/// </summary> /// </summary>
public abstract class AbstractGodotModule: IGodotModule public abstract class AbstractGodotModule : IGodotModule
{ {
/// <summary> /// <summary>
/// 当架构阶段发生变化时调用此方法 /// 当架构阶段发生变化时调用此方法
@ -15,7 +15,6 @@ public abstract class AbstractGodotModule: IGodotModule
/// <param name="arch">架构实例</param> /// <param name="arch">架构实例</param>
public virtual void OnPhase(ArchitecturePhase phase, IArchitecture arch) public virtual void OnPhase(ArchitecturePhase phase, IArchitecture arch)
{ {
} }
/// <summary> /// <summary>
@ -24,7 +23,6 @@ public abstract class AbstractGodotModule: IGodotModule
/// <param name="phase">当前的架构阶段</param> /// <param name="phase">当前的架构阶段</param>
public virtual void OnArchitecturePhase(ArchitecturePhase phase) public virtual void OnArchitecturePhase(ArchitecturePhase phase)
{ {
} }
/// <summary> /// <summary>
@ -44,7 +42,6 @@ public abstract class AbstractGodotModule: IGodotModule
/// <param name="architecture">被附加到的架构实例</param> /// <param name="architecture">被附加到的架构实例</param>
public virtual void OnAttach(Architecture architecture) public virtual void OnAttach(Architecture architecture)
{ {
} }
/// <summary> /// <summary>
@ -52,6 +49,5 @@ public abstract class AbstractGodotModule: IGodotModule
/// </summary> /// </summary>
public virtual void OnDetach() public virtual void OnDetach()
{ {
} }
} }

View File

@ -9,6 +9,7 @@ namespace GFramework.Godot.architecture;
public partial class ArchitectureAnchor : Node public partial class ArchitectureAnchor : Node
{ {
private Action? _onExit; private Action? _onExit;
/// <summary> /// <summary>
/// 绑定节点退出时的回调动作 /// 绑定节点退出时的回调动作
/// </summary> /// </summary>
@ -16,10 +17,8 @@ public partial class ArchitectureAnchor : Node
public void Bind(Action onExit) public void Bind(Action onExit)
{ {
if (_onExit != null) if (_onExit != null)
{
GD.PushWarning( GD.PushWarning(
$"{nameof(ArchitectureAnchor)} already bound. Rebinding will override previous callback."); $"{nameof(ArchitectureAnchor)} already bound. Rebinding will override previous callback.");
}
_onExit = onExit; _onExit = onExit;
} }
@ -34,4 +33,3 @@ public partial class ArchitectureAnchor : Node
callback?.Invoke(); callback?.Invoke();
} }
} }

View File

@ -12,21 +12,9 @@ namespace GFramework.Godot.assets;
/// </summary> /// </summary>
public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceFactorySystem, IArchitectureLifecycle public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceFactorySystem, IArchitectureLifecycle
{ {
private IAssetCatalogSystem? _assetCatalogSystem;
private ResourceFactory.Registry? _registry; private ResourceFactory.Registry? _registry;
private IResourceLoadSystem? _resourceLoadSystem; 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>
/// 架构阶段回调,在架构就绪时注册和预加载资源 /// 架构阶段回调,在架构就绪时注册和预加载资源
@ -44,11 +32,6 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
} }
} }
/// <summary>
/// 注册系统所需的各种资源类型。由子类实现具体注册逻辑。
/// </summary>
protected abstract void RegisterResources();
/// <summary> /// <summary>
/// 根据指定的键获取资源工厂函数。 /// 根据指定的键获取资源工厂函数。
@ -56,7 +39,10 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
/// <typeparam name="T">资源类型</typeparam> /// <typeparam name="T">资源类型</typeparam>
/// <param name="key">资源键</param> /// <param name="key">资源键</param>
/// <returns>返回创建指定类型资源的工厂函数</returns> /// <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>
/// 根据资产目录映射信息获取资源工厂函数。 /// 根据资产目录映射信息获取资源工厂函数。
@ -64,12 +50,31 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
/// <typeparam name="T">资源类型</typeparam> /// <typeparam name="T">资源类型</typeparam>
/// <param name="mapping">资产目录映射信息</param> /// <param name="mapping">资产目录映射信息</param>
/// <returns>返回创建指定类型资源的工厂函数</returns> /// <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 #region Register Helpers
/// <summary> /// <summary>
/// 注册场景单元到资源管理系统中 /// 注册场景单元到资源管理系统中
/// </summary> /// </summary>
@ -131,6 +136,5 @@ public abstract class AbstractResourceFactorySystem : AbstractSystem, IResourceF
); );
} }
#endregion #endregion
} }

View File

@ -16,9 +16,9 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
private readonly Dictionary<string, Resource> _loadedResources = new(); private readonly Dictionary<string, Resource> _loadedResources = new();
/// <summary> /// <summary>
/// 场景懒加载器缓存键为场景路径值为延迟加载的PackedScene对象 /// 资源获取/复制工厂委托缓存键为资源路径值为获取或复制资源的Func委托
/// </summary> /// </summary>
private readonly Dictionary<string, Lazy<PackedScene>> _sceneLoaders = new(); private readonly Dictionary<string, Delegate> _resourceFactories = new();
/// <summary> /// <summary>
/// 场景实例化工厂委托缓存键为场景路径值为创建该场景实例的Func委托。 /// 场景实例化工厂委托缓存键为场景路径值为创建该场景实例的Func委托。
@ -26,66 +26,9 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
private readonly Dictionary<string, Delegate> _sceneFactories = new(); private readonly Dictionary<string, Delegate> _sceneFactories = new();
/// <summary> /// <summary>
/// 资源获取/复制工厂委托缓存键为资源路径值为获取或复制资源的Func委托 /// 场景懒加载器缓存键为场景路径值为延迟加载的PackedScene对象
/// </summary> /// </summary>
private readonly Dictionary<string, Delegate> _resourceFactories = new(); private readonly Dictionary<string, Lazy<PackedScene>> _sceneLoaders = new();
/// <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
/// <summary> /// <summary>
/// 根据给定路径加载场景,并创建其节点实例。 /// 根据给定路径加载场景,并创建其节点实例。
@ -159,6 +102,64 @@ public class ResourceLoadSystem : AbstractSystem, IResourceLoadSystem
_resourceFactories[path] = factory; _resourceFactories[path] = factory;
return 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 #region
/// <summary> /// <summary>

View File

@ -252,10 +252,8 @@ public static class NodeExtensions
public static T OfType<T>(this Node? node) where T : Node 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; return t;
throw new InvalidCastException($"Cannot cast {node} to {typeof(T)}"); throw new InvalidCastException($"Cannot cast {node} to {typeof(T)}");
} }
} }

View File

@ -8,17 +8,14 @@ namespace GFramework.Godot.logging;
/// </summary> /// </summary>
public sealed class GodotLogger( public sealed class GodotLogger(
string? name = null, 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) protected override void Write(LogLevel level, string message, Exception? exception)
{ {
var prefix = $"[{level.ToString().ToUpper()}][{Name()}]"; var prefix = $"[{level.ToString().ToUpper()}][{Name()}]";
// 将异常信息追加到日志消息中 // 将异常信息追加到日志消息中
if (exception != null) if (exception != null) message += "\n" + exception;
{
message += "\n" + exception;
}
// 根据日志级别选择不同的输出方法 // 根据日志级别选择不同的输出方法
switch (level) switch (level)

View File

@ -5,7 +5,7 @@ namespace GFramework.Godot.logging;
/// <summary> /// <summary>
/// Godot日志工厂类用于创建Godot平台专用的日志记录器实例 /// Godot日志工厂类用于创建Godot平台专用的日志记录器实例
/// </summary> /// </summary>
public class GodotLoggerFactory: ILoggerFactory public class GodotLoggerFactory : ILoggerFactory
{ {
/// <summary> /// <summary>
/// 获取指定名称的日志记录器实例 /// 获取指定名称的日志记录器实例

View File

@ -10,24 +10,19 @@ namespace GFramework.Godot.system;
public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManagerSystem public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManagerSystem
{ {
/// <summary> /// <summary>
/// 音频资源加载系统依赖 /// 最大同时播放的音效数量
/// </summary> /// </summary>
protected IResourceLoadSystem? ResourceLoadSystem; protected const int MaxSoundPlayers = 10;
/// <summary> /// <summary>
/// 资源目录系统依赖 /// 最大同时播放的3D音效数量
/// </summary> /// </summary>
protected IAssetCatalogSystem? AssetCatalogSystem; protected const int MaxSound3DPlayers = 5;
/// <summary> /// <summary>
/// 背景音乐播放器 /// 可用3D音效播放器队列
/// </summary> /// </summary>
protected AudioStreamPlayer? MusicPlayer; protected readonly Queue<AudioStreamPlayer3D> AvailableSound3DPlayers = new();
/// <summary>
/// 音效播放器列表
/// </summary>
protected readonly List<AudioStreamPlayer> SoundPlayers = [];
/// <summary> /// <summary>
/// 可用音效播放器队列 /// 可用音效播放器队列
@ -40,120 +35,70 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
protected readonly List<AudioStreamPlayer3D> Sound3DPlayers = []; protected readonly List<AudioStreamPlayer3D> Sound3DPlayers = [];
/// <summary> /// <summary>
/// 可用3D音效播放器队列 /// 音效播放器列表
/// </summary> /// </summary>
protected readonly Queue<AudioStreamPlayer3D> AvailableSound3DPlayers = new(); protected readonly List<AudioStreamPlayer> SoundPlayers = [];
/// <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>
/// 环境音量 /// 环境音量
/// </summary> /// </summary>
protected float AmbientVolume = 1.0f; protected float AmbientVolume = 1.0f;
/// <summary>
/// 资源目录系统依赖
/// </summary>
protected IAssetCatalogSystem? AssetCatalogSystem;
/// <summary>
/// 主音量
/// </summary>
protected float MasterVolume = 1.0f;
/// <summary> /// <summary>
/// 音乐淡入淡出动画 /// 音乐淡入淡出动画
/// </summary> /// </summary>
protected Tween? MusicFadeTween; protected Tween? MusicFadeTween;
/// <summary> /// <summary>
/// 最大同时播放的音效数量 /// 背景音乐播放器
/// </summary> /// </summary>
protected const int MaxSoundPlayers = 10; protected AudioStreamPlayer? MusicPlayer;
/// <summary> /// <summary>
/// 最大同时播放的3D音效数 /// 背景音乐音量
/// </summary> /// </summary>
protected const int MaxSound3DPlayers = 5; 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>
/// 所有者节点的抽象属性 /// 所有者节点的抽象属性
/// </summary> /// </summary>
protected abstract Node Owner { get; } protected abstract Node Owner { get; }
/// <summary>
/// 系统初始化方法
/// </summary>
protected override void OnInit()
{
// 获取依赖的系统
ResourceLoadSystem = Context.GetSystem<IResourceLoadSystem>();
AssetCatalogSystem = Context.GetSystem<IAssetCatalogSystem>();
ResourceFactorySystem = Context.GetSystem<IResourceFactorySystem>();
// 初始化背景音乐播放器
MusicPlayer = new AudioStreamPlayer();
Owner.AddChild(MusicPlayer);
// 预创建音效播放器池
for (var i = 0; i < MaxSoundPlayers; i++)
{
var soundPlayer = new AudioStreamPlayer();
Owner.AddChild(soundPlayer);
soundPlayer.Finished += () => OnSoundFinished(soundPlayer);
SoundPlayers.Add(soundPlayer);
AvailableSoundPlayers.Enqueue(soundPlayer);
}
// 预创建3D音效播放器池
for (var i = 0; i < MaxSound3DPlayers; i++)
{
var sound3DPlayer = new AudioStreamPlayer3D();
Owner.AddChild(sound3DPlayer);
sound3DPlayer.Finished += () => OnSound3DFinished(sound3DPlayer);
Sound3DPlayers.Add(sound3DPlayer);
AvailableSound3DPlayers.Enqueue(sound3DPlayer);
}
}
/// <summary>
/// 当音效播放完成时的回调
/// </summary>
/// <param name="player">完成播放的音频播放器</param>
private void OnSoundFinished(AudioStreamPlayer player)
{
// 将播放器放回可用队列
AvailableSoundPlayers.Enqueue(player);
}
/// <summary>
/// 当3D音效播放完成时的回调
/// </summary>
/// <param name="player">完成播放的3D音频播放器</param>
private void OnSound3DFinished(AudioStreamPlayer3D player)
{
// 将播放器放回可用队列
AvailableSound3DPlayers.Enqueue(player);
}
/// <summary> /// <summary>
/// 播放背景音乐 /// 播放背景音乐
/// </summary> /// </summary>
@ -173,17 +118,6 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
MusicPlayer.Play(); MusicPlayer.Play();
} }
/// <summary>
/// 通过资源ID播放背景音乐
/// </summary>
/// <param name="musicId">音乐资源ID</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="loop">是否循环播放</param>
public virtual void PlayMusic(AssetCatalog.AssetId musicId, float volume = 1.0f, bool loop = true)
{
PlayMusic(musicId.Path, volume, loop);
}
/// <summary> /// <summary>
/// 播放音效 /// 播放音效
/// </summary> /// </summary>
@ -260,17 +194,6 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
player.Play(); player.Play();
} }
/// <summary>
/// 通过资源ID播放音效
/// </summary>
/// <param name="soundId">音效资源ID</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlaySound(AssetCatalog.AssetId soundId, float volume = 1.0f, float pitch = 1.0f)
{
PlaySound(soundId.Path, volume, pitch);
}
/// <summary> /// <summary>
/// 播放3D音效 /// 播放3D音效
/// </summary> /// </summary>
@ -324,10 +247,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
public virtual void SetMusicVolume(float volume) public virtual void SetMusicVolume(float volume)
{ {
MusicVolume = volume; MusicVolume = volume;
if (MusicPlayer != null) if (MusicPlayer != null) MusicPlayer.VolumeDb = LinearToDb(MusicVolume * MasterVolume);
{
MusicPlayer.VolumeDb = LinearToDb(MusicVolume * MasterVolume);
}
} }
/// <summary> /// <summary>
@ -366,10 +286,7 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
MasterVolume = volume; MasterVolume = volume;
// 更新音乐音量 // 更新音乐音量
if (MusicPlayer != null) if (MusicPlayer != null) MusicPlayer.VolumeDb = LinearToDb(MusicVolume * MasterVolume);
{
MusicPlayer.VolumeDb = LinearToDb(MusicVolume * MasterVolume);
}
} }
/// <summary> /// <summary>
@ -507,6 +424,83 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
// 可以通过AudioEffectReverb实现 // 可以通过AudioEffectReverb实现
} }
/// <summary>
/// 系统初始化方法
/// </summary>
protected override void OnInit()
{
// 获取依赖的系统
ResourceLoadSystem = Context.GetSystem<IResourceLoadSystem>();
AssetCatalogSystem = Context.GetSystem<IAssetCatalogSystem>();
ResourceFactorySystem = Context.GetSystem<IResourceFactorySystem>();
// 初始化背景音乐播放器
MusicPlayer = new AudioStreamPlayer();
Owner.AddChild(MusicPlayer);
// 预创建音效播放器池
for (var i = 0; i < MaxSoundPlayers; i++)
{
var soundPlayer = new AudioStreamPlayer();
Owner.AddChild(soundPlayer);
soundPlayer.Finished += () => OnSoundFinished(soundPlayer);
SoundPlayers.Add(soundPlayer);
AvailableSoundPlayers.Enqueue(soundPlayer);
}
// 预创建3D音效播放器池
for (var i = 0; i < MaxSound3DPlayers; i++)
{
var sound3DPlayer = new AudioStreamPlayer3D();
Owner.AddChild(sound3DPlayer);
sound3DPlayer.Finished += () => OnSound3DFinished(sound3DPlayer);
Sound3DPlayers.Add(sound3DPlayer);
AvailableSound3DPlayers.Enqueue(sound3DPlayer);
}
}
/// <summary>
/// 当音效播放完成时的回调
/// </summary>
/// <param name="player">完成播放的音频播放器</param>
private void OnSoundFinished(AudioStreamPlayer player)
{
// 将播放器放回可用队列
AvailableSoundPlayers.Enqueue(player);
}
/// <summary>
/// 当3D音效播放完成时的回调
/// </summary>
/// <param name="player">完成播放的3D音频播放器</param>
private void OnSound3DFinished(AudioStreamPlayer3D player)
{
// 将播放器放回可用队列
AvailableSound3DPlayers.Enqueue(player);
}
/// <summary>
/// 通过资源ID播放背景音乐
/// </summary>
/// <param name="musicId">音乐资源ID</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="loop">是否循环播放</param>
public virtual void PlayMusic(AssetCatalog.AssetId musicId, float volume = 1.0f, bool loop = true)
{
PlayMusic(musicId.Path, volume, loop);
}
/// <summary>
/// 通过资源ID播放音效
/// </summary>
/// <param name="soundId">音效资源ID</param>
/// <param name="volume">音量大小范围0-1</param>
/// <param name="pitch">音调调整</param>
public virtual void PlaySound(AssetCatalog.AssetId soundId, float volume = 1.0f, float pitch = 1.0f)
{
PlaySound(soundId.Path, volume, pitch);
}
/// <summary> /// <summary>
/// 将线性音量值转换为分贝值 /// 将线性音量值转换为分贝值
/// </summary> /// </summary>
@ -539,16 +533,10 @@ public abstract class AbstractAudioManagerSystem : AbstractSystem, IAudioManager
MusicPlayer?.QueueFree(); MusicPlayer?.QueueFree();
// 清理音效播放器池 // 清理音效播放器池
foreach (var player in SoundPlayers) foreach (var player in SoundPlayers) player.QueueFree();
{
player.QueueFree();
}
// 清理3D音效播放器池 // 清理3D音效播放器池
foreach (var player in Sound3DPlayers) foreach (var player in Sound3DPlayers) player.QueueFree();
{
player.QueueFree();
}
SoundPlayers.Clear(); SoundPlayers.Clear();
AvailableSoundPlayers.Clear(); AvailableSoundPlayers.Clear();

View File

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

View File

@ -1,13 +1,13 @@
using System; 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 生成扩展方法。
/// </summary>
[AttributeUsage(AttributeTargets.Enum)]
public sealed class GenerateEnumExtensionsAttribute : Attribute
{
/// <summary> /// <summary>
/// 是否为每个枚举项生成单独的 IsXXX 方法(默认 true /// 是否为每个枚举项生成单独的 IsXXX 方法(默认 true
/// </summary> /// </summary>
@ -17,5 +17,4 @@ namespace GFramework.SourceGenerators.Attributes.enums
/// 是否生成一个 IsIn(params T[]) 方法以简化多值判断(默认 true /// 是否生成一个 IsIn(params T[]) 方法以简化多值判断(默认 true
/// </summary> /// </summary>
public bool GenerateIsInMethod { get; set; } = true; public bool GenerateIsInMethod { get; set; } = true;
}
} }

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

@ -160,7 +160,7 @@ public sealed class LoggerGenerator : IIncrementalGenerator
sb.AppendLine($" public partial class {className}"); sb.AppendLine($" public partial class {className}");
sb.AppendLine(" {"); sb.AppendLine(" {");
sb.AppendLine($" /// <summary>Auto-generated logger</summary>"); sb.AppendLine(" /// <summary>Auto-generated logger</summary>");
sb.AppendLine( sb.AppendLine(
$" {access} {staticKeyword}readonly ILogger {fieldName} = " + $" {access} {staticKeyword}readonly ILogger {fieldName} = " +
$"new ConsoleLoggerFactory().GetLogger(\"{name}\");"); $"new ConsoleLoggerFactory().GetLogger(\"{name}\");");

View File

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