mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-25 13:33:28 +08:00
style(coding-style): 统一代码风格并优化文档格式
- 移除多余using语句和空行,统一代码缩进格式 - 优化注释文档中的缩进和对齐格式 - 简化条件语句和方法实现,提升代码可读性 - 重构协程系统相关类的字段和方法定义格式 - 更新架构服务中容器访问方式的实现 - 调整异步操作类的属性和方法组织结构 - [skip ci]
This commit is contained in:
parent
a71c7f6f1a
commit
b49079de3e
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using GFramework.Core.Abstractions.command;
|
||||
using GFramework.Core.Abstractions.environment;
|
||||
using GFramework.Core.Abstractions.events;
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GFramework.Core.Abstractions.architecture;
|
||||
namespace GFramework.Core.Abstractions.architecture;
|
||||
|
||||
/// <summary>
|
||||
/// 定义异步初始化接口,用于需要异步初始化的组件或服务
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using System.Threading.Tasks;
|
||||
using GFramework.Core.Abstractions.rule;
|
||||
|
||||
namespace GFramework.Core.Abstractions.command;
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GFramework.Core.Abstractions.command;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -28,5 +28,5 @@ public enum CoroutineState
|
||||
/// <summary>
|
||||
/// 协程已被取消
|
||||
/// </summary>
|
||||
Cancelled,
|
||||
Cancelled
|
||||
}
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace GFramework.Core.Abstractions.events;
|
||||
namespace GFramework.Core.Abstractions.events;
|
||||
|
||||
/// <summary>
|
||||
/// 事件接口,定义了事件注册的基本功能
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace GFramework.Core.Abstractions.events;
|
||||
namespace GFramework.Core.Abstractions.events;
|
||||
|
||||
/// <summary>
|
||||
/// 事件总线接口,提供事件的发送、注册和注销功能
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GFramework.Core.Abstractions.events;
|
||||
namespace GFramework.Core.Abstractions.events;
|
||||
|
||||
/// <summary>
|
||||
/// 提供统一注销功能的接口,用于管理需要注销的对象列表
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GFramework.Core.Abstractions.rule;
|
||||
using GFramework.Core.Abstractions.rule;
|
||||
using GFramework.Core.Abstractions.system;
|
||||
|
||||
namespace GFramework.Core.Abstractions.ioc;
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace GFramework.Core.Abstractions.logging;
|
||||
namespace GFramework.Core.Abstractions.logging;
|
||||
|
||||
/// <summary>
|
||||
/// 定义日志记录接口,提供日志记录和级别检查功能
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using GFramework.Core.Abstractions.events;
|
||||
|
||||
namespace GFramework.Core.Abstractions.property;
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GFramework.Core.Abstractions.query;
|
||||
namespace GFramework.Core.Abstractions.query;
|
||||
|
||||
/// <summary>
|
||||
/// 异步查询接口,定义了执行异步查询操作的方法
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GFramework.Core.Abstractions.query;
|
||||
namespace GFramework.Core.Abstractions.query;
|
||||
|
||||
/// <summary>
|
||||
/// 异步查询总线接口,用于处理异步查询请求
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using GFramework.Core.Abstractions.bases;
|
||||
using GFramework.Core.Abstractions.bases;
|
||||
using GFramework.Game.Abstractions.registry;
|
||||
|
||||
namespace GFramework.Core.Abstractions.registries;
|
||||
@ -35,9 +34,11 @@ public abstract class KeyValueRegistryBase<TKey, TValue>
|
||||
/// <returns>与键关联的值</returns>
|
||||
/// <exception cref="KeyNotFoundException">当键不存在时抛出异常</exception>
|
||||
public virtual TValue Get(TKey key)
|
||||
=> Map.TryGetValue(key, out var value)
|
||||
{
|
||||
return Map.TryGetValue(key, out var value)
|
||||
? value
|
||||
: throw new KeyNotFoundException($"{GetType().Name}: key not registered: {key}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否包含指定的键
|
||||
@ -45,7 +46,9 @@ public abstract class KeyValueRegistryBase<TKey, TValue>
|
||||
/// <param name="key">要检查的键</param>
|
||||
/// <returns>如果包含该键返回true,否则返回false</returns>
|
||||
public virtual bool Contains(TKey key)
|
||||
=> Map.ContainsKey(key);
|
||||
{
|
||||
return Map.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册键值对到注册表中
|
||||
@ -65,5 +68,7 @@ public abstract class KeyValueRegistryBase<TKey, TValue>
|
||||
/// <param name="mapping">包含键值对的映射对象</param>
|
||||
/// <returns>当前注册表实例,支持链式调用</returns>
|
||||
public virtual IRegistry<TKey, TValue> Registry(IKeyValue<TKey, TValue> mapping)
|
||||
=> Registry(mapping.Key, mapping.Value);
|
||||
{
|
||||
return Registry(mapping.Key, mapping.Value);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GFramework.Core.Abstractions.state;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using GFramework.Core.Abstractions.utility;
|
||||
using GFramework.Core.Abstractions.utility;
|
||||
|
||||
namespace GFramework.Core.Abstractions.storage;
|
||||
|
||||
|
||||
@ -6,13 +6,13 @@
|
||||
<TargetFrameworks>net10.0;net8.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageReference Include="NUnit" Version="4.4.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1"/>
|
||||
<PackageReference Include="NUnit" Version="4.4.0"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="6.1.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj" />
|
||||
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -50,10 +50,8 @@ public class ArchitectureConstantsTests
|
||||
Assert.That(ArchitectureConstants.PhaseOrder.Length, Is.EqualTo(expectedPhases.Length));
|
||||
|
||||
foreach (var expectedPhase in expectedPhases)
|
||||
{
|
||||
Assert.That(ArchitectureConstants.PhaseOrder, Does.Contain(expectedPhase));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseOrder数组是只读的
|
||||
@ -164,11 +162,9 @@ public class ArchitectureConstantsTests
|
||||
public void PhaseTransitions_Should_Have_Maximum_One_Transition_Per_Phase()
|
||||
{
|
||||
foreach (var transition in ArchitectureConstants.PhaseTransitions)
|
||||
{
|
||||
Assert.That(transition.Value, Has.Length.LessThanOrEqualTo(1),
|
||||
$"Phase {transition.Key} should have at most 1 transition");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试PhaseOrder和PhaseTransitions的一致性
|
||||
@ -179,7 +175,7 @@ public class ArchitectureConstantsTests
|
||||
var phaseOrder = ArchitectureConstants.PhaseOrder;
|
||||
var transitions = ArchitectureConstants.PhaseTransitions;
|
||||
|
||||
for (int i = 0; i < phaseOrder.Length - 1; i++)
|
||||
for (var i = 0; i < phaseOrder.Length - 1; i++)
|
||||
{
|
||||
var currentPhase = phaseOrder[i];
|
||||
var nextPhase = phaseOrder[i + 1];
|
||||
|
||||
@ -149,7 +149,7 @@ public class ArchitectureContextTests
|
||||
[Test]
|
||||
public void SendCommand_Should_ThrowArgumentNullException_When_Command_IsNull()
|
||||
{
|
||||
Assert.That(() => _context!.SendCommand((ICommand)null!),
|
||||
Assert.That(() => _context!.SendCommand(null!),
|
||||
Throws.ArgumentNullException.With.Property("ParamName").EqualTo("command"));
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ public class ArchitectureContextTests
|
||||
[Test]
|
||||
public void SendEvent_Should_SendEvent_When_EventType_IsValid()
|
||||
{
|
||||
bool eventReceived = false;
|
||||
var eventReceived = false;
|
||||
_context!.RegisterEvent<TestEventV2>(_ => eventReceived = true);
|
||||
_context.SendEvent<TestEventV2>();
|
||||
|
||||
@ -194,7 +194,7 @@ public class ArchitectureContextTests
|
||||
[Test]
|
||||
public void SendEvent_WithInstance_Should_SendEvent_When_EventInstance_IsValid()
|
||||
{
|
||||
bool eventReceived = false;
|
||||
var eventReceived = false;
|
||||
var testEvent = new TestEventV2();
|
||||
_context!.RegisterEvent<TestEventV2>(_ => eventReceived = true);
|
||||
_context.SendEvent(testEvent);
|
||||
@ -310,8 +310,15 @@ public class TestSystemV2 : ISystem
|
||||
private IArchitectureContext _context = null!;
|
||||
public int Id { get; init; }
|
||||
|
||||
public void SetContext(IArchitectureContext context) => _context = context;
|
||||
public IArchitectureContext GetContext() => _context;
|
||||
public void SetContext(IArchitectureContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public IArchitectureContext GetContext()
|
||||
{
|
||||
return _context;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
@ -331,8 +338,15 @@ public class TestModelV2 : IModel
|
||||
private IArchitectureContext _context = null!;
|
||||
public int Id { get; init; }
|
||||
|
||||
public void SetContext(IArchitectureContext context) => _context = context;
|
||||
public IArchitectureContext GetContext() => _context;
|
||||
public void SetContext(IArchitectureContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public IArchitectureContext GetContext()
|
||||
{
|
||||
return _context;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
@ -352,8 +366,15 @@ public class TestUtilityV2 : IUtility
|
||||
private IArchitectureContext _context = null!;
|
||||
public int Id { get; init; }
|
||||
|
||||
public void SetContext(IArchitectureContext context) => _context = context;
|
||||
public IArchitectureContext GetContext() => _context;
|
||||
public void SetContext(IArchitectureContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public IArchitectureContext GetContext()
|
||||
{
|
||||
return _context;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestQueryV2 : IQuery<int>
|
||||
@ -361,9 +382,20 @@ public class TestQueryV2 : IQuery<int>
|
||||
private IArchitectureContext _context = null!;
|
||||
public int Result { get; init; }
|
||||
|
||||
public int Do() => Result;
|
||||
public void SetContext(IArchitectureContext context) => _context = context;
|
||||
public IArchitectureContext GetContext() => _context;
|
||||
public int Do()
|
||||
{
|
||||
return Result;
|
||||
}
|
||||
|
||||
public void SetContext(IArchitectureContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public IArchitectureContext GetContext()
|
||||
{
|
||||
return _context;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestCommandV2 : ICommand
|
||||
@ -371,9 +403,20 @@ public class TestCommandV2 : ICommand
|
||||
private IArchitectureContext _context = null!;
|
||||
public bool Executed { get; private set; }
|
||||
|
||||
public void Execute() => Executed = true;
|
||||
public void SetContext(IArchitectureContext context) => _context = context;
|
||||
public IArchitectureContext GetContext() => _context;
|
||||
public void Execute()
|
||||
{
|
||||
Executed = true;
|
||||
}
|
||||
|
||||
public void SetContext(IArchitectureContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public IArchitectureContext GetContext()
|
||||
{
|
||||
return _context;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestCommandWithResultV2 : ICommand<int>
|
||||
@ -381,9 +424,20 @@ public class TestCommandWithResultV2 : ICommand<int>
|
||||
private IArchitectureContext _context = null!;
|
||||
public int Result { get; init; }
|
||||
|
||||
public int Execute() => Result;
|
||||
public void SetContext(IArchitectureContext context) => _context = context;
|
||||
public IArchitectureContext GetContext() => _context;
|
||||
public int Execute()
|
||||
{
|
||||
return Result;
|
||||
}
|
||||
|
||||
public void SetContext(IArchitectureContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public IArchitectureContext GetContext()
|
||||
{
|
||||
return _context;
|
||||
}
|
||||
}
|
||||
|
||||
public class TestEventV2
|
||||
|
||||
@ -227,10 +227,25 @@ public class TestArchitectureContextV3 : IArchitectureContext
|
||||
public ICommandBus CommandBus => new CommandBus();
|
||||
public IQueryBus QueryBus => new QueryBus();
|
||||
|
||||
public TService? GetService<TService>() where TService : class => _container.Get<TService>();
|
||||
public TModel? GetModel<TModel>() where TModel : class, IModel => _container.Get<TModel>();
|
||||
public TSystem? GetSystem<TSystem>() where TSystem : class, ISystem => _container.Get<TSystem>();
|
||||
public TUtility? GetUtility<TUtility>() where TUtility : class, IUtility => _container.Get<TUtility>();
|
||||
public TService? GetService<TService>() where TService : class
|
||||
{
|
||||
return _container.Get<TService>();
|
||||
}
|
||||
|
||||
public TModel? GetModel<TModel>() where TModel : class, IModel
|
||||
{
|
||||
return _container.Get<TModel>();
|
||||
}
|
||||
|
||||
public TSystem? GetSystem<TSystem>() where TSystem : class, ISystem
|
||||
{
|
||||
return _container.Get<TSystem>();
|
||||
}
|
||||
|
||||
public TUtility? GetUtility<TUtility>() where TUtility : class, IUtility
|
||||
{
|
||||
return _container.Get<TUtility>();
|
||||
}
|
||||
|
||||
public void SendEvent<TEvent>() where TEvent : new()
|
||||
{
|
||||
@ -240,7 +255,10 @@ public class TestArchitectureContextV3 : IArchitectureContext
|
||||
{
|
||||
}
|
||||
|
||||
public IUnRegister RegisterEvent<TEvent>(Action<TEvent> handler) => new DefaultUnRegister(() => { });
|
||||
public IUnRegister RegisterEvent<TEvent>(Action<TEvent> handler)
|
||||
{
|
||||
return new DefaultUnRegister(() => { });
|
||||
}
|
||||
|
||||
public void UnRegisterEvent<TEvent>(Action<TEvent> onEvent)
|
||||
{
|
||||
@ -250,7 +268,10 @@ public class TestArchitectureContextV3 : IArchitectureContext
|
||||
{
|
||||
}
|
||||
|
||||
public TResult SendCommand<TResult>(ICommand<TResult> command) => default!;
|
||||
public TResult SendCommand<TResult>(ICommand<TResult> command)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
public Task SendCommandAsync(IAsyncCommand command)
|
||||
{
|
||||
@ -262,11 +283,20 @@ public class TestArchitectureContextV3 : IArchitectureContext
|
||||
return (Task<TResult>)Task.CompletedTask;
|
||||
}
|
||||
|
||||
public TResult SendQuery<TResult>(IQuery<TResult> query) => default!;
|
||||
public TResult SendQuery<TResult>(IQuery<TResult> query)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
public Task<TResult> SendQueryAsync<TResult>(IAsyncQuery<TResult> query) => (Task<TResult>)Task.CompletedTask;
|
||||
public Task<TResult> SendQueryAsync<TResult>(IAsyncQuery<TResult> query)
|
||||
{
|
||||
return (Task<TResult>)Task.CompletedTask;
|
||||
}
|
||||
|
||||
public IEnvironment GetEnvironment() => _environment;
|
||||
public IEnvironment GetEnvironment()
|
||||
{
|
||||
return _environment;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -261,28 +261,40 @@ public class TestArchitectureContext : IArchitectureContext
|
||||
/// </summary>
|
||||
/// <typeparam name="TService">服务类型</typeparam>
|
||||
/// <returns>服务实例或null</returns>
|
||||
public TService? GetService<TService>() where TService : class => _container.Get<TService>();
|
||||
public TService? GetService<TService>() where TService : class
|
||||
{
|
||||
return _container.Get<TService>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的模型
|
||||
/// </summary>
|
||||
/// <typeparam name="TModel">模型类型</typeparam>
|
||||
/// <returns>模型实例或null</returns>
|
||||
public TModel? GetModel<TModel>() where TModel : class, IModel => _container.Get<TModel>();
|
||||
public TModel? GetModel<TModel>() where TModel : class, IModel
|
||||
{
|
||||
return _container.Get<TModel>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的系统
|
||||
/// </summary>
|
||||
/// <typeparam name="TSystem">系统类型</typeparam>
|
||||
/// <returns>系统实例或null</returns>
|
||||
public TSystem? GetSystem<TSystem>() where TSystem : class, ISystem => _container.Get<TSystem>();
|
||||
public TSystem? GetSystem<TSystem>() where TSystem : class, ISystem
|
||||
{
|
||||
return _container.Get<TSystem>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的工具
|
||||
/// </summary>
|
||||
/// <typeparam name="TUtility">工具类型</typeparam>
|
||||
/// <returns>工具实例或null</returns>
|
||||
public TUtility? GetUtility<TUtility>() where TUtility : class, IUtility => _container.Get<TUtility>();
|
||||
public TUtility? GetUtility<TUtility>() where TUtility : class, IUtility
|
||||
{
|
||||
return _container.Get<TUtility>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送事件
|
||||
@ -307,7 +319,10 @@ public class TestArchitectureContext : IArchitectureContext
|
||||
/// <typeparam name="TEvent">事件类型</typeparam>
|
||||
/// <param name="handler">事件处理委托</param>
|
||||
/// <returns>取消注册接口</returns>
|
||||
public IUnRegister RegisterEvent<TEvent>(Action<TEvent> handler) => new DefaultUnRegister(() => { });
|
||||
public IUnRegister RegisterEvent<TEvent>(Action<TEvent> handler)
|
||||
{
|
||||
return new DefaultUnRegister(() => { });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消注册事件处理器
|
||||
@ -332,7 +347,10 @@ public class TestArchitectureContext : IArchitectureContext
|
||||
/// <typeparam name="TResult">返回值类型</typeparam>
|
||||
/// <param name="command">命令对象</param>
|
||||
/// <returns>命令执行结果</returns>
|
||||
public TResult SendCommand<TResult>(ICommand<TResult> command) => default!;
|
||||
public TResult SendCommand<TResult>(ICommand<TResult> command)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
public Task SendCommandAsync(IAsyncCommand command)
|
||||
{
|
||||
@ -350,7 +368,10 @@ public class TestArchitectureContext : IArchitectureContext
|
||||
/// <typeparam name="TResult">查询结果类型</typeparam>
|
||||
/// <param name="query">查询对象</param>
|
||||
/// <returns>查询结果</returns>
|
||||
public TResult SendQuery<TResult>(IQuery<TResult> query) => default!;
|
||||
public TResult SendQuery<TResult>(IQuery<TResult> query)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送查询请求
|
||||
@ -358,11 +379,17 @@ public class TestArchitectureContext : IArchitectureContext
|
||||
/// <typeparam name="TResult">查询结果类型</typeparam>
|
||||
/// <param name="query">异步查询对象</param>
|
||||
/// <returns>查询结果</returns>
|
||||
public Task<TResult> SendQueryAsync<TResult>(IAsyncQuery<TResult> query) => (Task<TResult>)Task.CompletedTask;
|
||||
public Task<TResult> SendQueryAsync<TResult>(IAsyncQuery<TResult> query)
|
||||
{
|
||||
return (Task<TResult>)Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取环境对象
|
||||
/// </summary>
|
||||
/// <returns>环境对象</returns>
|
||||
public IEnvironment GetEnvironment() => Environment;
|
||||
public IEnvironment GetEnvironment()
|
||||
{
|
||||
return Environment;
|
||||
}
|
||||
}
|
||||
@ -39,10 +39,7 @@ public class CoroutineExtensionsTests
|
||||
var callCount = 0;
|
||||
var coroutine = CoroutineExtensions.RepeatEvery(0.1, () => callCount++, 3);
|
||||
|
||||
while (coroutine.MoveNext())
|
||||
{
|
||||
coroutine.Current.Update(0.1);
|
||||
}
|
||||
while (coroutine.MoveNext()) coroutine.Current.Update(0.1);
|
||||
|
||||
Assert.That(callCount, Is.EqualTo(3));
|
||||
}
|
||||
@ -102,10 +99,7 @@ public class CoroutineExtensionsTests
|
||||
|
||||
Assert.DoesNotThrow(() =>
|
||||
{
|
||||
while (coroutine.MoveNext())
|
||||
{
|
||||
coroutine.Current.Update(0.1);
|
||||
}
|
||||
while (coroutine.MoveNext()) coroutine.Current.Update(0.1);
|
||||
});
|
||||
}
|
||||
|
||||
@ -212,10 +206,7 @@ public class CoroutineExtensionsTests
|
||||
|
||||
var sequence = CoroutineExtensions.Sequence(coroutine1, coroutine2, coroutine3);
|
||||
|
||||
while (sequence.MoveNext())
|
||||
{
|
||||
sequence.Current.Update(0.1);
|
||||
}
|
||||
while (sequence.MoveNext()) sequence.Current.Update(0.1);
|
||||
|
||||
Assert.That(executionOrder, Is.EqualTo(new List<int> { 1, 2, 3 }));
|
||||
}
|
||||
@ -254,10 +245,7 @@ public class CoroutineExtensionsTests
|
||||
|
||||
Assert.Throws<NullReferenceException>(() =>
|
||||
{
|
||||
while (sequence.MoveNext())
|
||||
{
|
||||
sequence.Current.Update(0.1);
|
||||
}
|
||||
while (sequence.MoveNext()) sequence.Current.Update(0.1);
|
||||
});
|
||||
}
|
||||
|
||||
@ -268,7 +256,7 @@ public class CoroutineExtensionsTests
|
||||
public void ParallelCoroutines_Should_Return_Valid_Coroutine()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
var coroutine1 = CreateSimpleCoroutine();
|
||||
var coroutine2 = CreateSimpleCoroutine();
|
||||
|
||||
@ -284,7 +272,7 @@ public class CoroutineExtensionsTests
|
||||
public void ParallelCoroutines_Should_Execute_Coroutines_In_Parallel()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var executionCounts = new Dictionary<int, int> { { 1, 0 }, { 2, 0 }, { 3, 0 } };
|
||||
var coroutine1 = CreateDelayedCoroutine(() => executionCounts[1]++, 0.5);
|
||||
@ -297,10 +285,7 @@ public class CoroutineExtensionsTests
|
||||
|
||||
Assert.That(scheduler.ActiveCoroutineCount, Is.GreaterThan(0));
|
||||
|
||||
while (scheduler.ActiveCoroutineCount > 0)
|
||||
{
|
||||
scheduler.Update();
|
||||
}
|
||||
while (scheduler.ActiveCoroutineCount > 0) scheduler.Update();
|
||||
|
||||
Assert.That(executionCounts[1], Is.EqualTo(1));
|
||||
Assert.That(executionCounts[2], Is.EqualTo(1));
|
||||
@ -314,7 +299,7 @@ public class CoroutineExtensionsTests
|
||||
public void ParallelCoroutines_Should_Handle_Empty_Array()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var parallel = scheduler.ParallelCoroutines();
|
||||
|
||||
@ -328,7 +313,7 @@ public class CoroutineExtensionsTests
|
||||
public void ParallelCoroutines_Should_Handle_Null_Array()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var parallel = scheduler.ParallelCoroutines(null);
|
||||
|
||||
@ -374,10 +359,7 @@ public class CoroutineExtensionsTests
|
||||
|
||||
coroutine.MoveNext();
|
||||
|
||||
while (!coroutine.Current.IsDone)
|
||||
{
|
||||
coroutine.Current.Update(0.1);
|
||||
}
|
||||
while (!coroutine.Current.IsDone) coroutine.Current.Update(0.1);
|
||||
|
||||
Assert.That(progressValues.Count, Is.GreaterThan(0));
|
||||
Assert.That(progressValues[0], Is.EqualTo(0.0f).Within(0.01f));
|
||||
@ -461,10 +443,7 @@ public class CoroutineExtensionsTests
|
||||
|
||||
var sequence = CoroutineExtensions.Sequence(coroutine1, coroutine2);
|
||||
|
||||
while (sequence.MoveNext())
|
||||
{
|
||||
sequence.Current.Update(0.1);
|
||||
}
|
||||
while (sequence.MoveNext()) sequence.Current.Update(0.1);
|
||||
|
||||
Assert.That(sequence.MoveNext(), Is.False);
|
||||
}
|
||||
|
||||
@ -207,15 +207,9 @@ public class CoroutineHandleTests
|
||||
public void Multiple_Creates_Should_Increment_Keys()
|
||||
{
|
||||
var handles = new List<CoroutineHandle>();
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
handles.Add(new CoroutineHandle(1));
|
||||
}
|
||||
for (var i = 0; i < 5; i++) handles.Add(new CoroutineHandle(1));
|
||||
|
||||
for (var i = 0; i < handles.Count - 1; i++)
|
||||
{
|
||||
Assert.That(handles[i].Equals(handles[i + 1]), Is.False);
|
||||
}
|
||||
for (var i = 0; i < handles.Count - 1; i++) Assert.That(handles[i].Equals(handles[i + 1]), Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -219,10 +219,7 @@ public class CoroutineHelperTests
|
||||
var callCount = 0;
|
||||
var coroutine = CoroutineHelper.RepeatCall(0.1, 3, () => callCount++);
|
||||
|
||||
while (coroutine.MoveNext())
|
||||
{
|
||||
coroutine.Current.Update(0.1);
|
||||
}
|
||||
while (coroutine.MoveNext()) coroutine.Current.Update(0.1);
|
||||
|
||||
Assert.That(callCount, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ public class CoroutineSchedulerTests
|
||||
public void SetUp()
|
||||
{
|
||||
_timeSource = new TestTimeSource();
|
||||
_scheduler = new CoroutineScheduler(_timeSource, instanceId: 1, initialCapacity: 4);
|
||||
_scheduler = new CoroutineScheduler(_timeSource, 1, 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -327,15 +327,9 @@ public class CoroutineSchedulerTests
|
||||
public void Scheduler_Should_Expand_Capacity_When_Slots_Full()
|
||||
{
|
||||
var coroutines = new List<IEnumerator<IYieldInstruction>>();
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
coroutines.Add(CreateYieldingCoroutine(new Delay(1.0)));
|
||||
}
|
||||
for (var i = 0; i < 10; i++) coroutines.Add(CreateYieldingCoroutine(new Delay(1.0)));
|
||||
|
||||
foreach (var coroutine in coroutines)
|
||||
{
|
||||
_scheduler.Run(coroutine);
|
||||
}
|
||||
foreach (var coroutine in coroutines) _scheduler.Run(coroutine);
|
||||
|
||||
Assert.That(_scheduler.ActiveCoroutineCount, Is.EqualTo(10));
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void AsCoroutineInstructionOfT_Should_Return_WaitForTaskOfT()
|
||||
{
|
||||
var task = Task.FromResult(42);
|
||||
var instruction = task.AsCoroutineInstruction<int>();
|
||||
var instruction = task.AsCoroutineInstruction();
|
||||
|
||||
Assert.That(instruction, Is.InstanceOf<WaitForTask<int>>());
|
||||
}
|
||||
@ -64,7 +64,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void AsCoroutineInstructionOfT_Should_Access_Task_Result()
|
||||
{
|
||||
var task = Task.FromResult(42);
|
||||
var instruction = task.AsCoroutineInstruction<int>();
|
||||
var instruction = task.AsCoroutineInstruction();
|
||||
|
||||
task.Wait();
|
||||
|
||||
@ -90,7 +90,7 @@ public class TaskCoroutineExtensionsTests
|
||||
{
|
||||
Task<int> task = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => task.AsCoroutineInstruction<int>());
|
||||
Assert.Throws<ArgumentNullException>(() => task.AsCoroutineInstruction());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -112,7 +112,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void AsCoroutineInstructionOfT_Should_Handle_Faulted_Task()
|
||||
{
|
||||
var task = Task.FromException<int>(new InvalidOperationException("Test exception"));
|
||||
var instruction = task.AsCoroutineInstruction<int>();
|
||||
var instruction = task.AsCoroutineInstruction();
|
||||
|
||||
Assert.That(instruction, Is.InstanceOf<WaitForTask<int>>());
|
||||
}
|
||||
@ -124,7 +124,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void StartTaskAsCoroutine_Should_Return_Valid_Handle()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource);
|
||||
var task = Task.CompletedTask;
|
||||
|
||||
var handle = scheduler.StartTaskAsCoroutine(task);
|
||||
@ -139,7 +139,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void StartTaskAsCoroutineOfT_Should_Return_Valid_Handle()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource);
|
||||
var task = Task.FromResult(42);
|
||||
|
||||
var handle = scheduler.StartTaskAsCoroutine(task);
|
||||
@ -154,7 +154,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void StartTaskAsCoroutine_Should_Wait_For_Task_Completion()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource);
|
||||
|
||||
var completed = false;
|
||||
var tcs = new TaskCompletionSource<object?>();
|
||||
@ -180,7 +180,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void StartTaskAsCoroutineOfT_Should_Wait_For_Task_Completion()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource);
|
||||
|
||||
var tcs = new TaskCompletionSource<int>();
|
||||
|
||||
@ -204,7 +204,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void StartTaskAsCoroutine_Should_Handle_Completed_Task()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource);
|
||||
var task = Task.CompletedTask;
|
||||
|
||||
scheduler.StartTaskAsCoroutine(task);
|
||||
@ -221,7 +221,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void StartTaskAsCoroutine_Should_Handle_Faulted_Task()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource);
|
||||
var task = Task.FromException(new InvalidOperationException("Test"));
|
||||
|
||||
scheduler.StartTaskAsCoroutine(task);
|
||||
@ -236,7 +236,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void StartTaskAsCoroutineOfT_Should_Handle_Faulted_Task()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource);
|
||||
var task = Task.FromException<int>(new InvalidOperationException("Test"));
|
||||
|
||||
scheduler.StartTaskAsCoroutine(task);
|
||||
@ -252,7 +252,7 @@ public class TaskCoroutineExtensionsTests
|
||||
public void StartTaskAsCoroutine_Should_Work_With_Scheduler()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource);
|
||||
|
||||
var tcs = new TaskCompletionSource<object?>();
|
||||
scheduler.StartTaskAsCoroutine(tcs.Task);
|
||||
|
||||
@ -26,7 +26,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Not_Be_Done_Initially_With_Running_Coroutines()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
var coroutine1 = CreateDelayedCoroutine(() => { }, 1.0);
|
||||
var coroutine2 = CreateDelayedCoroutine(() => { }, 1.0);
|
||||
|
||||
@ -48,7 +48,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Be_Done_When_All_Coroutines_Complete()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
var coroutine1 = CreateSimpleCoroutine();
|
||||
var coroutine2 = CreateSimpleCoroutine();
|
||||
|
||||
@ -73,7 +73,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Wait_For_All_Delayed_Coroutines()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var executionCount = 0;
|
||||
var coroutine1 = CreateDelayedCoroutine(() => executionCount++, 1.0);
|
||||
@ -92,10 +92,7 @@ public class WaitForAllCoroutinesTests
|
||||
Assert.That(wait.IsDone, Is.False);
|
||||
Assert.That(executionCount, Is.EqualTo(0));
|
||||
|
||||
for (var i = 0; i < 12; i++)
|
||||
{
|
||||
scheduler.Update();
|
||||
}
|
||||
for (var i = 0; i < 12; i++) scheduler.Update();
|
||||
|
||||
Assert.That(wait.IsDone, Is.True);
|
||||
Assert.That(executionCount, Is.EqualTo(3));
|
||||
@ -108,7 +105,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Handle_Empty_Handles_List()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
var handles = Array.Empty<CoroutineHandle>();
|
||||
|
||||
var wait = new WaitForAllCoroutines(scheduler, handles);
|
||||
@ -123,7 +120,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Throw_ArgumentNullException_When_Handles_Is_Null()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => new WaitForAllCoroutines(scheduler, null!));
|
||||
}
|
||||
@ -146,7 +143,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Handle_Single_Coroutine()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
var coroutine = CreateSimpleCoroutine();
|
||||
|
||||
var handles = new List<CoroutineHandle> { scheduler.Run(coroutine) };
|
||||
@ -165,7 +162,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Not_Be_Done_When_Some_Coroutines_Complete()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var executionCount = 0;
|
||||
var coroutine1 = CreateSimpleCoroutine();
|
||||
@ -194,7 +191,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Handle_Killed_Coroutines()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var coroutine1 = CreateDelayedCoroutine(() => { }, 1.0);
|
||||
var coroutine2 = CreateDelayedCoroutine(() => { }, 1.0);
|
||||
@ -225,7 +222,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Handle_Paused_And_Resumed_Coroutines()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var executionCount = 0;
|
||||
var coroutine1 = CreateDelayedCoroutine(() => executionCount++, 1.0);
|
||||
@ -241,20 +238,14 @@ public class WaitForAllCoroutinesTests
|
||||
|
||||
scheduler.Pause(handles[0]);
|
||||
|
||||
for (var i = 0; i < 12; i++)
|
||||
{
|
||||
scheduler.Update();
|
||||
}
|
||||
for (var i = 0; i < 12; i++) scheduler.Update();
|
||||
|
||||
Assert.That(wait.IsDone, Is.False);
|
||||
Assert.That(executionCount, Is.EqualTo(1));
|
||||
|
||||
scheduler.Resume(handles[0]);
|
||||
|
||||
for (var i = 0; i < 12; i++)
|
||||
{
|
||||
scheduler.Update();
|
||||
}
|
||||
for (var i = 0; i < 12; i++) scheduler.Update();
|
||||
|
||||
Assert.That(wait.IsDone, Is.True);
|
||||
Assert.That(executionCount, Is.EqualTo(2));
|
||||
@ -267,7 +258,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Update_Should_Not_Affect_State()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
var coroutine = CreateDelayedCoroutine(() => { }, 1.0);
|
||||
|
||||
var handles = new List<CoroutineHandle> { scheduler.Run(coroutine) };
|
||||
@ -287,7 +278,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Handle_Invalid_Handles()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var handles = new List<CoroutineHandle> { default };
|
||||
|
||||
@ -303,7 +294,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Handle_Mixed_Valid_And_Invalid_Handles()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
var coroutine = CreateSimpleCoroutine();
|
||||
|
||||
var handles = new List<CoroutineHandle>
|
||||
@ -326,23 +317,17 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Handle_Many_Coroutines()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
var executionCount = 0;
|
||||
|
||||
var handles = new List<CoroutineHandle>();
|
||||
for (var i = 0; i < 20; i++)
|
||||
{
|
||||
handles.Add(scheduler.Run(CreateDelayedCoroutine(() => executionCount++, 1.0)));
|
||||
}
|
||||
for (var i = 0; i < 20; i++) handles.Add(scheduler.Run(CreateDelayedCoroutine(() => executionCount++, 1.0)));
|
||||
|
||||
var wait = new WaitForAllCoroutines(scheduler, handles);
|
||||
|
||||
Assert.That(wait.IsDone, Is.False);
|
||||
|
||||
for (var i = 0; i < 120; i++)
|
||||
{
|
||||
scheduler.Update();
|
||||
}
|
||||
for (var i = 0; i < 120; i++) scheduler.Update();
|
||||
|
||||
Assert.That(wait.IsDone, Is.True);
|
||||
Assert.That(executionCount, Is.EqualTo(20));
|
||||
@ -355,7 +340,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Handle_Coroutines_With_Exceptions()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var coroutine1 = CreateSimpleCoroutine();
|
||||
var coroutine2 = CreateExceptionCoroutine();
|
||||
@ -382,7 +367,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Work_With_ParallelCoroutines()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var executionOrder = new List<int>();
|
||||
var coroutine1 = CreateDelayedCoroutine(() => executionOrder.Add(1), 0.5);
|
||||
@ -412,7 +397,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Implement_IYieldInstruction()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
var handles = Array.Empty<CoroutineHandle>();
|
||||
|
||||
var wait = new WaitForAllCoroutines(scheduler, handles);
|
||||
@ -427,7 +412,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Be_Done_Immediately_When_All_Coroutines_Complete_Immediately()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
|
||||
var coroutine1 = CreateSimpleCoroutine();
|
||||
var coroutine2 = CreateSimpleCoroutine();
|
||||
@ -453,7 +438,7 @@ public class WaitForAllCoroutinesTests
|
||||
public void WaitForAllCoroutines_Should_Handle_Duplicate_Handles()
|
||||
{
|
||||
var timeSource = new TestTimeSource();
|
||||
var scheduler = new CoroutineScheduler(timeSource, instanceId: 1);
|
||||
var scheduler = new CoroutineScheduler(timeSource, 1);
|
||||
var coroutine = CreateDelayedCoroutine(() => { }, 1.0);
|
||||
|
||||
var handle = scheduler.Run(coroutine);
|
||||
@ -461,10 +446,7 @@ public class WaitForAllCoroutinesTests
|
||||
|
||||
var wait = new WaitForAllCoroutines(scheduler, handles);
|
||||
|
||||
for (var i = 0; i < 12; i++)
|
||||
{
|
||||
scheduler.Update();
|
||||
}
|
||||
for (var i = 0; i < 12; i++) scheduler.Update();
|
||||
|
||||
Assert.That(wait.IsDone, Is.True);
|
||||
}
|
||||
|
||||
@ -66,10 +66,7 @@ public class WaitForProgressTests
|
||||
var progressValues = new List<float>();
|
||||
var wait = new WaitForProgress(1.0, progressValues.Add);
|
||||
|
||||
while (!wait.IsDone)
|
||||
{
|
||||
wait.Update(0.1);
|
||||
}
|
||||
while (!wait.IsDone) wait.Update(0.1);
|
||||
|
||||
foreach (var progress in progressValues)
|
||||
{
|
||||
@ -207,10 +204,7 @@ public class WaitForProgressTests
|
||||
var progressValues = new List<float>();
|
||||
var wait = new WaitForProgress(1.0, progressValues.Add);
|
||||
|
||||
while (!wait.IsDone)
|
||||
{
|
||||
wait.Update(0.1);
|
||||
}
|
||||
while (!wait.IsDone) wait.Update(0.1);
|
||||
|
||||
Assert.That(progressValues[^1], Is.EqualTo(1.0f).Within(0.01f));
|
||||
}
|
||||
|
||||
@ -8,7 +8,9 @@ namespace GFramework.Core.Tests.coroutine;
|
||||
/// WaitForTask的单元测试类
|
||||
/// 测试内容包括:
|
||||
/// - WaitForTask初始化和等待
|
||||
/// - WaitForTask<T>初始化、等待和结果获取
|
||||
/// - WaitForTask
|
||||
/// <T>
|
||||
/// 初始化、等待和结果获取
|
||||
/// - 异常处理
|
||||
/// - 边界条件
|
||||
/// </summary>
|
||||
@ -185,7 +187,10 @@ public class WaitForTaskTests
|
||||
|
||||
Assert.That(wait.IsDone, Is.True);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => { var _ = wait.Result; });
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
var _ = wait.Result;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -271,10 +271,7 @@ public class YieldInstructionTests
|
||||
|
||||
Assert.That(wait.IsDone, Is.False);
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
Assert.That(wait.IsDone, Is.False);
|
||||
}
|
||||
for (var i = 0; i < 10; i++) Assert.That(wait.IsDone, Is.False);
|
||||
|
||||
continueWaiting = false;
|
||||
Assert.That(wait.IsDone, Is.True);
|
||||
|
||||
@ -56,7 +56,7 @@ public class UnRegisterTests
|
||||
[Test]
|
||||
public void BindablePropertyUnRegister_Should_UnRegister_From_Property()
|
||||
{
|
||||
var property = new BindableProperty<int>(0);
|
||||
var property = new BindableProperty<int>();
|
||||
var callCount = 0;
|
||||
|
||||
Action<int> handler = _ => { callCount++; };
|
||||
@ -76,7 +76,7 @@ public class UnRegisterTests
|
||||
[Test]
|
||||
public void BindablePropertyUnRegister_Should_Clear_References()
|
||||
{
|
||||
var property = new BindableProperty<int>(0);
|
||||
var property = new BindableProperty<int>();
|
||||
|
||||
Action<int> handler = _ => { };
|
||||
var unRegister = new BindablePropertyUnRegister<int>(property, handler);
|
||||
@ -106,7 +106,7 @@ public class UnRegisterTests
|
||||
[Test]
|
||||
public void BindablePropertyUnRegister_WithNull_Handler_Should_NotThrow()
|
||||
{
|
||||
var property = new BindableProperty<int>(0);
|
||||
var property = new BindableProperty<int>();
|
||||
var unRegister = new BindablePropertyUnRegister<int>(property, null!);
|
||||
|
||||
Assert.DoesNotThrow(() => unRegister.UnRegister());
|
||||
|
||||
@ -18,7 +18,7 @@ public class LoggerFactoryTests
|
||||
public void ConsoleLoggerFactory_GetLogger_ShouldReturnConsoleLogger()
|
||||
{
|
||||
var factory = new ConsoleLoggerFactory();
|
||||
var logger = factory.GetLogger("TestLogger", LogLevel.Info);
|
||||
var logger = factory.GetLogger("TestLogger");
|
||||
|
||||
Assert.That(logger, Is.Not.Null);
|
||||
Assert.That(logger, Is.InstanceOf<ConsoleLogger>());
|
||||
@ -228,7 +228,7 @@ public class LoggerFactoryTests
|
||||
public void ConsoleLoggerFactory_MultipleLoggers_ShouldBeIndependent()
|
||||
{
|
||||
var factory = new ConsoleLoggerFactory();
|
||||
var logger1 = factory.GetLogger("Logger1", LogLevel.Info);
|
||||
var logger1 = factory.GetLogger("Logger1");
|
||||
var logger2 = factory.GetLogger("Logger2", LogLevel.Debug);
|
||||
|
||||
Assert.That(logger1.Name(), Is.EqualTo("Logger1"));
|
||||
|
||||
@ -17,7 +17,7 @@ public class LoggerTests
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_logger = new TestLogger("TestLogger", LogLevel.Info);
|
||||
_logger = new TestLogger("TestLogger");
|
||||
}
|
||||
|
||||
private TestLogger _logger = null!;
|
||||
|
||||
@ -159,7 +159,7 @@ public class StateMachineSystemTests
|
||||
public void ChangeTo_Should_Send_StateChangedEvent()
|
||||
{
|
||||
// 订阅StateChangedEvent事件以验证事件是否被正确发送
|
||||
bool eventReceived = false;
|
||||
var eventReceived = false;
|
||||
StateChangedEvent? receivedEvent = null;
|
||||
|
||||
_eventBus!.Register<StateChangedEvent>(e =>
|
||||
@ -191,7 +191,7 @@ public class StateMachineSystemTests
|
||||
public void ChangeTo_Should_Send_StateChangedEvent_With_OldState()
|
||||
{
|
||||
// 订阅StateChangedEvent事件以验证事件是否被正确发送
|
||||
bool eventReceived = false;
|
||||
var eventReceived = false;
|
||||
StateChangedEvent? receivedEvent = null;
|
||||
|
||||
_eventBus!.Register<StateChangedEvent>(e =>
|
||||
@ -283,7 +283,10 @@ public class TestStateMachineSystemV5 : StateMachineSystem
|
||||
/// 获取状态机内部的状态字典
|
||||
/// </summary>
|
||||
/// <returns>类型到状态实例的映射字典</returns>
|
||||
public Dictionary<Type, IState> GetStates() => States;
|
||||
public Dictionary<Type, IState> GetStates()
|
||||
{
|
||||
return States;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -345,7 +348,10 @@ public class TestStateV5 : IState
|
||||
/// </summary>
|
||||
/// <param name="next">目标状态</param>
|
||||
/// <returns>始终返回true表示允许转换</returns>
|
||||
public bool CanTransitionTo(IState next) => true;
|
||||
public bool CanTransitionTo(IState next)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 进入状态时调用
|
||||
|
||||
@ -7,6 +7,6 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\$(AssemblyName).Abstractions\$(AssemblyName).Abstractions.csproj" />
|
||||
<ProjectReference Include="..\$(AssemblyName).Abstractions\$(AssemblyName).Abstractions.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using GFramework.Core.Abstractions.architecture;
|
||||
using GFramework.Core.Abstractions.enums;
|
||||
using GFramework.Core.Abstractions.environment;
|
||||
@ -86,9 +82,11 @@ public abstract class Architecture(
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
|
||||
private readonly TaskCompletionSource _readyTcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
public bool IsReady => CurrentPhase == ArchitecturePhase.Ready;
|
||||
|
||||
/// <summary>
|
||||
/// 待初始化组件的去重集合
|
||||
/// </summary>
|
||||
@ -336,14 +334,10 @@ public abstract class Architecture(
|
||||
private static async Task InitializeComponentAsync(IInitializable component, bool asyncMode)
|
||||
{
|
||||
if (asyncMode && component is IAsyncInitializable asyncInit)
|
||||
{
|
||||
await asyncInit.InitializeAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
component.Init();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 抽象初始化方法,由子类重写以进行自定义初始化操作
|
||||
@ -568,5 +562,6 @@ public abstract class Architecture(
|
||||
{
|
||||
return IsReady ? Task.CompletedTask : _readyTcs.Task;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@ -26,8 +26,6 @@ public class ArchitectureServices : IArchitectureServices
|
||||
/// </summary>
|
||||
private readonly ICommandBus _commandBus;
|
||||
|
||||
private readonly IIocContainer _container;
|
||||
|
||||
/// <summary>
|
||||
/// 事件总线实例
|
||||
/// </summary>
|
||||
@ -45,7 +43,7 @@ public class ArchitectureServices : IArchitectureServices
|
||||
/// </summary>
|
||||
public ArchitectureServices()
|
||||
{
|
||||
_container = new IocContainer();
|
||||
Container = new IocContainer();
|
||||
|
||||
// 创建服务实例
|
||||
_eventBus = new EventBus();
|
||||
@ -54,16 +52,16 @@ public class ArchitectureServices : IArchitectureServices
|
||||
_asyncQueryBus = new AsyncQueryBus();
|
||||
|
||||
// 将服务注册到容器
|
||||
_container.RegisterPlurality(_eventBus);
|
||||
_container.RegisterPlurality(_commandBus);
|
||||
_container.RegisterPlurality(_queryBus);
|
||||
_container.RegisterPlurality(_asyncQueryBus);
|
||||
Container.RegisterPlurality(_eventBus);
|
||||
Container.RegisterPlurality(_commandBus);
|
||||
Container.RegisterPlurality(_queryBus);
|
||||
Container.RegisterPlurality(_asyncQueryBus);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取依赖注入容器
|
||||
/// </summary>
|
||||
public IIocContainer Container => _container;
|
||||
public IIocContainer Container { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型事件系统
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Concurrent;
|
||||
using GFramework.Core.Abstractions.architecture;
|
||||
|
||||
namespace GFramework.Core.architecture;
|
||||
|
||||
@ -147,11 +147,11 @@ public enum ArchitecturePhase
|
||||
// 1. 定义你的架构(继承 Architecture 基类)
|
||||
public class GameArchitecture : Architecture
|
||||
{
|
||||
protected override void Init()
|
||||
{
|
||||
// 注册 Model
|
||||
RegisterModel(new PlayerModel());
|
||||
RegisterModel(new InventoryModel());
|
||||
protected override void Init()
|
||||
{
|
||||
// 注册 Model
|
||||
RegisterModel(new PlayerModel());
|
||||
RegisterModel(new InventoryModel());
|
||||
|
||||
// 注册 System
|
||||
RegisterSystem(new GameplaySystem());
|
||||
@ -161,6 +161,7 @@ public class GameArchitecture : Architecture
|
||||
RegisterUtility(new StorageUtility());
|
||||
RegisterUtility(new TimeUtility());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 2. 创建并初始化架构
|
||||
@ -175,7 +176,7 @@ architecture.Initialize();
|
||||
// 在 Controller 或其他组件中注入架构实例
|
||||
public class GameController : IController
|
||||
{
|
||||
private readonly IArchitecture _architecture;
|
||||
private readonly IArchitecture _architecture;
|
||||
|
||||
// 通过构造函数注入架构
|
||||
public GameController(IArchitecture architecture)
|
||||
@ -202,7 +203,9 @@ public class GameController : IController
|
||||
{
|
||||
// 处理玩家死亡事件
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**核心方法与属性:**
|
||||
@ -244,6 +247,7 @@ await architecture.InitializeAsync(); // 异步等待初始化完成
|
||||
```
|
||||
|
||||
**优势:**
|
||||
|
||||
- 支持异步初始化 Model 和 System
|
||||
- 可以利用异步 I/O 操作(如异步加载数据)
|
||||
- 提高初始化性能
|
||||
@ -259,6 +263,7 @@ public void InstallModule(IArchitectureModule module)
|
||||
```
|
||||
|
||||
**参数:**
|
||||
|
||||
- `module`:要安装的模块实例
|
||||
|
||||
**使用示例:**
|
||||
@ -291,6 +296,7 @@ public void RegisterLifecycleHook(IArchitectureLifecycle hook)
|
||||
```
|
||||
|
||||
**参数:**
|
||||
|
||||
- `hook`:生命周期钩子实例
|
||||
|
||||
**使用示例:**
|
||||
@ -389,28 +395,29 @@ architecture.InstallModule(module);
|
||||
// 3. 监听架构阶段变化
|
||||
public class GamePhaseListener : IArchitecturePhaseAware
|
||||
{
|
||||
public void OnArchitecturePhase(ArchitecturePhase phase)
|
||||
{
|
||||
switch (phase)
|
||||
{
|
||||
case ArchitecturePhase.Ready:
|
||||
GD.Print("架构已就绪,可以开始游戏了");
|
||||
break;
|
||||
case ArchitecturePhase.Destroying:
|
||||
GD.Print("架构正在销毁");
|
||||
break;
|
||||
}
|
||||
}
|
||||
public void OnArchitecturePhase(ArchitecturePhase phase)
|
||||
{
|
||||
switch (phase)
|
||||
{
|
||||
case ArchitecturePhase.Ready:
|
||||
GD.Print("架构已就绪,可以开始游戏了");
|
||||
break;
|
||||
case ArchitecturePhase.Destroying:
|
||||
GD.Print("架构正在销毁");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 生命周期钩子
|
||||
public class LifecycleHook : IArchitectureLifecycle
|
||||
{
|
||||
public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
|
||||
{
|
||||
GD.Print($"架构阶段变化: {phase}");
|
||||
}
|
||||
public void OnPhase(ArchitecturePhase phase, IArchitecture architecture)
|
||||
{
|
||||
GD.Print($"架构阶段变化: {phase}");
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### [`ArchitectureConfiguration`](ArchitectureConfiguration.cs)
|
||||
|
||||
@ -61,20 +61,29 @@ public readonly struct CoroutineHandle : IEquatable<CoroutineHandle>
|
||||
/// </summary>
|
||||
/// <param name="other">要比较的协程句柄</param>
|
||||
/// <returns>如果两个句柄的ID相同则返回true,否则返回false</returns>
|
||||
public bool Equals(CoroutineHandle other) => _id == other._id;
|
||||
public bool Equals(CoroutineHandle other)
|
||||
{
|
||||
return _id == other._id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 比较当前对象与指定对象是否相等
|
||||
/// </summary>
|
||||
/// <param name="obj">要比较的对象</param>
|
||||
/// <returns>如果对象是协程句柄且ID相同则返回true,否则返回false</returns>
|
||||
public override bool Equals(object? obj) => obj is CoroutineHandle handle && Equals(handle);
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is CoroutineHandle handle && Equals(handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前协程句柄的哈希码
|
||||
/// </summary>
|
||||
/// <returns>基于内部ID计算的哈希码</returns>
|
||||
public override int GetHashCode() => _id;
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 比较两个协程句柄是否相等
|
||||
@ -82,7 +91,10 @@ public readonly struct CoroutineHandle : IEquatable<CoroutineHandle>
|
||||
/// <param name="a">第一个协程句柄</param>
|
||||
/// <param name="b">第二个协程句柄</param>
|
||||
/// <returns>如果两个句柄的ID相同则返回true,否则返回false</returns>
|
||||
public static bool operator ==(CoroutineHandle a, CoroutineHandle b) => a._id == b._id;
|
||||
public static bool operator ==(CoroutineHandle a, CoroutineHandle b)
|
||||
{
|
||||
return a._id == b._id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 比较两个协程句柄是否不相等
|
||||
@ -90,5 +102,8 @@ public readonly struct CoroutineHandle : IEquatable<CoroutineHandle>
|
||||
/// <param name="a">第一个协程句柄</param>
|
||||
/// <param name="b">第二个协程句柄</param>
|
||||
/// <returns>如果两个句柄的ID不同则返回true,否则返回false</returns>
|
||||
public static bool operator !=(CoroutineHandle a, CoroutineHandle b) => a._id != b._id;
|
||||
public static bool operator !=(CoroutineHandle a, CoroutineHandle b)
|
||||
{
|
||||
return a._id != b._id;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
using System.Threading;
|
||||
using GFramework.Core.Abstractions.coroutine;
|
||||
using GFramework.Core.coroutine.instructions;
|
||||
|
||||
|
||||
@ -17,7 +17,6 @@ public sealed class CoroutineScheduler(
|
||||
private readonly Dictionary<string, HashSet<CoroutineHandle>> _tagged = new();
|
||||
private readonly ITimeSource _timeSource = timeSource ?? throw new ArgumentNullException(nameof(timeSource));
|
||||
private readonly Dictionary<CoroutineHandle, HashSet<CoroutineHandle>> _waiting = new();
|
||||
private int _activeCount;
|
||||
private int _nextSlot;
|
||||
|
||||
private CoroutineSlot?[] _slots = new CoroutineSlot?[initialCapacity];
|
||||
@ -30,7 +29,12 @@ public sealed class CoroutineScheduler(
|
||||
/// <summary>
|
||||
/// 获取活跃协程数量
|
||||
/// </summary>
|
||||
public int ActiveCoroutineCount => _activeCount;
|
||||
public int ActiveCoroutineCount { get; private set; }
|
||||
|
||||
public bool IsCoroutineAlive(CoroutineHandle handle)
|
||||
{
|
||||
return _metadata.ContainsKey(handle);
|
||||
}
|
||||
|
||||
#region Run / Update
|
||||
|
||||
@ -72,7 +76,7 @@ public sealed class CoroutineScheduler(
|
||||
AddTag(tag, handle);
|
||||
|
||||
Prewarm(slotIndex);
|
||||
_activeCount++;
|
||||
ActiveCoroutineCount++;
|
||||
|
||||
return handle;
|
||||
}
|
||||
@ -106,14 +110,10 @@ public sealed class CoroutineScheduler(
|
||||
|
||||
// 2️⃣ 推进协程
|
||||
if (!slot.Enumerator.MoveNext())
|
||||
{
|
||||
Complete(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
slot.Waiting = slot.Enumerator.Current;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnError(i, ex);
|
||||
@ -234,7 +234,7 @@ public sealed class CoroutineScheduler(
|
||||
/// <returns>被清除的协程数量</returns>
|
||||
public int Clear()
|
||||
{
|
||||
var count = _activeCount;
|
||||
var count = ActiveCoroutineCount;
|
||||
|
||||
Array.Clear(_slots);
|
||||
_metadata.Clear();
|
||||
@ -242,7 +242,7 @@ public sealed class CoroutineScheduler(
|
||||
_waiting.Clear();
|
||||
|
||||
_nextSlot = 0;
|
||||
_activeCount = 0;
|
||||
ActiveCoroutineCount = 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -264,14 +264,10 @@ public sealed class CoroutineScheduler(
|
||||
try
|
||||
{
|
||||
if (!slot.Enumerator.MoveNext())
|
||||
{
|
||||
Complete(slotIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
slot.Waiting = slot.Enumerator.Current;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnError(slotIndex, ex);
|
||||
@ -293,7 +289,7 @@ public sealed class CoroutineScheduler(
|
||||
return;
|
||||
|
||||
_slots[slotIndex] = null;
|
||||
_activeCount--;
|
||||
ActiveCoroutineCount--;
|
||||
|
||||
RemoveTag(handle);
|
||||
_metadata.Remove(handle);
|
||||
@ -368,8 +364,4 @@ public sealed class CoroutineScheduler(
|
||||
}
|
||||
|
||||
#endregion
|
||||
public bool IsCoroutineAlive(CoroutineHandle handle)
|
||||
{
|
||||
return _metadata.ContainsKey(handle);
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,11 @@ internal sealed class CoroutineSlot
|
||||
/// </summary>
|
||||
public required IEnumerator<IYieldInstruction> Enumerator;
|
||||
|
||||
/// <summary>
|
||||
/// 协程句柄,用于标识和管理协程实例
|
||||
/// </summary>
|
||||
public CoroutineHandle Handle;
|
||||
|
||||
/// <summary>
|
||||
/// 协程当前状态
|
||||
/// </summary>
|
||||
@ -21,9 +26,4 @@ internal sealed class CoroutineSlot
|
||||
/// 当前等待的指令,用于控制协程的暂停和恢复
|
||||
/// </summary>
|
||||
public IYieldInstruction? Waiting;
|
||||
|
||||
/// <summary>
|
||||
/// 协程句柄,用于标识和管理协程实例
|
||||
/// </summary>
|
||||
public CoroutineHandle Handle;
|
||||
}
|
||||
@ -20,10 +20,7 @@ public static class CoroutineExtensions
|
||||
Action action,
|
||||
int? count = null)
|
||||
{
|
||||
if (count is < 0)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
if (count is < 0) yield break;
|
||||
|
||||
var executedCount = 0;
|
||||
while (count == null || executedCount < count)
|
||||
@ -44,10 +41,7 @@ public static class CoroutineExtensions
|
||||
double delay,
|
||||
Action? action)
|
||||
{
|
||||
if (delay < 0)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
if (delay < 0) yield break;
|
||||
|
||||
yield return new Delay(delay);
|
||||
action?.Invoke();
|
||||
@ -63,10 +57,7 @@ public static class CoroutineExtensions
|
||||
{
|
||||
foreach (var coroutine in coroutines)
|
||||
{
|
||||
while (coroutine.MoveNext())
|
||||
{
|
||||
yield return coroutine.Current;
|
||||
}
|
||||
while (coroutine.MoveNext()) yield return coroutine.Current;
|
||||
|
||||
// 清理协程
|
||||
coroutine.Dispose();
|
||||
@ -84,10 +75,7 @@ public static class CoroutineExtensions
|
||||
this CoroutineScheduler scheduler,
|
||||
params IEnumerator<IYieldInstruction>[]? coroutines)
|
||||
{
|
||||
if (coroutines == null || coroutines.Length == 0)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
if (coroutines == null || coroutines.Length == 0) yield break;
|
||||
|
||||
// 启动所有协程并收集句柄
|
||||
var handles = new List<CoroutineHandle>();
|
||||
@ -98,7 +86,7 @@ public static class CoroutineExtensions
|
||||
}
|
||||
|
||||
// 等待所有协程完成
|
||||
yield return new WaitForAllCoroutines(scheduler,handles);
|
||||
yield return new WaitForAllCoroutines(scheduler, handles);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -120,12 +108,8 @@ public static class CoroutineExtensions
|
||||
onProgress?.Invoke(0.0f);
|
||||
|
||||
if (onProgress != null)
|
||||
{
|
||||
yield return new WaitForProgress(totalTime, onProgress);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return new Delay(totalTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using GFramework.Core.Abstractions.coroutine;
|
||||
|
||||
namespace GFramework.Core.coroutine.instructions;
|
||||
@ -13,16 +12,51 @@ public class AsyncOperation : IYieldInstruction, INotifyCompletion
|
||||
private volatile bool _completed;
|
||||
private volatile Action? _continuation;
|
||||
|
||||
/// <summary>
|
||||
/// 获取异步操作是否已完成
|
||||
/// </summary>
|
||||
public bool IsDone => _completed;
|
||||
|
||||
/// <summary>
|
||||
/// 获取异步操作的任务
|
||||
/// </summary>
|
||||
public Task Task => _tcs.Task;
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否已完成
|
||||
/// </summary>
|
||||
public bool IsCompleted => _completed;
|
||||
|
||||
/// <summary>
|
||||
/// 设置延续操作
|
||||
/// </summary>
|
||||
/// <param name="continuation">要执行的延续操作</param>
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
// 尝试添加延续
|
||||
var current = _continuation;
|
||||
var newContinuation = current == null ? continuation : current + continuation;
|
||||
|
||||
if (Interlocked.CompareExchange(ref _continuation, newContinuation, current) != current)
|
||||
{
|
||||
// 如果CAS失败,说明可能已经完成,直接执行
|
||||
if (_completed)
|
||||
continuation();
|
||||
else
|
||||
// 重试
|
||||
OnCompleted(continuation);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 双重检查:如果在设置延续后发现已完成,需要执行延续
|
||||
if (_completed)
|
||||
{
|
||||
var cont = Interlocked.Exchange(ref _continuation, null);
|
||||
if (cont != null) cont();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取异步操作是否已完成
|
||||
/// </summary>
|
||||
public bool IsDone => _completed;
|
||||
|
||||
/// <summary>
|
||||
/// 更新方法,用于处理时间更新逻辑
|
||||
/// </summary>
|
||||
@ -44,7 +78,6 @@ public class AsyncOperation : IYieldInstruction, INotifyCompletion
|
||||
|
||||
var continuation = Interlocked.Exchange(ref _continuation, null);
|
||||
if (continuation != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
continuation.Invoke();
|
||||
@ -54,7 +87,6 @@ public class AsyncOperation : IYieldInstruction, INotifyCompletion
|
||||
// 忽略延续中的异常
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标记异步操作因异常而失败
|
||||
@ -69,7 +101,6 @@ public class AsyncOperation : IYieldInstruction, INotifyCompletion
|
||||
|
||||
var continuation = Interlocked.Exchange(ref _continuation, null);
|
||||
if (continuation != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
continuation.Invoke();
|
||||
@ -79,44 +110,6 @@ public class AsyncOperation : IYieldInstruction, INotifyCompletion
|
||||
// 忽略延续中的异常
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置延续操作
|
||||
/// </summary>
|
||||
/// <param name="continuation">要执行的延续操作</param>
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
// 尝试添加延续
|
||||
var current = _continuation;
|
||||
var newContinuation = current == null ? continuation : current + continuation;
|
||||
|
||||
if (Interlocked.CompareExchange(ref _continuation, newContinuation, current) != current)
|
||||
{
|
||||
// 如果CAS失败,说明可能已经完成,直接执行
|
||||
if (_completed)
|
||||
{
|
||||
continuation();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 重试
|
||||
OnCompleted(continuation);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 双重检查:如果在设置延续后发现已完成,需要执行延续
|
||||
if (_completed)
|
||||
{
|
||||
var cont = Interlocked.Exchange(ref _continuation, null);
|
||||
if (cont != null)
|
||||
{
|
||||
cont();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取异步操作结果
|
||||
@ -134,9 +127,4 @@ public class AsyncOperation : IYieldInstruction, INotifyCompletion
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否已完成
|
||||
/// </summary>
|
||||
public bool IsCompleted => _completed;
|
||||
}
|
||||
@ -10,8 +10,10 @@ public sealed class WaitForAllCoroutines(
|
||||
IReadOnlyList<CoroutineHandle> handles)
|
||||
: IYieldInstruction
|
||||
{
|
||||
private readonly IReadOnlyList<CoroutineHandle> _handles =
|
||||
handles ?? throw new ArgumentNullException(nameof(handles));
|
||||
|
||||
private readonly CoroutineScheduler _scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
|
||||
private readonly IReadOnlyList<CoroutineHandle> _handles = handles ?? throw new ArgumentNullException(nameof(handles));
|
||||
|
||||
public void Update(double deltaTime)
|
||||
{
|
||||
@ -20,9 +22,6 @@ public sealed class WaitForAllCoroutines(
|
||||
|
||||
public bool IsDone
|
||||
{
|
||||
get
|
||||
{
|
||||
return _handles.All(handle => !_scheduler.IsCoroutineAlive(handle));
|
||||
}
|
||||
get { return _handles.All(handle => !_scheduler.IsCoroutineAlive(handle)); }
|
||||
}
|
||||
}
|
||||
@ -7,8 +7,6 @@ namespace GFramework.Core.coroutine.instructions;
|
||||
/// </summary>
|
||||
public sealed class WaitForCoroutine : IYieldInstruction
|
||||
{
|
||||
private bool _done;
|
||||
|
||||
/// <summary>
|
||||
/// 更新方法,用于处理时间更新逻辑
|
||||
/// </summary>
|
||||
@ -20,10 +18,13 @@ public sealed class WaitForCoroutine : IYieldInstruction
|
||||
/// <summary>
|
||||
/// 获取协程是否已完成的状态
|
||||
/// </summary>
|
||||
public bool IsDone => _done;
|
||||
public bool IsDone { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内部方法,用于标记协程完成状态
|
||||
/// </summary>
|
||||
internal void Complete() => _done = true;
|
||||
internal void Complete()
|
||||
{
|
||||
IsDone = true;
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,6 @@ public class WaitForProgress : IYieldInstruction
|
||||
private readonly double _duration;
|
||||
private readonly Action<float> _onProgress;
|
||||
private double _elapsed;
|
||||
private bool _progressCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化等待进度指令
|
||||
@ -25,7 +24,7 @@ public class WaitForProgress : IYieldInstruction
|
||||
_duration = duration;
|
||||
_onProgress = onProgress ?? throw new ArgumentNullException(nameof(onProgress));
|
||||
_elapsed = 0;
|
||||
_progressCompleted = false;
|
||||
IsDone = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -34,7 +33,7 @@ public class WaitForProgress : IYieldInstruction
|
||||
/// <param name="deltaTime">时间增量</param>
|
||||
public void Update(double deltaTime)
|
||||
{
|
||||
if (_progressCompleted)
|
||||
if (IsDone)
|
||||
return;
|
||||
|
||||
_elapsed += deltaTime;
|
||||
@ -43,7 +42,7 @@ public class WaitForProgress : IYieldInstruction
|
||||
if (_elapsed >= _duration)
|
||||
{
|
||||
_elapsed = _duration;
|
||||
_progressCompleted = true;
|
||||
IsDone = true;
|
||||
_onProgress(1.0f);
|
||||
}
|
||||
else
|
||||
@ -56,5 +55,5 @@ public class WaitForProgress : IYieldInstruction
|
||||
/// <summary>
|
||||
/// 获取等待是否已完成
|
||||
/// </summary>
|
||||
public bool IsDone => _progressCompleted;
|
||||
public bool IsDone { get; private set; }
|
||||
}
|
||||
@ -21,19 +21,22 @@ public sealed class WaitForTask<T> : IYieldInstruction
|
||||
|
||||
// 检查Task是否已经完成
|
||||
if (_task.IsCompleted)
|
||||
{
|
||||
_done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 注册完成回调
|
||||
_task.ContinueWith(_ =>
|
||||
{
|
||||
_done = true;
|
||||
}, TaskContinuationOptions.ExecuteSynchronously);
|
||||
}
|
||||
_task.ContinueWith(_ => { _done = true; }, TaskContinuationOptions.ExecuteSynchronously);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Task的结果值
|
||||
/// </summary>
|
||||
public T Result => _task.GetAwaiter().GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// 获取Task的异常(如果有)
|
||||
/// </summary>
|
||||
public Exception? Exception => _task.Exception;
|
||||
|
||||
/// <summary>
|
||||
/// 更新方法,用于处理时间更新逻辑
|
||||
/// </summary>
|
||||
@ -47,14 +50,4 @@ public sealed class WaitForTask<T> : IYieldInstruction
|
||||
/// 获取等待是否已完成
|
||||
/// </summary>
|
||||
public bool IsDone => _done;
|
||||
|
||||
/// <summary>
|
||||
/// 获取Task的结果值
|
||||
/// </summary>
|
||||
public T Result => _task.GetAwaiter().GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// 获取Task的异常(如果有)
|
||||
/// </summary>
|
||||
public Exception? Exception => _task.Exception;
|
||||
}
|
||||
@ -23,19 +23,17 @@ public sealed class WaitForTask : IYieldInstruction
|
||||
|
||||
// 检查Task是否已经完成
|
||||
if (_task.IsCompleted)
|
||||
{
|
||||
_done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 注册完成回调
|
||||
_task.ContinueWith(_ =>
|
||||
{
|
||||
_done = true;
|
||||
}, TaskContinuationOptions.ExecuteSynchronously);
|
||||
}
|
||||
_task.ContinueWith(_ => { _done = true; }, TaskContinuationOptions.ExecuteSynchronously);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Task的异常(如果有)
|
||||
/// </summary>
|
||||
public Exception? Exception => _task.Exception;
|
||||
|
||||
/// <summary>
|
||||
/// 更新方法,用于处理时间更新逻辑
|
||||
/// </summary>
|
||||
@ -49,9 +47,4 @@ public sealed class WaitForTask : IYieldInstruction
|
||||
/// 获取等待是否已完成
|
||||
/// </summary>
|
||||
public bool IsDone => _done;
|
||||
|
||||
/// <summary>
|
||||
/// 获取Task的异常(如果有)
|
||||
/// </summary>
|
||||
public Exception? Exception => _task.Exception;
|
||||
}
|
||||
@ -8,19 +8,17 @@ namespace GFramework.Core.coroutine.instructions;
|
||||
/// </summary>
|
||||
public sealed class WaitOneFrame : IYieldInstruction
|
||||
{
|
||||
private bool _done;
|
||||
|
||||
/// <summary>
|
||||
/// 更新方法,在每一帧被调用时将完成状态设置为true
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">时间间隔,表示当前帧与上一帧的时间差</param>
|
||||
public void Update(double deltaTime)
|
||||
{
|
||||
_done = true;
|
||||
IsDone = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前等待指令是否已完成
|
||||
/// </summary>
|
||||
public bool IsDone => _done;
|
||||
public bool IsDone { get; private set; }
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using GFramework.Core.Abstractions.events;
|
||||
using GFramework.Core.Abstractions.events;
|
||||
|
||||
namespace GFramework.Core.events;
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using GFramework.Core.Abstractions.events;
|
||||
using GFramework.Core.Abstractions.events;
|
||||
|
||||
namespace GFramework.Core.events;
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@ void UnRegister(); // 执行注销操作
|
||||
```
|
||||
|
||||
### 3. [
|
||||
|
||||
`IUnRegisterList`](file:///d:/Project/Rider/GFramework/GFramework.Core.Abstractions/events/IUnRegisterList.cs#L6-L10)
|
||||
|
||||
注销列表接口,用于批量管理注销对象。
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace GFramework.Core.extensions;
|
||||
namespace GFramework.Core.extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 提供基于运行时类型判断的对象扩展方法,
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using System.Threading;
|
||||
using GFramework.Core.Abstractions.ioc;
|
||||
using GFramework.Core.Abstractions.logging;
|
||||
using GFramework.Core.Abstractions.system;
|
||||
|
||||
@ -390,9 +390,11 @@ public bool Contains<T>() where T : class
|
||||
```
|
||||
|
||||
**参数:**
|
||||
|
||||
- 无泛型参数
|
||||
|
||||
**返回值:**
|
||||
|
||||
- 如果容器中包含指定类型的实例则返回 `true`,否则返回 `false`
|
||||
|
||||
**使用示例:**
|
||||
@ -414,6 +416,7 @@ if (!container.Contains<ISettingsService>())
|
||||
```
|
||||
|
||||
**应用场景:**
|
||||
|
||||
- 条件注册服务
|
||||
- 检查依赖是否可用
|
||||
- 动态功能开关
|
||||
@ -427,9 +430,11 @@ public bool ContainsInstance(object instance)
|
||||
```
|
||||
|
||||
**参数:**
|
||||
|
||||
- `instance`:待查询的实例对象
|
||||
|
||||
**返回值:**
|
||||
|
||||
- 若容器中包含该实例则返回 `true`,否则返回 `false`
|
||||
|
||||
**使用示例:**
|
||||
@ -455,6 +460,7 @@ if (!container.ContainsInstance(anotherService))
|
||||
```
|
||||
|
||||
**应用场景:**
|
||||
|
||||
- 避免重复注册同一实例
|
||||
- 检查对象是否已被管理
|
||||
- 调试和日志记录
|
||||
@ -486,11 +492,13 @@ Console.WriteLine($"Contains IService2: {container.Contains<IService2>()}"); //
|
||||
```
|
||||
|
||||
**应用场景:**
|
||||
|
||||
- 重置容器状态
|
||||
- 内存清理
|
||||
- 测试环境准备
|
||||
|
||||
**注意事项:**
|
||||
|
||||
- 容器冻结后也可以调用 `Clear()` 方法
|
||||
- 清空后,所有已注册的实例都将丢失
|
||||
- 不会自动清理已注册对象的其他引用
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using GFramework.Core.Abstractions.logging;
|
||||
using GFramework.Core.Abstractions.logging;
|
||||
|
||||
namespace GFramework.Core.logging;
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using GFramework.Core.Abstractions.logging;
|
||||
|
||||
|
||||
@ -61,10 +61,7 @@ public abstract class AbstractObjectPoolSystem<TKey, TObject>
|
||||
public void Clear()
|
||||
{
|
||||
// 遍历所有对象池,调用每个对象的销毁方法
|
||||
foreach (var obj in Pools.Values.SelectMany(pool => pool))
|
||||
{
|
||||
obj.OnPoolDestroy();
|
||||
}
|
||||
foreach (var obj in Pools.Values.SelectMany(pool => pool)) obj.OnPoolDestroy();
|
||||
|
||||
Pools.Clear();
|
||||
}
|
||||
|
||||
@ -477,6 +477,7 @@ public class DebuggablePoolSystem : AbstractObjectPoolSystem<string, PoolableObj
|
||||
### 1. 游戏对象池
|
||||
|
||||
**适用对象:**
|
||||
|
||||
- 子弹、箭矢、投射物
|
||||
- 敌人、NPC
|
||||
- 爆炸效果、粒子系统
|
||||
@ -559,6 +560,7 @@ public class ShootingSystem : AbstractSystem
|
||||
### 2. UI 元素池
|
||||
|
||||
**适用对象:**
|
||||
|
||||
- 对话框
|
||||
- 提示框
|
||||
- 菜单项
|
||||
@ -617,6 +619,7 @@ public class UISystem : AbstractSystem
|
||||
### 3. 网络消息对象池
|
||||
|
||||
**适用对象:**
|
||||
|
||||
- 网络包
|
||||
- 协议消息
|
||||
- 数据包
|
||||
|
||||
@ -8,7 +8,8 @@ namespace GFramework.Core.query;
|
||||
/// 继承自ContextAwareBase并实现IAsyncQuery<TResult>接口
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult">查询结果的类型</typeparam>
|
||||
public abstract class AbstractAsyncQuery<TResult> : ContextAwareBase, IAsyncQuery<TResult> {
|
||||
public abstract class AbstractAsyncQuery<TResult> : ContextAwareBase, IAsyncQuery<TResult>
|
||||
{
|
||||
/// <summary>
|
||||
/// 执行异步查询操作
|
||||
/// </summary>
|
||||
|
||||
@ -83,6 +83,7 @@ public GetPlayerGoldQuery() : base(new EmptyQueryInput())
|
||||
{
|
||||
return this.GetModel<PlayerModel>().Gold.Value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 查询玩家是否死亡
|
||||
@ -98,6 +99,7 @@ public IsPlayerDeadQuery() : base(new EmptyQueryInput())
|
||||
{
|
||||
return this.GetModel<PlayerModel>().Health.Value <= 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 查询背包中指定物品的数量
|
||||
@ -114,7 +116,9 @@ public GetItemCountQuery(string itemId) : base(new GetItemCountQueryInput(itemId
|
||||
var inventory = this.GetModel<InventoryModel>();
|
||||
return inventory.GetItemCount(input.ItemId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 2. 发送查询(在 Controller 中)
|
||||
@ -155,11 +159,11 @@ public partial class ShopUI : Control, IController
|
||||
``csharp
|
||||
public class CombatSystem : AbstractSystem
|
||||
{
|
||||
protected override void OnInit()
|
||||
{
|
||||
// 注册事件监听
|
||||
this.RegisterEvent<EnemyAttackEvent>(OnEnemyAttack);
|
||||
}
|
||||
protected override void OnInit()
|
||||
{
|
||||
// 注册事件监听
|
||||
this.RegisterEvent<EnemyAttackEvent>(OnEnemyAttack);
|
||||
}
|
||||
|
||||
private void OnEnemyAttack(EnemyAttackEvent e)
|
||||
{
|
||||
@ -172,7 +176,9 @@ public class CombatSystem : AbstractSystem
|
||||
this.SendCommand(new TakeDamageCommand { Damage = e.Damage });
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 高级用法
|
||||
@ -207,7 +213,7 @@ var enemies = this.SendQuery(new GetEnemiesInRangeQuery
|
||||
// 查询玩家是否可以使用技能
|
||||
public class CanUseSkillQuery : AbstractQuery<bool>
|
||||
{
|
||||
public string SkillId { get; set; }
|
||||
public string SkillId { get; set; }
|
||||
|
||||
protected override bool OnDo()
|
||||
{
|
||||
@ -221,27 +227,31 @@ public class CanUseSkillQuery : AbstractQuery<bool>
|
||||
return playerModel.Mana.Value >= skillCost.ManaCost
|
||||
&& !this.SendQuery(new IsSkillOnCooldownQuery { SkillId = SkillId });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class GetSkillCostQuery : AbstractQuery<SkillCost>
|
||||
{
|
||||
public string SkillId { get; set; }
|
||||
public string SkillId { get; set; }
|
||||
|
||||
protected override SkillCost OnDo()
|
||||
{
|
||||
return this.GetModel<SkillModel>().GetSkillCost(SkillId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class IsSkillOnCooldownQuery : AbstractQuery<bool>
|
||||
{
|
||||
public string SkillId { get; set; }
|
||||
public string SkillId { get; set; }
|
||||
|
||||
protected override bool OnDo()
|
||||
{
|
||||
return this.GetModel<SkillModel>().IsOnCooldown(SkillId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 3. 聚合数据查询
|
||||
@ -289,7 +299,7 @@ public class GetPlayerInfoQuery : AbstractQuery<PlayerInfo>
|
||||
// 在 AI System 中查询玩家状态
|
||||
public class EnemyAISystem : AbstractSystem
|
||||
{
|
||||
protected override void OnInit() { }
|
||||
protected override void OnInit() { }
|
||||
|
||||
public void UpdateEnemyBehavior(Enemy enemy)
|
||||
{
|
||||
@ -317,7 +327,9 @@ public class EnemyAISystem : AbstractSystem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Command vs Query
|
||||
@ -384,7 +396,7 @@ public class AddGoldCommand : AbstractCommand
|
||||
// 在 Model 中缓存复杂计算
|
||||
public class PlayerModel : AbstractModel
|
||||
{
|
||||
private int? _cachedPower;
|
||||
private int? _cachedPower;
|
||||
|
||||
public int GetPower()
|
||||
{
|
||||
@ -405,7 +417,9 @@ public class PlayerModel : AbstractModel
|
||||
{
|
||||
_cachedPower = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### 2. 批量查询
|
||||
|
||||
@ -21,6 +21,7 @@ public interface IContextAware
|
||||
```
|
||||
|
||||
**实现此接口的类型:**
|
||||
|
||||
- System
|
||||
- Query
|
||||
- Model
|
||||
|
||||
@ -55,10 +55,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
// 从历史记录中移除该状态的所有引用
|
||||
var tempStack = new Stack<IState>(_stateHistory.Reverse());
|
||||
_stateHistory.Clear();
|
||||
foreach (var historyState in tempStack.Where(s => s != state))
|
||||
{
|
||||
_stateHistory.Push(historyState);
|
||||
}
|
||||
foreach (var historyState in tempStack.Where(s => s != state)) _stateHistory.Push(historyState);
|
||||
|
||||
States.Remove(type);
|
||||
}
|
||||
@ -110,20 +107,29 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
/// </summary>
|
||||
/// <typeparam name="T">要检查的状态类型</typeparam>
|
||||
/// <returns>如果状态已注册则返回true,否则返回false</returns>
|
||||
public bool IsRegistered<T>() where T : IState => States.ContainsKey(typeof(T));
|
||||
public bool IsRegistered<T>() where T : IState
|
||||
{
|
||||
return States.ContainsKey(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的已注册状态实例
|
||||
/// </summary>
|
||||
/// <typeparam name="T">要获取的状态类型</typeparam>
|
||||
/// <returns>如果状态存在则返回对应实例,否则返回null</returns>
|
||||
public T? GetState<T>() where T : class, IState => States.TryGetValue(typeof(T), out var state) ? state as T : null;
|
||||
public T? GetState<T>() where T : class, IState
|
||||
{
|
||||
return States.TryGetValue(typeof(T), out var state) ? state as T : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有已注册状态的类型集合
|
||||
/// </summary>
|
||||
/// <returns>包含所有已注册状态类型的枚举器</returns>
|
||||
public IEnumerable<Type> GetRegisteredStateTypes() => States.Keys;
|
||||
public IEnumerable<Type> GetRegisteredStateTypes()
|
||||
{
|
||||
return States.Keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取上一个状态
|
||||
@ -163,10 +169,8 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
|
||||
// 检查上一个状态是否仍然注册
|
||||
if (!States.ContainsValue(previousState))
|
||||
{
|
||||
// 如果状态已被注销,继续尝试更早的状态
|
||||
return GoBack();
|
||||
}
|
||||
|
||||
// 回退时不添加到历史记录
|
||||
ChangeInternalWithoutHistory(previousState);
|
||||
@ -233,10 +237,7 @@ public class StateMachine(int maxHistorySize = 10) : IStateMachine
|
||||
// 移除最旧的记录(栈底元素)
|
||||
var tempStack = new Stack<IState>(_stateHistory.Reverse().Skip(1));
|
||||
_stateHistory.Clear();
|
||||
foreach (var state in tempStack.Reverse())
|
||||
{
|
||||
_stateHistory.Push(state);
|
||||
}
|
||||
foreach (var state in tempStack.Reverse()) _stateHistory.Push(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -50,10 +50,7 @@ public class StateMachineSystem : StateMachine, IStateMachineSystem
|
||||
/// </summary>
|
||||
public virtual void Init()
|
||||
{
|
||||
foreach (var state in States.Values.OfType<IContextAware>())
|
||||
{
|
||||
state.SetContext(_context);
|
||||
}
|
||||
foreach (var state in States.Values.OfType<IContextAware>()) state.SetContext(_context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -69,10 +66,7 @@ public class StateMachineSystem : StateMachine, IStateMachineSystem
|
||||
}
|
||||
|
||||
// 清理所有状态
|
||||
foreach (var state in States.Values.OfType<IDisposable>())
|
||||
{
|
||||
state.Destroy();
|
||||
}
|
||||
foreach (var state in States.Values.OfType<IDisposable>()) state.Destroy();
|
||||
|
||||
States.Clear();
|
||||
}
|
||||
|
||||
@ -13,5 +13,5 @@ public enum CacheEvictionPolicy
|
||||
/// <summary>
|
||||
/// 最少使用频率
|
||||
/// </summary>
|
||||
Lfu,
|
||||
Lfu
|
||||
}
|
||||
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace GFramework.Game.Abstractions.enums;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -23,5 +23,5 @@ public enum UiTransitionType
|
||||
/// <summary>
|
||||
/// 清空所有页面
|
||||
/// </summary>
|
||||
Clear,
|
||||
Clear
|
||||
}
|
||||
@ -8,7 +8,7 @@ public class GraphicsSettings : ISettingsData
|
||||
/// <summary>
|
||||
/// 获取或设置是否启用全屏模式
|
||||
/// </summary>
|
||||
public bool Fullscreen { get; set; } = false;
|
||||
public bool Fullscreen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置屏幕分辨率宽度
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GFramework.Game.Abstractions.setting;
|
||||
namespace GFramework.Game.Abstractions.setting;
|
||||
|
||||
/// <summary>
|
||||
/// 定义可应用设置的接口,继承自ISettingsSection
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace GFramework.Game.Abstractions.setting;
|
||||
namespace GFramework.Game.Abstractions.setting;
|
||||
|
||||
/// <summary>
|
||||
/// 设置变更事件基类
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GFramework.Core.Abstractions.model;
|
||||
using GFramework.Core.Abstractions.model;
|
||||
|
||||
namespace GFramework.Game.Abstractions.setting;
|
||||
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using GFramework.Core.Abstractions.utility;
|
||||
|
||||
namespace GFramework.Game.Abstractions.setting;
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using GFramework.Core.Abstractions.system;
|
||||
|
||||
namespace GFramework.Game.Abstractions.setting;
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace GFramework.Game.Abstractions.setting;
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
|
||||
/// <summary>
|
||||
/// UI缓存统计信息接口
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GFramework.Core.Abstractions.utility;
|
||||
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
|
||||
@ -23,6 +23,21 @@ public interface IUiPageBehavior
|
||||
/// </summary>
|
||||
bool IsAlive { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取页面是否为模态页面
|
||||
/// </summary>
|
||||
bool IsModal { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取页面是否阻断下层交互
|
||||
/// </summary>
|
||||
bool BlocksInput { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取页面是否需要蒙版
|
||||
/// </summary>
|
||||
bool RequiresMask { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 页面进入时调用的方法
|
||||
/// </summary>
|
||||
@ -53,20 +68,4 @@ public interface IUiPageBehavior
|
||||
/// 页面重新显示时调用的方法
|
||||
/// </summary>
|
||||
void OnShow();
|
||||
|
||||
/// <summary>
|
||||
/// 获取页面是否为模态页面
|
||||
/// </summary>
|
||||
bool IsModal { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取页面是否阻断下层交互
|
||||
/// </summary>
|
||||
bool BlocksInput { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取页面是否需要蒙版
|
||||
/// </summary>
|
||||
bool RequiresMask { get; }
|
||||
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
using System.Collections.Generic;
|
||||
using GFramework.Game.Abstractions.enums;
|
||||
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -74,6 +74,7 @@ public interface IUiRouter : ISystem
|
||||
IUiPageEnterParam? param = null,
|
||||
UiPopPolicy popPolicy = UiPopPolicy.Destroy,
|
||||
UiTransitionPolicy pushPolicy = UiTransitionPolicy.Exclusive);
|
||||
|
||||
/// <summary>
|
||||
/// 清空所有UI界面,重置路由状态
|
||||
/// </summary>
|
||||
@ -128,6 +129,7 @@ public interface IUiRouter : ISystem
|
||||
/// </summary>
|
||||
/// <typeparam name="T">守卫类型,必须实现 IUiRouteGuard 且有无参构造函数</typeparam>
|
||||
void AddGuard<T>() where T : IUiRouteGuard, new();
|
||||
|
||||
/// <summary>
|
||||
/// 移除路由守卫
|
||||
/// </summary>
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GFramework.Game.Abstractions.enums;
|
||||
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using GFramework.Game.Abstractions.enums;
|
||||
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
@ -40,12 +39,14 @@ public class UiCacheConfig
|
||||
/// <param name="maxSize">最大缓存数量</param>
|
||||
/// <param name="expireAfter">访问后过期时间</param>
|
||||
public static UiCacheConfig Lru(int maxSize = 10, TimeSpan? expireAfter = null)
|
||||
=> new()
|
||||
{
|
||||
return new UiCacheConfig
|
||||
{
|
||||
MaxCacheSize = maxSize,
|
||||
EvictionPolicy = CacheEvictionPolicy.Lru,
|
||||
ExpireAfterAccess = expireAfter
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建 LFU 策略配置
|
||||
@ -53,10 +54,12 @@ public class UiCacheConfig
|
||||
/// <param name="maxSize">最大缓存数量</param>
|
||||
/// <param name="expireAfter">访问后过期时间</param>
|
||||
public static UiCacheConfig Lfu(int maxSize = 10, TimeSpan? expireAfter = null)
|
||||
=> new()
|
||||
{
|
||||
return new UiCacheConfig
|
||||
{
|
||||
MaxCacheSize = maxSize,
|
||||
EvictionPolicy = CacheEvictionPolicy.Lfu,
|
||||
ExpireAfterAccess = expireAfter
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
|
||||
/// <summary>
|
||||
/// UI页面实例管理策略(控制实例的生命周期)
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GFramework.Game.Abstractions.enums;
|
||||
|
||||
namespace GFramework.Game.Abstractions.ui;
|
||||
|
||||
@ -7,10 +7,10 @@
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj" />
|
||||
<ProjectReference Include="..\$(AssemblyName).Abstractions\$(AssemblyName).Abstractions.csproj" />
|
||||
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj"/>
|
||||
<ProjectReference Include="..\$(AssemblyName).Abstractions\$(AssemblyName).Abstractions.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@ -30,24 +30,28 @@ GFramework.Game 为游戏开发提供了专门的功能模块,与 GFramework.C
|
||||
## 核心特性
|
||||
|
||||
### 🏗️ 模块化架构
|
||||
|
||||
- **AbstractModule**:可重用的架构模块基类
|
||||
- **生命周期管理**:与框架生命周期深度集成
|
||||
- **依赖注入**:模块间的依赖自动管理
|
||||
- **配置驱动**:灵活的模块配置系统
|
||||
|
||||
### 📦 资产管理
|
||||
|
||||
- **统一资源目录**:集中化的资源注册和查询
|
||||
- **类型安全**:编译时类型检查和泛型支持
|
||||
- **重复检测**:自动检测资源重复注册
|
||||
- **映射支持**:灵活的资源映射和别名系统
|
||||
|
||||
### 💾 存储系统
|
||||
|
||||
- **分层存储**:命名空间支持的存储隔离
|
||||
- **多格式支持**:JSON、二进制等多种存储格式
|
||||
- **异步操作**:完整的异步存储 API
|
||||
- **版本兼容**:存档版本管理和迁移支持
|
||||
|
||||
### 🔄 序列化系统
|
||||
|
||||
- **JSON 集成**:基于 Newtonsoft.Json 的序列化
|
||||
- **自定义序列化**:支持自定义序列化逻辑
|
||||
- **性能优化**:序列化缓存和优化策略
|
||||
|
||||
@ -15,7 +15,9 @@ public sealed class JsonSerializer : ISerializer
|
||||
/// <param name="value">要序列化的对象实例</param>
|
||||
/// <returns>序列化后的JSON字符串</returns>
|
||||
public string Serialize<T>(T value)
|
||||
=> JsonConvert.SerializeObject(value);
|
||||
{
|
||||
return JsonConvert.SerializeObject(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将JSON字符串反序列化为指定类型的对象
|
||||
@ -25,5 +27,7 @@ public sealed class JsonSerializer : ISerializer
|
||||
/// <returns>反序列化后的对象实例</returns>
|
||||
/// <exception cref="ArgumentException">当无法反序列化数据时抛出</exception>
|
||||
public T Deserialize<T>(string data)
|
||||
=> JsonConvert.DeserializeObject<T>(data) ?? throw new ArgumentException("Cannot deserialize data");
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(data) ?? throw new ArgumentException("Cannot deserialize data");
|
||||
}
|
||||
}
|
||||
@ -129,7 +129,9 @@ public class SettingsPersistence : AbstractContextUtility, ISettingsPersistence
|
||||
/// <typeparam name="T">设置数据类型</typeparam>
|
||||
/// <returns>格式为"Settings_类型名称"的键名</returns>
|
||||
private static string GetKey<T>() where T : ISettingsData
|
||||
=> GetKey(typeof(T));
|
||||
{
|
||||
return GetKey(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的存储键名
|
||||
@ -137,5 +139,7 @@ public class SettingsPersistence : AbstractContextUtility, ISettingsPersistence
|
||||
/// <param name="type">设置数据类型</param>
|
||||
/// <returns>格式为"Settings_类型名称"的键名</returns>
|
||||
private static string GetKey(Type type)
|
||||
=> $"Settings_{type.Name}";
|
||||
{
|
||||
return $"Settings_{type.Name}";
|
||||
}
|
||||
}
|
||||
@ -19,10 +19,7 @@ public class SettingsSystem : AbstractSystem, ISettingsSystem
|
||||
public Task ApplyAll()
|
||||
{
|
||||
// 遍历所有设置配置并尝试应用
|
||||
foreach (var section in _model.All())
|
||||
{
|
||||
TryApply(section);
|
||||
}
|
||||
foreach (var section in _model.All()) TryApply(section);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@ -33,7 +30,9 @@ public class SettingsSystem : AbstractSystem, ISettingsSystem
|
||||
/// <typeparam name="T">设置配置类型,必须是类且实现ISettingsSection接口</typeparam>
|
||||
/// <returns>完成的任务</returns>
|
||||
public Task Apply<T>() where T : class, ISettingsSection
|
||||
=> Apply(typeof(T));
|
||||
{
|
||||
return Apply(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用指定类型的设置配置
|
||||
@ -58,12 +57,8 @@ public class SettingsSystem : AbstractSystem, ISettingsSystem
|
||||
{
|
||||
// 去重后遍历设置类型,获取并应用对应的设置配置
|
||||
foreach (var type in settingsTypes.Distinct())
|
||||
{
|
||||
if (_model.TryGet(type, out var section))
|
||||
{
|
||||
TryApply(section);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@ -14,7 +14,9 @@ public sealed class GameStateMachineSystem : StateMachineSystem
|
||||
/// <typeparam name="T">要检查的状态类型,必须实现IState接口</typeparam>
|
||||
/// <returns>如果当前状态是指定类型则返回true,否则返回false</returns>
|
||||
public bool IsIn<T>() where T : IState
|
||||
=> Current is T;
|
||||
{
|
||||
return Current is T;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前状态的实例,如果当前状态是指定类型则进行类型转换
|
||||
@ -22,5 +24,7 @@ public sealed class GameStateMachineSystem : StateMachineSystem
|
||||
/// <typeparam name="T">要获取的状态类型,必须是引用类型并实现IState接口</typeparam>
|
||||
/// <returns>如果当前状态是指定类型则返回转换后的实例,否则返回null</returns>
|
||||
public T? Get<T>() where T : class, IState
|
||||
=> Current as T;
|
||||
{
|
||||
return Current as T;
|
||||
}
|
||||
}
|
||||
@ -129,7 +129,9 @@ public sealed class FileStorage : IFileStorage
|
||||
/// <param name="key">存储键</param>
|
||||
/// <returns>如果存储项存在则返回true,否则返回false</returns>
|
||||
public Task<bool> ExistsAsync(string key)
|
||||
=> Task.FromResult(Exists(key));
|
||||
{
|
||||
return Task.FromResult(Exists(key));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@ -16,7 +16,9 @@ public sealed class ScopedStorage(IStorage inner, string prefix) : IScopedStorag
|
||||
/// <param name="key">要检查的键</param>
|
||||
/// <returns>如果键存在则返回true,否则返回false</returns>
|
||||
public bool Exists(string key)
|
||||
=> inner.Exists(Key(key));
|
||||
{
|
||||
return inner.Exists(Key(key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步检查指定键是否存在
|
||||
@ -24,7 +26,9 @@ public sealed class ScopedStorage(IStorage inner, string prefix) : IScopedStorag
|
||||
/// <param name="key">要检查的键</param>
|
||||
/// <returns>如果键存在则返回true,否则返回false</returns>
|
||||
public Task<bool> ExistsAsync(string key)
|
||||
=> inner.ExistsAsync(Key(key));
|
||||
{
|
||||
return inner.ExistsAsync(Key(key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取指定键的值
|
||||
@ -33,7 +37,9 @@ public sealed class ScopedStorage(IStorage inner, string prefix) : IScopedStorag
|
||||
/// <param name="key">要读取的键</param>
|
||||
/// <returns>键对应的值</returns>
|
||||
public T Read<T>(string key)
|
||||
=> inner.Read<T>(Key(key));
|
||||
{
|
||||
return inner.Read<T>(Key(key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取指定键的值,如果键不存在则返回默认值
|
||||
@ -43,7 +49,9 @@ public sealed class ScopedStorage(IStorage inner, string prefix) : IScopedStorag
|
||||
/// <param name="defaultValue">当键不存在时返回的默认值</param>
|
||||
/// <returns>键对应的值或默认值</returns>
|
||||
public T Read<T>(string key, T defaultValue)
|
||||
=> inner.Read(Key(key), defaultValue);
|
||||
{
|
||||
return inner.Read(Key(key), defaultValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步读取指定键的值
|
||||
@ -52,7 +60,9 @@ public sealed class ScopedStorage(IStorage inner, string prefix) : IScopedStorag
|
||||
/// <param name="key">要读取的键</param>
|
||||
/// <returns>键对应的值的任务</returns>
|
||||
public Task<T> ReadAsync<T>(string key)
|
||||
=> inner.ReadAsync<T>(Key(key));
|
||||
{
|
||||
return inner.ReadAsync<T>(Key(key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入指定键值对
|
||||
@ -61,7 +71,9 @@ public sealed class ScopedStorage(IStorage inner, string prefix) : IScopedStorag
|
||||
/// <param name="key">要写入的键</param>
|
||||
/// <param name="value">要写入的值</param>
|
||||
public void Write<T>(string key, T value)
|
||||
=> inner.Write(Key(key), value);
|
||||
{
|
||||
inner.Write(Key(key), value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步写入指定键值对
|
||||
@ -70,14 +82,18 @@ public sealed class ScopedStorage(IStorage inner, string prefix) : IScopedStorag
|
||||
/// <param name="key">要写入的键</param>
|
||||
/// <param name="value">要写入的值</param>
|
||||
public Task WriteAsync<T>(string key, T value)
|
||||
=> inner.WriteAsync(Key(key), value);
|
||||
{
|
||||
return inner.WriteAsync(Key(key), value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定键
|
||||
/// </summary>
|
||||
/// <param name="key">要删除的键</param>
|
||||
public void Delete(string key)
|
||||
=> inner.Delete(Key(key));
|
||||
{
|
||||
inner.Delete(Key(key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为给定的键添加前缀
|
||||
@ -85,9 +101,11 @@ public sealed class ScopedStorage(IStorage inner, string prefix) : IScopedStorag
|
||||
/// <param name="key">原始键</param>
|
||||
/// <returns>添加前缀后的键</returns>
|
||||
private string Key(string key)
|
||||
=> string.IsNullOrEmpty(prefix)
|
||||
{
|
||||
return string.IsNullOrEmpty(prefix)
|
||||
? key
|
||||
: $"{prefix}/{key}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的作用域存储实例
|
||||
@ -95,5 +113,7 @@ public sealed class ScopedStorage(IStorage inner, string prefix) : IScopedStorag
|
||||
/// <param name="scope">新的作用域名称</param>
|
||||
/// <returns>新的作用域存储实例</returns>
|
||||
public IStorage Scope(string scope)
|
||||
=> new ScopedStorage(inner, Key(scope));
|
||||
{
|
||||
return new ScopedStorage(inner, Key(scope));
|
||||
}
|
||||
}
|
||||
@ -158,7 +158,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
|
||||
var @event = CreateEvent(
|
||||
nextUiKey,
|
||||
type: UiTransitionType.Pop
|
||||
UiTransitionType.Pop
|
||||
);
|
||||
|
||||
BeforeChange(@event);
|
||||
@ -484,10 +484,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
IUiPageEnterParam? param = null,
|
||||
UiInstancePolicy instancePolicy = UiInstancePolicy.Reuse)
|
||||
{
|
||||
if (layer == UiLayer.Page)
|
||||
{
|
||||
throw new ArgumentException("Use Push() for Page layer");
|
||||
}
|
||||
if (layer == UiLayer.Page) throw new ArgumentException("Use Push() for Page layer");
|
||||
|
||||
// 初始化层级字典
|
||||
if (!_layers.ContainsKey(layer))
|
||||
@ -575,10 +572,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
return;
|
||||
|
||||
var keys = layerDict.Keys.ToArray();
|
||||
foreach (var key in keys)
|
||||
{
|
||||
Hide(key, layer, destroy);
|
||||
}
|
||||
foreach (var key in keys) Hide(key, layer, destroy);
|
||||
|
||||
Log.Debug("Cleared layer: {0}, destroyed={1}", layer, destroy);
|
||||
}
|
||||
@ -641,10 +635,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(guard);
|
||||
|
||||
if (_guards.Remove(guard))
|
||||
{
|
||||
Log.Debug("Guard removed: {0}", guard.GetType().Name);
|
||||
}
|
||||
if (_guards.Remove(guard)) Log.Debug("Guard removed: {0}", guard.GetType().Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -653,7 +644,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
private async Task<bool> ExecuteEnterGuardsAsync(string uiKey, IUiPageEnterParam? param)
|
||||
{
|
||||
foreach (var guard in _guards)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Debug("Executing enter guard: {0} for {1}", guard.GetType().Name, uiKey);
|
||||
@ -674,11 +664,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Enter guard {0} failed: {1}", guard.GetType().Name, ex.Message);
|
||||
if (guard.CanInterrupt)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (guard.CanInterrupt) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -690,7 +676,6 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
private async Task<bool> ExecuteLeaveGuardsAsync(string uiKey)
|
||||
{
|
||||
foreach (var guard in _guards)
|
||||
{
|
||||
try
|
||||
{
|
||||
Log.Debug("Executing leave guard: {0} for {1}", guard.GetType().Name, uiKey);
|
||||
@ -711,11 +696,7 @@ public abstract class UiRouterBase : AbstractSystem, IUiRouter
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error("Leave guard {0} failed: {1}", guard.GetType().Name, ex.Message);
|
||||
if (guard.CanInterrupt)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (guard.CanInterrupt) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -14,8 +14,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GFramework.Game\GFramework.Game.csproj" />
|
||||
<ProjectReference Include="..\GFramework.Game.Abstractions\GFramework.Game.Abstractions.csproj" PrivateAssets="all" />
|
||||
<ProjectReference Include="..\GFramework.Core.Abstractions\GFramework.Core.Abstractions.csproj" PrivateAssets="all" />
|
||||
<ProjectReference Include="..\GFramework.Game\GFramework.Game.csproj"/>
|
||||
<ProjectReference Include="..\GFramework.Game.Abstractions\GFramework.Game.Abstractions.csproj" PrivateAssets="all"/>
|
||||
<ProjectReference Include="..\GFramework.Core.Abstractions\GFramework.Core.Abstractions.csproj" PrivateAssets="all"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@ -20,7 +20,8 @@ GFramework.Godot 是 GFramework 框架的 Godot 特定实现,将框架的架
|
||||
|
||||
## 概述
|
||||
|
||||
GFramework.Godot 提供了与 Godot 引擎的深度集成,让开发者能够在保持 GFramework 架构优势的同时,充分利用 Godot 的节点系统、信号机制和场景管理功能。
|
||||
GFramework.Godot 提供了与 Godot 引擎的深度集成,让开发者能够在保持 GFramework 架构优势的同时,充分利用 Godot
|
||||
的节点系统、信号机制和场景管理功能。
|
||||
|
||||
### 核心设计理念
|
||||
|
||||
@ -32,33 +33,39 @@ GFramework.Godot 提供了与 Godot 引擎的深度集成,让开发者能够
|
||||
## 核心特性
|
||||
|
||||
### 🎯 架构生命周期绑定
|
||||
|
||||
- 自动将框架初始化与 Godot 场景树绑定
|
||||
- 支持节点销毁时的自动清理
|
||||
- 阶段式架构初始化与 Godot `_Ready` 周期同步
|
||||
|
||||
### 🔧 丰富的 Node 扩展方法
|
||||
|
||||
- **50+** 个实用扩展方法
|
||||
- 安全的节点操作和验证
|
||||
- 流畅的场景树遍历和查找
|
||||
- 简化的输入处理
|
||||
|
||||
### 📡 流畅的信号 API
|
||||
|
||||
- 类型安全的信号连接
|
||||
- 链式调用支持
|
||||
- 自动生命周期管理
|
||||
- Godot 信号与框架事件系统的桥接
|
||||
|
||||
### 🏊♂️ 高效的节点池化
|
||||
|
||||
- 专用的 Node 对象池
|
||||
- 自动回收和重用机制
|
||||
- 内存友好的高频节点创建/销毁
|
||||
|
||||
### 📦 智能资源管理
|
||||
|
||||
- 简化的 Godot 资源加载
|
||||
- 类型安全的资源工厂
|
||||
- 缓存和预加载支持
|
||||
|
||||
### 📝 Godot 原生日志
|
||||
|
||||
- 与 Godot 日志系统完全集成
|
||||
- 框架日志自动输出到 Godot 控制台
|
||||
- 可配置的日志级别
|
||||
@ -725,6 +732,7 @@ public partial class MainScene : Node2D
|
||||
### 🏗️ 架构设计最佳实践
|
||||
|
||||
#### 1. 模块化设计
|
||||
|
||||
```csharp
|
||||
// 好的做法:按功能分组模块
|
||||
public class AudioModule : AbstractGodotModule { }
|
||||
@ -739,6 +747,7 @@ public class GameModule : AbstractGodotModule // ❌ 太大
|
||||
```
|
||||
|
||||
#### 2. 生命周期管理
|
||||
|
||||
```csharp
|
||||
// 好的做法:使用自动清理
|
||||
this.RegisterEvent<GameEvent>(OnGameEvent)
|
||||
@ -763,6 +772,7 @@ public override void _ExitTree()
|
||||
### 🎮 Godot 集成最佳实践
|
||||
|
||||
#### 1. 节点安全操作
|
||||
|
||||
```csharp
|
||||
// 好的做法:使用安全扩展
|
||||
var player = GetNodeX<Player>("Player");
|
||||
@ -773,6 +783,7 @@ var player = GetNode<Player>("Player"); // 可能抛出异常
|
||||
```
|
||||
|
||||
#### 2. 信号连接模式
|
||||
|
||||
```csharp
|
||||
// 好的做法:使用 SignalBuilder
|
||||
this.CreateSignalBuilder(Button.SignalName.Pressed)
|
||||
@ -786,6 +797,7 @@ Button.Pressed += OnButtonPressed; // 容易忘记清理
|
||||
### 🏊♂️ 性能优化最佳实践
|
||||
|
||||
#### 1. 节点池化策略
|
||||
|
||||
```csharp
|
||||
// 好的做法:高频创建对象使用池化
|
||||
public class BulletPool : AbstractNodePoolSystem<string, Bullet>
|
||||
@ -803,6 +815,7 @@ public void Shoot()
|
||||
```
|
||||
|
||||
#### 2. 资源预加载
|
||||
|
||||
```csharp
|
||||
// 好的做法:预加载常用资源
|
||||
public override void _Ready()
|
||||
@ -816,6 +829,7 @@ public override void _Ready()
|
||||
### 🔧 调试和错误处理
|
||||
|
||||
#### 1. 日志使用策略
|
||||
|
||||
```csharp
|
||||
// 好的做法:分级别记录
|
||||
Logger.Debug($"Player position: {Position}"); // 调试信息
|
||||
@ -828,6 +842,7 @@ Logger.Debug($"Frame: {Engine.GetProcessFrames()}"); // 太频繁
|
||||
```
|
||||
|
||||
#### 2. 异常处理
|
||||
|
||||
```csharp
|
||||
// 好的做法:优雅的错误处理
|
||||
public T LoadResource<T>(string path) where T : Resource
|
||||
|
||||
@ -56,10 +56,8 @@ public static class CoroutineExtensions
|
||||
private static bool AllNodesAlive(Node[] nodes)
|
||||
{
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
if (!Timing.IsNodeAlive(node))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -9,18 +9,16 @@ namespace GFramework.Godot.coroutine;
|
||||
public class GodotTimeSource(Func<double> getDeltaFunc) : ITimeSource
|
||||
{
|
||||
private readonly Func<double> _getDeltaFunc = getDeltaFunc ?? throw new ArgumentNullException(nameof(getDeltaFunc));
|
||||
private double _currentTime;
|
||||
private double _deltaTime;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前累计时间
|
||||
/// </summary>
|
||||
public double CurrentTime => _currentTime;
|
||||
public double CurrentTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取上一帧的时间增量
|
||||
/// </summary>
|
||||
public double DeltaTime => _deltaTime;
|
||||
public double DeltaTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间源,计算新的增量时间和累计时间
|
||||
@ -28,9 +26,9 @@ public class GodotTimeSource(Func<double> getDeltaFunc) : ITimeSource
|
||||
public void Update()
|
||||
{
|
||||
// 调用外部提供的函数获取当前帧的时间增量
|
||||
_deltaTime = _getDeltaFunc();
|
||||
DeltaTime = _getDeltaFunc();
|
||||
// 累加到总时间中
|
||||
_currentTime += _deltaTime;
|
||||
CurrentTime += DeltaTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -38,7 +36,7 @@ public class GodotTimeSource(Func<double> getDeltaFunc) : ITimeSource
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_currentTime = 0;
|
||||
_deltaTime = 0;
|
||||
CurrentTime = 0;
|
||||
DeltaTime = 0;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user