diff --git a/GFramework.Core.Abstractions/architecture/ArchitectureModuleRegistry.cs b/GFramework.Core.Abstractions/architecture/ArchitectureModuleRegistry.cs
index 1259545..ab5a7c3 100644
--- a/GFramework.Core.Abstractions/architecture/ArchitectureModuleRegistry.cs
+++ b/GFramework.Core.Abstractions/architecture/ArchitectureModuleRegistry.cs
@@ -1,3 +1,5 @@
+using System.Collections.Concurrent;
+
namespace GFramework.Core.Abstractions.architecture;
///
@@ -5,15 +7,20 @@ namespace GFramework.Core.Abstractions.architecture;
///
public static class ArchitectureModuleRegistry
{
- private static readonly List> _factories = [];
+ private static readonly ConcurrentDictionary> _factories = new();
///
- /// 注册模块工厂
+ /// 注册模块工厂(幂等操作,相同模块名只会注册一次)
///
/// 模块工厂函数
public static void Register(Func factory)
{
- _factories.Add(factory);
+ // 创建临时实例以获取模块名(用于幂等性检查)
+ var tempModule = factory();
+ var moduleName = tempModule.ModuleName;
+
+ // 幂等注册:相同模块名只注册一次
+ _factories.TryAdd(moduleName, factory);
}
///
@@ -22,7 +29,7 @@ public static class ArchitectureModuleRegistry
/// 模块实例集合
public static IEnumerable CreateModules()
{
- return _factories.Select(f => f());
+ return _factories.Values.Select(f => f());
}
///
diff --git a/GFramework.Core.Abstractions/architecture/IServiceModuleManager.cs b/GFramework.Core.Abstractions/architecture/IServiceModuleManager.cs
index 20b7d52..8c7face 100644
--- a/GFramework.Core.Abstractions/architecture/IServiceModuleManager.cs
+++ b/GFramework.Core.Abstractions/architecture/IServiceModuleManager.cs
@@ -1,5 +1,4 @@
using GFramework.Core.Abstractions.ioc;
-using GFramework.Core.Abstractions.properties;
namespace GFramework.Core.Abstractions.architecture;
@@ -18,8 +17,7 @@ public interface IServiceModuleManager
/// 注册内置的服务模块。
///
/// IoC容器实例,用于解析依赖。
- /// 架构属性配置,用于模块初始化。
- void RegisterBuiltInModules(IIocContainer container, ArchitectureProperties properties);
+ void RegisterBuiltInModules(IIocContainer container);
///
/// 获取所有已注册的服务模块。
diff --git a/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs b/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs
index 936204b..5621b33 100644
--- a/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs
+++ b/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs
@@ -4,7 +4,6 @@ using GFramework.Core.Abstractions.environment;
using GFramework.Core.Abstractions.events;
using GFramework.Core.Abstractions.ioc;
using GFramework.Core.Abstractions.model;
-using GFramework.Core.Abstractions.properties;
using GFramework.Core.Abstractions.query;
using GFramework.Core.Abstractions.system;
using GFramework.Core.Abstractions.utility;
@@ -47,8 +46,7 @@ public class ArchitectureServicesTests
private void RegisterBuiltInServices()
{
- var properties = new ArchitectureProperties();
- _services!.ModuleManager.RegisterBuiltInModules(_services.Container, properties);
+ _services!.ModuleManager.RegisterBuiltInModules(_services.Container);
}
///
@@ -215,13 +213,11 @@ public class ArchitectureServicesTests
[Test]
public void Multiple_Instances_Should_Have_Independent_EventBus()
{
- var properties = new ArchitectureProperties();
-
var services1 = new ArchitectureServices();
- services1.ModuleManager.RegisterBuiltInModules(services1.Container, properties);
+ services1.ModuleManager.RegisterBuiltInModules(services1.Container);
var services2 = new ArchitectureServices();
- services2.ModuleManager.RegisterBuiltInModules(services2.Container, properties);
+ services2.ModuleManager.RegisterBuiltInModules(services2.Container);
Assert.That(services1.EventBus, Is.Not.SameAs(services2.EventBus));
}
@@ -232,13 +228,11 @@ public class ArchitectureServicesTests
[Test]
public void Multiple_Instances_Should_Have_Independent_CommandBus()
{
- var properties = new ArchitectureProperties();
-
var services1 = new ArchitectureServices();
- services1.ModuleManager.RegisterBuiltInModules(services1.Container, properties);
+ services1.ModuleManager.RegisterBuiltInModules(services1.Container);
var services2 = new ArchitectureServices();
- services2.ModuleManager.RegisterBuiltInModules(services2.Container, properties);
+ services2.ModuleManager.RegisterBuiltInModules(services2.Container);
Assert.That(services1.CommandExecutor, Is.Not.SameAs(services2.CommandExecutor));
}
@@ -249,13 +243,11 @@ public class ArchitectureServicesTests
[Test]
public void Multiple_Instances_Should_Have_Independent_QueryBus()
{
- var properties = new ArchitectureProperties();
-
var services1 = new ArchitectureServices();
- services1.ModuleManager.RegisterBuiltInModules(services1.Container, properties);
+ services1.ModuleManager.RegisterBuiltInModules(services1.Container);
var services2 = new ArchitectureServices();
- services2.ModuleManager.RegisterBuiltInModules(services2.Container, properties);
+ services2.ModuleManager.RegisterBuiltInModules(services2.Container);
Assert.That(services1.QueryExecutor, Is.Not.SameAs(services2.QueryExecutor));
}
diff --git a/GFramework.Core/architecture/Architecture.cs b/GFramework.Core/architecture/Architecture.cs
index 717c17e..0ebdff6 100644
--- a/GFramework.Core/architecture/Architecture.cs
+++ b/GFramework.Core/architecture/Architecture.cs
@@ -641,8 +641,8 @@ public abstract class Architecture(
_logger = LoggerFactoryResolver.Provider.CreateLogger(GetType().Name);
Environment.Initialize();
- // 注册内置服务模块(根据配置)
- Services.ModuleManager.RegisterBuiltInModules(Container, Configuration.ArchitectureProperties);
+ // 注册内置服务模块
+ Services.ModuleManager.RegisterBuiltInModules(Container);
// 将 Environment 注册到容器(如果尚未注册)
if (!Container.Contains())
diff --git a/GFramework.Core/services/ServiceModuleManager.cs b/GFramework.Core/services/ServiceModuleManager.cs
index 68bd2c0..9ed0aac 100644
--- a/GFramework.Core/services/ServiceModuleManager.cs
+++ b/GFramework.Core/services/ServiceModuleManager.cs
@@ -2,7 +2,6 @@ using GFramework.Core.Abstractions.architecture;
using GFramework.Core.Abstractions.ioc;
using GFramework.Core.Abstractions.lifecycle;
using GFramework.Core.Abstractions.logging;
-using GFramework.Core.Abstractions.properties;
using GFramework.Core.logging;
using GFramework.Core.services.modules;
@@ -44,11 +43,10 @@ public sealed class ServiceModuleManager : IServiceModuleManager
///
/// 注册内置服务模块,并根据优先级排序后完成服务注册。
/// 内置模块包括事件总线、命令执行器、查询执行器等核心模块。
- /// 同时注册通过 ModuleInitializer 自动注册的外部模块。
+ /// 同时注册通过 ArchitectureModuleRegistry 自动注册的外部模块。
///
/// IoC容器实例,用于模块服务注册。
- /// 架构属性配置。
- public void RegisterBuiltInModules(IIocContainer container, ArchitectureProperties properties)
+ public void RegisterBuiltInModules(IIocContainer container)
{
if (_builtInModulesRegistered)
{
@@ -62,7 +60,7 @@ public sealed class ServiceModuleManager : IServiceModuleManager
RegisterModule(new QueryExecutorModule());
RegisterModule(new AsyncQueryExecutorModule());
- // 注册外部模块(通过 ModuleInitializer 自动注册)
+ // 注册外部模块(通过 ArchitectureModuleRegistry 自动注册)
foreach (var module in ArchitectureModuleRegistry.CreateModules())
{
RegisterModule(module);
diff --git a/GFramework.Ecs.Arch.Tests/integration/ExplicitRegistrationTests.cs b/GFramework.Ecs.Arch.Tests/integration/ExplicitRegistrationTests.cs
new file mode 100644
index 0000000..515e5c9
--- /dev/null
+++ b/GFramework.Ecs.Arch.Tests/integration/ExplicitRegistrationTests.cs
@@ -0,0 +1,135 @@
+using Arch.Core;
+using GFramework.Core.Abstractions.architecture;
+using GFramework.Core.architecture;
+using GFramework.Core.ioc;
+using GFramework.Ecs.Arch.Abstractions;
+using GFramework.Ecs.Arch.extensions;
+
+namespace GFramework.Ecs.Arch.Tests.integration;
+
+///
+/// 显式注册集成测试
+///
+[TestFixture]
+public class ExplicitRegistrationTests
+{
+ [SetUp]
+ public void Setup()
+ {
+ _container = new MicrosoftDiContainer();
+ _context = new ArchitectureContext(_container);
+
+ // 清空注册表,确保测试隔离
+ ArchitectureModuleRegistry.Clear();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ _container?.Clear();
+ _context = null;
+ ArchitectureModuleRegistry.Clear();
+ GameContext.Clear();
+ }
+
+ private MicrosoftDiContainer? _container;
+ private ArchitectureContext? _context;
+
+ ///
+ /// 测试 Arch ECS 模块显式注册
+ ///
+ [Test]
+ public void ArchEcsModule_Should_Be_Explicitly_Registered()
+ {
+ // Arrange
+ var architecture = new TestArchitecture();
+
+ // Act - 显式注册
+ architecture.UseArch();
+ architecture.Initialize();
+
+ // Assert - 验证 World 已注册(由 ArchEcsModule 注册)
+ var world = architecture.Context.GetService();
+ Assert.That(world, Is.Not.Null, "World should be registered by ArchEcsModule");
+
+ // 验证 IArchEcsModule 已注册
+ var ecsModule = architecture.Context.GetService();
+ Assert.That(ecsModule, Is.Not.Null, "IArchEcsModule should be registered");
+ }
+
+ ///
+ /// 测试 World 是否正确注册到容器
+ ///
+ [Test]
+ public void World_Should_Be_Registered_In_Container()
+ {
+ // Arrange
+ var architecture = new TestArchitecture();
+
+ // Act - 显式注册
+ architecture.UseArch();
+ architecture.Initialize();
+
+ // Assert
+ var world = architecture.Context.GetService();
+ Assert.That(world, Is.Not.Null, "World should be registered in container");
+ }
+
+ ///
+ /// 测试带配置的注册
+ ///
+ [Test]
+ public void UseArch_Should_Accept_Configuration()
+ {
+ // Arrange
+ var architecture = new TestArchitecture();
+ var configCalled = false;
+
+ // Act
+ architecture.UseArch(options =>
+ {
+ options.WorldCapacity = 2000;
+ options.EnableStatistics = true;
+ configCalled = true;
+ });
+
+ // Assert
+ Assert.That(configCalled, Is.True, "Configuration delegate should be called");
+ }
+
+ ///
+ /// 测试链式调用
+ ///
+ [Test]
+ public void UseArch_Should_Support_Chaining()
+ {
+ // Arrange & Act
+ var architecture = new TestArchitecture()
+ .UseArch()
+ .UseArch(options => options.WorldCapacity = 2000);
+
+ architecture.Initialize();
+
+ // Assert - 验证模块已注册
+ var world = architecture.Context.GetService();
+ Assert.That(world, Is.Not.Null, "World should be registered");
+
+ var ecsModule = architecture.Context.GetService();
+ Assert.That(ecsModule, Is.Not.Null, "IArchEcsModule should be registered");
+ }
+
+ ///
+ /// 测试架构类,用于测试
+ ///
+ private class TestArchitecture : Architecture
+ {
+ public TestArchitecture() : base(new ArchitectureConfiguration())
+ {
+ }
+
+ protected override void OnInitialize()
+ {
+ // 测试架构,无需额外初始化
+ }
+ }
+}
\ No newline at end of file
diff --git a/GFramework.Ecs.Arch/ArchEcsModule.cs b/GFramework.Ecs.Arch/ArchEcsModule.cs
index bbbdb94..31ab8e9 100644
--- a/GFramework.Ecs.Arch/ArchEcsModule.cs
+++ b/GFramework.Ecs.Arch/ArchEcsModule.cs
@@ -8,6 +8,7 @@ namespace GFramework.Ecs.Arch;
///
public sealed class ArchEcsModule : IArchEcsModule
{
+ private readonly ArchOptions _options;
private IIocContainer? _container;
private bool _isInitialized;
private IReadOnlyList> _systems = [];
@@ -16,9 +17,11 @@ public sealed class ArchEcsModule : IArchEcsModule
///
/// 构造函数
///
+ /// 配置选项
/// 是否启用模块
- public ArchEcsModule(bool enabled = true)
+ public ArchEcsModule(ArchOptions? options = null, bool enabled = true)
{
+ _options = options ?? new ArchOptions();
IsEnabled = enabled;
}
@@ -30,7 +33,7 @@ public sealed class ArchEcsModule : IArchEcsModule
///
/// 模块优先级
///
- public int Priority => 50;
+ public int Priority => _options.Priority;
///
/// 是否启用
@@ -49,8 +52,8 @@ public sealed class ArchEcsModule : IArchEcsModule
// 注册模块自身
container.RegisterPlurality(this);
- // 创建并注册 World
- _world = World.Create();
+ // 创建并注册 World(使用配置的容量)
+ _world = World.Create(_options.WorldCapacity);
container.Register(_world);
}
diff --git a/GFramework.Ecs.Arch/ArchOptions.cs b/GFramework.Ecs.Arch/ArchOptions.cs
new file mode 100644
index 0000000..adc17e4
--- /dev/null
+++ b/GFramework.Ecs.Arch/ArchOptions.cs
@@ -0,0 +1,22 @@
+namespace GFramework.Ecs.Arch;
+
+///
+/// Arch ECS 模块配置选项
+///
+public sealed class ArchOptions
+{
+ ///
+ /// World 初始容量(默认:1000)
+ ///
+ public int WorldCapacity { get; set; } = 1000;
+
+ ///
+ /// 是否启用统计信息(默认:false)
+ ///
+ public bool EnableStatistics { get; set; } = false;
+
+ ///
+ /// 模块优先级(默认:50)
+ ///
+ public int Priority { get; set; } = 50;
+}
\ No newline at end of file
diff --git a/GFramework.Ecs.Arch/extensions/ArchExtensions.cs b/GFramework.Ecs.Arch/extensions/ArchExtensions.cs
index 811f546..dda51b1 100644
--- a/GFramework.Ecs.Arch/extensions/ArchExtensions.cs
+++ b/GFramework.Ecs.Arch/extensions/ArchExtensions.cs
@@ -23,8 +23,8 @@ public static class ArchExtensions
var options = new ArchOptions();
configure?.Invoke(options);
- // 注册模块
- ArchitectureModuleRegistry.Register(() => new ArchEcsModule(enabled: true));
+ // 注册模块(传递配置选项)
+ ArchitectureModuleRegistry.Register(() => new ArchEcsModule(options, enabled: true));
return architecture;
}