Skip to content

高级模式教程

深入学习 GFramework 的高级特性和设计模式,构建更复杂和可维护的游戏系统。

目录

架构模式

1. CQRS (命令查询职责分离)

实现完整的 CQRS 模式,分离读写操作:

csharp
using GFramework.Core.command;
using GFramework.Core.query;
using GFramework.Core.events;

// 命令 - 负责写操作
public class CreatePlayerCommand : AbstractCommand
{
    public string PlayerName { get; set; }
    public PlayerClass Class { get; set; }
    public Vector3 InitialPosition { get; set; }
    
    protected override void OnExecute()
    {
        var playerModel = GetModel<PlayerModel>();
        
        // 验证命令
        if (string.IsNullOrWhiteSpace(PlayerName))
            throw new ArgumentException("Player name cannot be empty");
            
        if (playerModel.PlayerExists(PlayerName))
            throw new InvalidOperationException($"Player {PlayerName} already exists");
        
        // 创建玩家
        var playerData = new PlayerData
        {
            Id = Guid.NewGuid(),
            Name = PlayerName,
            Class = Class,
            Position = InitialPosition,
            Level = 1,
            Experience = 0,
            Health = 100,
            MaxHealth = 100,
            Mana = 50,
            MaxMana = 50,
            CreatedAt = DateTime.UtcNow
        };
        
        // 保存玩家数据
        playerModel.AddPlayer(playerData);
        
        // 发送事件
        SendEvent(new PlayerCreatedEvent { Player = playerData });
    }
}

// 查询 - 负责读操作
public class GetPlayerQuery : AbstractQuery<PlayerData>
{
    public string PlayerName { get; set; }
    
    protected override PlayerData OnDo()
    {
        var playerModel = GetModel<PlayerModel>();
        return playerModel.GetPlayer(PlayerName);
    }
}

public class GetAllPlayersQuery : AbstractQuery<List<PlayerData>>
{
    public PlayerClass? FilterByClass { get; set; }
    public int? MinLevel { get; set; }
    
    protected override List<PlayerData> OnDo()
    {
        var playerModel = GetModel<PlayerModel>();
        var players = playerModel.GetAllPlayers();
        
        // 应用过滤器
        if (FilterByClass.HasValue)
        {
            players = players.Where(p => p.Class == FilterByClass.Value).ToList();
        }
        
        if (MinLevel.HasValue)
        {
            players = players.Where(p => p.Level >= MinLevel.Value).ToList();
        }
        
        return players;
    }
}

// 复杂查询示例
public class GetPlayerStatisticsQuery : AbstractQuery<PlayerStatistics>
{
    public string PlayerName { get; set; }
    
    protected override PlayerStatistics OnDo()
    {
        var playerModel = GetModel<PlayerModel>();
        var player = playerModel.GetPlayer(PlayerName);
        
        if (player == null)
            return null;
        
        // 计算统计数据
        var statistics = new PlayerStatistics
        {
            PlayerId = player.Id,
            PlayerName = player.Name,
            Level = player.Level,
            Experience = player.Experience,
            ExperienceToNextLevel = CalculateExperienceToNextLevel(player.Level),
            HealthPercentage = (float)player.Health / player.MaxHealth * 100,
            ManaPercentage = (float)player.Mana / player.MaxMana * 100,
            PlayTime = player.PlayTime,
            LastLogin = player.LastLogin,
            AchievementsUnlocked = player.Achievements.Count,
            TotalItemsOwned = player.Inventory.Count
        };
        
        return statistics;
    }
    
    private int CalculateExperienceToNextLevel(int currentLevel)
    {
        // 经验值计算公式
        return currentLevel * 1000 + (currentLevel - 1) * 500;
    }
}

// 事件 - 领域事件
public struct PlayerCreatedEvent
{
    public PlayerData Player { get; set; }
}

public struct PlayerLevelUpEvent
{
    public string PlayerName { get; set; }
    public int NewLevel { get; set; }
    public int NewMaxHealth { get; set; }
    public int NewMaxMana { get; set; }
}

// 使用示例
[ContextAware]
[Log]
public partial class PlayerService : IController
{
    public void CreateNewPlayer(string name, PlayerClass playerClass)
    {
        var command = new CreatePlayerCommand
        {
            PlayerName = name,
            Class = playerClass,
            InitialPosition = Vector3.Zero
        };
        
        try
        {
            Context.SendCommand(command);
            Logger.Info($"Player {name} created successfully");
        }
        catch (Exception ex)
        {
            Logger.Error($"Failed to create player {name}: {ex.Message}");
            throw;
        }
    }
    
    public PlayerData GetPlayer(string name)
    {
        var query = new GetPlayerQuery { PlayerName = name };
        return Context.SendQuery(query);
    }
    
    public List<PlayerData> GetAllPlayers(PlayerClass? classFilter = null, int? minLevel = null)
    {
        var query = new GetAllPlayersQuery 
        { 
            FilterByClass = classFilter, 
            MinLevel = minLevel 
        };
        return Context.SendQuery(query);
    }
    
    public PlayerStatistics GetPlayerStatistics(string playerName)
    {
        var query = new GetPlayerStatisticsQuery { PlayerName = playerName };
        return Context.SendQuery(query);
    }
}

2. 领域驱动设计 (DDD)

实现领域驱动设计的核心概念:

csharp
// 领域实体
public class Player : AbstractEntity
{
    public PlayerId Id { get; private set; }
    public PlayerName Name { get; private set; }
    public PlayerClass Class { get; private set; }
    public Level Level { get; private set; }
    public Experience Experience { get; private set; }
    public Health Health { get; private set; }
    public Mana Mana { get; private set; }
    public Inventory Inventory { get; private set; }
    public List<Achievement> Achievements { get; private set; }
    
    private List<IDomainEvent> _domainEvents = new();
    
    public IReadOnlyCollection<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();
    
    public Player(PlayerId id, PlayerName name, PlayerClass playerClass)
    {
        Id = id ?? throw new ArgumentNullException(nameof(id));
        Name = name ?? throw new ArgumentNullException(nameof(name));
        Class = playerClass;
        
        Level = new Level(1);
        Experience = new Experience(0);
        Health = new Health(100, 100);
        Mana = new Mana(50, 50);
        Inventory = new Inventory();
        Achievements = new List<Achievement>();
        
        // 添加领域事件
        AddDomainEvent(new PlayerCreatedDomainEvent(Id, Name, Class));
    }
    
    public void GainExperience(int amount)
    {
        if (amount <= 0)
            throw new ArgumentException("Experience amount must be positive");
        
        var oldLevel = Level.Value;
        Experience.Add(amount);
        
        // 检查是否升级
        while (Experience.Value >= CalculateRequiredExperience(Level.Value + 1))
        {
            LevelUp();
        }
        
        if (Level.Value > oldLevel)
        {
            AddDomainEvent(new PlayerLevelUpDomainEvent(Id, Name, Level.Value, oldLevel));
        }
    }
    
    public void TakeDamage(int damage)
    {
        if (damage < 0)
            throw new ArgumentException("Damage cannot be negative");
        
        Health.Reduce(damage);
        
        if (Health.Value <= 0)
        {
            Health.Value = 0;
            AddDomainEvent(new PlayerDiedDomainEvent(Id, Name));
        }
        else
        {
            AddDomainEvent(new PlayerDamagedDomainEvent(Id, Name, damage, Health.Value));
        }
    }
    
    public void Heal(int amount)
    {
        if (amount <= 0)
            throw new ArgumentException("Heal amount must be positive");
        
        Health.Increase(amount);
        AddDomainEvent(new PlayerHealedDomainEvent(Id, Name, amount, Health.Value));
    }
    
    public void AddItem(Item item)
    {
        if (item == null)
            throw new ArgumentNullException(nameof(item));
        
        Inventory.AddItem(item);
        AddDomainEvent(new ItemAddedDomainEvent(Id, Name, item.Id, item.Name));
    }
    
    public void RemoveItem(ItemId itemId)
    {
        var item = Inventory.GetItem(itemId);
        if (item == null)
            throw new InvalidOperationException($"Item {itemId} not found in inventory");
        
        Inventory.RemoveItem(itemId);
        AddDomainEvent(new ItemRemovedDomainEvent(Id, Name, itemId, item.Name));
    }
    
    private void LevelUp()
    {
        var oldLevel = Level.Value;
        Level.Increase();
        
        // 增加属性
        var healthIncrease = CalculateHealthIncrease(Class);
        var manaIncrease = CalculateManaIncrease(Class);
        
        Health.IncreaseMax(healthIncrease);
        Health.RestoreToFull();
        
        Mana.IncreaseMax(manaIncrease);
        Mana.RestoreToFull();
        
        Logger.Info($"Player {Name.Value} leveled up to {Level.Value}");
    }
    
    private int CalculateRequiredExperience(int level)
    {
        return level * 1000 + (level - 1) * 500;
    }
    
    private int CalculateHealthIncrease(PlayerClass playerClass)
    {
        return playerClass switch
        {
            PlayerClass.Warrior => 20,
            PlayerClass.Mage => 10,
            PlayerClass.Rogue => 15,
            PlayerClass.Priest => 12,
            _ => 15
        };
    }
    
    private int CalculateManaIncrease(PlayerClass playerClass)
    {
        return playerClass switch
        {
            PlayerClass.Warrior => 5,
            PlayerClass.Mage => 20,
            PlayerClass.Rogue => 8,
            PlayerClass.Priest => 15,
            _ => 10
        };
    }
    
    private void AddDomainEvent(IDomainEvent domainEvent)
    {
        _domainEvents.Add(domainEvent);
    }
    
    public void ClearDomainEvents()
    {
        _domainEvents.Clear();
    }
}

// 值对象
public record PlayerId(Guid Value)
{
    public static PlayerId New() => new(Guid.NewGuid());
}

public record PlayerName(string Value)
{
    public PlayerName(string value) : base(value?.Trim() ?? string.Empty)
    {
        if (string.IsNullOrWhiteSpace(Value))
            throw new ArgumentException("Player name cannot be empty");
            
        if (Value.Length > 50)
            throw new ArgumentException("Player name cannot exceed 50 characters");
    }
}

public record Level(int Value)
{
    public Level(int value) : base(Math.Max(1, value))
    {
        if (value < 1)
            throw new ArgumentException("Level cannot be less than 1");
            
        if (value > 100)
            throw new ArgumentException("Level cannot exceed 100");
    }
    
    public void Increase() => Value + 1;
}

public record Experience(int Value)
{
    public Experience(int value) : base(Math.Max(0, value))
    {
        if (value < 0)
            throw new ArgumentException("Experience cannot be negative");
    }
    
    public void Add(int amount) => Value + amount;
}

public record Health(int Value, int MaxValue)
{
    public Health(int value, int maxValue) : base(Math.Max(0, value), Math.Max(1, maxValue))
    {
        if (value < 0)
            throw new ArgumentException("Health cannot be negative");
            
        if (maxValue <= 0)
            throw new ArgumentException("Max health must be positive");
            
        if (value > maxValue)
            Value = maxValue;
    }
    
    public void Reduce(int amount) => new(Math.Max(0, Value - amount), MaxValue);
    
    public void Increase(int amount) => new(Math.Min(MaxValue, Value + amount), MaxValue);
    
    public void IncreaseMax(int amount) => new(Value, MaxValue + amount);
    
    public void RestoreToFull() => new(MaxValue, MaxValue);
}

// 领域事件
public interface IDomainEvent
{
    DateTime OccurredAt { get; }
}

public record PlayerCreatedDomainEvent(PlayerId PlayerId, PlayerName PlayerName, PlayerClass Class) 
    : IDomainEvent
{
    public DateTime OccurredAt { get; } = DateTime.UtcNow;
}

public record PlayerLevelUpDomainEvent(PlayerId PlayerId, PlayerName PlayerName, int NewLevel, int OldLevel) 
    : IDomainEvent
{
    public DateTime OccurredAt { get; } = DateTime.UtcNow;
}

// 领域服务
public interface IPlayerDomainService
{
    bool CanPlayerAttack(Player attacker, Player target);
    int CalculateDamage(Player attacker, Player target);
    bool IsPlayerAlive(Player player);
}

public class PlayerDomainService : IPlayerDomainService
{
    public bool CanPlayerAttack(Player attacker, Player target)
    {
        return IsPlayerAlive(attacker) && IsPlayerAlive(target) && 
               attacker.Id != target.Id &&
               Vector3.Distance(attacker.Position, target.Position) <= GetAttackRange(attacker.Class);
    }
    
    public int CalculateDamage(Player attacker, Player target)
    {
        var baseDamage = GetBaseDamage(attacker.Class, attacker.Level.Value);
        var weaponDamage = attacker.Inventory.EquippedWeapon?.Damage ?? 0;
        var defense = target.Inventory.EquippedArmor?.Defense ?? 0;
        
        var totalDamage = baseDamage + weaponDamage - defense;
        return Math.Max(1, totalDamage); // 最少造成1点伤害
    }
    
    public bool IsPlayerAlive(Player player)
    {
        return player.Health.Value > 0;
    }
    
    private float GetAttackRange(PlayerClass playerClass)
    {
        return playerClass switch
        {
            PlayerClass.Warrior => 1.5f,
            PlayerClass.Mage => 10.0f,
            PlayerClass.Rogue => 1.2f,
            PlayerClass.Priest => 5.0f,
            _ => 2.0f
        };
    }
    
    private int GetBaseDamage(PlayerClass playerClass, int level)
    {
        var baseDamage = playerClass switch
        {
            PlayerClass.Warrior => 15,
            PlayerClass.Mage => 8,
            PlayerClass.Rogue => 12,
            PlayerClass.Priest => 6,
            _ => 10
        };
        
        return baseDamage + (level - 1) * 2; // 等级加成
    }
}

事件驱动架构

1. 事件溯源模式

实现事件的持久化和重放:

csharp
using GFramework.Core.events;
using System.Collections.Concurrent;

public class EventStore : IEventStore
{
    private readonly ConcurrentDictionary<string, List<IDomainEvent>> _eventStreams = new();
    private readonly ConcurrentDictionary<string, List<IDomainEvent>> _snapshots = new();
    private readonly object _lock = new();
    
    public async Task SaveEventsAsync(string streamId, IEnumerable<IDomainEvent> events, int expectedVersion = -1)
    {
        if (!_eventStreams.TryGetValue(streamId, out var eventStream))
        {
            eventStream = new List<IDomainEvent>();
            _eventStreams[streamId] = eventStream;
        }
        
        lock (_lock)
        {
            if (expectedVersion >= 0 && eventStream.Count != expectedVersion)
            {
                throw new ConcurrencyException($"Expected version {expectedVersion}, but stream has {eventStream.Count} events");
            }
            
            foreach (var evt in events)
            {
                eventStream.Add(evt);
            }
            
            // 定期创建快照
            if (eventStream.Count % 100 == 0)
            {
                await CreateSnapshotAsync(streamId);
            }
        }
    }
    
    public async Task<IEnumerable<IDomainEvent>> GetEventsAsync(string streamId, int fromVersion = 0)
    {
        // 检查是否可以从快照开始
        var snapshotVersion = GetSnapshotVersion(streamId, fromVersion);
        if (snapshotVersion >= 0)
        {
            var events = new List<IDomainEvent>();
            var snapshot = _snapshots[streamId][snapshotVersion];
            events.Add(snapshot);
            
            // 添加快照之后的事件
            if (_eventStreams.TryGetValue(streamId, out var eventStream))
            {
                events.AddRange(eventStream.Skip(snapshotVersion + 1));
            }
            
            return events;
        }
        
        // 返回所有事件
        return _eventStreams.TryGetValue(streamId, out var eventStream) 
            ? eventStream.Skip(fromVersion) 
            : Enumerable.Empty<IDomainEvent>();
    }
    
    private async Task CreateSnapshotAsync(string streamId)
    {
        // 这里应该根据事件重建聚合状态
        // 简化实现,实际应该更复杂
        if (_eventStreams.TryGetValue(streamId, out var eventStream))
        {
            var snapshot = new AggregateSnapshot(streamId, eventStream.Count - 1);
            
            if (!_snapshots.TryGetValue(streamId, out var snapshotList))
            {
                snapshotList = new List<IDomainEvent>();
                _snapshots[streamId] = snapshotList;
            }
            
            snapshotList.Add(snapshot);
        }
    }
    
    private int GetSnapshotVersion(string streamId, int fromVersion)
    {
        if (!_snapshots.TryGetValue(streamId, out var snapshotList))
            return -1;
            
        // 找到最近的快照版本
        for (int i = snapshotList.Count - 1; i >= 0; i--)
        {
            if (((AggregateSnapshot)snapshotList[i]).Version >= fromVersion)
                return i;
        }
        
        return -1;
    }
}

public interface IEventStore
{
    Task SaveEventsAsync(string streamId, IEnumerable<IDomainEvent> events, int expectedVersion = -1);
    Task<IEnumerable<IDomainEvent>> GetEventsAsync(string streamId, int fromVersion = 0);
}

public record AggregateSnapshot(string StreamId, int Version) : IDomainEvent
{
    public DateTime OccurredAt { get; } = DateTime.UtcNow;
}

public class ConcurrencyException : Exception
{
    public ConcurrencyException(string message) : base(message) { }
}

// 聚合根重建器
public class AggregateRootBuilder
{
    private readonly IEventStore _eventStore;
    
    public AggregateRootBuilder(IEventStore eventStore)
    {
        _eventStore = eventStore;
    }
    
    public async Task<T> RebuildAsync<T>(string aggregateId) where T : AggregateRoot, new()
    {
        var events = await _eventStore.GetEventsAsync(aggregateId);
        var aggregate = new T();
        
        foreach (var evt in events)
        {
            aggregate.ApplyEvent(evt);
        }
        
        aggregate.ClearUncommittedEvents();
        return aggregate;
    }
}

public abstract class AggregateRoot
{
    public string Id { get; protected set; }
    public int Version { get; protected set; }
    
    private readonly List<IDomainEvent> _uncommittedEvents = new();
    
    public IReadOnlyCollection<IDomainEvent> GetUncommittedEvents() => _uncommittedEvents.AsReadOnly();
    public void ClearUncommittedEvents() => _uncommittedEvents.Clear();
    
    protected void ApplyEvent(IDomainEvent evt)
    {
        // 调用具体的事件应用方法
        When(evt);
        
        // 添加到未提交事件列表
        _uncommittedEvents.Add(evt);
        Version++;
    }
    
    protected abstract void When(IDomainEvent evt);
    
    public void LoadFromHistory(IEnumerable<IDomainEvent> events)
    {
        foreach (var evt in events)
        {
            When(evt);
            Version++;
        }
    }
}

2. 事件总线模式

实现灵活的事件路由和处理:

csharp
using GFramework.Core.events;

public class EventBus : IEventBus
{
    private readonly Dictionary<Type, List<IEventHandler>> _handlers = new();
    private readonly Dictionary<Type, List<IAsyncEventHandler>> _asyncHandlers = new();
    private readonly IEventStore _eventStore;
    private readonly object _lock = new();
    
    public EventBus(IEventStore eventStore = null)
    {
        _eventStore = eventStore;
    }
    
    public void Subscribe<T>(IEventHandler<T> handler) where T : IEvent
    {
        lock (_lock)
        {
            var eventType = typeof(T);
            if (!_handlers.ContainsKey(eventType))
            {
                _handlers[eventType] = new List<IEventHandler>();
            }
            
            _handlers[eventType].Add(handler);
        }
    }
    
    public void SubscribeAsync<T>(IAsyncEventHandler<T> handler) where T : IEvent
    {
        lock (_lock)
        {
            var eventType = typeof(T);
            if (!_asyncHandlers.ContainsKey(eventType))
            {
                _asyncHandlers[eventType] = new List<IAsyncEventHandler>();
            }
            
            _asyncHandlers[eventType].Add(handler);
        }
    }
    
    public async Task PublishAsync<T>(T evt) where T : IEvent
    {
        // 持久化事件(如果有事件存储)
        if (_eventStore != null && evt is IDomainEvent domainEvent)
        {
            var streamId = GetStreamId(domainEvent);
            await _eventStore.SaveEventsAsync(streamId, new[] { domainEvent });
        }
        
        var eventType = typeof(T);
        var tasks = new List<Task>();
        
        // 处理同步处理器
        if (_handlers.TryGetValue(eventType, out var syncHandlers))
        {
            foreach (var handler in syncHandlers)
            {
                try
                {
                    if (handler is IEventHandler<T> typedHandler)
                    {
                        typedHandler.Handle(evt);
                    }
                }
                catch (Exception ex)
                {
                    // 记录错误但不中断其他处理器
                    GD.PrintErr($"Error in event handler: {ex.Message}");
                }
            }
        }
        
        // 处理异步处理器
        if (_asyncHandlers.TryGetValue(eventType, out var asyncHandlers))
        {
            foreach (var handler in asyncHandlers)
            {
                try
                {
                    if (handler is IAsyncEventHandler<T> typedHandler)
                    {
                        tasks.Add(typedHandler.HandleAsync(evt));
                    }
                }
                catch (Exception ex)
                {
                    GD.PrintErr($"Error in async event handler: {ex.Message}");
                }
            }
        }
        
        // 等待所有异步处理器完成
        if (tasks.Count > 0)
        {
            await Task.WhenAll(tasks);
        }
    }
    
    private string GetStreamId(IDomainEvent domainEvent)
    {
        // 根据领域事件类型生成流ID
        return domainEvent switch
        {
            PlayerCreatedDomainEvent evt => $"player-{evt.PlayerId}",
            PlayerLevelUpDomainEvent evt => $"player-{evt.PlayerId}",
            PlayerDiedDomainEvent evt => $"player-{evt.PlayerId}",
            _ => $"unknown-{Guid.NewGuid()}"
        };
    }
}

public interface IEventBus
{
    void Subscribe<T>(IEventHandler<T> handler) where T : IEvent;
    void SubscribeAsync<T>(IAsyncEventHandler<T> handler) where T : IEvent;
    Task PublishAsync<T>(T evt) where T : IEvent;
}

public interface IEventHandler<in T> where T : IEvent
{
    void Handle(T evt);
}

public interface IAsyncEventHandler<in T> where T : IEvent
{
    Task HandleAsync(T evt);
}

// 事件处理器示例
public class PlayerEventHandler : IEventHandler<PlayerLevelUpEvent>,
                                 IAsyncEventHandler<PlayerDiedEvent>
{
    private readonly IPlayerRepository _playerRepository;
    private readonly INotificationService _notificationService;
    
    public PlayerEventHandler(IPlayerRepository playerRepository, 
                            INotificationService notificationService)
    {
        _playerRepository = playerRepository;
        _notificationService = notificationService;
    }
    
    public void Handle(PlayerLevelUpEvent evt)
    {
        // 同步处理升级事件
        var player = _playerRepository.GetById(evt.PlayerId);
        if (player != null)
        {
            player.Level = evt.NewLevel;
            _playerRepository.Update(player);
            
            GD.Print($"Player {evt.PlayerName} leveled up to {evt.NewLevel}");
        }
    }
    
    public async Task HandleAsync(PlayerDiedEvent evt)
    {
        // 异步处理死亡事件
        var player = _playerRepository.GetById(evt.PlayerId);
        if (player != null)
        {
            player.IsAlive = false;
            player.DeathTime = DateTime.UtcNow;
            _playerRepository.Update(player);
            
            // 发送通知
            await _notificationService.SendNotificationAsync(
                $"Player {evt.PlayerName} has died", 
                NotificationType.Warning
            );
            
            // 记录到外部系统
            await LogPlayerDeathToAnalyticsAsync(evt);
        }
    }
    
    private async Task LogPlayerDeathToAnalyticsAsync(PlayerDiedEvent evt)
    {
        // 发送分析数据
        await Task.Delay(100); // 模拟网络请求
        GD.Print($"Death analytics sent for player {evt.PlayerId}");
    }
}

插件系统

1. 插件架构

实现可扩展的插件系统:

csharp
using System.Reflection;
using System.Collections.Concurrent;

public interface IPlugin
{
    string Name { get; }
    string Version { get; }
    string Description { get; }
    string Author { get; }
    string[] Dependencies { get; }
    
    Task InitializeAsync(IPluginContext context);
    Task ShutdownAsync();
    bool IsCompatible(string frameworkVersion);
}

public interface IPluginContext
{
    IArchitecture Architecture { get; }
    IServiceContainer Services { get; }
    IEventManager Events { get; }
    ILogger Logger { get; }
    
    void RegisterService<T>(T service) where T : class;
    T GetService<T>() where T : class;
    void RegisterEventHandler<T>(IEventHandler<T> handler) where T : IEvent;
}

public class PluginManager : IPluginContext
{
    private readonly Dictionary<string, IPlugin> _loadedPlugins = new();
    private readonly ConcurrentDictionary<Type, object> _services = new();
    private readonly List<IEventHandler> _eventHandlers = new();
    private readonly IArchitecture _architecture;
    private readonly ILogger _logger;
    
    public IArchitecture Architecture => _architecture;
    public IServiceContainer Services => this;
    public IEventManager Events => _architecture.Context;
    public ILogger Logger => _logger;
    
    public PluginManager(IArchitecture architecture, ILogger logger)
    {
        _architecture = architecture;
        _logger = logger;
    }
    
    public async Task LoadPluginAsync(string pluginPath)
    {
        try
        {
            _logger.Info($"Loading plugin from: {pluginPath}");
            
            // 加载程序集
            var assembly = Assembly.LoadFrom(pluginPath);
            
            // 查找插件类型
            var pluginTypes = assembly.GetTypes()
                .Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);
            
            foreach (var pluginType in pluginTypes)
            {
                var plugin = (IPlugin)Activator.CreateInstance(pluginType);
                await LoadPluginInstanceAsync(plugin);
            }
        }
        catch (Exception ex)
        {
            _logger.Error($"Failed to load plugin from {pluginPath}: {ex.Message}");
            throw;
        }
    }
    
    private async Task LoadPluginInstanceAsync(IPlugin plugin)
    {
        // 检查兼容性
        if (!plugin.IsCompatible(GetCurrentFrameworkVersion()))
        {
            throw new IncompatiblePluginException(
                $"Plugin {plugin.Name} v{plugin.Version} is not compatible with framework version {GetCurrentFrameworkVersion()}"
            );
        }
        
        // 检查依赖
        foreach (var dependency in plugin.Dependencies)
        {
            if (!_loadedPlugins.ContainsKey(dependency))
            {
                throw new MissingDependencyException(
                    $"Plugin {plugin.Name} requires plugin {dependency} to be loaded first"
                );
            }
        }
        
        // 初始化插件
        await plugin.InitializeAsync(this);
        _loadedPlugins[plugin.Name] = plugin;
        
        _logger.Info($"Plugin {plugin.Name} v{plugin.Version} loaded successfully");
    }
    
    public async Task UnloadPluginAsync(string pluginName)
    {
        if (!_loadedPlugins.TryGetValue(pluginName, out var plugin))
        {
            throw new PluginNotFoundException($"Plugin {pluginName} is not loaded");
        }
        
        try
        {
            // 检查是否有其他插件依赖此插件
            var dependentPlugins = _loadedPlugins.Values
                .Where(p => p.Dependencies.Contains(pluginName))
                .ToList();
                
            if (dependentPlugins.Any())
            {
                var dependentNames = string.Join(", ", dependentPlugins.Select(p => p.Name));
                throw new DependencyException(
                    $"Cannot unload plugin {pluginName} because the following plugins depend on it: {dependentNames}"
                );
            }
            
            // 关闭插件
            await plugin.ShutdownAsync();
            _loadedPlugins.Remove(pluginName);
            
            _logger.Info($"Plugin {pluginName} unloaded successfully");
        }
        catch (Exception ex)
        {
            _logger.Error($"Failed to unload plugin {pluginName}: {ex.Message}");
            throw;
        }
    }
    
    public IEnumerable<IPlugin> GetLoadedPlugins()
    {
        return _loadedPlugins.Values.ToList();
    }
    
    public IPlugin GetPlugin(string name)
    {
        return _loadedPlugins.TryGetValue(name, out var plugin) ? plugin : null;
    }
    
    // IPluginContext 实现
    public void RegisterService<T>(T service) where T : class
    {
        _services.TryAdd(typeof(T), service);
        _logger.Debug($"Service {typeof(T).Name} registered by plugin system");
    }
    
    public T GetService<T>() where T : class
    {
        if (_services.TryGetValue(typeof(T), out var service))
        {
            return (T)service;
        }
        
        // 尝试从架构中获取
        return _architecture.Context.GetUtility<T>();
    }
    
    public void RegisterEventHandler<T>(IEventHandler<T> handler) where T : IEvent
    {
        _eventHandlers.Add(handler);
        _architecture.Context.RegisterEvent<T>(handler.Handle);
        _logger.Debug($"Event handler for {typeof(T).Name} registered by plugin system");
    }
    
    private string GetCurrentFrameworkVersion()
    {
        return "1.0.0"; // 应该从配置或程序集中读取
    }
}

// 插件示例
public class ChatPlugin : IPlugin
{
    public string Name => "Chat";
    public string Version => "1.2.0";
    public string Description => "In-game chat system with moderation features";
    public string Author => "GameStudio";
    public string[] Dependencies => new[] { "Authentication" };
    
    private IChatService _chatService;
    private ILogger _logger;
    
    public async Task InitializeAsync(IPluginContext context)
    {
        _logger = context.Logger;
        
        // 创建聊天服务
        _chatService = new ChatService(context.Architecture);
        
        // 注册服务
        context.RegisterService<IChatService>(_chatService);
        
        // 注册事件处理器
        context.RegisterEventHandler<PlayerJoinEvent>(OnPlayerJoin);
        context.RegisterEventHandler<PlayerLeaveEvent>(OnPlayerLeave);
        context.RegisterEventHandler<ChatMessageEvent>(OnChatMessage);
        
        _logger.Info("Chat plugin initialized");
        
        await Task.CompletedTask;
    }
    
    public async Task ShutdownAsync()
    {
        _chatService?.Dispose();
        _logger.Info("Chat plugin shutdown");
        await Task.CompletedTask;
    }
    
    public bool IsCompatible(string frameworkVersion)
    {
        // 检查版本兼容性
        return Version.TryParse(frameworkVersion, out var version) && 
               version >= new Version(1, 0, 0);
    }
    
    private void OnPlayerJoin(PlayerJoinEvent evt)
    {
        _chatService.SendSystemMessage($"{evt.PlayerName} joined the game");
    }
    
    private void OnPlayerLeave(PlayerLeaveEvent evt)
    {
        _chatService.SendSystemMessage($"{evt.PlayerName} left the game");
    }
    
    private void OnChatMessage(ChatMessageEvent evt)
    {
        _chatService.SendMessage(evt.PlayerId, evt.Message, evt.Channel);
    }
}

public interface IChatService
{
    void SendMessage(string playerId, string message, string channel = "global");
    void SendSystemMessage(string message);
    void Dispose();
}

public class ChatService : IChatService
{
    private readonly IArchitecture _architecture;
    private readonly Dictionary<string, ChatChannel> _channels = new();
    
    public ChatService(IArchitecture architecture)
    {
        _architecture = architecture;
        InitializeChannels();
    }
    
    private void InitializeChannels()
    {
        _channels["global"] = new ChatChannel("global", "Global Chat");
        _channels["trade"] = new ChatChannel("trade", "Trade Chat");
        _channels["guild"] = new ChatChannel("guild", "Guild Chat");
    }
    
    public void SendMessage(string playerId, string message, string channel = "global")
    {
        if (!_channels.TryGetValue(channel, out var chatChannel))
        {
            throw new ArgumentException($"Unknown channel: {channel}");
        }
        
        var chatMessage = new ChatMessage
        {
            PlayerId = playerId,
            Message = FilterMessage(message),
            Timestamp = DateTime.UtcNow,
            Channel = channel
        };
        
        chatChannel.AddMessage(chatMessage);
        
        // 发送事件
        _architecture.Context.SendEvent(new ChatMessageReceivedEvent(chatMessage));
    }
    
    public void SendSystemMessage(string message)
    {
        var systemMessage = new ChatMessage
        {
            PlayerId = "system",
            Message = message,
            Timestamp = DateTime.UtcNow,
            Channel = "system"
        };
        
        _channels["global"].AddMessage(systemMessage);
        _architecture.Context.SendEvent(new ChatMessageReceivedEvent(systemMessage));
    }
    
    private string FilterMessage(string message)
    {
        // 实现聊天过滤逻辑
        return message;
    }
    
    public void Dispose()
    {
        _channels.Clear();
    }
}

public class ChatChannel
{
    public string Name { get; }
    public string Description { get; }
    public Queue<ChatMessage> Messages { get; } = new();
    public int MaxMessages { get; set; } = 100;
    
    public ChatChannel(string name, string description)
    {
        Name = name;
        Description = description;
    }
    
    public void AddMessage(ChatMessage message)
    {
        Messages.Enqueue(message);
        
        // 限制消息数量
        while (Messages.Count > MaxMessages)
        {
            Messages.Dequeue();
        }
    }
}

public record ChatMessage
{
    public string PlayerId { get; init; }
    public string Message { get; init; }
    public DateTime Timestamp { get; init; }
    public string Channel { get; init; }
}

public struct ChatMessageReceivedEvent
{
    public ChatMessage Message { get; init; }
}

网络集成

1. 网络架构

实现基于事件的网络系统:

csharp
using Godot;
using System.Net.WebSockets;

public class NetworkManager : Node, INetworkManager
{
    private ClientWebSocket _webSocket;
    private CancellationTokenSource _cancellationTokenSource;
    private readonly ConcurrentQueue<NetworkMessage> _messageQueue = new();
    private readonly Dictionary<string, Type> _messageTypes = new();
    private bool _isConnected = false;
    
    [Signal]
    public delegate void ConnectedEventHandler();
    
    [Signal]
    public delegate void DisconnectedEventHandler(string reason);
    
    [Signal]
    public delegate void MessageReceivedEventHandler(NetworkMessage message);
    
    [Signal]
    public delegate void ConnectionFailedEventHandler(string error);
    
    public override void _Ready()
    {
        RegisterMessageTypes();
        SetProcess(true);
    }
    
    private void RegisterMessageTypes()
    {
        _messageTypes["player_position"] = typeof(PlayerPositionMessage);
        _messageTypes["chat_message"] = typeof(ChatMessageMessage);
        _messageTypes["player_action"] = typeof(PlayerActionMessage);
        _messageTypes["game_state"] = typeof(GameStateMessage);
    }
    
    public async Task ConnectAsync(string url)
    {
        try
        {
            _webSocket = new ClientWebSocket();
            _cancellationTokenSource = new CancellationTokenSource();
            
            GD.Print($"Connecting to {url}");
            await _webSocket.ConnectAsync(new Uri(url), _cancellationTokenSource.Token);
            
            _isConnected = true;
            EmitSignal(SignalName.Connected);
            
            // 启动消息接收循环
            _ = Task.Run(ReceiveMessagesLoop);
            
            GD.Print("Connected to server");
        }
        catch (Exception ex)
        {
            GD.PrintErr($"Connection failed: {ex.Message}");
            EmitSignal(SignalName.ConnectionFailed, ex.Message);
        }
    }
    
    public async Task DisconnectAsync()
    {
        if (_webSocket != null && _webSocket.State == WebSocketState.Open)
        {
            _isConnected = false;
            _cancellationTokenSource?.Cancel();
            
            try
            {
                await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Disconnecting", CancellationToken.None);
            }
            catch (Exception ex)
            {
                GD.PrintErr($"Error during disconnect: {ex.Message}");
            }
            
            EmitSignal(SignalName.Disconnected, "Manual disconnect");
        }
    }
    
    public async Task SendMessageAsync(NetworkMessage message)
    {
        if (!_isConnected || _webSocket?.State != WebSocketState.Open)
        {
            GD.PrintErr("Not connected to server");
            return;
        }
        
        try
        {
            var json = Json.Stringify(message.Serialize());
            var buffer = System.Text.Encoding.UTF8.GetBytes(json);
            
            await _webSocket.SendAsync(new ArraySegment<byte>(buffer), 
                WebSocketMessageType.Text, true, _cancellationTokenSource.Token);
        }
        catch (Exception ex)
        {
            GD.PrintErr($"Failed to send message: {ex.Message}");
        }
    }
    
    private async Task ReceiveMessagesLoop()
    {
        var buffer = new byte[4096];
        
        while (_isConnected && _cancellationTokenSource?.Token.IsCancellationRequested == false)
        {
            try
            {
                var result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), 
                    _cancellationTokenSource.Token);
                
                if (result.MessageType == WebSocketMessageType.Text)
                {
                    var json = System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count);
                    var messageData = Json.ParseString(json);
                    var message = ParseMessage(messageData);
                    
                    if (message != null)
                    {
                        _messageQueue.Enqueue(message);
                    }
                }
                else if (result.MessageType == WebSocketMessageType.Close)
                {
                    _isConnected = false;
                    EmitSignal(SignalName.Disconnected, "Server closed connection");
                    break;
                }
            }
            catch (OperationCanceledException)
            {
                // 正常的取消操作
                break;
            }
            catch (Exception ex)
            {
                GD.PrintErr($"Error receiving message: {ex.Message}");
                _isConnected = false;
                EmitSignal(SignalName.Disconnected, ex.Message);
                break;
            }
        }
    }
    
    private NetworkMessage ParseMessage(Godot.Collections.Dictionary messageData)
    {
        if (!messageData.ContainsKey("type"))
        {
            GD.PrintErr("Message missing type field");
            return null;
        }
        
        var messageType = messageData["type"].ToString();
        if (!_messageTypes.TryGetValue(messageType, out var type))
        {
            GD.PrintErr($"Unknown message type: {messageType}");
            return null;
        }
        
        var message = (NetworkMessage)Activator.CreateInstance(type);
        message.Deserialize(messageData);
        
        return message;
    }
    
    public override void _Process(double delta)
    {
        // 处理接收到的消息
        while (_messageQueue.TryDequeue(out var message))
        {
            EmitSignal(SignalName.MessageReceived, message);
            HandleNetworkMessage(message);
        }
    }
    
    private void HandleNetworkMessage(NetworkMessage message)
    {
        // 根据消息类型处理网络消息
        switch (message)
        {
            case PlayerPositionMessage posMsg:
                HandlePlayerPosition(posMsg);
                break;
            case ChatMessageMessage chatMsg:
                HandleChatMessage(chatMsg);
                break;
            case PlayerActionMessage actionMsg:
                HandlePlayerAction(actionMsg);
                break;
            case GameStateMessage stateMsg:
                HandleGameState(stateMsg);
                break;
        }
    }
    
    private void HandlePlayerPosition(PlayerPositionMessage message)
    {
        // 更新其他玩家位置
        Context.SendEvent(new NetworkPlayerPositionEvent
        {
            PlayerId = message.PlayerId,
            Position = new Vector2(message.X, message.Y)
        });
    }
    
    private void HandleChatMessage(ChatMessageMessage message)
    {
        // 显示聊天消息
        Context.SendEvent(new NetworkChatEvent
        {
            PlayerName = message.PlayerName,
            Message = message.Content,
            Channel = message.Channel
        });
    }
    
    private void HandlePlayerAction(PlayerActionMessage message)
    {
        // 处理玩家动作
        Context.SendEvent(new NetworkPlayerActionEvent
        {
            PlayerId = message.PlayerId,
            Action = message.Action,
            Data = message.Data
        });
    }
    
    private void HandleGameState(GameStateMessage message)
    {
        // 更新游戏状态
        Context.SendEvent(new NetworkGameStateEvent
        {
            State = message.State,
            Data = message.Data
        });
    }
    
    public override void _ExitTree()
    {
        _cancellationTokenSource?.Cancel();
        _webSocket?.Dispose();
        base._ExitTree();
    }
}

// 网络消息基类
public abstract class NetworkMessage
{
    public abstract string Type { get; }
    
    public abstract Godot.Collections.Dictionary Serialize();
    public abstract void Deserialize(Godot.Collections.Dictionary data);
}

// 具体网络消息
public class PlayerPositionMessage : NetworkMessage
{
    public string PlayerId { get; set; }
    public float X { get; set; }
    public float Y { get; set; }
    public float Rotation { get; set; }
    
    public override string Type => "player_position";
    
    public override Godot.Collections.Dictionary Serialize()
    {
        return new Godot.Collections.Dictionary
        {
            ["type"] = Type,
            ["player_id"] = PlayerId,
            ["x"] = X,
            ["y"] = Y,
            ["rotation"] = Rotation
        };
    }
    
    public override void Deserialize(Godot.Collections.Dictionary data)
    {
        PlayerId = data["player_id"].ToString();
        X = (float)data["x"];
        Y = (float)data["y"];
        Rotation = (float)data["rotation"];
    }
}

// 网络事件
public struct NetworkPlayerPositionEvent
{
    public string PlayerId { get; set; }
    public Vector2 Position { get; set; }
}

public struct NetworkChatEvent
{
    public string PlayerName { get; set; }
    public string Message { get; set; }
    public string Channel { get; set; }
}

// 网络控制器
[ContextAware]
[Log]
public partial class NetworkController : Node, IController
{
    private NetworkManager _networkManager;
    
    public override void _Ready()
    {
        _networkManager = new NetworkManager();
        AddChild(_networkManager);
        
        // 连接网络事件
        _networkManager.Connected += OnNetworkConnected;
        _networkManager.Disconnected += OnNetworkDisconnected;
        _networkManager.MessageReceived += OnNetworkMessageReceived;
        _networkManager.ConnectionFailed += OnConnectionFailed;
    }
    
    public async Task ConnectToServer(string url)
    {
        Logger.Info($"Connecting to server: {url}");
        await _networkManager.ConnectAsync(url);
    }
    
    public void SendPlayerPosition(Vector2 position)
    {
        var message = new PlayerPositionMessage
        {
            PlayerId = Context.GetModel<PlayerModel>().PlayerId,
            X = position.X,
            Y = position.Y,
            Rotation = 0f // 根据实际需要设置
        };
        
        _networkManager.SendMessageAsync(message);
    }
    
    public void SendChatMessage(string message, string channel = "global")
    {
        var chatMessage = new ChatMessageMessage
        {
            PlayerName = Context.GetModel<PlayerModel>().Name,
            Content = message,
            Channel = channel
        };
        
        _networkManager.SendMessageAsync(chatMessage);
    }
    
    private void OnNetworkConnected()
    {
        Logger.Info("Connected to network server");
        Context.SendEvent(new NetworkConnectedEvent());
    }
    
    private void OnNetworkDisconnected(string reason)
    {
        Logger.Info($"Disconnected from network server: {reason}");
        Context.SendEvent(new NetworkDisconnectedEvent { Reason = reason });
    }
    
    private void OnNetworkMessageReceived(NetworkMessage message)
    {
        Logger.Debug($"Received network message: {message.Type}");
    }
    
    private void OnConnectionFailed(string error)
    {
        Logger.Error($"Network connection failed: {error}");
        Context.SendEvent(new NetworkConnectionFailedEvent { Error = error });
    }
}

总结

通过本高级模式教程,你已经学会了:

  • CQRS 模式 - 分离命令和查询职责
  • 领域驱动设计 - 构建丰富的领域模型
  • 事件溯源 - 持久化和重放领域事件
  • 插件系统 - 可扩展的插件架构
  • 网络集成 - 实时多人游戏网络支持

这些高级模式将帮助你构建企业级的大型游戏系统。


教程版本: 1.0.0
更新日期: 2026-01-12

基于 Apache 2.0 许可证发布