mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 10:34:30 +08:00
docs(sidebar): 更新侧边栏导航结构并移除API参考页面
- 调整Core模块导航链接结构,从overview页面改为根路径 - 重构Core模块侧边栏,将原有的6个主要类别扩展为15个详细分类 - 精简Game模块侧边栏,保留场景管理和游戏设置两个主要功能 - 更新Godot集成模块侧边栏,新增协程、信号、存储等功能分类 - 修改源码生成器模块命名,将枚举扩展重命名为枚举生成器 - 新增抽象接口侧边栏,包含Core和Game抽象接口文档 - 调整教程模块顺序,新增入门教程和Godot集成教程分类 - 移除独立的API参考导航项,将其整合到相应模块中 - 修正生成器API文档链接路径错误问题
This commit is contained in:
parent
bc89ff07a1
commit
317eddca9b
@ -41,12 +41,11 @@ export default defineConfig({
|
|||||||
nav: [
|
nav: [
|
||||||
{ text: '首页', link: '/zh-CN/' },
|
{ text: '首页', link: '/zh-CN/' },
|
||||||
{ text: '入门指南', link: '/zh-CN/getting-started/installation' },
|
{ text: '入门指南', link: '/zh-CN/getting-started/installation' },
|
||||||
{ text: 'Core', link: '/zh-CN/core/overview' },
|
{ text: 'Core', link: '/zh-CN/core/' },
|
||||||
{ text: 'Game', link: '/zh-CN/game/overview' },
|
{ text: 'Game', link: '/zh-CN/game/overview' },
|
||||||
{ text: 'Godot', link: '/zh-CN/godot/overview' },
|
{ text: 'Godot', link: '/zh-CN/godot/overview' },
|
||||||
{ text: '源码生成器', link: '/zh-CN/source-generators/overview' },
|
{ text: '源码生成器', link: '/zh-CN/source-generators/overview' },
|
||||||
{ text: '教程', link: '/zh-CN/tutorials/basic-tutorial' },
|
{ text: '教程', link: '/zh-CN/tutorials/basic-tutorial' },
|
||||||
{ text: 'API参考', link: '/zh-CN/api-reference/core-api' }
|
|
||||||
],
|
],
|
||||||
|
|
||||||
sidebar: {
|
sidebar: {
|
||||||
@ -65,12 +64,22 @@ export default defineConfig({
|
|||||||
{
|
{
|
||||||
text: 'Core 核心框架',
|
text: 'Core 核心框架',
|
||||||
items: [
|
items: [
|
||||||
{ text: '概览', link: '/zh-CN/core/overview' },
|
{ text: '概览', link: '/zh-CN/core/' },
|
||||||
{ text: '架构组件', link: '/zh-CN/core/architecture/architecture' },
|
{ text: '架构组件', link: '/zh-CN/core/architecture' },
|
||||||
{ text: '命令查询系统', link: '/zh-CN/core/command-query/commands' },
|
{ text: '命令系统', link: '/zh-CN/core/command' },
|
||||||
{ text: '事件系统', link: '/zh-CN/core/events/event-bus' },
|
{ text: '查询系统', link: '/zh-CN/core/query' },
|
||||||
{ text: '属性系统', link: '/zh-CN/core/property/bindable-property' },
|
{ text: '事件系统', link: '/zh-CN/core/events' },
|
||||||
{ text: '工具类', link: '/zh-CN/core/utilities/ioc-container' }
|
{ text: '属性系统', link: '/zh-CN/core/property' },
|
||||||
|
{ text: 'IoC容器', link: '/zh-CN/core/ioc' },
|
||||||
|
{ text: '对象池', link: '/zh-CN/core/pool' },
|
||||||
|
{ text: '日志系统', link: '/zh-CN/core/logging' },
|
||||||
|
{ text: '扩展方法', link: '/zh-CN/core/extensions' },
|
||||||
|
{ text: '工具类', link: '/zh-CN/core/utility' },
|
||||||
|
{ text: '模型层', link: '/zh-CN/core/model' },
|
||||||
|
{ text: '系统层', link: '/zh-CN/core/system' },
|
||||||
|
{ text: '控制器', link: '/zh-CN/core/controller' },
|
||||||
|
{ text: '规则系统', link: '/zh-CN/core/rule' },
|
||||||
|
{ text: '环境接口', link: '/zh-CN/core/environment' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -80,10 +89,8 @@ export default defineConfig({
|
|||||||
text: 'Game 游戏模块',
|
text: 'Game 游戏模块',
|
||||||
items: [
|
items: [
|
||||||
{ text: '概览', link: '/zh-CN/game/overview' },
|
{ text: '概览', link: '/zh-CN/game/overview' },
|
||||||
{ text: '模块系统', link: '/zh-CN/game/modules/architecture-modules' },
|
{ text: '场景管理', link: '/zh-CN/game/scene-management' },
|
||||||
{ text: '存储系统', link: '/zh-CN/game/storage/scoped-storage' },
|
{ text: '游戏设置', link: '/zh-CN/game/setting' }
|
||||||
{ text: '资源管理', link: '/zh-CN/game/assets/asset-catalog' },
|
|
||||||
{ text: '序列化', link: '/zh-CN/game/serialization/json-serializer' }
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -93,10 +100,11 @@ export default defineConfig({
|
|||||||
text: 'Godot 集成',
|
text: 'Godot 集成',
|
||||||
items: [
|
items: [
|
||||||
{ text: '概览', link: '/zh-CN/godot/overview' },
|
{ text: '概览', link: '/zh-CN/godot/overview' },
|
||||||
{ text: '集成指南', link: '/zh-CN/godot/integration/architecture-integration' },
|
{ text: '协程系统', link: '/zh-CN/godot/coroutine' },
|
||||||
{ text: '节点扩展', link: '/zh-CN/godot/node-extensions/node-extensions' },
|
{ text: '节点扩展', link: '/zh-CN/godot/extensions' },
|
||||||
{ text: '对象池', link: '/zh-CN/godot/pooling/node-pool' },
|
{ text: '信号系统', link: '/zh-CN/godot/signal' },
|
||||||
{ text: '日志系统', link: '/zh-CN/godot/logging/godot-logger' }
|
{ text: '存储系统', link: '/zh-CN/godot/storage' },
|
||||||
|
{ text: '设置系统', link: '/zh-CN/godot/setting' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -105,21 +113,32 @@ export default defineConfig({
|
|||||||
{
|
{
|
||||||
text: '源码生成器',
|
text: '源码生成器',
|
||||||
items: [
|
items: [
|
||||||
{ text: '概览', link: '/zh-CN/source-generators/overview' },
|
{ text: '概览', link: '/zh-CN/source-generators/' },
|
||||||
{ text: '日志生成器', link: '/zh-CN/source-generators/logging-generator' },
|
{ text: '日志生成器', link: '/zh-CN/source-generators/logging-generator' },
|
||||||
{ text: '枚举扩展', link: '/zh-CN/source-generators/enum-extensions' },
|
{ text: '枚举扩展', link: '/zh-CN/source-generators/enum-generator' },
|
||||||
{ text: '规则生成器', link: '/zh-CN/source-generators/rule-generator' }
|
{ text: '规则生成器', link: '/zh-CN/source-generators/rule-generator' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'/zh-CN/abstractions/': [
|
||||||
|
{
|
||||||
|
text: '抽象接口',
|
||||||
|
items: [
|
||||||
|
{ text: 'Core Abstractions', link: '/zh-CN/abstractions/core-abstractions' },
|
||||||
|
{ text: 'Game Abstractions', link: '/zh-CN/abstractions/game-abstractions' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
'/zh-CN/tutorials/': [
|
'/zh-CN/tutorials/': [
|
||||||
{
|
{
|
||||||
text: '教程',
|
text: '教程',
|
||||||
items: [
|
items: [
|
||||||
|
{ text: '入门教程', link: '/zh-CN/tutorials/getting-started' },
|
||||||
{ text: '基础教程', link: '/zh-CN/tutorials/basic-tutorial' },
|
{ text: '基础教程', link: '/zh-CN/tutorials/basic-tutorial' },
|
||||||
{ text: '高级模式', link: '/zh-CN/tutorials/advanced-patterns' },
|
{ text: 'Godot集成', link: '/zh-CN/tutorials/godot-integration' },
|
||||||
{ text: '最佳实践', link: '/zh-CN/tutorials/best-practices' }
|
{ text: '高级模式', link: '/zh-CN/tutorials/advanced-patterns' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -131,7 +150,7 @@ export default defineConfig({
|
|||||||
{ text: 'Core API', link: '/zh-CN/api-reference/core-api' },
|
{ text: 'Core API', link: '/zh-CN/api-reference/core-api' },
|
||||||
{ text: 'Game API', link: '/zh-CN/api-reference/game-api' },
|
{ text: 'Game API', link: '/zh-CN/api-reference/game-api' },
|
||||||
{ text: 'Godot API', link: '/zh-CN/api-reference/godot-api' },
|
{ text: 'Godot API', link: '/zh-CN/api-reference/godot-api' },
|
||||||
{ text: '生成器 API', link: '/zh-CN/api-reference/generators-api' }
|
{ text: '生成器 API', link: '/zh-CN/api-reference/source-generators-api' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
192
docs/zh-CN/abstractions/core-abstractions.md
Normal file
192
docs/zh-CN/abstractions/core-abstractions.md
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
# Core Abstractions
|
||||||
|
|
||||||
|
> GFramework.Core.Abstractions 核心抽象接口定义
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
GFramework.Core.Abstractions 包含了框架的所有核心接口定义,这些接口定义了组件之间的契约,实现了依赖倒置和面向接口编程。
|
||||||
|
|
||||||
|
## 核心接口
|
||||||
|
|
||||||
|
### IArchitecture
|
||||||
|
|
||||||
|
应用程序架构接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IArchitecture
|
||||||
|
{
|
||||||
|
void Initialize();
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
|
T GetModel<T>() where T : IModel;
|
||||||
|
T GetSystem<T>() where T : ISystem;
|
||||||
|
T GetUtility<T>() where T : IUtility;
|
||||||
|
|
||||||
|
void RegisterModel(IModel model);
|
||||||
|
void RegisterSystem(ISystem system);
|
||||||
|
void RegisterUtility(IUtility utility);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### IModel
|
||||||
|
|
||||||
|
数据模型接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IModel
|
||||||
|
{
|
||||||
|
void Init();
|
||||||
|
void Dispose();
|
||||||
|
|
||||||
|
IArchitecture Architecture { get; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ISystem
|
||||||
|
|
||||||
|
业务逻辑系统接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface ISystem
|
||||||
|
{
|
||||||
|
void Init();
|
||||||
|
void Dispose();
|
||||||
|
|
||||||
|
IArchitecture Architecture { get; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### IController
|
||||||
|
|
||||||
|
控制器接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IController : IBelongToArchitecture
|
||||||
|
{
|
||||||
|
void Init();
|
||||||
|
void Dispose();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### IUtility
|
||||||
|
|
||||||
|
工具类接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IUtility
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 事件接口
|
||||||
|
|
||||||
|
### IEvent
|
||||||
|
|
||||||
|
事件基接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### IEventHandler
|
||||||
|
|
||||||
|
事件处理器接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IEventHandler<TEvent> where TEvent : IEvent
|
||||||
|
{
|
||||||
|
void Handle(TEvent event);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 命令查询接口
|
||||||
|
|
||||||
|
### ICommand
|
||||||
|
|
||||||
|
命令接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface ICommand
|
||||||
|
{
|
||||||
|
void Execute();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### IQuery
|
||||||
|
|
||||||
|
查询接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IQuery<TResult>
|
||||||
|
{
|
||||||
|
TResult Execute();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 依赖注入接口
|
||||||
|
|
||||||
|
### IIocContainer
|
||||||
|
|
||||||
|
IOC 容器接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IIocContainer
|
||||||
|
{
|
||||||
|
void Register<TInterface, TImplementation>() where TImplementation : TInterface;
|
||||||
|
void Register<TInterface>(TInterface instance);
|
||||||
|
TInterface Resolve<TInterface>();
|
||||||
|
bool IsRegistered<TInterface>();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 生命周期接口
|
||||||
|
|
||||||
|
### ILifecycle
|
||||||
|
|
||||||
|
组件生命周期接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface ILifecycle
|
||||||
|
{
|
||||||
|
void OnInit();
|
||||||
|
void OnDestroy();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
### 通过接口实现依赖注入
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class MyService : IMyService
|
||||||
|
{
|
||||||
|
private readonly IArchitecture _architecture;
|
||||||
|
|
||||||
|
public MyService(IArchitecture architecture)
|
||||||
|
{
|
||||||
|
_architecture = architecture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 自定义事件
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class PlayerDiedEvent : IEvent
|
||||||
|
{
|
||||||
|
public int PlayerId { get; set; }
|
||||||
|
public Vector2 Position { get; set; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**相关文档**:
|
||||||
|
|
||||||
|
- [Core 概述](../core)
|
||||||
|
- [Architecture](../core/architecture)
|
||||||
|
- [Events](../core/events)
|
||||||
|
- [Command](../core/command)
|
||||||
|
- [Query](../core/query)
|
||||||
113
docs/zh-CN/abstractions/game-abstractions.md
Normal file
113
docs/zh-CN/abstractions/game-abstractions.md
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
# Game Abstractions
|
||||||
|
|
||||||
|
> GFramework.Game.Abstractions 游戏模块抽象接口定义
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
GFramework.Game.Abstractions 包含了游戏特定功能的抽象接口,这些接口定义了游戏开发中的通用契约。
|
||||||
|
|
||||||
|
## 存档接口
|
||||||
|
|
||||||
|
### ISaveSystem
|
||||||
|
|
||||||
|
存档系统接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface ISaveSystem
|
||||||
|
{
|
||||||
|
void Save(string slotId, SaveData data);
|
||||||
|
SaveData Load(string slotId);
|
||||||
|
bool HasSave(string slotId);
|
||||||
|
void Delete(string slotId);
|
||||||
|
List<SaveSlotInfo> GetAllSaveSlots();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ISaveData
|
||||||
|
|
||||||
|
存档数据接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface ISaveData
|
||||||
|
{
|
||||||
|
int Version { get; }
|
||||||
|
DateTime Timestamp { get; }
|
||||||
|
void Validate();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 设置接口
|
||||||
|
|
||||||
|
### IGameSettings
|
||||||
|
|
||||||
|
游戏设置接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IGameSettings
|
||||||
|
{
|
||||||
|
AudioSettings Audio { get; }
|
||||||
|
GraphicsSettings Graphics { get; }
|
||||||
|
InputSettings Input { get; }
|
||||||
|
|
||||||
|
void Save();
|
||||||
|
void Load();
|
||||||
|
void ResetToDefaults();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 场景管理接口
|
||||||
|
|
||||||
|
### ISceneManager
|
||||||
|
|
||||||
|
场景管理器接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface ISceneManager
|
||||||
|
{
|
||||||
|
void SwitchScene<TScene>() where TScene : IScene;
|
||||||
|
Task SwitchSceneAsync<TScene>() where TScnee : IScene;
|
||||||
|
|
||||||
|
void PushScene<TScene>() where TScene : IScene;
|
||||||
|
void PopScene();
|
||||||
|
|
||||||
|
IScene CurrentScene { get; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### IScene
|
||||||
|
|
||||||
|
场景接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IScene
|
||||||
|
{
|
||||||
|
void OnEnter();
|
||||||
|
void OnExit();
|
||||||
|
void OnUpdate(float delta);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 资源管理接口
|
||||||
|
|
||||||
|
### IAssetManager
|
||||||
|
|
||||||
|
资源管理器接口:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public interface IAssetManager
|
||||||
|
{
|
||||||
|
T Load<T>(string path) where T : Resource;
|
||||||
|
void Preload<T>(string path) where T : Resource;
|
||||||
|
void Unload(string path);
|
||||||
|
bool IsLoaded(string path);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**相关文档**:
|
||||||
|
|
||||||
|
- [Game 概述](../game)
|
||||||
|
- [Core Abstractions](./core-abstractions)
|
||||||
|
- [存档系统](../game/storage)
|
||||||
|
- [场景管理](../game/scene-management)
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,834 +0,0 @@
|
|||||||
# GFramework.Game API 参考
|
|
||||||
|
|
||||||
> GFramework.Game 模块的完整 API 参考文档,包含游戏特定功能的详细说明。
|
|
||||||
|
|
||||||
## 📋 目录
|
|
||||||
|
|
||||||
- [架构模块](#架构模块)
|
|
||||||
- [资产管理系统](#资产管理系统)
|
|
||||||
- [存储系统](#存储系统)
|
|
||||||
- [序列化系统](#序列化系统)
|
|
||||||
- [数据模型](#数据模型)
|
|
||||||
- [工具类](#工具类)
|
|
||||||
|
|
||||||
## 架构模块
|
|
||||||
|
|
||||||
### IArchitectureModule
|
|
||||||
|
|
||||||
架构模块接口,定义了模块的基本行为。
|
|
||||||
|
|
||||||
#### 方法签名
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
void Install(IArchitecture architecture);
|
|
||||||
void OnAttach(Architecture architecture);
|
|
||||||
void OnDetach(Architecture architecture);
|
|
||||||
void OnPhase(ArchitecturePhase phase, IArchitecture architecture);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class AudioModule : IArchitectureModule
|
|
||||||
{
|
|
||||||
public void Install(IArchitecture architecture)
|
|
||||||
{
|
|
||||||
architecture.RegisterSystem(new AudioSystem());
|
|
||||||
architecture.RegisterUtility(new AudioUtility());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnAttach(Architecture architecture)
|
|
||||||
{
|
|
||||||
Logger.Info("Audio module attached to architecture");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnDetach(Architecture architecture)
|
|
||||||
{
|
|
||||||
Logger.Info("Audio module detached from architecture");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
|
|
||||||
{
|
|
||||||
switch (phase)
|
|
||||||
{
|
|
||||||
case ArchitecturePhase.Ready:
|
|
||||||
// 架构准备就绪,可以开始播放背景音乐
|
|
||||||
PlayBackgroundMusic();
|
|
||||||
break;
|
|
||||||
case ArchitecturePhase.Destroying:
|
|
||||||
// 架构正在销毁,清理音频资源
|
|
||||||
CleanupAudioResources();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### AbstractModule
|
|
||||||
|
|
||||||
抽象模块基类,实现了 IArchitectureModule 接口。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public AbstractModule();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 可用方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 发送事件
|
|
||||||
protected void SendEvent<T>(T e) where T : new();
|
|
||||||
protected void SendEvent<T>(T e);
|
|
||||||
|
|
||||||
// 获取模型
|
|
||||||
protected T GetModel<T>() where T : class, IModel;
|
|
||||||
protected T GetSystem<T>() where T : class, ISystem;
|
|
||||||
protected T GetUtility<T>() where T : class, IUtility;
|
|
||||||
|
|
||||||
// 发送命令
|
|
||||||
protected void SendCommand(ICommand command);
|
|
||||||
protected TResult SendCommand<TResult>(ICommand<TResult> command);
|
|
||||||
|
|
||||||
// 发送查询
|
|
||||||
protected TResult SendQuery<TResult>(IQuery<TResult> query);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class SaveModule : AbstractModule
|
|
||||||
{
|
|
||||||
private Timer _autoSaveTimer;
|
|
||||||
|
|
||||||
public override void Install(IArchitecture architecture)
|
|
||||||
{
|
|
||||||
architecture.RegisterSystem(new SaveSystem());
|
|
||||||
architecture.RegisterUtility(new SaveUtility());
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnAttach(Architecture architecture)
|
|
||||||
{
|
|
||||||
// 创建自动保存计时器
|
|
||||||
_autoSaveTimer = new Timer();
|
|
||||||
_autoSaveTimer.WaitTime = 300; // 5分钟
|
|
||||||
_autoSaveTimer.Timeout += OnAutoSave;
|
|
||||||
// 这里无法使用 AddChild,因为不是 Node
|
|
||||||
// 在具体的模块实现中处理
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnDetach(Architecture architecture)
|
|
||||||
{
|
|
||||||
_autoSaveTimer?.Stop();
|
|
||||||
_autoSaveTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
|
|
||||||
{
|
|
||||||
switch (phase)
|
|
||||||
{
|
|
||||||
case ArchitecturePhase.Ready:
|
|
||||||
Logger.Info("Save module ready");
|
|
||||||
break;
|
|
||||||
case ArchitecturePhase.Destroying:
|
|
||||||
Logger.Info("Save module destroying");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAutoSave()
|
|
||||||
{
|
|
||||||
var saveSystem = GetSystem<SaveSystem>();
|
|
||||||
saveSystem.SaveAutoSave();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 资产管理系统
|
|
||||||
|
|
||||||
### IAssetCatalogUtility
|
|
||||||
|
|
||||||
资产目录工具接口,定义了资产管理的基本行为。
|
|
||||||
|
|
||||||
#### 方法签名
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 场景资产注册
|
|
||||||
void RegisterSceneUnit(string key, string scenePath);
|
|
||||||
void RegisterScenePage(string key, string scenePath);
|
|
||||||
void RegisterAsset<T>(string key, string path) where T : Resource;
|
|
||||||
void RegisterAsset(string key, Type type, string path);
|
|
||||||
|
|
||||||
// 映射资产注册
|
|
||||||
void RegisterSceneUnit(string key, AssetMapping mapping);
|
|
||||||
void RegisterScenePage(string key, AssetMapping mapping);
|
|
||||||
void RegisterAsset(string key, AssetMapping mapping);
|
|
||||||
|
|
||||||
// 查询方法
|
|
||||||
bool HasSceneUnit(string key);
|
|
||||||
bool HasScenePage(string key);
|
|
||||||
bool HasAsset<T>(string key);
|
|
||||||
bool HasAsset(string key, Type type);
|
|
||||||
|
|
||||||
// 获取方法
|
|
||||||
T GetScene<T>(string key) where T : PackedScene;
|
|
||||||
T GetScenePage<T>(string key) where T : PackedScene;
|
|
||||||
T GetAsset<T>(string key) where T : Resource;
|
|
||||||
T GetAsset(string key, Type type);
|
|
||||||
|
|
||||||
// 元数据获取
|
|
||||||
AssetCatalogMapping GetAssetMetadata(string key);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### AssetCatalogMapping
|
|
||||||
|
|
||||||
资产映射数据类。
|
|
||||||
|
|
||||||
#### 属性
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public string Key { get; set; }
|
|
||||||
public string Path { get; set; }
|
|
||||||
public Type Type { get; set; }
|
|
||||||
public Dictionary<string, object> Metadata { get; set; }
|
|
||||||
public DateTime RegisteredAt { get; set; }
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class GameAssetCatalog : AbstractAssetCatalogUtility
|
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
// 注册场景资产
|
|
||||||
RegisterSceneUnit("Player", "res://scenes/Player.tscn");
|
|
||||||
RegisterSceneUnit("Enemy", "res://scenes/Enemy.tscn");
|
|
||||||
RegisterScenePage("MainMenu", "res://ui/MainMenu.tscn");
|
|
||||||
RegisterScenePage("GameUI", "res://ui/GameUI.tscn");
|
|
||||||
|
|
||||||
// 注册通用资产
|
|
||||||
RegisterAsset<Texture2D>("PlayerTexture", "res://textures/player.png");
|
|
||||||
RegisterAsset<Texture2D>("EnemyTexture", "res://textures/enemy.png");
|
|
||||||
RegisterAsset<AudioStream>("ShootSound", "res://audio/shoot.wav");
|
|
||||||
RegisterAsset<AudioStream>("ExplosionSound", "res://audio/explosion.wav");
|
|
||||||
|
|
||||||
// 使用元数据注册
|
|
||||||
var playerMapping = new AssetMapping
|
|
||||||
{
|
|
||||||
Key = "Player",
|
|
||||||
Path = "res://scenes/Player.tscn",
|
|
||||||
Type = typeof(PackedScene),
|
|
||||||
Metadata = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["category"] = "character",
|
|
||||||
["tags"] = new[] { "player", "hero", "controlled" },
|
|
||||||
["health"] = 100,
|
|
||||||
["speed"] = 5.0f
|
|
||||||
}
|
|
||||||
};
|
|
||||||
RegisterSceneUnit("Player", playerMapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool ValidateAsset(string key, string path)
|
|
||||||
{
|
|
||||||
if (!FileAccess.FileExists(path))
|
|
||||||
{
|
|
||||||
GD.PrintErr($"Asset file not found: {path}");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(key))
|
|
||||||
{
|
|
||||||
GD.PrintErr("Asset key cannot be empty");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnAssetLoaded(string key, object asset)
|
|
||||||
{
|
|
||||||
GD.Print($"Asset loaded: {key} of type {asset.GetType().Name}");
|
|
||||||
|
|
||||||
// 对特定资产进行额外处理
|
|
||||||
if (key == "Player" && asset is PackedScene playerScene)
|
|
||||||
{
|
|
||||||
PreloadPlayerComponents(playerScene);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PreloadPlayerComponents(PackedScene playerScene)
|
|
||||||
{
|
|
||||||
// 预加载玩家组件到内存
|
|
||||||
playerScene.Instantiate(); // 实例化以加载子节点
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取资产
|
|
||||||
public PackedScene GetPlayerScene() => GetScene<PackedScene>("Player");
|
|
||||||
public PackedScene GetEnemyScene() => GetScene<PackedScene>("Enemy");
|
|
||||||
public Texture2D GetPlayerTexture() => GetAsset<Texture2D>("PlayerTexture");
|
|
||||||
public AudioStream GetShootSound() => GetAsset<AudioStream>("ShootSound");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### AbstractResourceFactoryUtility
|
|
||||||
|
|
||||||
抽象资源工厂工具基类。
|
|
||||||
|
|
||||||
#### 抽象方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
protected abstract void RegisterFactories();
|
|
||||||
protected abstract T CreateFactory<T>(string path, Dictionary<string, object> metadata = null) where T : class;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class GameResourceFactory : AbstractResourceFactoryUtility
|
|
||||||
{
|
|
||||||
protected override void RegisterFactories()
|
|
||||||
{
|
|
||||||
RegisterFactory<PlayerData>("res://data/players/{id}.json");
|
|
||||||
RegisterFactory<WeaponConfig>("res://data/weapons/{id}.json");
|
|
||||||
RegisterFactory<LevelData>("res://data/levels/{id}.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayerData CreatePlayer(string playerId)
|
|
||||||
{
|
|
||||||
var playerPath = $"res://data/players/{playerId}.json";
|
|
||||||
return CreateFactory<PlayerData>(playerPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public WeaponConfig CreateWeapon(string weaponId)
|
|
||||||
{
|
|
||||||
var metadata = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["weaponId"] = weaponId,
|
|
||||||
["loadTime"] = DateTime.Now
|
|
||||||
};
|
|
||||||
|
|
||||||
return CreateFactory<WeaponConfig>($"res://data/weapons/{weaponId}.json", metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LevelData CreateLevel(string levelId)
|
|
||||||
{
|
|
||||||
return CreateFactory<LevelData>($"res://data/levels/{levelId}.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override PlayerData CreateFactory<PlayerData>(string path, Dictionary<string, object> metadata)
|
|
||||||
{
|
|
||||||
if (!FileAccess.FileExists(path))
|
|
||||||
{
|
|
||||||
return new PlayerData(); // 返回默认数据
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var json = FileAccess.Open(path, FileAccess.ModeFlags.Read).GetAsText();
|
|
||||||
var data = JsonConvert.DeserializeObject<PlayerData>(json);
|
|
||||||
|
|
||||||
// 如果有元数据,可以用来修改数据
|
|
||||||
if (metadata != null)
|
|
||||||
{
|
|
||||||
data.LastLoadedAt = metadata.GetValueOrDefault("loadTime", DateTime.Now);
|
|
||||||
data.LoadCount = metadata.GetValueOrDefault("loadCount", 0) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
GD.PrintErr($"Failed to load player data from {path}: {ex.Message}");
|
|
||||||
return new PlayerData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 存储系统
|
|
||||||
|
|
||||||
### IStorage
|
|
||||||
|
|
||||||
存储接口,定义了数据持久化的基本行为。
|
|
||||||
|
|
||||||
#### 方法签名
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 读写操作
|
|
||||||
void Write<T>(string key, T data);
|
|
||||||
T Read<T>(string key, T defaultValue = default);
|
|
||||||
Task WriteAsync<T>(string key, T data);
|
|
||||||
Task<T> ReadAsync<T>(string key, T defaultValue = default);
|
|
||||||
|
|
||||||
// 存在检查
|
|
||||||
bool Has(string key);
|
|
||||||
void Delete(string key);
|
|
||||||
void Clear();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### IScopedStorage
|
|
||||||
|
|
||||||
作用域存储接口,支持命名空间隔离。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public ScopedStorage(IStorage storage, string scope, string delimiter = ".");
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 创建根存储
|
|
||||||
var rootStorage = new FileStorage("user://data/");
|
|
||||||
|
|
||||||
// 创建分层存储
|
|
||||||
var playerStorage = new ScopedStorage(rootStorage, "player");
|
|
||||||
var saveStorage = new ScopedStorage(rootStorage, "saves");
|
|
||||||
var settingsStorage = new ScopedStorage(rootStorage, "settings");
|
|
||||||
|
|
||||||
// 使用分层存储
|
|
||||||
playerStorage.Write("profile", playerProfile);
|
|
||||||
playerStorage.Write("inventory", inventory);
|
|
||||||
playerStorage.Write("stats", playerStats);
|
|
||||||
|
|
||||||
saveStorage.Write("slot_1", saveData);
|
|
||||||
saveStorage.Write("slot_2", saveData);
|
|
||||||
|
|
||||||
settingsStorage.Write("graphics", graphicsSettings);
|
|
||||||
settingsStorage.Write("audio", audioSettings);
|
|
||||||
|
|
||||||
// 读取数据
|
|
||||||
var profile = playerStorage.Read<PlayerProfile>("profile", new PlayerProfile());
|
|
||||||
var inventory = playerStorage.Read<Inventory>("inventory", new Inventory());
|
|
||||||
|
|
||||||
// 使用完整路径
|
|
||||||
playerStorage.Write("savegames/auto", autoSaveData); // 写入 player/savegames/auto.json
|
|
||||||
```
|
|
||||||
|
|
||||||
### FileStorage
|
|
||||||
|
|
||||||
文件存储实现,基于 Godot 的 FileAccess。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public FileStorage(string rootPath, bool createDirectoryIfNotExists = true);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 创建文件存储
|
|
||||||
var storage = new FileStorage("user://saves");
|
|
||||||
|
|
||||||
// 基础用法
|
|
||||||
storage.Write("player", playerData);
|
|
||||||
var loadedPlayer = storage.Read<Player>("player", new Player());
|
|
||||||
|
|
||||||
// 异步用法
|
|
||||||
await storage.WriteAsync("player", playerData);
|
|
||||||
var loadedPlayer = await storage.ReadAsync<Player>("player");
|
|
||||||
|
|
||||||
// 检查存在性
|
|
||||||
bool hasPlayerData = storage.Has("player");
|
|
||||||
storage.Delete("old_save");
|
|
||||||
storage.Clear();
|
|
||||||
```
|
|
||||||
|
|
||||||
### JsonStorage
|
|
||||||
|
|
||||||
JSON 存储实现,使用 Newtonsoft.Json 进行序列化。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public JsonStorage(IFileStorage fileStorage, JsonSerializerSettings settings = null);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
var fileStorage = new FileStorage("user://saves");
|
|
||||||
var settings = new JsonSerializerSettings
|
|
||||||
{
|
|
||||||
Formatting = Formatting.Indented,
|
|
||||||
NullValueHandling = NullValueHandling.Ignore,
|
|
||||||
DefaultValueHandling = DefaultValueHandling.Populate
|
|
||||||
};
|
|
||||||
|
|
||||||
var storage = new JsonStorage(fileStorage, settings);
|
|
||||||
|
|
||||||
// 自定义序列化
|
|
||||||
storage.Write("player", playerData, customSerializer);
|
|
||||||
|
|
||||||
// 压缩缩存储
|
|
||||||
storage.Write("player", playerData, serializer: new JsonSerializer
|
|
||||||
{
|
|
||||||
Formatting = Formatting.None
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### CachedStorage
|
|
||||||
|
|
||||||
缓存存储实现,提高频繁访问的性能。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public CachedStorage(IStorage innerStorage, TimeSpan cacheExpiry = default);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
var fileStorage = new FileStorage("user://saves");
|
|
||||||
var cachedStorage = new CachedStorage(fileStorage, TimeSpan.FromMinutes(5));
|
|
||||||
|
|
||||||
// 第一次读取会从存储加载
|
|
||||||
var player1 = cachedStorage.Read<Player>("player");
|
|
||||||
|
|
||||||
// 第二次读取会从缓存返回(如果未过期)
|
|
||||||
var player2 = cachedStorage.Read<Player>("player");
|
|
||||||
|
|
||||||
// 手动清除缓存
|
|
||||||
cachedStorage.ClearCache();
|
|
||||||
|
|
||||||
// 检查缓存状态
|
|
||||||
var playerInCache = cachedStorage.IsCached("player");
|
|
||||||
```
|
|
||||||
|
|
||||||
## 序列化系统
|
|
||||||
|
|
||||||
### JsonSerializer
|
|
||||||
|
|
||||||
JSON 序列化工具类,基于 Newtonsoft.Json。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public JsonSerializer(JsonSerializerSettings settings = null);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 基础序列化
|
|
||||||
public string Serialize<T>(T data);
|
|
||||||
public void SerializeToFile<T>(string path, T data);
|
|
||||||
|
|
||||||
// 反序列化
|
|
||||||
public T Deserialize<T>(string json);
|
|
||||||
public T DeserializeFromFile<T>(string path, T defaultValue = default);
|
|
||||||
|
|
||||||
// 异步序列化
|
|
||||||
public Task<string> SerializeAsync<T>(T data);
|
|
||||||
public Task<T> DeserializeAsync<T>(string json, T defaultValue = default);
|
|
||||||
|
|
||||||
// 压缩序列化
|
|
||||||
public string SerializeCompressed<T>(T data);
|
|
||||||
public T DeserializeCompressed<T>(string compressedJson);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
var serializer = new JsonSerializer();
|
|
||||||
|
|
||||||
// 基础序列化
|
|
||||||
var json = serializer.Serialize(playerData);
|
|
||||||
var loadedPlayer = serializer.Deserialize<Player>(json);
|
|
||||||
|
|
||||||
// 文件操作
|
|
||||||
serializer.SerializeToFile("player.json", playerData);
|
|
||||||
var loadedFromFile = serializer.DeserializeFromFile<Player>("player.json");
|
|
||||||
|
|
||||||
// 异步操作
|
|
||||||
var json = await serializer.SerializeAsync(playerData);
|
|
||||||
var loadedAsync = await serializer.DeserializeAsync<Player>(json);
|
|
||||||
|
|
||||||
// 压缩操作
|
|
||||||
var compressed = serializer.SerializeCompressed(playerData);
|
|
||||||
var decompressed = serializer.DeserializeCompressed<Player>(compressed);
|
|
||||||
```
|
|
||||||
|
|
||||||
### ISerializable
|
|
||||||
|
|
||||||
可序列化接口。
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class PlayerData : ISerializable
|
|
||||||
{
|
|
||||||
public string PlayerId { get; set; }
|
|
||||||
public int Level { get; set; }
|
|
||||||
public int Score { get; set; }
|
|
||||||
public Vector2 Position { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("last_saved_at")]
|
|
||||||
public DateTime LastSavedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("inventory_items")]
|
|
||||||
public List<InventoryItem> Inventory { get; set; }
|
|
||||||
|
|
||||||
// 自定义序列化方法
|
|
||||||
[OnSerializing]
|
|
||||||
public void OnSerializing()
|
|
||||||
{
|
|
||||||
// 序列化前的处理
|
|
||||||
LastSavedAt = DateTime.Now;
|
|
||||||
}
|
|
||||||
|
|
||||||
[OnDeserialized]
|
|
||||||
public void OnDeserialized()
|
|
||||||
{
|
|
||||||
// 反序列化后的处理
|
|
||||||
if (LastSavedAt == default)
|
|
||||||
{
|
|
||||||
LastSavedAt = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 数据模型
|
|
||||||
|
|
||||||
### SaveData
|
|
||||||
|
|
||||||
存档数据类。
|
|
||||||
|
|
||||||
#### 属性
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public string Version { get; set; } = "1.0.0";
|
|
||||||
public DateTime SavedAt { get; set; }
|
|
||||||
public Dictionary<string, object> PlayerData { get; set; } = new();
|
|
||||||
public Dictionary<string, object> GameData { get; set; } = new();
|
|
||||||
public Dictionary<string, object> SystemData { get; set; } = new();
|
|
||||||
public Dictionary<string, object> ModuleData { get; set; } = new();
|
|
||||||
public Dictionary<string, object> SettingsData { get; set; } = new();
|
|
||||||
```
|
|
||||||
|
|
||||||
### PlayerData
|
|
||||||
|
|
||||||
玩家数据类。
|
|
||||||
|
|
||||||
#### 属性
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[JsonProperty("player_id")]
|
|
||||||
public string PlayerId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("player_name")]
|
|
||||||
public string PlayerName { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("level")]
|
|
||||||
public int Level { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("experience")]
|
|
||||||
public long Experience { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("health")]
|
|
||||||
public int Health { get; set; }
|
|
||||||
public int MaxHealth { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("position")]
|
|
||||||
public Vector3 Position { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("inventory")]
|
|
||||||
public InventoryData Inventory { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("skills")]
|
|
||||||
public List<SkillData> Skills { get; set; }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### GameData
|
|
||||||
|
|
||||||
游戏数据类。
|
|
||||||
|
|
||||||
#### 属性
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[JsonProperty("current_level")]
|
|
||||||
public int CurrentLevel { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("high_score")]
|
|
||||||
public int HighScore { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("total_play_time")]
|
|
||||||
public float TotalPlayTime { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("enemies_defeated")]
|
|
||||||
public int EnemiesDefeated { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("achievements_unlocked")]
|
|
||||||
public List<string> AchievementsUnlocked { get; set; }
|
|
||||||
```
|
|
||||||
|
|
||||||
### InventoryData
|
|
||||||
|
|
||||||
背包数据类。
|
|
||||||
|
|
||||||
#### 属性
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[JsonProperty("slots")]
|
|
||||||
public List<InventorySlot> Slots { get; set; } = new();
|
|
||||||
|
|
||||||
[JsonProperty("equipment")]
|
|
||||||
public Dictionary<string, string> Equipment { get; set; } = new();
|
|
||||||
```
|
|
||||||
|
|
||||||
### InventorySlot
|
|
||||||
|
|
||||||
背包槽位类。
|
|
||||||
|
|
||||||
#### 属性
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[JsonProperty("item_id")]
|
|
||||||
public string ItemId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("quantity")]
|
|
||||||
public int Quantity { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("durability")]
|
|
||||||
public int Durability { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("metadata")]
|
|
||||||
public Dictionary<string, object> Metadata { get; set; } = new();
|
|
||||||
```
|
|
||||||
|
|
||||||
## 工具类
|
|
||||||
|
|
||||||
### StorageUtility
|
|
||||||
|
|
||||||
存储工具类,提供高级存储功能。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public StorageUtility(IStorage storage, IVersionMigrationManager migrationManager = null);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 自动保存
|
|
||||||
public void EnableAutoSave(IArchitecture architecture, float intervalMinutes = 5.0f);
|
|
||||||
public void DisableAutoSave();
|
|
||||||
|
|
||||||
// 存档管理
|
|
||||||
public void CreateSave(int slotId, SaveData data);
|
|
||||||
public SaveData LoadSave(int slotId);
|
|
||||||
public List<SaveSlotInfo> GetSaveSlots();
|
|
||||||
public void DeleteSave(int slotId);
|
|
||||||
|
|
||||||
// 数据迁移
|
|
||||||
public void RegisterMigration<T>(int fromVersion, int toVersion, Func<T, T> migrator);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[ContextAware]
|
|
||||||
[Log]
|
|
||||||
public partial class GameManager : Node, IController
|
|
||||||
{
|
|
||||||
private StorageUtility _storageUtility;
|
|
||||||
|
|
||||||
protected override void OnInit()
|
|
||||||
{
|
|
||||||
_storageUtility = Context.GetUtility<StorageUtility>();
|
|
||||||
|
|
||||||
// 注册数据迁移
|
|
||||||
_storageUtility.RegisterMigration<PlayerData>(1, 2, MigratePlayerDataV1ToV2);
|
|
||||||
_storageUtility.RegisterMigration<PlayerData>(2, 3, MigratePlayerDataV2ToV3);
|
|
||||||
|
|
||||||
// 启用自动保存
|
|
||||||
_storageUtility.EnableAutoSave(Context, 5.0f);
|
|
||||||
|
|
||||||
// 监听存档相关事件
|
|
||||||
this.RegisterEvent<SaveRequestEvent>(OnSaveRequest);
|
|
||||||
this.RegisterEvent<LoadRequestEvent>(OnLoadRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSaveRequest(SaveRequestEvent e)
|
|
||||||
{
|
|
||||||
var saveData = CreateSaveData();
|
|
||||||
_storageUtility.CreateSave(e.SlotId, saveData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnLoadRequest(LoadRequestEvent e)
|
|
||||||
{
|
|
||||||
var saveData = _storageUtility.LoadSave(e.SlotId);
|
|
||||||
if (saveData != null)
|
|
||||||
{
|
|
||||||
RestoreGameData(saveData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private SaveData CreateSaveData()
|
|
||||||
{
|
|
||||||
var playerModel = Context.GetModel<PlayerModel>();
|
|
||||||
var gameModel = Context.GetModel<GameModel>();
|
|
||||||
|
|
||||||
return new SaveData
|
|
||||||
{
|
|
||||||
Version = "1.0.0",
|
|
||||||
SavedAt = DateTime.Now,
|
|
||||||
PlayerData = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["player"] = playerModel.GetData(),
|
|
||||||
["statistics"] = playerModel.GetStatistics()
|
|
||||||
},
|
|
||||||
GameData = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["game"] = gameModel.GetData()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlayerData MigratePlayerDataV1ToV2(PlayerData v1Data)
|
|
||||||
{
|
|
||||||
return new PlayerData
|
|
||||||
{
|
|
||||||
PlayerId = v1Data.PlayerId,
|
|
||||||
PlayerName = v1Data.PlayerName,
|
|
||||||
Level = v1Data.Level,
|
|
||||||
Experience = v1Data.Experience,
|
|
||||||
Health = v1Data.Health,
|
|
||||||
MaxHealth = Math.Max(100, v1Data.MaxHealth), // V2 新增最大生命值
|
|
||||||
Position = v1Data.Position,
|
|
||||||
Inventory = v1Data.Inventory,
|
|
||||||
Skills = v1Data.Skills // V1 的 Kills 字段在 V2 中重命名为 Skills
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlayerData MigratePlayerDataV2ToV3(PlayerData v2Data)
|
|
||||||
{
|
|
||||||
return new PlayerData
|
|
||||||
{
|
|
||||||
PlayerId = v2Data.PlayerId,
|
|
||||||
PlayerName = Versioning.GetVersionString(v2Data.Version),
|
|
||||||
Level = v2Data.Level,
|
|
||||||
Experience = v2Data.Experience,
|
|
||||||
Health = v2Data.Health,
|
|
||||||
MaxHealth = v2Data.MaxHealth,
|
|
||||||
Position = v2Data.Position,
|
|
||||||
Inventory = v2Data.Inventory,
|
|
||||||
Skills = v2Data.Skills,
|
|
||||||
Achievements = v2Data.Achievements ?? new List<string>() // V3 新增成就系统
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**文档版本**: 1.0.0
|
|
||||||
**更新日期**: 2026-01-12
|
|
||||||
@ -1,951 +0,0 @@
|
|||||||
# GFramework.Godot API 参考
|
|
||||||
|
|
||||||
> GFramework.Godot 模块的完整 API 参考文档,包含 Godot 特定扩展和集成的详细说明。
|
|
||||||
|
|
||||||
## 📋 目录
|
|
||||||
|
|
||||||
- [架构集成](#架构集成)
|
|
||||||
- [Node 扩展方法](#node-扩展方法)
|
|
||||||
- [信号系统](#信号系统)
|
|
||||||
- [节点池化](#节点池化)
|
|
||||||
- [资源管理](#资源管理)
|
|
||||||
- [日志系统](#日志系统)
|
|
||||||
- [池化管理](#池化管理)
|
|
||||||
- [音频系统](#音频系统)
|
|
||||||
|
|
||||||
## 架构集成
|
|
||||||
|
|
||||||
### AbstractArchitecture
|
|
||||||
|
|
||||||
Godot 特定的架构基类,继承自 Core.Architecture。
|
|
||||||
|
|
||||||
#### 新增方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// Godot 模块安装
|
|
||||||
protected void InstallGodotModule(IGodotModule module);
|
|
||||||
|
|
||||||
protected void InstallGodotModule<T>() where T : IGodotModule, new();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class GameArchitecture : AbstractArchitecture
|
|
||||||
{
|
|
||||||
protected override void Init()
|
|
||||||
{
|
|
||||||
RegisterModel(new PlayerModel());
|
|
||||||
RegisterSystem(new CombatSystem());
|
|
||||||
RegisterUtility(new StorageUtility());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void InstallModules()
|
|
||||||
{
|
|
||||||
InstallGodotModule(new AudioModule());
|
|
||||||
InstallGodotModule(new InputModule());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### IGodotModule
|
|
||||||
|
|
||||||
Godot 模块接口,继承自 IArchitectureModule。
|
|
||||||
|
|
||||||
#### 属性
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
Node Node { get; }
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
void Install(IArchitecture architecture);
|
|
||||||
void OnAttach(Architecture architecture);
|
|
||||||
void OnDetach(Architecture architecture);
|
|
||||||
void OnPhase(ArchitecturePhase phase, IArchitecture architecture);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class AudioModule : AbstractGodotModule
|
|
||||||
{
|
|
||||||
// 模块节点本身
|
|
||||||
public override Node Node => this;
|
|
||||||
|
|
||||||
private AudioStreamPlayer _musicPlayer;
|
|
||||||
|
|
||||||
public override void Install(IArchitecture architecture)
|
|
||||||
{
|
|
||||||
// 注册音频系统
|
|
||||||
architecture.RegisterSystem(new AudioSystem());
|
|
||||||
architecture.RegisterUtility(new AudioUtility());
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnAttach(Architecture architecture)
|
|
||||||
{
|
|
||||||
// 创建音频播放器
|
|
||||||
_musicPlayer = new AudioStreamPlayer();
|
|
||||||
AddChild(_musicPlayer);
|
|
||||||
|
|
||||||
Logger.Info("Audio module attached");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnDetach(Architecture architecture)
|
|
||||||
{
|
|
||||||
// 清理音频播放器
|
|
||||||
_musicPlayer?.QueueFree();
|
|
||||||
|
|
||||||
Logger.Info("Audio module detached");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
|
|
||||||
{
|
|
||||||
switch (phase)
|
|
||||||
{
|
|
||||||
case ArchitecturePhase.Ready:
|
|
||||||
PlayBackgroundMusic();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PlayBackgroundMusic()
|
|
||||||
{
|
|
||||||
var music = GD.Load<AudioStream>("res://audio/background.ogg");
|
|
||||||
_musicPlayer.Stream = music;
|
|
||||||
_musicPlayer.Play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### AbstractGodotModule
|
|
||||||
|
|
||||||
Godot 模块抽象基类,实现了 IGodotModule 接口。
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[ContextAware]
|
|
||||||
[Log]
|
|
||||||
public partial class SaveModule : AbstractGodotModule
|
|
||||||
{
|
|
||||||
private Timer _autoSaveTimer;
|
|
||||||
|
|
||||||
public override void Install(IArchitecture architecture)
|
|
||||||
{
|
|
||||||
architecture.RegisterSystem(new SaveSystem());
|
|
||||||
architecture.RegisterUtility(new SaveUtility());
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnAttach(Architecture architecture)
|
|
||||||
{
|
|
||||||
// 创建自动保存计时器
|
|
||||||
_autoSaveTimer = new Timer();
|
|
||||||
_autoSaveTimer.WaitTime = 300; // 5分钟
|
|
||||||
_autoSaveTimer.Timeout += OnAutoSave;
|
|
||||||
AddChild(_autoSaveTimer);
|
|
||||||
_autoSaveTimer.Start();
|
|
||||||
|
|
||||||
Logger.Info("Save module attached with auto-save enabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAutoSave()
|
|
||||||
{
|
|
||||||
var saveSystem = Context.GetSystem<SaveSystem>();
|
|
||||||
saveSystem.SaveGame("autosave");
|
|
||||||
Logger.Debug("Auto-save completed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Node 扩展方法
|
|
||||||
|
|
||||||
### 安全节点获取
|
|
||||||
|
|
||||||
#### GetNodeX<T>()
|
|
||||||
|
|
||||||
安全获取子节点,自动类型转换和 null 检查。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static T GetNodeX<T>(this Node node, string path) where T : class;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 安全获取节点
|
|
||||||
var player = GetNodeX<Player>("Player");
|
|
||||||
var healthBar = GetNodeX<ProgressBar>("UI/HealthBar");
|
|
||||||
|
|
||||||
// 如果节点不存在或类型不匹配,会抛出异常
|
|
||||||
// 使用时不需要额外的 null 检查
|
|
||||||
```
|
|
||||||
|
|
||||||
#### GetChildX<T>()
|
|
||||||
|
|
||||||
安全查找子节点,支持递归查找。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static T GetChildX<T>(this Node node, string path) where T : class;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 递归查找子节点
|
|
||||||
var player = FindChildX<Player>("Player");
|
|
||||||
var sprite = FindChildX<Sprite2D>("Enemy/Sprite");
|
|
||||||
```
|
|
||||||
|
|
||||||
### 节点验证
|
|
||||||
|
|
||||||
#### IsValidNode()
|
|
||||||
|
|
||||||
检查节点是否有效且在场景树中。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static bool IsValidNode(this Node node);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### IsInvalidNode()
|
|
||||||
|
|
||||||
检查节点是否无效或不在场景树中。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static bool IsInvalidNode(this Node node);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
Node someNode = GetNode("SomeNode");
|
|
||||||
|
|
||||||
if (IsValidNode(someNode))
|
|
||||||
{
|
|
||||||
someNode.DoSomething();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsInvalidNode(someNode))
|
|
||||||
{
|
|
||||||
// 节点无效,需要重新获取
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 安全节点操作
|
|
||||||
|
|
||||||
#### AddChildX()
|
|
||||||
|
|
||||||
安全添加子节点,包含验证。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static void AddChildX(this Node parent, Node child, bool forceReadableName = false, InternalMode internalMode = 0);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### QueueFreeX()
|
|
||||||
|
|
||||||
安全销毁节点,包含验证。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static void QueueFreeX(this Node node);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### FreeX()
|
|
||||||
|
|
||||||
立即销毁节点,谨慎使用。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static void FreeX(this Node node);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 创建并添加子节点
|
|
||||||
var bullet = bulletScene.Instantiate<Bullet>();
|
|
||||||
AddChildX(bullet);
|
|
||||||
|
|
||||||
// 安全销毁节点
|
|
||||||
bullet.QueueFreeX();
|
|
||||||
|
|
||||||
// 立即销毁(谨慎使用)
|
|
||||||
tempNode.FreeX();
|
|
||||||
```
|
|
||||||
|
|
||||||
### 异步节点操作
|
|
||||||
|
|
||||||
#### WaitUntilReady()
|
|
||||||
|
|
||||||
等待节点准备就绪。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static async Task WaitUntilReady(this Node node);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### WaitUntil()
|
|
||||||
|
|
||||||
等待条件满足。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static async Task WaitUntil(this Node node, Func<bool> condition);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### WaitUntilTimeout()
|
|
||||||
|
|
||||||
等待指定时间或条件满足。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static async Task WaitUntilTimeout(this Node node, float timeoutSeconds);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 等待节点准备就绪
|
|
||||||
await this.WaitUntilReady();
|
|
||||||
|
|
||||||
// 等待条件满足
|
|
||||||
await this.WaitUntil(() => SomeCondition());
|
|
||||||
|
|
||||||
// 等待 2 秒
|
|
||||||
await this.WaitUntilTimeout(2.0f);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 场景树操作
|
|
||||||
|
|
||||||
#### GetParentX<T>()
|
|
||||||
|
|
||||||
安全获取父节点。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static T GetParentX<T>(this Node node) where T : class;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ForEachChild()
|
|
||||||
|
|
||||||
遍历所有子节点。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static void ForEachChild<T>(this Node node, Action<T> action) where T : Node;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 获取父节点
|
|
||||||
var parent = GetParentX<GameLevel>();
|
|
||||||
|
|
||||||
// 遍历所有子节点
|
|
||||||
this.ForEachChild<Node>(child => {
|
|
||||||
if (child is Sprite2D sprite)
|
|
||||||
{
|
|
||||||
ProcessSprite(sprite);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## 信号系统
|
|
||||||
|
|
||||||
### SignalBuilder
|
|
||||||
|
|
||||||
信号构建器,提供流畅的信号连接 API。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public SignalBuilder(Node node);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 连接方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public SignalBuilder Connect(Callable callable);
|
|
||||||
public SignalBuilder Connect<T1>(Callable<T1> callable);
|
|
||||||
public SignalBuilder Connect<T1, T2>(Callable<T1, T2> callable);
|
|
||||||
public SignalBuilder Connect<T1, T2, T3>(Callable<T1, T2, T3> callable);
|
|
||||||
public SignalBuilder Connect<T1, T2, T3, T4>(Callable<T1, T2, T3, T4> callable);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 配置方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public SignalBuilder WithFlags(ConnectFlags flags);
|
|
||||||
public SignalBuilder CallImmediately();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 生命周期方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public SignalBuilder UnRegisterWhenNodeExitTree(Node node);
|
|
||||||
public SignalBuilder AddToUnregisterList(IUnRegisterList unregisterList);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 基础连接
|
|
||||||
this.CreateSignalBuilder(Button.SignalName.Pressed)
|
|
||||||
.Connect(OnButtonPressed)
|
|
||||||
.UnRegisterWhenNodeExitTree(this);
|
|
||||||
|
|
||||||
// 带标志的连接
|
|
||||||
this.CreateSignalBuilder(Timer.SignalName.Timeout)
|
|
||||||
.WithFlags(ConnectFlags.OneShot)
|
|
||||||
.Connect(OnTimerTimeout);
|
|
||||||
|
|
||||||
// 立即调用连接
|
|
||||||
this.CreateSignalBuilder(CustomSignal.SignalName.CustomEvent)
|
|
||||||
.CallImmediately()
|
|
||||||
.Connect(OnCustomEvent);
|
|
||||||
|
|
||||||
// 多参数连接
|
|
||||||
this.CreateSignalBuilder()
|
|
||||||
.AddSignal(SignalName.Parameter1, OnParameter1)
|
|
||||||
.AddSignal(SignalName.Parameter2, OnParameter2)
|
|
||||||
.AddSignal(SignalName.Parameter3, OnParameter3)
|
|
||||||
.UnRegisterWhenNodeExitTree(this);
|
|
||||||
```
|
|
||||||
|
|
||||||
### SignalExtension
|
|
||||||
|
|
||||||
信号扩展方法,简化信号创建。
|
|
||||||
|
|
||||||
#### CreateSignalBuilder()
|
|
||||||
|
|
||||||
创建信号构建器。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static SignalBuilder CreateSignalBuilder(this Node node, string signalName);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ConnectSignal()
|
|
||||||
|
|
||||||
直接连接信号。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static IUnRegister ConnectSignal(this Node node, string signalName, Callable callable);
|
|
||||||
public static IUnRegister ConnectSignal<T1>(this Node node, string signalName, Callable<T1> callable);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 创建信号构建器连接
|
|
||||||
this.CreateSignalBuilder(Button.SignalName.Pressed)
|
|
||||||
.Connect(OnButtonPressed);
|
|
||||||
|
|
||||||
// 直接连接信号
|
|
||||||
this.ConnectSignal(Button.SignalName.Pressed, Callable.From(OnButtonPressed));
|
|
||||||
|
|
||||||
// 多参数信号连接
|
|
||||||
this.ConnectSignal(ComplexSignal.SignalName.DataChanged,
|
|
||||||
Callable.From(OnDataChanged));
|
|
||||||
```
|
|
||||||
|
|
||||||
### 信号与框架事件桥接
|
|
||||||
|
|
||||||
#### SignalEventBridge
|
|
||||||
|
|
||||||
信号事件桥接器,将 Godot 信号转换为框架事件。
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[ContextAware]
|
|
||||||
[Log]
|
|
||||||
public partial class GameController : Node, IController
|
|
||||||
{
|
|
||||||
public override void _Ready()
|
|
||||||
{
|
|
||||||
// Godot 信号 -> 框架事件
|
|
||||||
this.CreateSignalBuilder(Button.SignalName.Pressed)
|
|
||||||
.Connect(() => {
|
|
||||||
Context.SendEvent(new ButtonClickEvent { ButtonId = "start" });
|
|
||||||
})
|
|
||||||
.UnRegisterWhenNodeExitTree(this);
|
|
||||||
|
|
||||||
// 框架事件 -> Godot 信号
|
|
||||||
this.RegisterEvent<PlayerHealthChangeEvent>(OnPlayerHealthChange)
|
|
||||||
.UnRegisterWhenNodeExitTree(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlayerHealthChange(PlayerHealthChangeEvent e)
|
|
||||||
{
|
|
||||||
// 更新 Godot UI
|
|
||||||
var healthBar = GetNode<ProgressBar>("UI/HealthBar");
|
|
||||||
healthBar.Value = (float)e.NewHealth / e.MaxHealth * 100;
|
|
||||||
|
|
||||||
// 发送 Godot 信号
|
|
||||||
EmitSignal(SignalName.HealthUpdated, e.NewHealth, e.MaxHealth);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Signal]
|
|
||||||
public delegate void HealthUpdatedEventHandler(int newHealth, int maxHealth);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 节点池化
|
|
||||||
|
|
||||||
### AbstractNodePoolSystem<TKey, TNode>
|
|
||||||
|
|
||||||
节点池化系统基类,TNode 必须是 Node。
|
|
||||||
|
|
||||||
#### 抽象方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
protected abstract TNode CreateItem(TKey key);
|
|
||||||
protected abstract void OnSpawn(TNode item, TKey key);
|
|
||||||
protected abstract void OnDespawn(TNode item);
|
|
||||||
protected abstract bool CanDespawn(TNode item);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 公共方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public TNode Spawn(TKey key);
|
|
||||||
public void Despawn(TNode item);
|
|
||||||
public void DespawnAll();
|
|
||||||
public int GetActiveCount(TKey key);
|
|
||||||
public int GetTotalCount(TKey key);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class BulletPoolSystem : AbstractNodePoolSystem<string, Bullet>
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, PackedScene> _scenes = new();
|
|
||||||
|
|
||||||
public BulletPoolSystem()
|
|
||||||
{
|
|
||||||
_scenes["player"] = GD.Load<PackedScene>("res://scenes/PlayerBullet.tscn");
|
|
||||||
_scenes["enemy"] = GD.Load<PackedScene>("res://scenes/EnemyBullet.tscn");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Bullet CreateItem(string key)
|
|
||||||
{
|
|
||||||
if (_scenes.TryGetValue(key, out var scene))
|
|
||||||
{
|
|
||||||
return scene.Instantiate<Bullet>();
|
|
||||||
}
|
|
||||||
throw new ArgumentException($"Unknown bullet type: {key}");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnSpawn(Bullet item, string key)
|
|
||||||
{
|
|
||||||
item.Reset();
|
|
||||||
item.Position = Vector2.Zero;
|
|
||||||
item.Visible = true;
|
|
||||||
item.SetCollisionLayerValue(1, true);
|
|
||||||
item.SetCollisionMaskValue(1, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDespawn(Bullet item)
|
|
||||||
{
|
|
||||||
item.Visible = false;
|
|
||||||
item.SetCollisionLayerValue(1, false);
|
|
||||||
item.SetCollisionMaskValue(1, false);
|
|
||||||
|
|
||||||
// 移除父节点
|
|
||||||
item.GetParent()?.RemoveChild(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool CanDespawn(Bullet item)
|
|
||||||
{
|
|
||||||
return !item.IsActive && item.GetParent() != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用示例
|
|
||||||
var bulletPool = new BulletPoolSystem();
|
|
||||||
|
|
||||||
// 从池中获取子弹
|
|
||||||
var bullet = bulletPool.Spawn("player");
|
|
||||||
AddChild(bullet);
|
|
||||||
|
|
||||||
// 回收子弹
|
|
||||||
bulletPool.Despawn(bullet);
|
|
||||||
```
|
|
||||||
|
|
||||||
### IPoolableNode
|
|
||||||
|
|
||||||
可池化节点接口。
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public interface IPoolableNode
|
|
||||||
{
|
|
||||||
void Reset();
|
|
||||||
void SetActive(bool active);
|
|
||||||
bool IsActive { get; }
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public partial class Bullet : Area2D, IPoolableNode
|
|
||||||
{
|
|
||||||
[Export] public float Speed { get; set; } = 500.0f;
|
|
||||||
[Export] public float Damage { get; set; } = 10.0f;
|
|
||||||
|
|
||||||
private bool _isActive;
|
|
||||||
|
|
||||||
public bool IsActive => _isActive;
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
Position = Vector2.Zero;
|
|
||||||
Rotation = 0;
|
|
||||||
Velocity = Vector2.Zero;
|
|
||||||
_isActive = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetActive(bool active)
|
|
||||||
{
|
|
||||||
_isActive = active;
|
|
||||||
Visible = active;
|
|
||||||
SetProcess(active);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _Ready()
|
|
||||||
{
|
|
||||||
BodyEntered += OnBodyEntered;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnBodyEntered(Node body)
|
|
||||||
{
|
|
||||||
if (body is Enemy enemy && _isActive)
|
|
||||||
{
|
|
||||||
enemy.TakeDamage(Damage);
|
|
||||||
// 子弹命中敌人,回收到池中
|
|
||||||
var bulletPool = GetNode<BulletPoolSystem>("/root/BulletPool");
|
|
||||||
bulletPool?.Despawn(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _Process(double delta)
|
|
||||||
{
|
|
||||||
if (!_isActive) return;
|
|
||||||
|
|
||||||
Position += Transform.X * (float)(Speed * delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 资源管理
|
|
||||||
|
|
||||||
### ResourceLoadUtility
|
|
||||||
|
|
||||||
资源加载工具类,简化和缓存 Godot 资源加载。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public ResourceLoadUtility();
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public T LoadResource<T>(string path) where T : Resource;
|
|
||||||
public async Task<T> LoadResourceAsync<T>(string path) where T : Resource;
|
|
||||||
public void PreloadResource<T>(string path) where T : Resource;
|
|
||||||
public bool HasResource<T>(string path) where T : Resource;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
var resourceLoader = new ResourceLoadUtility();
|
|
||||||
|
|
||||||
// 同步加载资源
|
|
||||||
var playerTexture = resourceLoader.LoadResource<Texture2D>("res://textures/player.png");
|
|
||||||
var playerScene = resourceLoader.LoadResource<PackedScene>("res://scenes/Player.tscn");
|
|
||||||
|
|
||||||
// 异步加载资源
|
|
||||||
var musicStream = await resourceLoader.LoadResourceAsync<AudioStream>("res://audio/background.ogg");
|
|
||||||
|
|
||||||
// 预加载资源
|
|
||||||
resourceLoader.PreloadResource<Texture2D>("res://textures/enemy.png");
|
|
||||||
resourceLoader.PreloadResource<PackedScene>("res://scenes/enemy.tscn");
|
|
||||||
```
|
|
||||||
|
|
||||||
### AbstractResourceFactoryUtility
|
|
||||||
|
|
||||||
抽象资源工厂工具基类。
|
|
||||||
|
|
||||||
#### 抽象方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
protected abstract void RegisterFactories();
|
|
||||||
protected abstract T CreateFactory<T>(string path, Dictionary<string, object> metadata = null) where T : class;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public class GameResourceFactory : AbstractResourceFactoryUtility
|
|
||||||
{
|
|
||||||
protected override void RegisterFactories()
|
|
||||||
{
|
|
||||||
RegisterFactory<PlayerData>("res://data/players/{id}.json");
|
|
||||||
RegisterFactory<WeaponConfig>("res://data/weapons/{id}.json");
|
|
||||||
RegisterFactory<LevelConfig>("res://data/levels/{id}.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayerData CreatePlayer(string playerId)
|
|
||||||
{
|
|
||||||
return CreateFactory<PlayerData>($"res://data/players/{playerId}.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
public WeaponConfig CreateWeapon(string weaponId)
|
|
||||||
{
|
|
||||||
var metadata = new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
["weaponId"] = weaponId,
|
|
||||||
["loadTime"] = DateTime.Now
|
|
||||||
};
|
|
||||||
|
|
||||||
return CreateFactory<WeaponConfig>($"res://data/weapons/{weaponId}.json", metadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 日志系统
|
|
||||||
|
|
||||||
### GodotLogger
|
|
||||||
|
|
||||||
Godot 特定的日志实现。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public GodotLogger(string categoryName);
|
|
||||||
public GodotLogger(string categoryName, LogLevel minLevel);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public void Log<T>(LogLevel level, T message, params object[] args);
|
|
||||||
public void Debug<T>(T message, params object[] args);
|
|
||||||
public void Info<T>(T message, params object[] args);
|
|
||||||
public void Warning<T>(T message, params object[] args);
|
|
||||||
public void Error<T>(T message, params object[] args);
|
|
||||||
public void Error<T>(Exception exception, T message, params object[] args);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 创建日志器
|
|
||||||
var logger = new GodotLogger("GameController");
|
|
||||||
|
|
||||||
// 不同级别的日志
|
|
||||||
logger.Debug("Player position: {0}", player.Position);
|
|
||||||
logger.Info("Game started");
|
|
||||||
logger.Warning("Low health: {0}", player.Health);
|
|
||||||
logger.Error("Failed to load resource: {0}", resourcePath);
|
|
||||||
|
|
||||||
// 带异常的错误日志
|
|
||||||
logger.Error(exception, "An error occurred while processing player input");
|
|
||||||
```
|
|
||||||
|
|
||||||
### GodotLoggerFactory
|
|
||||||
|
|
||||||
Godot 日志工厂。
|
|
||||||
|
|
||||||
#### 方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public ILogger CreateLogger(string categoryName);
|
|
||||||
public ILogger CreateLogger(Type type);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
var factory = new GodotLoggerFactory();
|
|
||||||
|
|
||||||
// 创建日志器
|
|
||||||
var gameLogger = factory.CreateLogger("GameController");
|
|
||||||
var playerLogger = factory.CreateLogger(typeof(PlayerController));
|
|
||||||
|
|
||||||
// 在架构中使用
|
|
||||||
public class GameArchitecture : AbstractArchitecture
|
|
||||||
{
|
|
||||||
protected override void Init()
|
|
||||||
{
|
|
||||||
LoggerProperties = new LoggerProperties
|
|
||||||
{
|
|
||||||
LoggerFactoryProvider = new GodotLoggerFactoryProvider(),
|
|
||||||
MinLevel = LogLevel.Info
|
|
||||||
};
|
|
||||||
|
|
||||||
RegisterSystem(new GameController());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 池化管理
|
|
||||||
|
|
||||||
### AbstractObjectPool<T>
|
|
||||||
|
|
||||||
通用对象池基类。
|
|
||||||
|
|
||||||
#### 构造函数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public AbstractObjectPool(
|
|
||||||
Func<T> createFunc,
|
|
||||||
Action<T> actionOnGet = null,
|
|
||||||
Action<T> actionOnRelease = null,
|
|
||||||
bool collectionCheck = false
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public T Get();
|
|
||||||
public void Release(T item);
|
|
||||||
public void Clear();
|
|
||||||
public int CountInactive { get; }
|
|
||||||
public int CountAll { get; }
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 创建对象池
|
|
||||||
var explosionPool = new AbstractObjectPool<ExplosionEffect>(
|
|
||||||
createFunc: () => new ExplosionEffect(),
|
|
||||||
actionOnGet: effect => effect.Reset(),
|
|
||||||
actionOnRelease: effect => Cleanup()
|
|
||||||
);
|
|
||||||
|
|
||||||
// 使用对象池
|
|
||||||
var effect = explosionPool.Get();
|
|
||||||
effect.Play(effect.Position);
|
|
||||||
|
|
||||||
// 回收对象
|
|
||||||
explosionPool.Release(effect);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 音频系统
|
|
||||||
|
|
||||||
### AudioSystem
|
|
||||||
|
|
||||||
音频系统,管理音乐和音效播放。
|
|
||||||
|
|
||||||
#### 使用示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[ContextAware]
|
|
||||||
[Log]
|
|
||||||
public partial class AudioSystem : AbstractSystem
|
|
||||||
{
|
|
||||||
private AudioStreamPlayer _musicPlayer;
|
|
||||||
private readonly Dictionary<string, AudioStream> _soundCache = new();
|
|
||||||
|
|
||||||
protected override void OnInit()
|
|
||||||
{
|
|
||||||
InitializeAudioPlayers();
|
|
||||||
CacheSounds();
|
|
||||||
|
|
||||||
// 监听音频事件
|
|
||||||
this.RegisterEvent<PlaySoundEvent>(OnPlaySound);
|
|
||||||
this.RegisterEvent<PlayMusicEvent>(OnPlayMusic);
|
|
||||||
this.RegisterEvent<StopMusicEvent>(OnStopMusic);
|
|
||||||
this.RegisterEvent<SetVolumeEvent>(OnSetVolume);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeAudioPlayers()
|
|
||||||
{
|
|
||||||
_musicPlayer = new AudioStreamPlayer();
|
|
||||||
AddChild(_musicPlayer);
|
|
||||||
|
|
||||||
// 配置音乐播放器
|
|
||||||
_musicPlayer.Bus = "Music";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CacheSounds()
|
|
||||||
{
|
|
||||||
var soundPaths = new[]
|
|
||||||
{
|
|
||||||
"res://audio/jump.wav",
|
|
||||||
"res://audio/attack.wav",
|
|
||||||
"res://audio/hurt.wav",
|
|
||||||
"res://audio/victory.wav"
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var path in soundPaths)
|
|
||||||
{
|
|
||||||
var sound = GD.Load<AudioStream>(path);
|
|
||||||
var soundName = Path.GetFileNameWithoutExtension(path);
|
|
||||||
_soundCache[soundName] = sound;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPlaySound(PlaySoundEvent e)
|
|
||||||
{
|
|
||||||
if (_soundCache.TryGetValue(e.SoundName, out var sound))
|
|
||||||
{
|
|
||||||
PlaySound(sound);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Warning($"Sound not found: {e.SoundName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PlayMusic(PlayMusicEvent e)
|
|
||||||
{
|
|
||||||
var music = GD.Load<AudioStream>(e.MusicPath);
|
|
||||||
_musicPlayer.Stream = music;
|
|
||||||
_musicPlayer.Play();
|
|
||||||
|
|
||||||
Logger.Info($"Playing music: {e.MusicPath}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnStopMusic(StopMusicEvent e)
|
|
||||||
{
|
|
||||||
_musicPlayer.Stop();
|
|
||||||
Logger.Info("Music stopped");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSetVolume(SetVolumeEvent e)
|
|
||||||
{
|
|
||||||
AudioServer.SetBusVolume(e.BusName, e.Volume);
|
|
||||||
Logger.Info($"Set volume for bus {e.BusName}: {e.Volume}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PlaySound(AudioStream sound)
|
|
||||||
{
|
|
||||||
var player = new AudioStreamPlayer();
|
|
||||||
player.Stream = sound;
|
|
||||||
player.Bus = "SFX";
|
|
||||||
player.Play();
|
|
||||||
|
|
||||||
// 自动清理播放器
|
|
||||||
this.CreateSignalBuilder(player.SignalName.Finished)
|
|
||||||
.WithFlags(ConnectFlags.OneShot)
|
|
||||||
.Connect(() => player.QueueFree())
|
|
||||||
.UnRegisterWhenNodeExitTree(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 音频事件
|
|
||||||
public struct PlaySoundEvent { public string SoundName; }
|
|
||||||
public struct PlayMusicEvent { public string MusicPath; }
|
|
||||||
public struct StopMusicEvent { }
|
|
||||||
public struct SetVolumeEvent { public string BusName; public float Volume; }
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**文档版本**: 1.0.0
|
|
||||||
**更新日期**: 2026-01-12
|
|
||||||
@ -1,601 +0,0 @@
|
|||||||
# GFramework.SourceGenerators API 参考
|
|
||||||
|
|
||||||
> GFramework.SourceGenerators 模块的完整 API 参考文档,包含所有源代码生成器的详细说明。
|
|
||||||
|
|
||||||
## 📋 目录
|
|
||||||
|
|
||||||
- [日志生成器](#日志生成器)
|
|
||||||
- [上下文感知生成器](#上下文感知生成器)
|
|
||||||
- [枚举扩展生成器](#枚举扩展生成器)
|
|
||||||
- [诊断系统](#诊断系统)
|
|
||||||
- [通用工具](#通用工具)
|
|
||||||
|
|
||||||
## 日志生成器
|
|
||||||
|
|
||||||
### [Log] 属性
|
|
||||||
|
|
||||||
为标记的类自动生成 ILogger 字段。
|
|
||||||
|
|
||||||
#### 构造函数参数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[Log(
|
|
||||||
string fieldName = "Logger", // 生成的字段名
|
|
||||||
AccessModifier accessModifier = AccessModifier.Private, // 访问修饰符
|
|
||||||
bool isStatic = true, // 是否生成静态字段
|
|
||||||
string loggerName = null, // 自定义日志器名称
|
|
||||||
LogLevel minLevel = LogLevel.None, // 最小日志级别
|
|
||||||
bool includeLoggerInterface = false // 是否包含 ILogger 接口
|
|
||||||
bool enableConditionalCompilation = false // 是否启用条件编译
|
|
||||||
string loggerInterfaceName = "ILogger" // 日志接口名称
|
|
||||||
bool suppressAutoGeneratedAttribute = false // 是否抑制自动生成属性
|
|
||||||
string category = null // 日志类别
|
|
||||||
bool forceContextualLogging = false // 是否强制上下文日志
|
|
||||||
bool enableStructuredLogging = false // 是否启用结构化日志
|
|
||||||
string loggerFactoryName = null // 日志工厂名称
|
|
||||||
string logMessagePrefix = null // 日志消息前缀
|
|
||||||
bool enablePerformanceLogging = false // 是否启用性能日志
|
|
||||||
bool enableAsyncLogging = false // 是否启用异步日志
|
|
||||||
bool enableFluentLogging = false // 是否启用流畅日志
|
|
||||||
bool enableScopedLogging = false // 是否启用作用域日志
|
|
||||||
)]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 生成的代码示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 默认配置生成的代码
|
|
||||||
public partial class MyClass
|
|
||||||
{
|
|
||||||
private static readonly ILogger Logger =
|
|
||||||
LoggerFactory.Create(builder => builder
|
|
||||||
.AddConsole()
|
|
||||||
.SetMinimumLevel(LogLevel.Information)
|
|
||||||
.CreateLogger<MyClass>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自定义配置生成的代码
|
|
||||||
[Log(
|
|
||||||
fieldName = "CustomLogger",
|
|
||||||
accessModifier = AccessModifier.Public,
|
|
||||||
isStatic = false,
|
|
||||||
loggerName = "Custom.MyClass",
|
|
||||||
minLevel = LogLevel.Debug,
|
|
||||||
includeLoggerInterface = true
|
|
||||||
)]
|
|
||||||
public partial class CustomClass : ILogger
|
|
||||||
{
|
|
||||||
public ILogger CustomLogger { get; }
|
|
||||||
|
|
||||||
static CustomClass()
|
|
||||||
{
|
|
||||||
CustomLogger = LoggerFactory.Create(builder => builder
|
|
||||||
.AddConsole()
|
|
||||||
.SetMinimumLevel(LogLevel.Debug)
|
|
||||||
.CreateLogger<CustomClass>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 支持的方法
|
|
||||||
|
|
||||||
生成的 Logger 支持以下方法:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 基础日志方法
|
|
||||||
Logger.LogDebug("Debug message");
|
|
||||||
Logger.LogInformation("Info message");
|
|
||||||
Logger.LogWarning("Warning message");
|
|
||||||
Logger.LogError("Error message");
|
|
||||||
Logger.LogCritical("Critical message");
|
|
||||||
|
|
||||||
// 带格式化的日志方法
|
|
||||||
Logger.LogInformation("Player {Name} has {Health} health", playerName, playerHealth);
|
|
||||||
|
|
||||||
// 异步日志方法
|
|
||||||
await Logger.LogInformationAsync("Async message");
|
|
||||||
|
|
||||||
// 结构化日志
|
|
||||||
Logger.LogInformation(new { PlayerName = "John", Health = 100 }, "Player {Name} has {Health} health");
|
|
||||||
```
|
|
||||||
|
|
||||||
## 上下文感知生成器
|
|
||||||
|
|
||||||
### [ContextAware] 属性
|
|
||||||
|
|
||||||
为标记的类自动实现 IContextAware 接口。
|
|
||||||
|
|
||||||
#### 生成的代码示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[ContextAware]
|
|
||||||
public partial class MyClass : IContextAware
|
|
||||||
{
|
|
||||||
private IContextAware.Context _context;
|
|
||||||
|
|
||||||
public IContextAware.Context Context => _context ??= new LazyContext(this);
|
|
||||||
|
|
||||||
public void SetContext(IContextAware.Context context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IContextAware.Context GetContext()
|
|
||||||
{
|
|
||||||
return _context;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用延迟初始化
|
|
||||||
[ContextAware(useLazy = true)]
|
|
||||||
public partial class LazyContextClass : IContextAware
|
|
||||||
{
|
|
||||||
private Lazy<IContextAware.Context> _context;
|
|
||||||
|
|
||||||
public IContextAware.Context Context => _context.Value;
|
|
||||||
|
|
||||||
public void SetContext(IContextAware.Context context)
|
|
||||||
{
|
|
||||||
_context = new Lazy<IContextAware.Context>(() => context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 带上下文验证
|
|
||||||
[ContextAware(validateContext = true)]
|
|
||||||
public partial class ValidatedContextClass : IContextAware
|
|
||||||
{
|
|
||||||
private IContextAware.Context _context;
|
|
||||||
|
|
||||||
public IContextAware.Context Context =>
|
|
||||||
{
|
|
||||||
get => _context;
|
|
||||||
private set
|
|
||||||
{
|
|
||||||
_context = value;
|
|
||||||
if (_context?.IsInvalid == true)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Context is invalid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 可用的方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 获取模型
|
|
||||||
var playerModel = Context.GetModel<PlayerModel>();
|
|
||||||
var gameModel = Context.GetModel<GameModel>();
|
|
||||||
|
|
||||||
// 获取系统
|
|
||||||
var combatSystem = Context.GetSystem<CombatSystem>();
|
|
||||||
var audioSystem = Context.GetSystem<AudioSystem>();
|
|
||||||
|
|
||||||
// 获取工具
|
|
||||||
var storageUtility = Context.GetUtility<StorageUtility>();
|
|
||||||
var mathUtility = Context.GetUtility<MathUtility>();
|
|
||||||
|
|
||||||
// 发送事件
|
|
||||||
Context.SendEvent<PlayerDiedEvent>();
|
|
||||||
Context.SendEvent<DamageDealtEvent>(new DamageDealtEvent { Damage = 50 });
|
|
||||||
|
|
||||||
// 发送命令
|
|
||||||
Context.SendCommand(new AttackCommand());
|
|
||||||
var result = Context.SendCommand<AttackResult>(new AttackCommand());
|
|
||||||
|
|
||||||
// 发送查询
|
|
||||||
var canAttack = Context.SendQuery<CanAttackQuery>();
|
|
||||||
var playerData = Context.SendQuery<GetPlayerDataQuery>();
|
|
||||||
```
|
|
||||||
|
|
||||||
## 枚举扩展生成器
|
|
||||||
|
|
||||||
### [GenerateEnumExtensions] 属性
|
|
||||||
|
|
||||||
为枚举类型自动生成扩展方法。
|
|
||||||
|
|
||||||
#### 构造函数参数
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[GenerateEnumExtensions(
|
|
||||||
bool generateIsMethods = true, // 是否生成 IsX() 方法
|
|
||||||
bool generateHasMethod = true, // 是否生成 HasX() 方法
|
|
||||||
bool generateInMethod = true, // 是否生成 In(params T[]) 方法
|
|
||||||
bool generateTryParseMethod = false, // 是否生成 TryParse() 方法
|
|
||||||
string customPrefix = "Is", // 自定义方法名前缀
|
|
||||||
bool includeToString = false, // 是否生成 ToString 扩展
|
|
||||||
bool generateAllMethod = false, // 是否生成 All() 方法
|
|
||||||
bool generateCountMethod = false, // 是否生成 Count() 方法
|
|
||||||
bool generateDescriptionMethod = false, // 是否生成 Description() 方法
|
|
||||||
bool generateValuesMethod = false, // 是否生成 Values() 方法
|
|
||||||
string customNamespace = null, // 自定义命名空间
|
|
||||||
bool generateExtensionMethods = true, // 是否生成扩展方法
|
|
||||||
bool generateFlagMethods = true, // 是否为位标志枚举生成方法
|
|
||||||
bool generateValidationMethods = false, // 是否生成验证方法
|
|
||||||
bool generateUtilityMethods = false, // 是否生成工具方法
|
|
||||||
bool generateQueryableMethods = false, // 是否生成查询方法
|
|
||||||
string customMethodNameFormat = null, // 自定义方法名格式
|
|
||||||
bool generateDocumentation = false, // 是否生成文档注释
|
|
||||||
bool generateExamples = false, // 是否生成使用示例
|
|
||||||
)]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 普通枚举生成的代码示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[GenerateEnumExtensions]
|
|
||||||
public enum PlayerState
|
|
||||||
{
|
|
||||||
Idle,
|
|
||||||
Walking,
|
|
||||||
Running,
|
|
||||||
Jumping,
|
|
||||||
Attacking
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成的扩展方法
|
|
||||||
public static class PlayerStateExtensions
|
|
||||||
{
|
|
||||||
public static bool IsIdle(this PlayerState state) => state == PlayerState.Idle;
|
|
||||||
public static bool IsWalking(this PlayerState state) => state == PlayerState.Walking;
|
|
||||||
public static bool IsRunning(this PlayerState state) => state == PlayerState.Running;
|
|
||||||
public static bool IsJumping(this PlayerState state) => state == PlayerState.Jumping;
|
|
||||||
public static bool IsAttacking(this PlayerState state) => state == PlayerState.Attacking;
|
|
||||||
|
|
||||||
public static bool In(this PlayerState state, params PlayerState[] values)
|
|
||||||
{
|
|
||||||
return values.Contains(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 位标志枚举生成的代码示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[GenerateEnumExtensions]
|
|
||||||
[Flags]
|
|
||||||
public enum PlayerPermissions
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
CanMove = 1 << 0,
|
|
||||||
CanAttack = 1 << 1,
|
|
||||||
CanUseItems = 1 << 2,
|
|
||||||
CanChat = 1 << 3,
|
|
||||||
CanTrade = 1 << 4
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成的扩展方法
|
|
||||||
public static class PlayerPermissionsExtensions
|
|
||||||
{
|
|
||||||
public static bool HasCanMove(this PlayerPermissions permissions) => permissions.HasFlag(PlayerPermissions.CanMove);
|
|
||||||
public static bool HasCanAttack(this PlayerPermissions permissions) => permissions.HasFlag(PlayerPermissions.CanAttack);
|
|
||||||
public static bool HasCanUseItems(this PlayerPermissions permissions) => permissions.HasFlag(PlayerPermissions.CanUseItems);
|
|
||||||
|
|
||||||
public static bool HasAny(this PlayerPermissions permissions, params PlayerPermissions[] flags)
|
|
||||||
{
|
|
||||||
return flags.Any(flag => permissions.HasFlag(flag));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool HasAll(this PlayerPermissions permissions, params PlayerPermissions[] flags)
|
|
||||||
{
|
|
||||||
return flags.All(flag => permissions.HasFlag(flag));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PlayerPermissions Add(this PlayerPermissions permissions, PlayerPermissions other)
|
|
||||||
{
|
|
||||||
return permissions | other;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PlayerPermissions Remove(this PlayerPermissions permissions, PlayerPermissions other)
|
|
||||||
{
|
|
||||||
return permissions & ~other;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PlayerPermissions Toggle(this PlayerPermissions permissions, PlayerPermissions flag)
|
|
||||||
{
|
|
||||||
return permissions ^ flag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 高级功能示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
[GenerateEnumExtensions(
|
|
||||||
customPrefix = "Is",
|
|
||||||
includeToString = true,
|
|
||||||
generateDescriptionMethod = true,
|
|
||||||
generateUtilityMethods = true
|
|
||||||
)]
|
|
||||||
public enum GameState
|
|
||||||
{
|
|
||||||
[Description("游戏菜单状态")]
|
|
||||||
Menu,
|
|
||||||
|
|
||||||
[Description("游戏进行中")]
|
|
||||||
Playing,
|
|
||||||
|
|
||||||
[Description("游戏暂停")]
|
|
||||||
Paused,
|
|
||||||
|
|
||||||
[Description("游戏结束")]
|
|
||||||
GameOver
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成的扩展方法包含更多功能
|
|
||||||
public static class GameStateExtensions
|
|
||||||
{
|
|
||||||
// IsX() 方法
|
|
||||||
public static bool IsMenu(this GameState state) => state == GameState.Menu;
|
|
||||||
public static bool IsPlaying(this GameState state) => state == GameState.Playing;
|
|
||||||
public static bool IsPaused(this GameState state) => state == GameState.Paused;
|
|
||||||
public static bool IsGameOver(this GameState state) => state == GameState.GameOver;
|
|
||||||
|
|
||||||
// ToString() 扩展
|
|
||||||
public static string ToDisplayString(this GameState state)
|
|
||||||
{
|
|
||||||
return state switch
|
|
||||||
{
|
|
||||||
GameState.Menu => "游戏菜单",
|
|
||||||
GameState.Playing => "游戏进行中",
|
|
||||||
GameState.Paused => "游戏暂停",
|
|
||||||
GameState.GameOver => "游戏结束"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Description() 扩展
|
|
||||||
public static string GetDescription(this GameState state)
|
|
||||||
{
|
|
||||||
return typeof(GameState)
|
|
||||||
.GetMember(state.ToString())
|
|
||||||
?.GetCustomAttribute<DescriptionAttribute>()
|
|
||||||
?.Description ?? state.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 工具方法
|
|
||||||
public static bool IsFinalState(this GameState state) => state == GameState.GameOver;
|
|
||||||
public static bool IsPlayingState(this GameState state) => state == GameState.Playing;
|
|
||||||
public static bool CanPause(this GameState state) => state == GameState.Playing;
|
|
||||||
|
|
||||||
// 验证方法
|
|
||||||
public static bool IsValidTransition(this GameState from, GameState to)
|
|
||||||
{
|
|
||||||
return (from, to) switch
|
|
||||||
{
|
|
||||||
(GameState.Menu, GameState.Playing) => true,
|
|
||||||
(GameState.Playing, GameState.Paused) => true,
|
|
||||||
(GameState.Paused, GameState.Playing) => true,
|
|
||||||
(GameState.Playing, GameState.GameOver) => true,
|
|
||||||
_ => false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 诊断系统
|
|
||||||
|
|
||||||
### GF_Logging_001 - 日志字段名冲突
|
|
||||||
|
|
||||||
当使用 `[Log]` 属性时,如果已存在同名字段或属性,会触发此诊断。
|
|
||||||
|
|
||||||
#### 示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 错误示例:字段名冲突
|
|
||||||
[Log(fieldName = "Logger")]
|
|
||||||
public partial class MyClass
|
|
||||||
{
|
|
||||||
private readonly ILogger Logger; // ❌ 冲突!
|
|
||||||
}
|
|
||||||
|
|
||||||
// 正确的解决方案
|
|
||||||
[Log(fieldName = "CustomLogger")]
|
|
||||||
public partial class MyClass
|
|
||||||
{
|
|
||||||
private readonly ILogger CustomLogger; // ✅ 使用不同的字段名
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 诊断消息
|
|
||||||
|
|
||||||
```
|
|
||||||
error GF_Logging_001: Logger field name 'Logger' conflicts with existing field in type 'MyClass'
|
|
||||||
```
|
|
||||||
|
|
||||||
### GF_Rule_001 - 上下文感知接口冲突
|
|
||||||
|
|
||||||
当使用 `[ContextAware]` 属性时,如果类型已经实现了 IContextAware 接口,会触发此诊断。
|
|
||||||
|
|
||||||
#### 示例
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 错误示例:接口冲突
|
|
||||||
[ContextAware]
|
|
||||||
public partial class MyClass : IContextAware // ❌ 冲突!
|
|
||||||
{
|
|
||||||
public IContextAware.Context Context { get; set; }
|
|
||||||
public void SetContext(IContextAware.Context context) { }
|
|
||||||
public IContextAware.Context GetContext() { return Context; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// 正确的解决方案:移除手动实现
|
|
||||||
[ContextAware]
|
|
||||||
public partial class MyClass // ✅ 让生成器实现接口
|
|
||||||
{
|
|
||||||
// 移除手动实现的代码
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 诊断消息
|
|
||||||
|
|
||||||
```
|
|
||||||
error GF_Rule_001: Type 'MyClass' already implements 'IContextAware' interface. Remove the [ContextAware] attribute or manual implementation.
|
|
||||||
```
|
|
||||||
|
|
||||||
## 通用工具
|
|
||||||
|
|
||||||
### TypeHelper
|
|
||||||
|
|
||||||
类型操作的工具类。
|
|
||||||
|
|
||||||
#### 主要方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static class TypeHelper
|
|
||||||
{
|
|
||||||
// 类型检查
|
|
||||||
public static bool IsNullable(Type type);
|
|
||||||
public static bool IsGenericType(Type type);
|
|
||||||
public static bool IsValueType(Type type);
|
|
||||||
public static bool IsEnum(Type type);
|
|
||||||
|
|
||||||
// 泛型类型信息
|
|
||||||
public static Type GetGenericTypeDefinition(Type type);
|
|
||||||
public static Type[] GetGenericArguments(Type type);
|
|
||||||
public static bool ImplementsInterface(Type type, Type interfaceType);
|
|
||||||
|
|
||||||
// 属性信息
|
|
||||||
public static PropertyInfo[] GetProperties(Type type, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
public static PropertyInfo GetProperty(Type type, string name, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
public static bool HasProperty(Type type, string name);
|
|
||||||
|
|
||||||
// 方法信息
|
|
||||||
public static MethodInfo[] GetMethods(Type type, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
public static MethodInfo GetMethod(Type type, string name, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
public static bool HasMethod(Type type, string name);
|
|
||||||
|
|
||||||
// 构造函数信息
|
|
||||||
public static ConstructorInfo[] GetConstructors(Type type, BindingFlags flags = BindingFlags.Public | BindingFlags.Instance);
|
|
||||||
public static ConstructorInfo GetConstructor(Type type, Type[] parameterTypes);
|
|
||||||
|
|
||||||
// 可实例化检查
|
|
||||||
public static bool HasParameterlessConstructor(Type type);
|
|
||||||
public static bool HasConstructor(Type type, params Type[] parameterTypes);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### SymbolHelper
|
|
||||||
|
|
||||||
符号操作的工具类。
|
|
||||||
|
|
||||||
#### 主要方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static class SymbolHelper
|
|
||||||
{
|
|
||||||
// 获取符号信息
|
|
||||||
public static ITypeSymbol GetSymbolInfo(INamedTypeSymbol symbol, Compilation compilation);
|
|
||||||
public static IMethodSymbol GetMethodInfo(IMethodSymbol symbol);
|
|
||||||
public static IPropertySymbol GetPropertyInfo(IPropertySymbol symbol);
|
|
||||||
public static IEventSymbol GetEventInfo(IEventSymbol symbol);
|
|
||||||
|
|
||||||
// 符号比较
|
|
||||||
public static bool IsSameSymbol(ISymbol symbol1, ISymbol symbol2);
|
|
||||||
public static string GetFullyQualifiedName(ISymbol symbol);
|
|
||||||
public static string GetDocumentationCommentXml(ISymbol symbol);
|
|
||||||
|
|
||||||
// 符号查找
|
|
||||||
public static IEnumerable<ISymbol> GetMembers(INamedTypeSymbol symbol);
|
|
||||||
public static ISymbol GetMember(INamedTypeSymbol symbol, string name);
|
|
||||||
public static IEnumerable<AttributeData> GetAttributes(ISymbol symbol);
|
|
||||||
public static T GetAttribute<T>(ISymbol symbol);
|
|
||||||
public static bool HasAttribute<T>(ISymbol symbol);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### CompilationHelper
|
|
||||||
|
|
||||||
编译操作的工具类。
|
|
||||||
|
|
||||||
#### 主要方法
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public static class CompilationHelper
|
|
||||||
{
|
|
||||||
// 获取编译
|
|
||||||
public static Compilation GetCompilation(Compilation startingCompilation);
|
|
||||||
public static Compilation GetCompilation(SyntaxTree syntaxTree);
|
|
||||||
public static Compilation GetCompilation(IEnumerable<SyntaxTree> syntaxTrees);
|
|
||||||
|
|
||||||
// 获取语义模型
|
|
||||||
public static SemanticModel GetSemanticModel(Compilation compilation);
|
|
||||||
public static SemanticModel GetSemanticModel(SyntaxTree syntaxTree);
|
|
||||||
|
|
||||||
// 符号查找
|
|
||||||
public static INamedTypeSymbol GetDeclaredTypeSymbol(Compilation compilation, string name);
|
|
||||||
public static IMethodSymbol GetDeclaredMethodSymbol(Compilation compilation, string name);
|
|
||||||
public static IPropertySymbol GetDeclaredPropertySymbol(Compilation compilation, string name);
|
|
||||||
|
|
||||||
// 类型解析
|
|
||||||
public static INamedTypeSymbol ResolveType(Compilation compilation, string metadataName);
|
|
||||||
public static ITypeSymbol ResolveType(Compilation compilation, Type type);
|
|
||||||
public static IMethodSymbol ResolveMethod(Compilation compilation, string methodFullName, params ITypeSymbol[] parameterTypes);
|
|
||||||
|
|
||||||
// 编译检查
|
|
||||||
public static bool HasCompilationErrors(Compilation compilation);
|
|
||||||
public static IEnumerable<Diagnostic> GetCompilationDiagnostics(Compilation compilation);
|
|
||||||
public static string GetCompilationErrors(Compilation compilation);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 配置示例
|
|
||||||
|
|
||||||
### 项目文件配置
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
|
||||||
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="GeWuYou.GFramework.SourceGenerators" Version="1.0.0" />
|
|
||||||
<PackageReference Include="GeWuYou.GFramework.SourceGenerators.Attributes" Version="1.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Remove="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 编辑器配置
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"sourceGenerators": {
|
|
||||||
"debug": true,
|
|
||||||
"logLevel": "Information",
|
|
||||||
"outputDirectory": "Generated",
|
|
||||||
"enableDocumentation": true,
|
|
||||||
"enablePerformanceLogging": false
|
|
||||||
},
|
|
||||||
"loggingGenerator": {
|
|
||||||
"defaultFieldName": "Logger",
|
|
||||||
"defaultAccessLevel": "Private",
|
|
||||||
"defaultStatic": true,
|
|
||||||
"defaultMinLevel": "None"
|
|
||||||
},
|
|
||||||
"contextAwareGenerator": {
|
|
||||||
"useLazyInit": false,
|
|
||||||
"validateContext": false
|
|
||||||
},
|
|
||||||
"enumExtensionsGenerator": {
|
|
||||||
"generateIsMethods": true,
|
|
||||||
"generateHasMethod": true,
|
|
||||||
"generateInMethod": true,
|
|
||||||
"customPrefix": "Is"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**文档版本**: 1.0.0
|
|
||||||
**更新日期**: 2026-01-12
|
|
||||||
@ -284,23 +284,23 @@ public class PlayerController : IController
|
|||||||
|
|
||||||
## 包说明
|
## 包说明
|
||||||
|
|
||||||
| 包名 | 职责 | 文档 |
|
| 包名 | 职责 | 文档 |
|
||||||
|------------------|-----------------|------------------------------------|
|
|------------------|-----------------|----------------------|
|
||||||
| **architecture** | 架构核心,管理所有组件生命周期 | [查看](/core/architecture/README.md) |
|
| **architecture** | 架构核心,管理所有组件生命周期 | [查看](./architecture) |
|
||||||
| **constants** | 框架常量定义 | 本文档 |
|
| **constants** | 框架常量定义 | 本文档 |
|
||||||
| **model** | 数据模型层,存储状态 | [查看](/core/model/README.md) |
|
| **model** | 数据模型层,存储状态 | [查看](./model) |
|
||||||
| **system** | 业务逻辑层,处理业务规则 | [查看](/core/system/README.md) |
|
| **system** | 业务逻辑层,处理业务规则 | [查看](./system) |
|
||||||
| **controller** | 控制器层,连接视图和逻辑 | (在 Abstractions 中) |
|
| **controller** | 控制器层,连接视图和逻辑 | (在 Abstractions 中) |
|
||||||
| **utility** | 工具类层,提供无状态工具 | [查看](/core/utility/README.md) |
|
| **utility** | 工具类层,提供无状态工具 | [查看](./utility) |
|
||||||
| **command** | 命令模式,封装写操作 | [查看](/core/command/README.md) |
|
| **command** | 命令模式,封装写操作 | [查看](./command) |
|
||||||
| **query** | 查询模式,封装读操作 | [查看](/core/query/README.md) |
|
| **query** | 查询模式,封装读操作 | [查看](./query) |
|
||||||
| **events** | 事件系统,组件间通信 | [查看](/core/events/README.md) |
|
| **events** | 事件系统,组件间通信 | [查看](./events) |
|
||||||
| **property** | 可绑定属性,响应式编程 | [查看](/core/property/README.md) |
|
| **property** | 可绑定属性,响应式编程 | [查看](./property) |
|
||||||
| **ioc** | IoC 容器,依赖注入 | [查看](/core/ioc/README.md) |
|
| **ioc** | IoC 容器,依赖注入 | [查看](./ioc) |
|
||||||
| **rule** | 规则接口,定义组件约束 | [查看](/core/rule/README.md) |
|
| **rule** | 规则接口,定义组件约束 | [查看](./rule) |
|
||||||
| **extensions** | 扩展方法,简化 API 调用 | [查看](/core/extensions/README.md) |
|
| **extensions** | 扩展方法,简化 API 调用 | [查看](./extensions) |
|
||||||
| **logging** | 日志系统,记录运行日志 | [查看](/core/logging/README.md) |
|
| **logging** | 日志系统,记录运行日志 | [查看](./logging) |
|
||||||
| **environment** | 环境接口,提供运行环境信息 | [查看](/core/environment/README.md) |
|
| **environment** | 环境接口,提供运行环境信息 | [查看](./environment) |
|
||||||
|
|
||||||
## 组件联动
|
## 组件联动
|
||||||
|
|
||||||
503
docs/zh-CN/game/scene-management.md
Normal file
503
docs/zh-CN/game/scene-management.md
Normal file
@ -0,0 +1,503 @@
|
|||||||
|
# 场景管理
|
||||||
|
|
||||||
|
> GFramework.Game 模块提供的场景管理功能,实现游戏场景的加载、切换和状态管理
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
GFramework.Game 提供了统一的场景管理系统,支持场景的异步加载、切换动画、状态保持等功能。通过场景管理,您可以优雅地处理游戏中的各种场景转换,如主菜单、游戏界面、设置菜单等。
|
||||||
|
|
||||||
|
## 核心特性
|
||||||
|
|
||||||
|
- **异步加载**:支持后台异步加载场景,避免卡顿
|
||||||
|
- **场景切换动画**:内置淡入淡出等切换效果
|
||||||
|
- **状态保持**:场景切换时保持必要的游戏状态
|
||||||
|
- **场景栈**:支持场景叠加(如弹出菜单)
|
||||||
|
- **资源管理**:自动管理场景资源的加载和卸载
|
||||||
|
|
||||||
|
## 基本用法
|
||||||
|
|
||||||
|
### 定义场景
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using GFramework.Game.scene;
|
||||||
|
|
||||||
|
public class GameScene : GameSceneBase
|
||||||
|
{
|
||||||
|
protected override void OnLoad()
|
||||||
|
{
|
||||||
|
// 场景加载时的初始化
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnUnload()
|
||||||
|
{
|
||||||
|
// 场景卸载时的清理
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnEnter()
|
||||||
|
{
|
||||||
|
// 进入场景
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnExit()
|
||||||
|
{
|
||||||
|
// 退出场景
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 场景管理器
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using GFramework.Game.scene;
|
||||||
|
|
||||||
|
[ContextAware]
|
||||||
|
public partial class SceneManager : Node
|
||||||
|
{
|
||||||
|
private ISceneManager _sceneManager;
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
_sceneManager = Context.GetSystem<ISceneManager>();
|
||||||
|
|
||||||
|
// 初始化场景管理器
|
||||||
|
_sceneManager.Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SwitchToGameScene()
|
||||||
|
{
|
||||||
|
await _sceneManager.SwitchSceneAsync<GameScene>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 场景加载
|
||||||
|
|
||||||
|
### 同步加载
|
||||||
|
|
||||||
|
适用于小场景的快速切换:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public void LoadMainMenu()
|
||||||
|
{
|
||||||
|
_sceneManager.SwitchScene<MainMenuScene>();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 异步加载
|
||||||
|
|
||||||
|
大场景建议使用异步加载:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public async Task LoadGameLevel(string levelName)
|
||||||
|
{
|
||||||
|
// 显示加载界面
|
||||||
|
loadingUI.Show();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 异步加载场景
|
||||||
|
await _sceneManager.SwitchSceneAsync<GameLevelScene>(scene =>
|
||||||
|
{
|
||||||
|
// 可以在这里传递场景参数
|
||||||
|
var gameScene = scene as GameLevelScene;
|
||||||
|
gameScene.LevelName = levelName;
|
||||||
|
});
|
||||||
|
|
||||||
|
GD.Print("场景加载完成");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
GD.PrintErr($"场景加载失败: {ex.Message}");
|
||||||
|
loadingUI.ShowError();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
loadingUI.Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 加载进度
|
||||||
|
|
||||||
|
监听加载进度:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public async Task LoadSceneWithProgress<TScene>() where TScene : IScene
|
||||||
|
{
|
||||||
|
loadingUI.Show();
|
||||||
|
|
||||||
|
var progress = new Progress<float>(value =>
|
||||||
|
{
|
||||||
|
loadingUI.UpdateProgress(value * 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
await _sceneManager.SwitchSceneAsync<TScene>(progress: progress);
|
||||||
|
|
||||||
|
loadingUI.Hide();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 场景切换动画
|
||||||
|
|
||||||
|
### 内置切换效果
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public async Task SwitchWithFade()
|
||||||
|
{
|
||||||
|
// 使用淡入淡出效果
|
||||||
|
await _sceneManager.SwitchSceneAsync<GameScene>(
|
||||||
|
transition: new FadeTransition(
|
||||||
|
duration: 0.5f,
|
||||||
|
fadeColor: Colors.Black
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SlideTransition()
|
||||||
|
{
|
||||||
|
// 使用滑动效果
|
||||||
|
await _sceneManager.SwitchSceneAsync<GameScene>(
|
||||||
|
transition: new SlideTransition(
|
||||||
|
direction: Vector2.Left,
|
||||||
|
duration: 0.3f
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 自定义切换动画
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class CustomTransition : ISceneTransition
|
||||||
|
{
|
||||||
|
public float Duration { get; } = 1.0f;
|
||||||
|
|
||||||
|
public async Task PlayAsync(Node fromScene, Node toScene)
|
||||||
|
{
|
||||||
|
// 自定义动画逻辑
|
||||||
|
var tween = CreateTween();
|
||||||
|
|
||||||
|
// 旧场景缩小消失
|
||||||
|
tween.TweenProperty(fromScene, "scale", Vector2.Zero, Duration / 2)
|
||||||
|
.SetTrans(Tween.TransitionType.BackIn);
|
||||||
|
|
||||||
|
await ToSignal(tween, Tween.SignalName.Finished);
|
||||||
|
|
||||||
|
fromScene.Visible = false;
|
||||||
|
toScene.Visible = true;
|
||||||
|
toScene.Scale = Vector2.Zero;
|
||||||
|
|
||||||
|
// 新场景放大出现
|
||||||
|
tween = CreateTween();
|
||||||
|
tween.TweenProperty(toScene, "scale", Vector2.One, Duration / 2)
|
||||||
|
.SetTrans(Tween.TransitionType.BackOut);
|
||||||
|
|
||||||
|
await ToSignal(tween, Tween.SignalName.Finished);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 场景栈
|
||||||
|
|
||||||
|
### 推送场景
|
||||||
|
|
||||||
|
将新场景推入栈中:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public void PushPauseMenu()
|
||||||
|
{
|
||||||
|
_sceneManager.PushScene<PauseMenuScene>();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 弹出场景
|
||||||
|
|
||||||
|
弹出栈顶场景:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public void PopScene()
|
||||||
|
{
|
||||||
|
_sceneManager.PopScene();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例:带返回的导航
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public async Task NavigateToSettings()
|
||||||
|
{
|
||||||
|
// 保存当前场景引用
|
||||||
|
var previousScene = _sceneManager.CurrentScene;
|
||||||
|
|
||||||
|
// 推入设置场景
|
||||||
|
await _sceneManager.PushSceneAsync<SettingsScene>();
|
||||||
|
|
||||||
|
// 设置场景有返回按钮
|
||||||
|
await _sceneManager.PushSceneAsync<ConfirmDialog>(
|
||||||
|
data: new ConfirmData
|
||||||
|
{
|
||||||
|
Message = "是否保存设置?",
|
||||||
|
OnConfirm = () => _sceneManager.PopScene(), // 不保存,直接返回
|
||||||
|
OnCancel = () =>
|
||||||
|
{
|
||||||
|
// 保存设置后返回
|
||||||
|
SaveSettings();
|
||||||
|
_sceneManager.PopScene();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 场景状态管理
|
||||||
|
|
||||||
|
### 保存状态
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class GameScene : GameSceneBase
|
||||||
|
{
|
||||||
|
private GameState _state;
|
||||||
|
|
||||||
|
protected override void OnLoad()
|
||||||
|
{
|
||||||
|
// 从存档加载状态
|
||||||
|
_state = LoadGameState();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnUnload()
|
||||||
|
{
|
||||||
|
// 保存状态
|
||||||
|
SaveGameState(_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnExit()
|
||||||
|
{
|
||||||
|
// 清理工作
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 跨场景数据传递
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 传递数据到新场景
|
||||||
|
await _sceneManager.SwitchSceneAsync<GameScene>(data: new GameData
|
||||||
|
{
|
||||||
|
Level = 5,
|
||||||
|
Difficulty = Difficulty.Hard,
|
||||||
|
ContinueToken = saveToken
|
||||||
|
});
|
||||||
|
|
||||||
|
// 在目标场景中接收数据
|
||||||
|
public class GameScene : GameSceneBase
|
||||||
|
{
|
||||||
|
public override void OnEnter(object data)
|
||||||
|
{
|
||||||
|
var gameData = data as GameData;
|
||||||
|
InitializeLevel(gameData.Level, gameData.Difficulty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 预加载策略
|
||||||
|
|
||||||
|
### 预加载资源
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public void PreloadCommonResources()
|
||||||
|
{
|
||||||
|
_sceneManager.PreloadScene<MainMenuScene>();
|
||||||
|
_sceneManager.PreloadScene<GameLevelScene>(count: 3);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 预加载配置
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var config = new ScenePreloadConfig
|
||||||
|
{
|
||||||
|
PreloadCount = 5,
|
||||||
|
Priority = ResourceLoader.CacheMode.Cache,
|
||||||
|
Timeout = 30.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
_sceneManager.ConfigurePreload(config);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 资源管理
|
||||||
|
|
||||||
|
### 自动卸载
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 配置自动卸载策略
|
||||||
|
var unloadConfig = new SceneUnloadConfig
|
||||||
|
{
|
||||||
|
UnloadDelay = 30.0f, // 30秒后卸载
|
||||||
|
KeepReferences = true, // 保持引用
|
||||||
|
ForceUnloadOnMemoryPressure = true // 内存紧张时强制卸载
|
||||||
|
};
|
||||||
|
|
||||||
|
_sceneManager.ConfigureUnload(unloadConfig);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 手动卸载
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 卸载指定场景
|
||||||
|
_sceneManager.UnloadScene<MainMenuScene>();
|
||||||
|
|
||||||
|
// 卸载所有场景
|
||||||
|
_sceneManager.UnloadAllScenes();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 1. 场景设计原则
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 推荐:每个场景职责单一
|
||||||
|
public class MainMenuScene : GameSceneBase { /* 主菜单 */ }
|
||||||
|
public class SettingsScene : GameSceneBase { /* 设置菜单 */ }
|
||||||
|
public class GameHUDScene : GameSceneBase { /* 游戏HUD */ }
|
||||||
|
|
||||||
|
// 避免:场景职责过多
|
||||||
|
public class MegaScene : GameSceneBase
|
||||||
|
{
|
||||||
|
/* 包含菜单、设置、HUD、存档管理... 不要这样设计 */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 场景切换优化
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 推荐:使用异步加载
|
||||||
|
public async Task LoadGame()
|
||||||
|
{
|
||||||
|
loadingUI.Show("正在加载游戏...");
|
||||||
|
await _sceneManager.SwitchSceneAsync<GameScene>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 避免:同步加载大场景
|
||||||
|
public void LoadGame()
|
||||||
|
{
|
||||||
|
// 这会导致游戏卡顿
|
||||||
|
_sceneManager.SwitchScene<GameScene>();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 内存管理
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class GameScene : GameSceneBase
|
||||||
|
{
|
||||||
|
private Texture2D[] _largeTextures;
|
||||||
|
|
||||||
|
protected override void OnLoad()
|
||||||
|
{
|
||||||
|
// 加载资源
|
||||||
|
_largeTextures = LoadLargeTextures();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnUnload()
|
||||||
|
{
|
||||||
|
// 及时释放大资源
|
||||||
|
foreach (var texture in _largeTextures)
|
||||||
|
{
|
||||||
|
texture.Dispose();
|
||||||
|
}
|
||||||
|
_largeTextures = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 错误处理
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public async Task SafeLoadScene<TScene>() where TScene : IScene
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _sceneManager.SwitchSceneAsync<TScene>();
|
||||||
|
}
|
||||||
|
catch (SceneNotFoundException)
|
||||||
|
{
|
||||||
|
Logger.Error($"场景 {typeof(TScene)} 未找到");
|
||||||
|
// 回退到默认场景
|
||||||
|
await _sceneManager.SwitchSceneAsync<FallbackScene>();
|
||||||
|
}
|
||||||
|
catch (ResourceLoadException ex)
|
||||||
|
{
|
||||||
|
Logger.Error($"资源加载失败: {ex.Message}");
|
||||||
|
await ShowRetryDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 与其他模块集成
|
||||||
|
|
||||||
|
### 与 Game 模块集成
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class GameLevelScene : GameSceneBase
|
||||||
|
{
|
||||||
|
private GameManager _gameManager;
|
||||||
|
|
||||||
|
public override void OnEnter()
|
||||||
|
{
|
||||||
|
// 初始化游戏管理器
|
||||||
|
_gameManager = Context.GetSystem<GameManager>();
|
||||||
|
_gameManager.StartGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnExit()
|
||||||
|
{
|
||||||
|
_gameManager.EndGame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 与存档系统集成
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class GameScene : GameSceneBase
|
||||||
|
{
|
||||||
|
private ISaveSystem _saveSystem;
|
||||||
|
|
||||||
|
protected override void OnLoad()
|
||||||
|
{
|
||||||
|
_saveSystem = Context.GetUtility<ISaveSystem>();
|
||||||
|
|
||||||
|
// 检查是否有自动存档
|
||||||
|
if (_saveSystem.HasAutoSave())
|
||||||
|
{
|
||||||
|
var dialog = Context.GetSystem<IDialogSystem>();
|
||||||
|
await dialog.ShowAsync("发现自动存档,是否继续?",
|
||||||
|
onConfirm: () => LoadAutoSave(),
|
||||||
|
onCancel: () => StartNewGame()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadAutoSave()
|
||||||
|
{
|
||||||
|
var saveData = _saveSystem.LoadAutoSave();
|
||||||
|
RestoreGameState(saveData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnExit()
|
||||||
|
{
|
||||||
|
// 自动保存
|
||||||
|
_saveSystem.SaveAutoSave(CreateSaveData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**相关文档**:
|
||||||
|
|
||||||
|
- [Game 概述](./overview)
|
||||||
|
- [游戏设置](./setting)
|
||||||
|
- [存储系统](./storage)
|
||||||
|
- [存档系统](../game/storage)
|
||||||
@ -348,7 +348,7 @@ public class PlayerManager
|
|||||||
|
|
||||||
## 下一步学习
|
## 下一步学习
|
||||||
|
|
||||||
- [深入了解 Architecture 组件](/core/architecture/architecture)
|
- [深入了解 Architecture 组件](./core/architecture)
|
||||||
- [掌握事件系统](/core/events/event-bus)
|
- [掌握事件系统](./core/events)
|
||||||
- [学习命令查询模式](/core/command-query/commands)
|
- [学习命令查询模式](./core/command)
|
||||||
- [探索属性系统](/core/property/bindable-property)
|
- [探索属性系统](./core/property)
|
||||||
@ -182,6 +182,6 @@ dotnet build
|
|||||||
|
|
||||||
安装完成后,建议:
|
安装完成后,建议:
|
||||||
|
|
||||||
1. [快速开始](/getting-started/quick-start) - 构建第一个应用
|
1. [快速开始](./getting-started/quick-start) - 构建第一个应用
|
||||||
2. [架构概览](/getting-started/architecture-overview) - 了解核心概念
|
2. [架构概览](./getting-started/architecture-overview) - 了解核心概念
|
||||||
3. [Core 模块文档](/core/overview) - 深入学习核心功能
|
3. [Core 模块文档](./core) - 深入学习核心功能
|
||||||
@ -321,7 +321,7 @@ Press any key to exit...
|
|||||||
|
|
||||||
接下来您可以:
|
接下来您可以:
|
||||||
|
|
||||||
- [深入了解架构组件](/core/architecture/architecture)
|
- [深入了解架构组件](./core/architecture)
|
||||||
- [学习事件系统](/core/events/event-bus)
|
- [学习事件系统](./core/events)
|
||||||
- [探索 Godot 集成](/godot/overview)(如果您使用 Godot)
|
- [探索 Godot 集成](./godot/overview)
|
||||||
- [查看完整教程](/tutorials/basic-tutorial)
|
- [查看完整教程](./tutorials/basic-tutorial)
|
||||||
406
docs/zh-CN/godot/coroutine.md
Normal file
406
docs/zh-CN/godot/coroutine.md
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
# Godot 协程系统
|
||||||
|
|
||||||
|
> GFramework 在 Godot 引擎中的协程支持,实现异步操作的优雅管理
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
GFramework.Godot 提供了与 Godot 引擎深度集成的协程系统,让异步编程变得简单直观。通过协程,您可以暂停执行、等待条件满足、或延迟执行操作,而不会阻塞主线程。
|
||||||
|
|
||||||
|
## 核心特性
|
||||||
|
|
||||||
|
- **无缝集成**:与 Godot 的 `_Process`、`_Ready` 等生命周期方法完美配合
|
||||||
|
- **类型安全**:强类型的协程返回结果处理
|
||||||
|
- **自动清理**:协程与节点生命周期自动绑定,避免内存泄漏
|
||||||
|
- **丰富的等待条件**:支持等待信号、时间延迟、帧结束等多种条件
|
||||||
|
|
||||||
|
## 基本用法
|
||||||
|
|
||||||
|
### 创建协程
|
||||||
|
|
||||||
|
使用 `StartCoroutine` 方法启动协程:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using GFramework.Godot.coroutine;
|
||||||
|
|
||||||
|
[ContextAware]
|
||||||
|
public partial class MyNode : Node
|
||||||
|
{
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
// 启动协程
|
||||||
|
this.StartCoroutine(DoSomethingAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
private System.Collections.IEnumerator DoSomethingAsync()
|
||||||
|
{
|
||||||
|
GD.Print("开始执行");
|
||||||
|
|
||||||
|
// 等待 2 秒
|
||||||
|
yield return new WaitForSeconds(2.0f);
|
||||||
|
|
||||||
|
GD.Print("2 秒后继续执行");
|
||||||
|
|
||||||
|
// 等待下一帧
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
|
||||||
|
GD.Print("下一帧继续");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 等待信号
|
||||||
|
|
||||||
|
协程可以等待 Godot 信号:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator WaitForSignalExample()
|
||||||
|
{
|
||||||
|
GD.Print("等待按钮点击");
|
||||||
|
|
||||||
|
// 等待按钮被点击
|
||||||
|
var button = GetNode<Button>("Button");
|
||||||
|
yield return new WaitSignal(button, Button.SignalName.Pressed);
|
||||||
|
|
||||||
|
GD.Print("按钮被点击了!");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 等待条件
|
||||||
|
|
||||||
|
等待自定义条件满足:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator WaitUntilCondition()
|
||||||
|
{
|
||||||
|
GD.Print("等待生命值恢复");
|
||||||
|
|
||||||
|
// 等待生命值大于 50
|
||||||
|
var playerModel = Context.GetModel<PlayerModel>();
|
||||||
|
yield return new WaitUntil(() => playerModel.Health.Value > 50);
|
||||||
|
|
||||||
|
GD.Print("生命值已恢复!");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 等待类型
|
||||||
|
|
||||||
|
### WaitForSeconds
|
||||||
|
|
||||||
|
等待指定时间(秒):
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator DelayExample()
|
||||||
|
{
|
||||||
|
GD.Print("开始倒计时");
|
||||||
|
|
||||||
|
yield return new WaitForSeconds(1.0f);
|
||||||
|
GD.Print("1 秒过去了");
|
||||||
|
|
||||||
|
yield return new WaitForSeconds(0.5f);
|
||||||
|
GD.Print("又过去了 0.5 秒");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### WaitForSecondsRealtime
|
||||||
|
|
||||||
|
等待实时时间(不受游戏暂停影响):
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator RealTimeDelay()
|
||||||
|
{
|
||||||
|
// 暂停游戏时也会继续计时
|
||||||
|
yield return new WaitForSecondsRealtime(5.0f);
|
||||||
|
|
||||||
|
GD.Print("5 秒真实时间已过");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### WaitForEndOfFrame
|
||||||
|
|
||||||
|
等待当前帧结束:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator EndOfFrameExample()
|
||||||
|
{
|
||||||
|
// 修改数据
|
||||||
|
someData.Value = 100;
|
||||||
|
|
||||||
|
// 等待帧结束后再执行渲染相关操作
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
|
||||||
|
// 现在可以安全地执行渲染操作
|
||||||
|
UpdateRendering();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### WaitUntil
|
||||||
|
|
||||||
|
等待条件满足:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator WaitUntilExample()
|
||||||
|
{
|
||||||
|
var health = Context.GetModel<PlayerModel>().Health;
|
||||||
|
|
||||||
|
// 持续等待直到条件满足
|
||||||
|
yield return new WaitUntil(() => health.Value > 0);
|
||||||
|
|
||||||
|
GD.Print("玩家复活了!");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### WaitWhile
|
||||||
|
|
||||||
|
等待条件不再满足:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator WaitWhileExample()
|
||||||
|
{
|
||||||
|
var gameState = Context.GetModel<GameModel>();
|
||||||
|
|
||||||
|
// 等待游戏不再暂停
|
||||||
|
yield return new WaitWhile(() => gameState.IsPaused.Value);
|
||||||
|
|
||||||
|
GD.Print("游戏继续");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 进阶用法
|
||||||
|
|
||||||
|
### 组合等待
|
||||||
|
|
||||||
|
可以组合多种等待条件:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator CombinedWait()
|
||||||
|
{
|
||||||
|
var health = Context.GetModel<PlayerModel>().Health;
|
||||||
|
var button = GetNode<Button>("Button");
|
||||||
|
|
||||||
|
// 等待生命值恢复或按钮点击(任一条件满足即可)
|
||||||
|
yield return new WaitAny(
|
||||||
|
new WaitUntil(() => health.Value > 50),
|
||||||
|
new WaitSignal(button, Button.SignalName.Pressed)
|
||||||
|
);
|
||||||
|
|
||||||
|
GD.Print("条件满足,继续执行");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 超时处理
|
||||||
|
|
||||||
|
为等待添加超时:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator WithTimeout()
|
||||||
|
{
|
||||||
|
var task = new WaitForSeconds(5.0f);
|
||||||
|
var timeout = new WaitForSeconds(5.0f);
|
||||||
|
|
||||||
|
// 等待任务完成,最多等 5 秒
|
||||||
|
bool completed = yield return new WaitRace(task, timeout);
|
||||||
|
|
||||||
|
if (completed)
|
||||||
|
{
|
||||||
|
GD.Print("任务完成");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GD.Print("任务超时");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 协程取消
|
||||||
|
|
||||||
|
支持取消正在执行的协程:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private CoroutineHandle _coroutine;
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
_coroutine = this.StartCoroutine(LongRunningTask());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelTask()
|
||||||
|
{
|
||||||
|
_coroutine?.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private System.Collections.IEnumerator LongRunningTask()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
GD.Print($"进度: {i}%");
|
||||||
|
yield return new WaitForSeconds(0.1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (CoroutineCancelledException)
|
||||||
|
{
|
||||||
|
GD.Print("协程被取消");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 1. 自动生命周期管理
|
||||||
|
|
||||||
|
使用 `[ContextAware]` 特性确保协程在节点离开场景树时自动取消:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[ContextAware]
|
||||||
|
public partial class MyController : Node
|
||||||
|
{
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
// 当节点离开场景树时,协程会自动取消
|
||||||
|
this.StartCoroutine(AutoCleanupCoroutine());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 避免在协程中直接修改 UI
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 不推荐:直接在协程中频繁更新 UI
|
||||||
|
private System.Collections.IEnumerator BadExample()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
label.Text = $"进度: {i}"; // 可能导致性能问题
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 推荐:使用 BindableProperty 自动更新
|
||||||
|
private System.Collections.IEnumerator GoodExample()
|
||||||
|
{
|
||||||
|
var progress = new BindableProperty<int>(0);
|
||||||
|
|
||||||
|
// 使用 BindableProperty 注册 UI 更新
|
||||||
|
progress.Register(value => label.Text = $"进度: {value}")
|
||||||
|
.UnRegisterWhenNodeExitTree(this);
|
||||||
|
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
progress.Value = i; // 自动更新 UI
|
||||||
|
yield return new WaitForEndOfFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 使用协程进行资源加载
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator LoadResourcesAsync()
|
||||||
|
{
|
||||||
|
GD.Print("开始加载资源");
|
||||||
|
|
||||||
|
// 显示加载界面
|
||||||
|
loadingScreen.Visible = true;
|
||||||
|
|
||||||
|
// 异步加载资源
|
||||||
|
var textures = new List<Texture2D>();
|
||||||
|
foreach (var path in resourcePaths)
|
||||||
|
{
|
||||||
|
var texture = ResourceLoader.LoadThreadedGet<Texture2D>(path);
|
||||||
|
|
||||||
|
// 等待每张图片加载完成
|
||||||
|
yield return new WaitUntil(() => texture.GetLoadingStatus() == ResourceLoader.Loaded);
|
||||||
|
|
||||||
|
textures.Add(texture);
|
||||||
|
|
||||||
|
// 更新加载进度
|
||||||
|
UpdateProgress(textures.Count, resourcePaths.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载完成
|
||||||
|
loadingScreen.Visible = false;
|
||||||
|
OnResourcesLoaded(textures);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 场景切换处理
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
private System.Collections.IEnumerator SceneTransitionAsync()
|
||||||
|
{
|
||||||
|
GD.Print("开始场景切换");
|
||||||
|
|
||||||
|
// 淡出当前场景
|
||||||
|
fadeAnimation.Play("FadeOut");
|
||||||
|
yield return new WaitSignal(fadeAnimation, AnimationPlayer.SignalName.AnimationFinished);
|
||||||
|
|
||||||
|
// 卸载当前场景
|
||||||
|
GetTree().CurrentScene.QueueFree();
|
||||||
|
|
||||||
|
// 加载新场景
|
||||||
|
var nextScene = ResourceLoader.Load<PackedScene>("res://scenes/NextScene.tscn");
|
||||||
|
var instance = nextScene.Instantiate();
|
||||||
|
GetTree().Root.AddChild(instance);
|
||||||
|
|
||||||
|
// 淡入新场景
|
||||||
|
fadeAnimation.Play("FadeIn");
|
||||||
|
yield return new WaitSignal(fadeAnimation, AnimationPlayer.SignalName.AnimationFinished);
|
||||||
|
|
||||||
|
GD.Print("场景切换完成");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 与 Source Generators 集成
|
||||||
|
|
||||||
|
GFramework.SourceGenerators 可以自动为您的节点生成协程相关代码:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[Log]
|
||||||
|
[ContextAware]
|
||||||
|
public partial class MyNode : Node
|
||||||
|
{
|
||||||
|
// Source Generator 会自动生成 Logger 字段
|
||||||
|
// 无需手动编写日志代码
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
Logger.Info("节点已准备就绪");
|
||||||
|
|
||||||
|
this.StartCoroutine(ComplexAsyncOperation());
|
||||||
|
}
|
||||||
|
|
||||||
|
private System.Collections.IEnumerator ComplexAsyncOperation()
|
||||||
|
{
|
||||||
|
Logger.Debug("开始复杂异步操作");
|
||||||
|
|
||||||
|
yield return new WaitForSeconds(1.0f);
|
||||||
|
|
||||||
|
Logger.Debug("操作完成");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
|
||||||
|
### Q: 协程会在游戏暂停时继续执行吗?
|
||||||
|
|
||||||
|
A: 默认情况下,`WaitForSeconds` 会受到游戏暂停的影响。如果您需要在暂停时继续计时,请使用 `WaitForSecondsRealtime`。
|
||||||
|
|
||||||
|
### Q: 如何调试协程?
|
||||||
|
|
||||||
|
A: 您可以在协程内部使用 `GD.Print()` 或 `Logger.Debug()` 来输出调试信息。VS Code 和 Rider 也支持在协程中设置断点。
|
||||||
|
|
||||||
|
### Q: 协程中出现异常会怎样?
|
||||||
|
|
||||||
|
A: 未捕获的异常会导致协程停止执行,并可能传播到调用方。建议使用 try-catch 包装可能抛出异常的代码。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**相关文档**:
|
||||||
|
|
||||||
|
- [Godot 概述](./overview)
|
||||||
|
- [Node 扩展方法](./extensions)
|
||||||
|
- [信号系统](./signal)
|
||||||
|
- [事件系统](../core/events)
|
||||||
@ -16,9 +16,6 @@ hero:
|
|||||||
- theme: alt
|
- theme: alt
|
||||||
text: 架构概览
|
text: 架构概览
|
||||||
link: /getting-started/architecture-overview
|
link: /getting-started/architecture-overview
|
||||||
- theme: alt
|
|
||||||
text: API 参考
|
|
||||||
link: /api-reference/core-api
|
|
||||||
|
|
||||||
features:
|
features:
|
||||||
- title: 🏗️ 清洁架构
|
- title: 🏗️ 清洁架构
|
||||||
|
|||||||
174
docs/zh-CN/source-generators/enum-generator.md
Normal file
174
docs/zh-CN/source-generators/enum-generator.md
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
# 枚举扩展生成器
|
||||||
|
|
||||||
|
> GFramework.SourceGenerators 自动生成枚举扩展方法
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
枚举扩展生成器为枚举类型自动生成常用的扩展方法,如获取描述、转换为字符串、解析等。这大大简化了枚举的操作。
|
||||||
|
|
||||||
|
## 基本用法
|
||||||
|
|
||||||
|
### 标记枚举
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using GFramework.SourceGenerators.Attributes;
|
||||||
|
|
||||||
|
[EnumExtensions]
|
||||||
|
public enum PlayerState
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
Running,
|
||||||
|
Jumping,
|
||||||
|
Attacking
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 生成的方法
|
||||||
|
|
||||||
|
上面的代码会被转换为:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public static class PlayerStateExtensions
|
||||||
|
{
|
||||||
|
public static string GetDescription(this PlayerState value)
|
||||||
|
{
|
||||||
|
// 返回枚举的描述
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasFlag(this PlayerState value, PlayerState flag)
|
||||||
|
{
|
||||||
|
// 检查是否包含标志
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PlayerState FromString(string value)
|
||||||
|
{
|
||||||
|
// 从字符串解析枚举
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常用方法
|
||||||
|
|
||||||
|
### 获取描述
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[EnumExtensions]
|
||||||
|
public enum ItemQuality
|
||||||
|
{
|
||||||
|
[Description("普通")]
|
||||||
|
Common,
|
||||||
|
|
||||||
|
[Description("稀有")]
|
||||||
|
Rare,
|
||||||
|
|
||||||
|
[Description("史诗")]
|
||||||
|
Epic
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PrintQuality(ItemQuality quality)
|
||||||
|
{
|
||||||
|
// 获取描述文本
|
||||||
|
Console.WriteLine(quality.GetDescription());
|
||||||
|
// 输出: "普通" / "稀有" / "史诗"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 安全解析
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public void ParseState(string input)
|
||||||
|
{
|
||||||
|
// 安全地解析字符串为枚举
|
||||||
|
if (PlayerState.Running.TryParse(input, out var state))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"状态: {state}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 获取所有值
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public void ListAllStates()
|
||||||
|
{
|
||||||
|
// 获取所有枚举值
|
||||||
|
foreach (var state in PlayerState.GetAllValues())
|
||||||
|
{
|
||||||
|
Console.WriteLine(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 标志枚举
|
||||||
|
|
||||||
|
对于使用 `[Flags]` 特性的枚举:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[EnumExtensions]
|
||||||
|
[Flags]
|
||||||
|
public enum PlayerPermissions
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Read = 1,
|
||||||
|
Write = 2,
|
||||||
|
Execute = 4,
|
||||||
|
All = Read | Write | Execute
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CheckPermissions()
|
||||||
|
{
|
||||||
|
var permissions = PlayerPermissions.Read | PlayerPermissions.Write;
|
||||||
|
|
||||||
|
// 检查是否包含特定权限
|
||||||
|
if (permissions.HasFlag(PlayerPermissions.Write))
|
||||||
|
{
|
||||||
|
Console.WriteLine("有写入权限");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有设置的标志
|
||||||
|
foreach (var flag in permissions.GetFlags())
|
||||||
|
{
|
||||||
|
Console.WriteLine($"权限: {flag}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 自定义行为
|
||||||
|
|
||||||
|
### 忽略某些值
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[EnumExtensions(IgnoreValues = new[] { ItemQuality.Undefined })]
|
||||||
|
public enum ItemQuality
|
||||||
|
{
|
||||||
|
Undefined,
|
||||||
|
Common,
|
||||||
|
Rare,
|
||||||
|
Epic
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllValues() 不会返回 Undefined
|
||||||
|
```
|
||||||
|
|
||||||
|
### 自定义转换
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[EnumExtensions(CaseSensitive = false)]
|
||||||
|
public enum Difficulty
|
||||||
|
{
|
||||||
|
Easy,
|
||||||
|
Medium,
|
||||||
|
Hard
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromString("EASY") 也能正确解析
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**相关文档**:
|
||||||
|
|
||||||
|
- [Source Generators 概述](./overview)
|
||||||
|
- [日志生成器](./logging-generator)
|
||||||
|
- [规则生成器](./rule-generator)
|
||||||
|
- [API 参考](../api-reference/source-generators-api)
|
||||||
161
docs/zh-CN/source-generators/logging-generator.md
Normal file
161
docs/zh-CN/source-generators/logging-generator.md
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
# 日志生成器
|
||||||
|
|
||||||
|
> GFramework.SourceGenerators 自动生成日志代码,减少样板代码
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
日志生成器是一个 Source Generator,它会自动为标记了 `[Log]` 特性的类生成 Logger 字段和日志方法调用。这消除了手动编写日志代码的需要,让开发者专注于业务逻辑。
|
||||||
|
|
||||||
|
## 基本用法
|
||||||
|
|
||||||
|
### 标记类
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using GFramework.SourceGenerators.Attributes;
|
||||||
|
|
||||||
|
[Log]
|
||||||
|
public partial class MyService
|
||||||
|
{
|
||||||
|
public void DoSomething()
|
||||||
|
{
|
||||||
|
// 自动生成 Logger 字段
|
||||||
|
// 自动生成日志调用
|
||||||
|
Logger.Info("执行操作");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 生成代码
|
||||||
|
|
||||||
|
上面的代码会被编译时转换为:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public partial class MyService
|
||||||
|
{
|
||||||
|
// 自动生成的字段
|
||||||
|
[CompilerGenerated]
|
||||||
|
private ILogger _logger;
|
||||||
|
|
||||||
|
// 自动生成的属性
|
||||||
|
[CompilerGenerated]
|
||||||
|
public ILogger Logger
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_logger == null)
|
||||||
|
{
|
||||||
|
_logger = LoggerFactory.CreateLogger<MyService>();
|
||||||
|
}
|
||||||
|
return _logger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 日志级别
|
||||||
|
|
||||||
|
生成的日志方法支持多种级别:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[Log]
|
||||||
|
public partial class MyClass
|
||||||
|
{
|
||||||
|
public void Example()
|
||||||
|
{
|
||||||
|
// 调试信息
|
||||||
|
Logger.Debug($"调试信息: {value}");
|
||||||
|
|
||||||
|
// 普通信息
|
||||||
|
Logger.Info("操作成功");
|
||||||
|
|
||||||
|
// 警告
|
||||||
|
Logger.Warning($"警告: {message}");
|
||||||
|
|
||||||
|
// 错误
|
||||||
|
Logger.Error($"错误: {ex.Message}");
|
||||||
|
|
||||||
|
// 严重错误
|
||||||
|
Logger.Critical("系统故障");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 自定义日志类别
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[Log(LogCategory.Gameplay)]
|
||||||
|
public partial class GameplaySystem
|
||||||
|
{
|
||||||
|
// 日志会标记为 Gameplay 类别
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
Logger.Info("游戏逻辑更新");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 与其他模块集成
|
||||||
|
|
||||||
|
### 与 Godot 集成
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[Log]
|
||||||
|
[ContextAware]
|
||||||
|
public partial class GodotController : Node
|
||||||
|
{
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
Logger.Info("控制器已准备就绪");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 与架构集成
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[Log]
|
||||||
|
public partial class MySystem : AbstractSystem
|
||||||
|
{
|
||||||
|
protected override void OnInit()
|
||||||
|
{
|
||||||
|
Logger.Info("系统初始化");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置选项
|
||||||
|
|
||||||
|
### 禁用自动生成
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 禁用自动日志调用生成
|
||||||
|
[Log(AutoLog = false)]
|
||||||
|
public partial class MyClass
|
||||||
|
{
|
||||||
|
// 仍会生成 Logger 字段,但不会自动生成日志调用
|
||||||
|
public void DoSomething()
|
||||||
|
{
|
||||||
|
// 需要手动调用 Logger
|
||||||
|
Logger.Info("手动日志");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 自定义字段名称
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[Log(FieldName = "_customLogger")]
|
||||||
|
public partial class MyClass
|
||||||
|
{
|
||||||
|
// Logger 字段名称为 _customLogger
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**相关文档**:
|
||||||
|
|
||||||
|
- [Source Generators 概述](./overview)
|
||||||
|
- [枚举扩展生成器](./enum-generator)
|
||||||
|
- [规则生成器](./rule-generator)
|
||||||
|
- [API 参考](../api-reference/source-generators-api)
|
||||||
164
docs/zh-CN/source-generators/rule-generator.md
Normal file
164
docs/zh-CN/source-generators/rule-generator.md
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
# 规则生成器
|
||||||
|
|
||||||
|
> GFramework.SourceGenerators 自动生成规则验证代码
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
规则生成器为实现了规则接口的类型自动生成验证方法。这使得规则定义更加简洁,并确保规则的一致性。
|
||||||
|
|
||||||
|
## 基本用法
|
||||||
|
|
||||||
|
### 定义规则
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using GFramework.SourceGenerators.Attributes;
|
||||||
|
|
||||||
|
[RuleFor(typeof(Player))]
|
||||||
|
public class PlayerRule : IRule<Player>
|
||||||
|
{
|
||||||
|
public RuleResult Validate(Player player)
|
||||||
|
{
|
||||||
|
if (player.Health <= 0)
|
||||||
|
{
|
||||||
|
return RuleResult.Invalid("玩家生命值不能为零或负数");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(player.Name))
|
||||||
|
{
|
||||||
|
return RuleResult.Invalid("玩家名称不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
return RuleResult.Valid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 使用生成的验证器
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class PlayerValidator
|
||||||
|
{
|
||||||
|
// 自动生成 Validate 方法
|
||||||
|
public void ValidatePlayer(Player player)
|
||||||
|
{
|
||||||
|
var result = PlayerRuleValidator.Validate(player);
|
||||||
|
|
||||||
|
if (!result.IsValid)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"验证失败: {result.ErrorMessage}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 组合规则
|
||||||
|
|
||||||
|
### 多规则组合
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[RuleFor(typeof(Player), RuleCombinationType.And)]
|
||||||
|
public class PlayerHealthRule : IRule<Player>
|
||||||
|
{
|
||||||
|
public RuleResult Validate(Player player)
|
||||||
|
{
|
||||||
|
if (player.Health <= 0)
|
||||||
|
return RuleResult.Invalid("生命值必须大于0");
|
||||||
|
return RuleResult.Valid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[RuleFor(typeof(Player), RuleCombinationType.And)]
|
||||||
|
public class PlayerNameRule : IRule<Player>
|
||||||
|
{
|
||||||
|
public RuleResult Validate(Player player)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(player.Name))
|
||||||
|
return RuleResult.Invalid("名称不能为空");
|
||||||
|
return RuleResult.Valid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 验证所有规则
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public void ValidateAll(Player player)
|
||||||
|
{
|
||||||
|
var results = PlayerRuleValidator.ValidateAll(player);
|
||||||
|
|
||||||
|
foreach (var result in results)
|
||||||
|
{
|
||||||
|
if (!result.IsValid)
|
||||||
|
{
|
||||||
|
Console.WriteLine(result.ErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 异步规则
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[RuleFor(typeof(Player), IsAsync = true)]
|
||||||
|
public class AsyncPlayerRule : IAsyncRule<Player>
|
||||||
|
{
|
||||||
|
public async Task<RuleResult> ValidateAsync(Player player)
|
||||||
|
{
|
||||||
|
// 异步验证,如检查服务器
|
||||||
|
var isBanned = await CheckBanStatus(player.Id);
|
||||||
|
|
||||||
|
if (isBanned)
|
||||||
|
{
|
||||||
|
return RuleResult.Invalid("玩家已被封禁");
|
||||||
|
}
|
||||||
|
|
||||||
|
return RuleResult.Valid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 1. 单一职责
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 推荐:每个规则只验证一个方面
|
||||||
|
[RuleFor(typeof(Player))]
|
||||||
|
public class PlayerHealthRule : IRule<Player> { }
|
||||||
|
|
||||||
|
[RuleFor(typeof(Player))]
|
||||||
|
public class PlayerNameRule : IRule<Player> { }
|
||||||
|
|
||||||
|
// 避免:在一个规则中验证多个方面
|
||||||
|
[RuleFor(typeof(Player))]
|
||||||
|
public class PlayerMegaRule : IRule<Player>
|
||||||
|
{
|
||||||
|
public RuleResult Validate(Player player)
|
||||||
|
{
|
||||||
|
// 验证健康、名称、等级...
|
||||||
|
// 不要这样设计
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 清晰的错误信息
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public RuleResult Validate(Player player)
|
||||||
|
{
|
||||||
|
// 推荐:具体的错误信息
|
||||||
|
return RuleResult.Invalid($"玩家 {player.Name} 的生命值 {player.Health} 不能小于 1");
|
||||||
|
|
||||||
|
// 避免:模糊的错误信息
|
||||||
|
return RuleResult.Invalid("无效的玩家");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**相关文档**:
|
||||||
|
|
||||||
|
- [Source Generators 概述](./overview)
|
||||||
|
- [日志生成器](./logging-generator)
|
||||||
|
- [枚举扩展生成器](./enum-generator)
|
||||||
|
- [API 参考](../api-reference/source-generators-api)
|
||||||
@ -437,9 +437,9 @@ dotnet test
|
|||||||
|
|
||||||
### 学习资源
|
### 学习资源
|
||||||
|
|
||||||
- [GFramework 主文档](/)
|
- [GFramework 主文档](../)
|
||||||
- [Core 模块文档](/core/overview)
|
- [Core 模块文档](../core)
|
||||||
- [Godot 集成文档](/godot/overview)
|
- [Godot 集成文档](../godot/overview)
|
||||||
- [API 参考](/api-reference/core-api)
|
- [API 参考](../api-reference/core-api)
|
||||||
|
|
||||||
享受游戏开发的乐趣吧!🎮
|
享受游戏开发的乐趣吧!🎮
|
||||||
Loading…
x
Reference in New Issue
Block a user