docs(architecture): 更新架构设计模式指南文档

- 将标题从"架构模式最佳实践"改为"架构设计模式指南"
- 添加全面的架构设计模式介绍和概述
- 新增MVC模式详细说明,包括概念、GFramework实现示例和最佳实践
- 新增MVVM模式详细说明,包括概念、GFramework实现示例和最佳实践
- 新增命令模式详细说明,包括概念、实现示例和撤销功能支持
- 新增查询模式详细说明,包括CQRS概念和复杂查询示例
- 新增事件驱动模式详细说明,包括事件定义和监听实现
- 新增依赖注入模式详细说明,包括构造函数注入示例
- 新增服务定位器模式详细说明,包括与依赖注入对比
- 新增对象池模式详细说明,包括通用对象池实现
- 新增状态模式详细说明,包括异步状态和状态机系统
- 补充模式选择与组合建议,针对小型、中型、大型项目提供不同方案
- 更新代码示例中的泛型语法格式,统一使用尖括号表示法
This commit is contained in:
GeWuYou 2026-03-07 17:32:26 +08:00
parent 739565d278
commit 9edf64193f
10 changed files with 12018 additions and 84 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,384 @@
---
title: 移动平台优化指南
description: 针对移动平台的性能优化、内存管理和电池优化最佳实践
---
# 移动平台优化指南
## 概述
移动平台游戏开发面临着独特的挑战:有限的内存、较弱的处理器、电池续航限制、触摸输入、多样的屏幕尺寸等。本指南将帮助你使用
GFramework 开发高性能的移动游戏,提供针对性的优化策略和最佳实践。
**移动平台的主要限制**
- **内存限制**:移动设备内存通常在 2-8GB远低于 PC
- **CPU 性能**:移动 CPU 性能较弱,且受热量限制
- **GPU 性能**:移动 GPU 功能有限,填充率和带宽受限
- **电池续航**:高性能运行会快速消耗电池
- **存储空间**:应用包大小受限,用户存储空间有限
- **网络环境**:移动网络不稳定,延迟较高
**优化目标**
- 减少内存占用(目标:<200MB
- 降低 CPU 使用率(目标:<30%
- 优化 GPU 渲染目标60 FPS
- 延长电池续航目标3+ 小时)
- 减小包体大小(目标:<100MB
## 核心概念
### 1. 内存管理
移动设备内存有限,需要精细管理:
```csharp
// 监控内存使用
public class MemoryMonitor : AbstractSystem
{
private const long MemoryWarningThreshold = 150 * 1024 * 1024; // 150MB
private const long MemoryCriticalThreshold = 200 * 1024 * 1024; // 200MB
protected override void OnInit()
{
this.RegisterEvent<GameUpdateEvent>(OnUpdate);
}
private void OnUpdate(GameUpdateEvent e)
{
// 每 5 秒检查一次内存
if (e.TotalTime % 5.0 < e.DeltaTime)
{
CheckMemoryUsage();
}
}
private void CheckMemoryUsage()
{
var memoryUsage = GC.GetTotalMemory(false);
if (memoryUsage > MemoryCriticalThreshold)
{
// 内存严重不足,强制清理
SendEvent(new MemoryCriticalEvent());
ForceMemoryCleanup();
}
else if (memoryUsage > MemoryWarningThreshold)
{
// 内存警告,温和清理
SendEvent(new MemoryWarningEvent());
SoftMemoryCleanup();
}
}
private void ForceMemoryCleanup()
{
// 卸载不必要的资源
var resourceManager = this.GetUtility<IResourceManager>();
resourceManager.UnloadUnusedResources();
// 清理对象池
var poolSystem = this.GetSystem<ObjectPoolSystem>();
poolSystem.TrimPools();
// 强制 GC
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
private void SoftMemoryCleanup()
{
// 温和清理:只清理明确不需要的资源
var resourceManager = this.GetUtility<IResourceManager>();
resourceManager.UnloadUnusedResources();
}
}
```
### 2. 性能分析
使用性能分析工具识别瓶颈:
```csharp
public class PerformanceProfiler : AbstractSystem
{
private readonly Dictionary<string, PerformanceMetrics> _metrics = new();
public IDisposable Profile(string name)
{
return new ProfileScope(name, this);
}
private void RecordMetric(string name, double duration)
{
if (!_metrics.TryGetValue(name, out var metrics))
{
metrics = new PerformanceMetrics();
_metrics[name] = metrics;
}
metrics.AddSample(duration);
}
public void PrintReport()
{
Console.WriteLine("\n=== 性能报告 ===");
foreach (var (name, metrics) in _metrics.OrderByDescending(x => x.Value.AverageMs))
{
Console.WriteLine($"{name}:");
Console.WriteLine($" 平均: {metrics.AverageMs:F2}ms");
Console.WriteLine($" 最大: {metrics.MaxMs:F2}ms");
Console.WriteLine($" 最小: {metrics.MinMs:F2}ms");
Console.WriteLine($" 调用次数: {metrics.SampleCount}");
}
}
private class ProfileScope : IDisposable
{
private readonly string _name;
private readonly PerformanceProfiler _profiler;
private readonly Stopwatch _stopwatch;
public ProfileScope(string name, PerformanceProfiler profiler)
{
_name = name;
_profiler = profiler;
_stopwatch = Stopwatch.StartNew();
}
public void Dispose()
{
_stopwatch.Stop();
_profiler.RecordMetric(_name, _stopwatch.Elapsed.TotalMilliseconds);
}
}
}
// 使用示例
public class GameSystem : AbstractSystem
{
private PerformanceProfiler _profiler;
protected override void OnInit()
{
_profiler = this.GetSystem<PerformanceProfiler>();
}
private void UpdateGame()
{
using (_profiler.Profile("GameUpdate"))
{
// 游戏更新逻辑
}
}
}
```
### 3. 电池优化
减少不必要的计算和渲染:
```csharp
public class PowerSavingSystem : AbstractSystem
{
private bool _isPowerSavingMode;
private int _targetFrameRate = 60;
protected override void OnInit()
{
this.RegisterEvent<BatteryLowEvent>(OnBatteryLow);
this.RegisterEvent<BatteryNormalEvent>(OnBatteryNormal);
}
private void OnBatteryLow(BatteryLowEvent e)
{
EnablePowerSavingMode();
}
private void OnBatteryNormal(BatteryNormalEvent e)
{
DisablePowerSavingMode();
}
private void EnablePowerSavingMode()
{
_isPowerSavingMode = true;
// 降低帧率
_targetFrameRate = 30;
Application.targetFrameRate = _targetFrameRate;
// 降低渲染质量
QualitySettings.SetQualityLevel(0);
// 减少粒子效果
SendEvent(new ReduceEffectsEvent());
// 暂停非关键系统
PauseNonCriticalSystems();
Console.WriteLine("省电模式已启用");
}
private void DisablePowerSavingMode()
{
_isPowerSavingMode = false;
// 恢复帧率
_targetFrameRate = 60;
Application.targetFrameRate = _targetFrameRate;
// 恢复渲染质量
QualitySettings.SetQualityLevel(2);
// 恢复粒子效果
SendEvent(new RestoreEffectsEvent());
// 恢复非关键系统
ResumeNonCriticalSystems();
Console.WriteLine("省电模式已禁用");
}
private void PauseNonCriticalSystems()
{
// 暂停动画系统
var animationSystem = this.GetSystem<AnimationSystem>();
animationSystem?.Pause();
// 暂停音效系统(保留音乐)
var audioSystem = this.GetSystem<AudioSystem>();
audioSystem?.PauseSoundEffects();
}
private void ResumeNonCriticalSystems()
{
var animationSystem = this.GetSystem<AnimationSystem>();
animationSystem?.Resume();
var audioSystem = this.GetSystem<AudioSystem>();
audioSystem?.ResumeSoundEffects();
}
}
```
## 内存优化
### 1. 资源管理策略
实现智能资源加载和卸载:
```csharp
public class MobileResourceManager : AbstractSystem
{
private readonly IResourceManager _resourceManager;
private readonly Dictionary<string, ResourcePriority> _resourcePriorities = new();
private readonly HashSet<string> _loadedResources = new();
public MobileResourceManager(IResourceManager resourceManager)
{
_resourceManager = resourceManager;
}
protected override void OnInit()
{
// 配置资源优先级
ConfigureResourcePriorities();
// 监听场景切换事件
this.RegisterEvent<SceneChangedEvent>(OnSceneChanged);
// 监听内存警告
this.RegisterEvent<MemoryWarningEvent>(OnMemoryWarning);
}
private void ConfigureResourcePriorities()
{
// 高优先级UI、玩家资源
_resourcePriorities["ui/"] = ResourcePriority.High;
_resourcePriorities["player/"] = ResourcePriority.High;
// 中优先级:敌人、道具
_resourcePriorities["enemy/"] = ResourcePriority.Medium;
_resourcePriorities["item/"] = ResourcePriority.Medium;
// 低优先级:特效、装饰
_resourcePriorities["effect/"] = ResourcePriority.Low;
_resourcePriorities["decoration/"] = ResourcePriority.Low;
}
public async Task<T> LoadResourceAsync<T>(string path) where T : class
{
// 检查内存
if (IsMemoryLow())
{
// 内存不足,先清理低优先级资源
UnloadLowPriorityResources();
}
var resource = await _resourceManager.LoadAsync<T>(path);
_loadedResources.Add(path);
return resource;
}
private void OnSceneChanged(SceneChangedEvent e)
{
// 场景切换时,卸载旧场景资源
UnloadSceneResources(e.PreviousScene);
// 预加载新场景资源
PreloadSceneResources(e.NewScene);
}
private void OnMemoryWarning(MemoryWarningEvent e)
{
// 内存警告,卸载低优先级资源
UnloadLowPriorityResources();
}
private void UnloadLowPriorityResources()
{
var resourcesToUnload = _loadedResources
.Where(path => GetResourcePriority(path) == ResourcePriority.Low)
.ToList();
foreach (var path in resourcesToUnload)
{
_resourceManager.Unload(path);
_loadedResources.Remove(path);
}
Console.WriteLine($"卸载了 {resourcesToUnload.Count} 个低优先级资源");
}
private ResourcePriority GetResourcePriority(string path)
{
foreach (var (prefix, priority) in _resourcePriorities)
{
if (path.StartsWith(prefix))
return priority;
}
return ResourcePriority.Medium;
}
private bool IsMemoryLow()
{
var memoryUsage = GC.GetTotalMemory(false);
return memoryUsage > 150 * 1024 * 1024; // 150MB
}
}
public enum ResourcePriority
{
Low,
Medium,
High
}
```
### 2. 纹理压缩和优化

View File

@ -0,0 +1,546 @@
# 多人游戏架构指南
> 基于 GFramework 架构设计高性能、可扩展的多人游戏系统。
## 📋 目录
- [概述](#概述)
- [核心概念](#核心概念)
- [架构设计](#架构设计)
- [状态管理](#状态管理)
- [命令模式与输入处理](#命令模式与输入处理)
- [事件同步](#事件同步)
- [网络优化](#网络优化)
- [安全考虑](#安全考虑)
- [最佳实践](#最佳实践)
- [常见问题](#常见问题)
## 概述
多人游戏开发面临着单机游戏所没有的独特挑战:
### 主要挑战
1. **网络延迟** - 玩家操作和服务器响应之间存在不可避免的延迟
2. **状态同步** - 确保所有客户端看到一致的游戏状态
3. **带宽限制** - 需要高效传输游戏数据,避免网络拥塞
4. **作弊防护** - 防止客户端篡改游戏逻辑和数据
5. **并发处理** - 同时处理多个玩家的输入和状态更新
6. **断线重连** - 优雅处理网络中断和玩家重新连接
### GFramework 的优势
GFramework 的架构设计天然适合多人游戏开发:
- **分层架构** - 清晰分离客户端逻辑、网络层和服务器逻辑
- **事件系统** - 松耦合的事件驱动架构便于状态同步
- **命令模式** - 统一的输入处理和验证机制
- **Model-System 分离** - 数据和逻辑分离便于状态管理
- **模块化设计** - 网络功能可以作为独立模块集成
## 核心概念
### 1. 客户端-服务器架构
```csharp
// 服务器架构
public class ServerArchitecture : Architecture
{
protected override void Init()
{
// 注册服务器专用的 Model
RegisterModel(new ServerGameStateModel());
RegisterModel(new PlayerConnectionModel());
// 注册服务器专用的 System
RegisterSystem(new ServerNetworkSystem());
RegisterSystem(new AuthorityGameLogicSystem());
RegisterSystem(new StateReplicationSystem());
RegisterSystem(new AntiCheatSystem());
// 注册工具
RegisterUtility(new NetworkUtility());
RegisterUtility(new ValidationUtility());
}
}
// 客户端架构
public class ClientArchitecture : Architecture
{
protected override void Init()
{
// 注册客户端专用的 Model
RegisterModel(new ClientGameStateModel());
RegisterModel(new PredictionModel());
// 注册客户端专用的 System
RegisterSystem(new ClientNetworkSystem());
RegisterSystem(new PredictionSystem());
RegisterSystem(new InterpolationSystem());
RegisterSystem(new ClientInputSystem());
// 注册工具
RegisterUtility(new NetworkUtility());
}
}
```
### 2. 状态同步策略
#### 状态同步 (State Synchronization)
服务器定期向客户端发送完整的游戏状态。
```csharp
// 游戏状态快照
public struct GameStateSnapshot
{
public uint Tick { get; set; }
public long Timestamp { get; set; }
public PlayerState[] Players { get; set; }
public EntityState[] Entities { get; set; }
}
public struct PlayerState
{
public string PlayerId { get; set; }
public Vector3 Position { get; set; }
public Quaternion Rotation { get; set; }
public int Health { get; set; }
public PlayerAnimationState AnimationState { get; set; }
}
// 状态复制系统
public class StateReplicationSystem : AbstractSystem
{
private ServerGameStateModel _gameState;
private PlayerConnectionModel _connections;
private uint _currentTick;
protected override void OnInit()
{
_gameState = this.GetModel<ServerGameStateModel>();
_connections = this.GetModel<PlayerConnectionModel>();
// 每个 tick 复制状态
this.RegisterEvent<ServerTickEvent>(OnServerTick);
}
private void OnServerTick(ServerTickEvent e)
{
_currentTick++;
// 创建状态快照
var snapshot = CreateSnapshot();
// 发送给所有连接的客户端
foreach (var connection in _connections.ActiveConnections)
{
SendSnapshotToClient(connection, snapshot);
}
}
private GameStateSnapshot CreateSnapshot()
{
return new GameStateSnapshot
{
Tick = _currentTick,
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
Players = _gameState.Players.Select(p => new PlayerState
{
PlayerId = p.Id,
Position = p.Position,
Rotation = p.Rotation,
Health = p.Health,
AnimationState = p.AnimationState
}).ToArray(),
Entities = _gameState.Entities.Select(e => CreateEntityState(e)).ToArray()
};
}
}
```
#### 增量同步 (Delta Synchronization)
只发送状态变化,减少带宽消耗。
```csharp
// 增量状态
public struct DeltaState
{
public uint Tick { get; set; }
public uint BaseTick { get; set; }
public PlayerDelta[] PlayerDeltas { get; set; }
public EntityDelta[] EntityDeltas { get; set; }
}
public struct PlayerDelta
{
public string PlayerId { get; set; }
public DeltaFlags Flags { get; set; }
public Vector3? Position { get; set; }
public Quaternion? Rotation { get; set; }
public int? Health { get; set; }
}
[Flags]
public enum DeltaFlags
{
None = 0,
Position = 1 << 0,
Rotation = 1 << 1,
Health = 1 << 2,
Animation = 1 << 3
}
// 增量复制系统
public class DeltaReplicationSystem : AbstractSystem
{
private readonly Dictionary<uint, GameStateSnapshot> _snapshotHistory = new();
private const int MaxHistorySize = 60; // 保留 60 个快照
protected override void OnInit()
{
this.RegisterEvent<ServerTickEvent>(OnServerTick);
}
private void OnServerTick(ServerTickEvent e)
{
var currentSnapshot = CreateSnapshot();
_snapshotHistory[e.Tick] = currentSnapshot;
// 清理旧快照
CleanupOldSnapshots(e.Tick);
// 为每个客户端生成增量
foreach (var connection in GetConnections())
{
var lastAckedTick = connection.LastAcknowledgedTick;
if (_snapshotHistory.TryGetValue(lastAckedTick, out var baseSnapshot))
{
var delta = CreateDelta(baseSnapshot, currentSnapshot);
SendDeltaToClient(connection, delta);
}
else
{
// 客户端太落后,发送完整快照
SendSnapshotToClient(connection, currentSnapshot);
}
}
}
private DeltaState CreateDelta(GameStateSnapshot baseSnapshot, GameStateSnapshot currentSnapshot)
{
var delta = new DeltaState
{
Tick = currentSnapshot.Tick,
BaseTick = baseSnapshot.Tick,
PlayerDeltas = new List<PlayerDelta>()
};
// 比较玩家状态
foreach (var currentPlayer in currentSnapshot.Players)
{
var basePlayer = baseSnapshot.Players.FirstOrDefault(p => p.PlayerId == currentPlayer.PlayerId);
if (basePlayer.PlayerId == null)
{
// 新玩家,发送完整状态
delta.PlayerDeltas.Add(CreateFullPlayerDelta(currentPlayer));
}
else
{
// 计算差异
var playerDelta = CreatePlayerDelta(basePlayer, currentPlayer);
if (playerDelta.Flags != DeltaFlags.None)
{
delta.PlayerDeltas.Add(playerDelta);
}
}
}
return delta;
}
private PlayerDelta CreatePlayerDelta(PlayerState baseState, PlayerState currentState)
{
var delta = new PlayerDelta { PlayerId = currentState.PlayerId };
if (Vector3.Distance(baseState.Position, currentState.Position) > 0.01f)
{
delta.Flags |= DeltaFlags.Position;
delta.Position = currentState.Position;
}
if (Quaternion.Angle(baseState.Rotation, currentState.Rotation) > 0.1f)
{
delta.Flags |= DeltaFlags.Rotation;
delta.Rotation = currentState.Rotation;
}
if (baseState.Health != currentState.Health)
{
delta.Flags |= DeltaFlags.Health;
delta.Health = currentState.Health;
}
return delta;
}
}
```
### 3. 客户端预测与回滚
客户端立即响应玩家输入,然后在收到服务器确认后进行校正。
```csharp
// 输入命令
public struct PlayerInputCommand
{
public uint Tick { get; set; }
public long Timestamp { get; set; }
public Vector2 MoveDirection { get; set; }
public Vector2 LookDirection { get; set; }
public InputFlags Flags { get; set; }
}
[Flags]
public enum InputFlags
{
None = 0,
Jump = 1 << 0,
Attack = 1 << 1,
Interact = 1 << 2,
Reload = 1 << 3
}
// 客户端预测系统
public class ClientPredictionSystem : AbstractSystem
{
private PredictionModel _prediction;
private ClientGameStateModel _gameState;
private readonly Queue<PlayerInputCommand> _pendingInputs = new();
private uint _lastProcessedServerTick;
protected override void OnInit()
{
_prediction = this.GetModel<PredictionModel>();
_gameState = this.GetModel<ClientGameStateModel>();
this.RegisterEvent<PlayerInputEvent>(OnPlayerInput);
this.RegisterEvent<ServerStateReceivedEvent>(OnServerStateReceived);
}
private void OnPlayerInput(PlayerInputEvent e)
{
var input = new PlayerInputCommand
{
Tick = _prediction.CurrentTick,
Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
MoveDirection = e.MoveDirection,
LookDirection = e.LookDirection,
Flags = e.Flags
};
// 保存输入用于重放
_pendingInputs.Enqueue(input);
// 立即应用预测
ApplyInput(input);
// 发送到服务器
SendInputToServer(input);
}
private void OnServerStateReceived(ServerStateReceivedEvent e)
{
_lastProcessedServerTick = e.Snapshot.Tick;
// 应用服务器状态
ApplyServerState(e.Snapshot);
// 移除已确认的输入
while (_pendingInputs.Count > 0 && _pendingInputs.Peek().Tick <= e.Snapshot.Tick)
{
_pendingInputs.Dequeue();
}
// 重放未确认的输入
ReplayPendingInputs();
}
private void ApplyInput(PlayerInputCommand input)
{
var player = _gameState.LocalPlayer;
// 应用移动
var movement = input.MoveDirection * player.Speed * Time.DeltaTime;
player.Position += new Vector3(movement.X, 0, movement.Y);
// 应用旋转
if (input.LookDirection != Vector2.Zero)
{
player.Rotation = Quaternion.LookRotation(
new Vector3(input.LookDirection.X, 0, input.LookDirection.Y)
);
}
// 应用动作
if ((input.Flags & InputFlags.Jump) != 0 && player.IsGrounded)
{
player.Velocity = new Vector3(player.Velocity.X, player.JumpForce, player.Velocity.Z);
}
}
private void ReplayPendingInputs()
{
// 从服务器状态开始重放所有未确认的输入
var savedState = SavePlayerState();
foreach (var input in _pendingInputs)
{
ApplyInput(input);
}
}
}
```
## 架构设计
### 1. 分离逻辑层
```csharp
// 共享游戏逻辑 (客户端和服务器都使用)
public class SharedGameLogic
{
public static void ProcessMovement(PlayerState player, Vector2 moveDirection, float deltaTime)
{
var movement = moveDirection.Normalized() * player.Speed * deltaTime;
player.Position += new Vector3(movement.X, 0, movement.Y);
}
public static bool CanJump(PlayerState player)
{
return player.IsGrounded && !player.IsStunned;
}
public static int CalculateDamage(int attackPower, int defense, float criticalChance)
{
var baseDamage = Math.Max(1, attackPower - defense);
var isCritical = Random.Shared.NextDouble() < criticalChance;
return isCritical ? baseDamage * 2 : baseDamage;
}
}
// 服务器权威逻辑
public class ServerGameLogicSystem : AbstractSystem
{
private ServerGameStateModel _gameState;
protected override void OnInit()
{
_gameState = this.GetModel<ServerGameStateModel>();
this.RegisterEvent<PlayerInputReceivedEvent>(OnPlayerInputReceived);
this.RegisterEvent<AttackRequestEvent>(OnAttackRequest);
}
private void OnPlayerInputReceived(PlayerInputReceivedEvent e)
{
var player = _gameState.GetPlayer(e.PlayerId);
// 验证输入
if (!ValidateInput(e.Input))
{
SendInputRejection(e.PlayerId, "Invalid input");
return;
}
// 应用共享逻辑
SharedGameLogic.ProcessMovement(player, e.Input.MoveDirection, Time.DeltaTime);
// 服务器端验证
if ((e.Input.Flags & InputFlags.Jump) != 0)
{
if (SharedGameLogic.CanJump(player))
{
player.Velocity = new Vector3(player.Velocity.X, player.JumpForce, player.Velocity.Z);
}
}
}
private void OnAttackRequest(AttackRequestEvent e)
{
var attacker = _gameState.GetPlayer(e.AttackerId);
var target = _gameState.GetPlayer(e.TargetId);
// 服务器端验证
if (!CanAttack(attacker, target))
{
return;
}
// 计算伤害
var damage = SharedGameLogic.CalculateDamage(
attacker.AttackPower,
target.Defense,
attacker.CriticalChance
);
// 应用伤害
target.Health = Math.Max(0, target.Health - damage);
// 广播事件
this.SendEvent(new PlayerDamagedEvent
{
AttackerId = e.AttackerId,
TargetId = e.TargetId,
Damage = damage,
RemainingHealth = target.Health
});
if (target.Health == 0)
{
this.SendEvent(new PlayerDiedEvent
{
PlayerId = e.TargetId,
KillerId = e.AttackerId
});
}
}
}
// 客户端表现逻辑
public class ClientPresentationSystem : AbstractSystem
{
protected override void OnInit()
{
this.RegisterEvent<PlayerDamagedEvent>(OnPlayerDamaged);
this.RegisterEvent<PlayerDiedEvent>(OnPlayerDied);
}
private void OnPlayerDamaged(PlayerDamagedEvent e)
{
// 播放受击特效
PlayDamageEffect(e.TargetId, e.Damage);
// 播放受击音效
PlayDamageSound(e.TargetId);
// 更新 UI
UpdateHealthBar(e.TargetId, e.RemainingHealth);
}
private void OnPlayerDied(PlayerDiedEvent e)
{
// 播放死亡动画
PlayDeathAnimation(e.PlayerId);
// 播放死亡音效
PlayDeathSound(e.PlayerId);
// 显示击杀提示
ShowKillFeed(e.KillerId, e.PlayerId);
}
}

File diff suppressed because it is too large Load Diff

839
docs/zh-CN/contributing.md Normal file
View File

@ -0,0 +1,839 @@
# 贡献指南
欢迎为 GFramework 贡献代码!本指南将帮助你了解如何参与项目开发。
## 概述
GFramework 是一个开源的游戏开发框架,我们欢迎所有形式的贡献:
- 报告 Bug 和提出功能建议
- 提交代码修复和新功能
- 改进文档和示例
- 参与讨论和代码审查
## 行为准则
### 社区规范
我们致力于为所有贡献者提供友好、安全和包容的环境。参与本项目时,请遵守以下准则:
- **尊重他人**:尊重不同的观点和经验
- **建设性沟通**:提供有建设性的反馈,避免人身攻击
- **协作精神**:帮助新贡献者融入社区
- **专业态度**:保持专业和礼貌的交流方式
### 不可接受的行为
- 使用性别化语言或图像
- 人身攻击或侮辱性评论
- 骚扰行为(公开或私下)
- 未经许可发布他人的私人信息
- 其他不道德或不专业的行为
## 如何贡献
### 报告问题
发现 Bug 或有功能建议时,请通过 GitHub Issues 提交:
1. **搜索现有 Issue**:避免重复提交
2. **使用清晰的标题**:简洁描述问题
3. **提供详细信息**
- Bug 报告:复现步骤、预期行为、实际行为、环境信息
- 功能建议:使用场景、预期效果、可能的实现方案
**Bug 报告模板**
```markdown
**描述**
简要描述 Bug
**复现步骤**
1. 执行操作 A
2. 执行操作 B
3. 观察到错误
**预期行为**
应该发生什么
**实际行为**
实际发生了什么
**环境信息**
- GFramework 版本:
- .NET 版本:
- 操作系统:
- Godot 版本(如适用):
**附加信息**
日志、截图等
```
### 提交 Pull Request
#### 基本流程
1. **Fork 仓库**:在 GitHub 上 Fork 本项目
2. **克隆到本地**
```bash
git clone https://github.com/your-username/GFramework.git
cd GFramework
```
3. **创建特性分支**
```bash
git checkout -b feature/your-feature-name
# 或
git checkout -b fix/your-bug-fix
```
4. **进行开发**:编写代码、添加测试、更新文档
5. **提交更改**:遵循提交规范(见下文)
6. **推送分支**
```bash
git push origin feature/your-feature-name
```
7. **创建 PR**:在 GitHub 上创建 Pull Request
#### PR 要求
- **清晰的标题**:简洁描述变更内容
- **详细的描述**
- 变更的背景和动机
- 实现方案说明
- 测试验证结果
- 相关 Issue 链接(如有)
- **代码质量**:通过所有 CI 检查
- **测试覆盖**:为新功能添加测试
- **文档更新**:更新相关文档
### 改进文档
文档改进同样重要:
- **修正错误**:拼写、语法、技术错误
- **补充示例**:添加代码示例和使用场景
- **完善说明**:改进不清晰的描述
- **翻译工作**:帮助翻译文档(如需要)
文档位于 `docs/` 目录,使用 Markdown 格式编写。
## 开发环境设置
### 前置要求
- **.NET SDK**8.0、9.0 或 10.0
- **Git**:版本控制工具
- **IDE**(推荐):
- Visual Studio 2022+
- JetBrains Rider
- Visual Studio Code + C# Dev Kit
### 克隆仓库
```bash
# 克隆你 Fork 的仓库
git clone https://github.com/your-username/GFramework.git
cd GFramework
# 添加上游仓库
git remote add upstream https://github.com/GeWuYou/GFramework.git
```
### 安装依赖
```bash
# 恢复 NuGet 包
dotnet restore
# 恢复 .NET 本地工具
dotnet tool restore
```
### 构建项目
```bash
# 构建所有项目
dotnet build
# 构建特定配置
dotnet build -c Release
```
### 运行测试
```bash
# 运行所有测试
dotnet test
# 运行特定测试项目
dotnet test GFramework.Core.Tests
dotnet test GFramework.SourceGenerators.Tests
# 生成测试覆盖率报告
dotnet test --collect:"XPlat Code Coverage"
```
### 验证代码质量
项目使用 MegaLinter 进行代码质量检查:
```bash
# 本地运行 MegaLinter需要 Docker
docker run --rm -v $(pwd):/tmp/lint oxsecurity/megalinter:v9
# 或使用 CI 流程验证
git push origin your-branch
```
## 代码规范
### 命名规范
遵循 C# 标准命名约定:
- **类、接口、方法**PascalCase
```csharp
public class PlayerController { }
public interface IEventBus { }
public void ProcessInput() { }
```
- **私有字段**_camelCase下划线前缀
```csharp
private int _health;
private readonly ILogger _logger;
```
- **参数、局部变量**camelCase
```csharp
public void SetHealth(int newHealth)
{
var oldHealth = _health;
_health = newHealth;
}
```
- **常量**PascalCase
```csharp
public const int MaxPlayers = 4;
private const string DefaultName = "Player";
```
- **接口**I 前缀
```csharp
public interface IArchitecture { }
public interface ICommand<TInput> { }
```
### 代码风格
- **缩进**4 个空格(不使用 Tab
- **大括号**Allman 风格(独占一行)
```csharp
if (condition)
{
DoSomething();
}
```
- **using 指令**:文件顶部,按字母顺序排列
```csharp
using System;
using System.Collections.Generic;
using GFramework.Core.Abstractions;
```
- **空行**
- 命名空间后空一行
- 类成员之间空一行
- 逻辑块之间适当空行
- **行长度**:建议不超过 120 字符
### 注释规范
#### XML 文档注释
所有公共 API 必须包含 XML 文档注释:
```csharp
/// <summary>
/// 架构基类,提供系统、模型、工具等组件的注册与管理功能。
/// </summary>
/// <typeparam name="TModel">模型类型</typeparam>
/// <param name="configuration">架构配置</param>
/// <returns>注册的模型实例</returns>
/// <exception cref="ArgumentNullException">当 model 为 null 时抛出</exception>
public TModel RegisterModel<TModel>(TModel model) where TModel : IModel
{
// 实现代码
}
```
#### 代码注释
- **何时添加注释**
- 复杂的算法逻辑
- 非显而易见的设计决策
- 临时解决方案(使用 TODO 或 HACK 标记)
- 性能关键代码的优化说明
- **注释风格**
```csharp
// 单行注释使用双斜杠
// 多行注释可以使用多个单行注释
// 每行都以双斜杠开始
/* 或使用块注释
* 适用于较长的说明
*/
```
- **避免无用注释**
```csharp
// 不好:注释重复代码内容
// 设置健康值为 100
health = 100;
// 好:解释为什么这样做
// 初始化时设置满血,避免首次战斗时的边界情况
health = MaxHealth;
```
### 设计原则
- **SOLID 原则**:遵循面向对象设计原则
- **依赖注入**:优先使用构造函数注入
- **接口隔离**:定义小而专注的接口
- **不可变性**:优先使用 `readonly` 和不可变类型
- **异步编程**I/O 操作使用 `async`/`await`
## 提交规范
### Commit 消息格式
使用 Conventional Commits 规范:
```
<type>(<scope>): <subject>
<body>
<footer>
```
#### Type类型
- **feat**:新功能
- **fix**Bug 修复
- **docs**:文档更新
- **style**:代码格式调整(不影响功能)
- **refactor**:重构(不是新功能也不是修复)
- **perf**:性能优化
- **test**:添加或修改测试
- **chore**:构建过程或辅助工具的变动
- **ci**CI 配置文件和脚本的变动
#### Scope范围
指明变更影响的模块:
- `core`GFramework.Core
- `game`GFramework.Game
- `godot`GFramework.Godot
- `generators`:源码生成器
- `docs`:文档
- `tests`:测试
#### Subject主题
- 使用祈使句,现在时态:"add" 而不是 "added" 或 "adds"
- 首字母小写
- 结尾不加句号
- 限制在 50 字符以内
#### Body正文
- 详细描述变更的动机和实现细节
- 与主题空一行
- 每行不超过 72 字符
#### Footer页脚
- 关联 Issue`Closes #123`
- 破坏性变更:`BREAKING CHANGE: 描述`
#### 示例
```bash
# 简单提交
git commit -m "feat(core): add event priority support"
# 详细提交
git commit -m "fix(godot): resolve scene loading race condition
修复了在快速切换场景时可能出现的资源加载竞态条件。
通过引入场景加载锁机制,确保同一时间只有一个场景在加载。
Closes #456"
# 破坏性变更
git commit -m "refactor(core): change IArchitecture interface
BREAKING CHANGE: IArchitecture.Init() 现在返回 Task 而不是 void。
所有继承 Architecture 的类需要更新为异步初始化。
Migration guide: 将 Init() 改为 async Task Init()
"
```
### 分支策略
- **main**:主分支,保持稳定
- **feature/***:新功能分支
- `feature/event-priority`
- `feature/godot-ui-system`
- **fix/***Bug 修复分支
- `fix/memory-leak`
- `fix/null-reference`
- **docs/***:文档更新分支
- `docs/api-reference`
- `docs/tutorial-update`
- **refactor/***:重构分支
- `refactor/logging-system`
#### 分支命名规范
- 使用小写字母和连字符
- 简洁描述分支目的
- 避免使用个人名称
## 测试要求
### 单元测试
所有新功能和 Bug 修复都应包含单元测试:
```csharp
using Xunit;
namespace GFramework.Core.Tests.events;
public class EventBusTests
{
[Fact]
public void Subscribe_ShouldReceiveEvent()
{
// Arrange
var eventBus = new EventBus();
var received = false;
// Act
eventBus.Subscribe&lt;TestEvent&gt;(e =&gt; received = true);
eventBus.Publish(new TestEvent());
// Assert
Assert.True(received);
}
[Theory]
[InlineData(1)]
[InlineData(10)]
[InlineData(100)]
public void Subscribe_MultipleEvents_ShouldReceiveAll(int count)
{
// 测试实现
}
}
```
### 测试组织
- **测试项目**`*.Tests` 后缀
- **测试类**`*Tests` 后缀,与被测试类对应
- **测试方法**`MethodName_Scenario_ExpectedResult` 格式
- **测试数据**:使用 `[Theory]``[InlineData]` 进行参数化测试
### 测试覆盖率
- **目标**:新代码覆盖率 &gt; 80%
- **关键路径**:核心功能覆盖率 &gt; 90%
- **边界情况**:测试异常情况和边界值
### 集成测试
对于涉及多个组件交互的功能,添加集成测试:
```csharp
public class ArchitectureIntegrationTests
{
[Fact]
public async Task Architecture_FullLifecycle_ShouldWork()
{
// Arrange
var architecture = new TestArchitecture();
// Act
await architecture.InitAsync();
var result = architecture.GetModel&lt;TestModel&gt;();
await architecture.DestroyAsync();
// Assert
Assert.NotNull(result);
}
}
```
### 性能测试
对性能敏感的代码,添加基准测试:
```csharp
using BenchmarkDotNet.Attributes;
[MemoryDiagnoser]
public class EventBusBenchmarks
{
private EventBus _eventBus;
[GlobalSetup]
public void Setup()
{
_eventBus = new EventBus();
}
[Benchmark]
public void Publish_1000Events()
{
for (int i = 0; i &lt; 1000; i++)
{
_eventBus.Publish(new TestEvent());
}
}
}
```
## 文档要求
### XML 注释
所有公共 API 必须包含完整的 XML 文档注释:
```csharp
/// &lt;summary&gt;
/// 事件总线接口,提供事件的发布和订阅功能。
/// &lt;/summary&gt;
/// &lt;remarks&gt;
/// 事件总线使用观察者模式实现,支持类型安全的事件分发。
/// 所有订阅都是弱引用,避免内存泄漏。
/// &lt;/remarks&gt;
public interface IEventBus
{
/// &lt;summary&gt;
/// 订阅指定类型的事件。
/// &lt;/summary&gt;
/// &lt;typeparam name="TEvent"&gt;事件类型&lt;/typeparam&gt;
/// &lt;param name="handler"&gt;事件处理器&lt;/param&gt;
/// &lt;returns&gt;取消订阅的句柄&lt;/returns&gt;
/// &lt;exception cref="ArgumentNullException"&gt;当 handler 为 null 时抛出&lt;/exception&gt;
/// &lt;example&gt;
/// &lt;code&gt;
/// var unregister = eventBus.Subscribe&amp;lt;PlayerDiedEvent&amp;gt;(e =&amp;gt;
/// {
/// Console.WriteLine($"Player {e.PlayerId} died");
/// });
///
/// // 取消订阅
/// unregister.Dispose();
/// &lt;/code&gt;
/// &lt;/example&gt;
IUnRegister Subscribe&lt;TEvent&gt;(Action&lt;TEvent&gt; handler) where TEvent : IEvent;
}
```
### Markdown 文档
#### 文档结构
```markdown
# 标题
简要介绍模块功能和用途。
## 核心概念
解释关键概念和术语。
## 快速开始
提供最简单的使用示例。
## 详细用法
### 功能 A
详细说明和代码示例。
### 功能 B
详细说明和代码示例。
## 最佳实践
推荐的使用模式和注意事项。
## 常见问题
FAQ 列表。
## 相关资源
链接到相关文档和示例。
```
#### 代码示例
- **完整性**:示例代码应该可以直接运行
- **注释**:关键步骤添加注释说明
- **格式化**:使用正确的语法高亮
```csharp
// 创建架构实例
var architecture = new GameArchitecture();
// 初始化架构
await architecture.InitAsync();
// 注册模型
var playerModel = architecture.GetModel&lt;PlayerModel&gt;();
// 发送命令
await architecture.SendCommandAsync(new AttackCommand
{
TargetId = enemyId
});
```
#### 图表
使用 Mermaid 或 ASCII 图表说明复杂概念:
```markdown
```mermaid
graph TD
A[Controller] --&gt; B[Command]
B --&gt; C[System]
C --&gt; D[Model]
```
```
## PR 流程
### 创建 PR
1. **确保分支最新**
```bash
git fetch upstream
git rebase upstream/main
```
2. **推送到 Fork**
```bash
git push origin feature/your-feature
```
3. **创建 PR**
- 在 GitHub 上点击 "New Pull Request"
- 选择 base: `main` ← compare: `your-branch`
- 填写 PR 模板
### PR 模板
```markdown
## 变更说明
简要描述本 PR 的变更内容。
## 变更类型
- [ ] Bug 修复
- [ ] 新功能
- [ ] 破坏性变更
- [ ] 文档更新
- [ ] 性能优化
- [ ] 代码重构
## 相关 Issue
Closes #123
## 测试
描述如何测试这些变更:
- [ ] 添加了单元测试
- [ ] 添加了集成测试
- [ ] 手动测试通过
## 检查清单
- [ ] 代码遵循项目规范
- [ ] 添加了必要的注释
- [ ] 更新了相关文档
- [ ] 所有测试通过
- [ ] 没有引入新的警告
## 截图(如适用)
添加截图或 GIF 展示变更效果。
## 附加说明
其他需要说明的内容。
```
### 代码审查
PR 提交后,维护者会进行代码审查:
- **响应反馈**:及时回复审查意见
- **修改代码**:根据建议进行调整
- **讨论方案**:对有争议的地方进行讨论
- **保持耐心**:审查可能需要时间
#### 审查关注点
- **功能正确性**:代码是否实现了预期功能
- **代码质量**:是否遵循项目规范
- **测试覆盖**:是否有足够的测试
- **性能影响**:是否有性能问题
- **向后兼容**:是否破坏现有 API
### 合并流程
1. **通过 CI 检查**:所有自动化测试通过
2. **代码审查通过**:至少一位维护者批准
3. **解决冲突**:如有冲突需先解决
4. **合并方式**
- 功能分支Squash and merge
- 修复分支Merge commit
- 文档更新Squash and merge
## 常见问题
### 如何同步上游更新?
```bash
# 获取上游更新
git fetch upstream
# 合并到本地 main
git checkout main
git merge upstream/main
# 更新你的 Fork
git push origin main
# 更新特性分支
git checkout feature/your-feature
git rebase main
```
### 如何解决合并冲突?
```bash
# 拉取最新代码
git fetch upstream
git rebase upstream/main
# 如果有冲突,手动解决后
git add .
git rebase --continue
# 强制推送(因为 rebase 改变了历史)
git push origin feature/your-feature --force-with-lease
```
### 提交了错误的代码怎么办?
```bash
# 修改最后一次提交
git add .
git commit --amend
# 或者撤销最后一次提交
git reset --soft HEAD~1
# 修改后重新提交
git add .
git commit -m "fix: correct implementation"
```
### 如何运行特定的测试?
```bash
# 运行单个测试类
dotnet test --filter "FullyQualifiedName~EventBusTests"
# 运行单个测试方法
dotnet test --filter "FullyQualifiedName~EventBusTests.Subscribe_ShouldReceiveEvent"
# 运行特定类别的测试
dotnet test --filter "Category=Integration"
```
### 如何生成文档?
```bash
# 安装 VitePress如果还没安装
cd docs
npm install
# 本地预览文档
npm run docs:dev
# 构建文档
npm run docs:build
```
### 代码审查需要多长时间?
- **简单修复**:通常 1-3 天
- **新功能**:可能需要 1-2 周
- **大型重构**:可能需要更长时间
请耐心等待,维护者会尽快审查。
### 我的 PR 被拒绝了怎么办?
不要气馁!被拒绝的原因可能是:
- 不符合项目方向
- 需要更多讨论
- 实现方式需要调整
你可以:
- 在 Issue 中讨论方案
- 根据反馈调整实现
- 寻求维护者的建议
### 如何成为维护者?
持续贡献高质量的代码和文档,积极参与社区讨论,帮助其他贡献者。维护者会邀请活跃且负责任的贡献者加入维护团队。
## 获取帮助
如果你在贡献过程中遇到问题:
- **GitHub Issues**:提问或报告问题
- **GitHub Discussions**:参与讨论
- **代码注释**:查看现有代码的注释和文档
## 致谢
感谢所有为 GFramework 做出贡献的开发者!你们的努力让这个项目变得更好。
## 许可证
通过向本项目提交代码,你同意你的贡献将在 Apache License 2.0 下发布。

View File

@ -0,0 +1,950 @@
# 版本迁移指南
本文档提供 GFramework 不同版本之间的迁移指导,帮助开发者平滑升级到新版本。
## 概述
### 迁移指南的使用
本迁移指南旨在帮助开发者:
- **了解版本间的重大变更**:明确不同版本之间的 API 变化和行为差异
- **规划迁移路径**:根据项目实际情况选择合适的迁移策略
- **减少迁移风险**:通过详细的步骤说明和代码示例降低升级风险
- **快速定位问题**:提供常见问题的解决方案和回滚策略
### 阅读建议
1. **确认当前版本**:查看项目中使用的 GFramework 版本号
2. **查看目标版本**:确定要升级到的目标版本
3. **阅读相关章节**:重点关注涉及的版本迁移章节
4. **测试验证**:在测试环境中完成迁移并充分测试
5. **逐步升级**:对于跨多个大版本的升级,建议分步进行
## 版本兼容性
### 版本号说明
GFramework 遵循 [语义化版本](https://semver.org/lang/zh-CN/) 规范:
```
主版本号.次版本号.修订号 (MAJOR.MINOR.PATCH)
```
- **主版本号MAJOR**:不兼容的 API 变更
- **次版本号MINOR**:向后兼容的功能新增
- **修订号PATCH**:向后兼容的问题修正
### 兼容性矩阵
| 源版本 | 目标版本 | 兼容性 | 迁移难度 | 说明 |
|-------|-------|---------|------|---------------|
| 0.0.x | 0.0.y | ✅ 完全兼容 | 低 | 修订版本,直接升级 |
| 0.0.x | 1.0.0 | ⚠️ 部分兼容 | 中 | 需要代码调整 |
| 0.x.x | 1.x.x | ❌ 不兼容 | 高 | 重大变更,需要重构 |
| 1.x.x | 1.y.y | ✅ 向后兼容 | 低 | 次版本升级,可能有废弃警告 |
| 1.x.x | 2.0.0 | ❌ 不兼容 | 高 | 重大变更,需要重构 |
### .NET 版本支持
| GFramework 版本 | .NET 8.0 | .NET 9.0 | .NET 10.0 |
|---------------|----------|----------|-----------|
| 0.0.x | ✅ | ✅ | ✅ |
| 1.0.x | ✅ | ✅ | ✅ |
| 2.0.x | ❌ | ✅ | ✅ |
### Godot 版本支持
| GFramework 版本 | Godot 4.3 | Godot 4.4 | Godot 4.5 | Godot 4.6+ |
|---------------|-----------|-----------|-----------|------------|
| 0.0.x | ✅ | ✅ | ✅ | ✅ |
| 1.0.x | ❌ | ✅ | ✅ | ✅ |
| 2.0.x | ❌ | ❌ | ✅ | ✅ |
## 从 0.x 迁移到 1.x
### 重大变更概述
1.0 版本是 GFramework 的第一个稳定版本,引入了多项重大变更以提升框架的稳定性、性能和可维护性。
#### 架构层面变更
- **架构初始化方式变更**:统一使用异步初始化
- **生命周期阶段调整**:简化阶段流程,移除冗余阶段
- **IOC 容器增强**:支持作用域和生命周期管理
- **模块系统重构**:引入新的模块注册机制
#### API 变更
- **命名空间调整**:部分类型移动到新的命名空间
- **接口签名变更**:部分接口方法签名调整
- **废弃 API 移除**:移除 0.x 中标记为废弃的 API
- **泛型约束调整**:部分泛型方法增加或调整约束
#### 行为变更
- **事件传播机制**:优化事件传播逻辑
- **协程调度策略**:改进协程调度算法
- **资源管理策略**:引入新的资源释放策略
### 迁移前准备
#### 1. 备份项目
```bash
# 创建项目备份
git checkout -b backup-before-migration
git push origin backup-before-migration
# 或使用文件系统备份
cp -r YourProject YourProject-backup
```
#### 2. 检查当前版本
```bash
# 查看当前使用的 GFramework 版本
dotnet list package | grep GFramework
```
#### 3. 更新依赖工具
```bash
# 更新 .NET SDK
dotnet --version
# 更新 NuGet 客户端
dotnet nuget --version
```
#### 4. 运行现有测试
```bash
# 确保所有测试通过
dotnet test
# 记录测试结果作为基准
dotnet test --logger "trx;LogFileName=baseline-tests.trx"
```
### 迁移步骤
#### 步骤 1更新 NuGet 包
```bash
# 更新核心包
dotnet add package GeWuYou.GFramework.Core --version 1.0.0
dotnet add package GeWuYou.GFramework.Core.Abstractions --version 1.0.0
# 更新游戏扩展包
dotnet add package GeWuYou.GFramework.Game --version 1.0.0
dotnet add package GeWuYou.GFramework.Game.Abstractions --version 1.0.0
# 更新 Godot 集成包(如果使用)
dotnet add package GeWuYou.GFramework.Godot --version 1.0.0
# 更新源码生成器
dotnet add package GeWuYou.GFramework.SourceGenerators --version 1.0.0
```
#### 步骤 2更新命名空间引用
**0.x 版本:**
```csharp
using GFramework.Core;
using GFramework.Core.Architecture;
using GFramework.Core.Events;
```
**1.x 版本:**
```csharp
using GFramework.Core.Abstractions.Architecture;
using GFramework.Core.Abstractions.Events;
using GFramework.Core.Architecture;
using GFramework.Core.Events;
```
#### 步骤 3更新架构初始化代码
**0.x 版本:**
```csharp
public class GameArchitecture : Architecture
{
protected override void Init()
{
RegisterModel(new PlayerModel());
RegisterSystem(new GameplaySystem());
}
}
// 同步初始化
var architecture = new GameArchitecture();
architecture.Initialize();
```
**1.x 版本:**
```csharp
public class GameArchitecture : Architecture
{
protected override void Init()
{
RegisterModel(new PlayerModel());
RegisterSystem(new GameplaySystem());
}
}
// 推荐使用异步初始化
var architecture = new GameArchitecture();
await architecture.InitializeAsync();
// 或者使用同步初始化(不推荐)
// architecture.Initialize();
```
#### 步骤 4更新事件注册代码
**0.x 版本:**
```csharp
// 注册事件
this.RegisterEvent&lt;PlayerDiedEvent&gt;(OnPlayerDied);
// 发送事件
this.SendEvent(new PlayerDiedEvent());
```
**1.x 版本:**
```csharp
// 注册事件API 保持兼容)
this.RegisterEvent&lt;PlayerDiedEvent&gt;(OnPlayerDied);
// 发送事件API 保持兼容)
this.SendEvent(new PlayerDiedEvent());
// 新增:带优先级的事件注册
this.RegisterEvent&lt;PlayerDiedEvent&gt;(OnPlayerDied, priority: 100);
```
#### 步骤 5更新命令和查询代码
**0.x 版本:**
```csharp
public class MovePlayerCommand : AbstractCommand
{
public Vector2 Direction { get; set; }
protected override void OnDo()
{
// 执行逻辑
}
}
// 发送命令
this.SendCommand(new MovePlayerCommand { Direction = direction });
```
**1.x 版本:**
```csharp
// 命令 API 保持兼容
public class MovePlayerCommand : AbstractCommand
{
public Vector2 Direction { get; set; }
protected override void OnDo()
{
// 执行逻辑
}
}
// 发送命令API 保持兼容)
this.SendCommand(new MovePlayerCommand { Direction = direction });
// 新增:异步命令支持
public class LoadDataCommand : AbstractAsyncCommand
{
protected override async Task OnDoAsync()
{
await Task.Delay(100);
}
}
```
#### 步骤 6更新 IOC 容器使用
**0.x 版本:**
```csharp
// 注册服务
RegisterUtility(new StorageUtility());
// 获取服务
var storage = this.GetUtility&lt;StorageUtility&gt;();
```
**1.x 版本:**
```csharp
// 注册服务API 保持兼容)
RegisterUtility(new StorageUtility());
// 获取服务API 保持兼容)
var storage = this.GetUtility&lt;StorageUtility&gt;();
// 新增:按优先级获取服务
var storages = this.GetUtilities&lt;IStorageUtility&gt;();
var primaryStorage = storages.FirstOrDefault();
```
#### 步骤 7更新协程代码
**0.x 版本:**
```csharp
// 启动协程
var handle = CoroutineHelper.Start(MyCoroutine());
// 等待协程
yield return new WaitForCoroutine(handle);
```
**1.x 版本:**
```csharp
// 启动协程API 保持兼容)
var handle = CoroutineHelper.Start(MyCoroutine());
// 等待协程API 保持兼容)
yield return new WaitForCoroutine(handle);
// 新增:协程分组和优先级
var handle = CoroutineHelper.Start(
MyCoroutine(),
group: "gameplay",
priority: CoroutinePriority.High
);
```
### API 变更详解
#### 废弃的 API
以下 API 在 1.0 版本中已被移除:
##### 1. 同步命令查询扩展(已废弃)
**0.x 版本:**
```csharp
// 这些方法在 1.0 中已移除
this.SendCommandSync(command);
this.SendQuerySync(query);
```
**1.x 版本:**
```csharp
// 使用标准方法
this.SendCommand(command);
this.SendQuery(query);
// 或使用异步方法
await this.SendCommandAsync(command);
await this.SendQueryAsync(query);
```
##### 2. 旧版事件 API已废弃
**0.x 版本:**
```csharp
// 旧版事件注册方式
EventBus.Register&lt;MyEvent&gt;(handler);
```
**1.x 版本:**
```csharp
// 使用新的事件注册方式
this.RegisterEvent&lt;MyEvent&gt;(handler);
// 或使用事件总线
this.GetEventBus().Register&lt;MyEvent&gt;(handler);
```
##### 3. 直接访问 IOC 容器(已限制)
**0.x 版本:**
```csharp
// 直接访问容器
var container = architecture.Container;
container.Register&lt;IService, ServiceImpl&gt;();
```
**1.x 版本:**
```csharp
// 使用架构提供的注册方法
architecture.RegisterUtility&lt;IService&gt;(new ServiceImpl());
// 或在 Init 方法中注册
protected override void Init()
{
RegisterUtility&lt;IService&gt;(new ServiceImpl());
}
```
#### 新增的 API
##### 1. 优先级支持
```csharp
// 事件优先级
this.RegisterEvent&lt;MyEvent&gt;(handler, priority: 100);
// 服务优先级
RegisterUtility&lt;IService&gt;(service, priority: 10);
// 协程优先级
CoroutineHelper.Start(routine, priority: CoroutinePriority.High);
```
##### 2. 异步初始化增强
```csharp
// 异步初始化架构
await architecture.InitializeAsync();
// 等待架构就绪
await architecture.WaitUntilReadyAsync();
// 异步初始化组件
public class MyModel : AbstractModel, IAsyncInitializable
{
public async Task InitializeAsync()
{
await LoadDataAsync();
}
}
```
##### 3. 事件过滤和统计
```csharp
// 事件过滤
this.RegisterEvent&lt;MyEvent&gt;(handler, filter: e => e.IsValid);
// 事件统计
var stats = eventBus.GetStatistics();
Console.WriteLine($"Total events: {stats.TotalEventsSent}");
```
##### 4. 协程分组管理
```csharp
// 创建协程组
var handle = CoroutineHelper.Start(
routine,
group: "ui-animations"
);
// 暂停协程组
CoroutineHelper.PauseGroup("ui-animations");
// 恢复协程组
CoroutineHelper.ResumeGroup("ui-animations");
// 停止协程组
CoroutineHelper.StopGroup("ui-animations");
```
### 配置变更
#### 架构配置
**0.x 版本:**
```csharp
var architecture = new GameArchitecture();
```
**1.x 版本:**
```csharp
// 使用配置对象
var config = new ArchitectureConfiguration
{
ArchitectureProperties = new ArchitectureProperties
{
StrictPhaseValidation = true,
AllowLateRegistration = false
},
LoggerProperties = new LoggerProperties
{
MinimumLevel = LogLevel.Information
}
};
var architecture = new GameArchitecture(configuration: config);
```
#### 日志配置
**0.x 版本:**
```csharp
// 使用默认日志
```
**1.x 版本:**
```csharp
// 配置日志系统
var logConfig = new LoggingConfiguration
{
MinimumLevel = LogLevel.Debug,
Appenders = new List&lt;ILogAppender&gt;
{
new ConsoleAppender(),
new FileAppender("logs/game.log")
},
Filters = new List&lt;ILogFilter&gt;
{
new LogLevelFilter(LogLevel.Warning),
new NamespaceFilter("GFramework.*")
}
};
```
### 依赖变更
#### NuGet 包更新
| 包名 | 0.x 版本 | 1.x 版本 | 变更说明 |
|------------------------------------------|--------|--------|----------|
| Microsoft.Extensions.DependencyInjection | 8.0.0 | 10.0.3 | 升级到最新版本 |
| Arch | 1.x | 2.1.0 | ECS 框架升级 |
| Arch.System | 1.0.x | 1.1.0 | 系统组件升级 |
#### 包拆分
1.0 版本对包结构进行了优化:
**0.x 版本:**
```xml
<PackageReference Include="GeWuYou.GFramework" Version="0.0.200" />
```
**1.x 版本:**
```xml
<!-- 推荐按需引用 -->
<PackageReference Include="GeWuYou.GFramework.Core" Version="1.0.0" />
<PackageReference Include="GeWuYou.GFramework.Core.Abstractions" Version="1.0.0" />
<PackageReference Include="GeWuYou.GFramework.Game" Version="1.0.0" />
<PackageReference Include="GeWuYou.GFramework.Godot" Version="1.0.0" />
```
### 代码迁移工具
#### 自动化迁移工具
GFramework 提供了迁移工具来自动化部分迁移工作:
```bash
# 安装迁移工具
dotnet tool install -g GFramework.MigrationTool
# 运行迁移分析
gframework-migrate analyze --project YourProject.csproj
# 执行自动迁移
gframework-migrate apply --project YourProject.csproj --target-version 1.0.0
# 生成迁移报告
gframework-migrate report --output migration-report.html
```
#### 手动迁移检查清单
使用以下清单确保完整迁移:
- [ ] 更新所有 NuGet 包到 1.0.0
- [ ] 更新命名空间引用
- [ ] 替换废弃的 API
- [ ] 更新架构初始化代码
- [ ] 更新配置代码
- [ ] 运行所有单元测试
- [ ] 运行集成测试
- [ ] 执行性能测试
- [ ] 更新文档和注释
- [ ] 代码审查
### 测试迁移
#### 单元测试更新
**0.x 版本:**
```csharp
[Test]
public void TestArchitectureInit()
{
var architecture = new TestArchitecture();
architecture.Initialize();
Assert.That(architecture.CurrentPhase, Is.EqualTo(ArchitecturePhase.Ready));
}
```
**1.x 版本:**
```csharp
[Test]
public async Task TestArchitectureInit()
{
var architecture = new TestArchitecture();
await architecture.InitializeAsync();
Assert.That(architecture.CurrentPhase, Is.EqualTo(ArchitecturePhase.Ready));
}
```
#### 集成测试更新
**0.x 版本:**
```csharp
[Test]
public void TestGameFlow()
{
var game = new GameArchitecture();
game.Initialize();
game.SendCommand(new StartGameCommand());
var score = game.SendQuery(new GetScoreQuery());
Assert.That(score, Is.EqualTo(0));
}
```
**1.x 版本:**
```csharp
[Test]
public async Task TestGameFlow()
{
var game = new GameArchitecture();
await game.InitializeAsync();
await game.SendCommandAsync(new StartGameCommand());
var score = await game.SendQueryAsync(new GetScoreQuery());
Assert.That(score, Is.EqualTo(0));
}
```
## 常见问题
### 编译错误
#### 问题 1命名空间找不到
**错误信息:**
```
error CS0246: The type or namespace name 'IArchitecture' could not be found
```
**解决方案:**
```csharp
// 添加正确的命名空间引用
using GFramework.Core.Abstractions.Architecture;
```
#### 问题 2方法签名不匹配
**错误信息:**
```
error CS1501: No overload for method 'RegisterEvent' takes 1 arguments
```
**解决方案:**
```csharp
// 0.x 版本
this.RegisterEvent&lt;MyEvent&gt;(handler);
// 1.x 版本(兼容)
this.RegisterEvent&lt;MyEvent&gt;(handler);
// 1.x 版本(带优先级)
this.RegisterEvent&lt;MyEvent&gt;(handler, priority: 100);
```
#### 问题 3泛型约束不满足
**错误信息:**
```
error CS0311: The type 'MyType' cannot be used as type parameter 'T'
in the generic type or method. There is no implicit reference conversion
from 'MyType' to 'GFramework.Core.Abstractions.IModel'.
```
**解决方案:**
```csharp
// 确保类型实现了正确的接口
public class MyModel : AbstractModel, IModel
{
// 实现
}
```
### 运行时错误
#### 问题 1架构未初始化
**错误信息:**
```
InvalidOperationException: Architecture is not initialized
```
**解决方案:**
```csharp
// 确保在使用前初始化架构
var architecture = new GameArchitecture();
await architecture.InitializeAsync();
await architecture.WaitUntilReadyAsync();
// 然后再使用
this.SendCommand(new MyCommand());
```
#### 问题 2服务未注册
**错误信息:**
```
InvalidOperationException: Service of type 'IMyService' is not registered
```
**解决方案:**
```csharp
// 在 Init 方法中注册服务
protected override void Init()
{
RegisterUtility&lt;IMyService&gt;(new MyServiceImpl());
}
```
#### 问题 3事件处理器未触发
**问题描述:**
事件发送后,注册的处理器没有被调用。
**解决方案:**
```csharp
// 确保事件处理器正确注册
var unregister = this.RegisterEvent&lt;MyEvent&gt;(OnMyEvent);
// 确保在对象销毁时注销
protected override void OnDestroy()
{
unregister?.UnRegister();
}
// 检查事件类型是否匹配
this.SendEvent(new MyEvent()); // 确保类型完全一致
```
### 性能问题
#### 问题 1初始化时间过长
**问题描述:**
架构初始化耗时明显增加。
**解决方案:**
```csharp
// 使用异步初始化
await architecture.InitializeAsync();
// 对于耗时的初始化操作,使用异步方法
public class MyModel : AbstractModel, IAsyncInitializable
{
public async Task InitializeAsync()
{
// 异步加载数据
await LoadDataAsync();
}
}
```
#### 问题 2事件处理性能下降
**问题描述:**
事件处理速度变慢。
**解决方案:**
```csharp
// 使用事件过滤减少不必要的处理
this.RegisterEvent&lt;MyEvent&gt;(
handler,
filter: e => e.ShouldProcess
);
// 使用优先级控制处理顺序
this.RegisterEvent&lt;MyEvent&gt;(
criticalHandler,
priority: 100
);
```
### 兼容性问题
#### 问题 1Godot 版本不兼容
**问题描述:**
升级后在 Godot 4.3 中无法运行。
**解决方案:**
```bash
# GFramework 1.0 要求 Godot 4.4+
# 升级 Godot 到 4.4 或更高版本
```
#### 问题 2.NET 版本不兼容
**问题描述:**
项目使用 .NET 7.0,无法使用 GFramework 1.0。
**解决方案:**
```xml
<!-- 升级项目到 .NET 8.0 或更高版本 -->
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
```
## 回滚方案
如果迁移过程中遇到无法解决的问题,可以按以下步骤回滚:
### 步骤 1恢复包版本
```bash
# 回滚到 0.x 版本
dotnet add package GeWuYou.GFramework.Core --version 0.0.200
dotnet add package GeWuYou.GFramework.Core.Abstractions --version 0.0.200
dotnet add package GeWuYou.GFramework.Game --version 0.0.200
dotnet add package GeWuYou.GFramework.Godot --version 0.0.200
```
### 步骤 2恢复代码
```bash
# 从备份分支恢复
git checkout backup-before-migration
# 或从文件系统备份恢复
rm -rf YourProject
cp -r YourProject-backup YourProject
```
### 步骤 3验证回滚
```bash
# 清理构建缓存
dotnet clean
rm -rf bin obj
# 重新构建
dotnet build
# 运行测试
dotnet test
```
### 步骤 4记录问题
创建问题报告,包含:
- 遇到的具体错误
- 错误发生的环境信息
- 复现步骤
- 相关代码片段
提交到 [GitHub Issues](https://github.com/GeWuYou/GFramework/issues)。
## 获取帮助
### 官方资源
- **文档中心**[https://gewuyou.github.io/GFramework/](https://gewuyou.github.io/GFramework/)
- **GitHub 仓库**[https://github.com/GeWuYou/GFramework](https://github.com/GeWuYou/GFramework)
- **问题追踪**[https://github.com/GeWuYou/GFramework/issues](https://github.com/GeWuYou/GFramework/issues)
- **讨论区**[https://github.com/GeWuYou/GFramework/discussions](https://github.com/GeWuYou/GFramework/discussions)
### 社区支持
- 在 GitHub Discussions 中提问
- 查看已有的 Issues 和 Pull Requests
- 参考示例项目和教程
### 商业支持
如需专业的迁移支持服务,请联系项目维护团队。
## 附录
### A. 完整的 API 对照表
| 0.x API | 1.x API | 说明 |
|-----------------------------|----------------------------------------|------------|
| `architecture.Initialize()` | `await architecture.InitializeAsync()` | 推荐使用异步初始化 |
| `this.SendCommandSync()` | `this.SendCommand()` | 移除 Sync 后缀 |
| `this.SendQuerySync()` | `this.SendQuery()` | 移除 Sync 后缀 |
| `EventBus.Register()` | `this.RegisterEvent()` | 使用扩展方法 |
| `Container.Register()` | `RegisterUtility()` | 使用架构方法 |
### B. 迁移时间估算
| 项目规模 | 预估时间 | 说明 |
|---------------|-------|--------------|
| 小型(&lt;10k 行) | 1-2 天 | 主要是包更新和测试 |
| 中型10k-50k 行) | 3-5 天 | 需要代码审查和重构 |
| 大型(&gt;50k 行) | 1-2 周 | 需要分模块迁移和充分测试 |
### C. 相关资源
- [架构设计文档](./core/architecture.md)
- [事件系统文档](./core/events.md)
- [命令查询文档](./core/command.md)
- [协程系统文档](./core/coroutine.md)
- [最佳实践](./best-practices/architecture-patterns.md)
---
**文档版本**1.0.0
**最后更新**2026-03-07
**许可证**Apache 2.0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff