mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 02:24:30 +08:00
refactor(pause): 将暂停状态变化事件改为标准事件模式
- 将 OnPauseStateChanged 事件从 Action<PauseGroup, bool> 类型改为 EventHandler<PauseStateChangedEventArgs> - 添加 PauseStateChangedEventArgs 类来封装事件数据 - 更新所有事件处理方法的签名以匹配新的事件参数 - 修改文档中相关的事件处理代码示例 - 在 PauseStackManager 中添加 RaisePauseStateChanged 方法统一处理事件触发 - 更新测试代码以适应新的事件处理方式
This commit is contained in:
parent
86645d34cb
commit
f3d45169cd
46
GFramework.Core.Abstractions/Concurrency/LockInfo.cs
Normal file
46
GFramework.Core.Abstractions/Concurrency/LockInfo.cs
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2025 GeWuYou
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace GFramework.Core.Abstractions.Concurrency;
|
||||
|
||||
/// <summary>
|
||||
/// 锁信息(用于调试)
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public readonly struct LockInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 锁的键。
|
||||
/// </summary>
|
||||
public string Key { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前引用计数。
|
||||
/// </summary>
|
||||
public int ReferenceCount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后访问时间戳(Environment.TickCount64)。
|
||||
/// </summary>
|
||||
public long LastAccessTicks { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 等待队列长度(近似值)。
|
||||
/// 注意:这是一个基于 SemaphoreSlim.CurrentCount 的近似指示器,
|
||||
/// 当 CurrentCount == 0 时表示锁被持有且可能有等待者,返回 1;
|
||||
/// 否则返回 0。这不是精确的等待者数量,仅用于调试参考。
|
||||
/// </summary>
|
||||
public int WaitingCount { get; init; }
|
||||
}
|
||||
@ -11,11 +11,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace GFramework.Core.Abstractions.Concurrency;
|
||||
|
||||
/// <summary>
|
||||
/// 锁统计信息
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public readonly struct LockStatistics
|
||||
{
|
||||
/// <summary>
|
||||
@ -37,33 +40,4 @@ public readonly struct LockStatistics
|
||||
/// 累计清理的锁数量
|
||||
/// </summary>
|
||||
public int TotalCleaned { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 锁信息(用于调试)
|
||||
/// </summary>
|
||||
public readonly struct LockInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 锁的键
|
||||
/// </summary>
|
||||
public string Key { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前引用计数
|
||||
/// </summary>
|
||||
public int ReferenceCount { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后访问时间戳(Environment.TickCount64)
|
||||
/// </summary>
|
||||
public long LastAccessTicks { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 等待队列长度(近似值)
|
||||
/// 注意:这是一个基于 SemaphoreSlim.CurrentCount 的近似指示器,
|
||||
/// 当 CurrentCount == 0 时表示锁被持有且可能有等待者,返回 1;
|
||||
/// 否则返回 0。这不是精确的等待者数量,仅用于调试参考。
|
||||
/// </summary>
|
||||
public int WaitingCount { get; init; }
|
||||
}
|
||||
@ -75,7 +75,9 @@ public interface IPauseStackManager : IContextUtility
|
||||
void UnregisterHandler(IPauseHandler handler);
|
||||
|
||||
/// <summary>
|
||||
/// 暂停状态变化事件
|
||||
/// 暂停状态变化事件。
|
||||
/// 事件遵循标准 .NET 事件模式,事件源为触发通知的暂停管理器实例,
|
||||
/// 事件数据由 <see cref="PauseStateChangedEventArgs"/> 提供。
|
||||
/// </summary>
|
||||
event Action<PauseGroup, bool>? OnPauseStateChanged;
|
||||
event EventHandler<PauseStateChangedEventArgs>? OnPauseStateChanged;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
namespace GFramework.Core.Abstractions.Pause;
|
||||
|
||||
/// <summary>
|
||||
/// 表示暂停状态变化事件的数据。
|
||||
/// 该类型用于向事件订阅者传递暂停组以及该组变化后的暂停状态。
|
||||
/// </summary>
|
||||
public sealed class PauseStateChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化 <see cref="PauseStateChangedEventArgs"/> 的新实例。
|
||||
/// </summary>
|
||||
/// <param name="group">发生状态变化的暂停组。</param>
|
||||
/// <param name="isPaused">暂停组变化后的新状态。</param>
|
||||
public PauseStateChangedEventArgs(PauseGroup group, bool isPaused)
|
||||
{
|
||||
Group = group;
|
||||
IsPaused = isPaused;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取发生状态变化的暂停组。
|
||||
/// </summary>
|
||||
public PauseGroup Group { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取暂停组变化后的新状态。
|
||||
/// 为 <see langword="true"/> 表示进入暂停,为 <see langword="false"/> 表示恢复运行。
|
||||
/// </summary>
|
||||
public bool IsPaused { get; }
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
using GFramework.Core.Abstractions.Pause;
|
||||
using GFramework.Core.Pause;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GFramework.Core.Tests.Pause;
|
||||
|
||||
@ -220,11 +219,11 @@ public class PauseStackManagerTests
|
||||
PauseGroup? eventGroup = null;
|
||||
bool? eventIsPaused = null;
|
||||
|
||||
_manager.OnPauseStateChanged += (group, isPaused) =>
|
||||
_manager.OnPauseStateChanged += (_, e) =>
|
||||
{
|
||||
eventTriggered = true;
|
||||
eventGroup = group;
|
||||
eventIsPaused = isPaused;
|
||||
eventGroup = e.Group;
|
||||
eventIsPaused = e.IsPaused;
|
||||
};
|
||||
|
||||
_manager.Push("Test", PauseGroup.Gameplay);
|
||||
@ -243,10 +242,10 @@ public class PauseStackManagerTests
|
||||
var token = _manager.Push("Test");
|
||||
|
||||
bool eventTriggered = false;
|
||||
_manager.OnPauseStateChanged += (group, isPaused) =>
|
||||
_manager.OnPauseStateChanged += (_, e) =>
|
||||
{
|
||||
eventTriggered = true;
|
||||
Assert.That(isPaused, Is.False);
|
||||
Assert.That(e.IsPaused, Is.False);
|
||||
};
|
||||
|
||||
_manager.Pop(token);
|
||||
|
||||
@ -17,11 +17,6 @@ internal sealed class CoroutineSlot
|
||||
/// </summary>
|
||||
public CoroutineHandle Handle;
|
||||
|
||||
/// <summary>
|
||||
/// 协程是否已经开始执行
|
||||
/// </summary>
|
||||
public bool HasStarted;
|
||||
|
||||
/// <summary>
|
||||
/// 协程的优先级
|
||||
/// </summary>
|
||||
|
||||
@ -208,13 +208,10 @@ public class PriorityEvent<T> : IEvent
|
||||
MergeAndSortHandlers(T t)
|
||||
{
|
||||
var (normalSnapshot, contextSnapshot) = CreateSnapshots();
|
||||
// 使用快照避免迭代期间修改
|
||||
// 使用统一的投影方法显式固定元组的可空标注,避免 LINQ 在 Concat 时推断出不兼容的签名。
|
||||
return normalSnapshot
|
||||
.Select(h => (h.Priority, Handler: (Action?)(() => h.Handler.Invoke(t)),
|
||||
ContextHandler: (Action<EventContext<T>>?)null, IsContext: false))
|
||||
.Concat(contextSnapshot
|
||||
.Select(h => (h.Priority, Handler: (Action?)null,
|
||||
ContextHandler: (Action<EventContext<T>>?)h.Handler, IsContext: true)))
|
||||
.Select(h => CreateNormalHandlerInvocation(h, t))
|
||||
.Concat(contextSnapshot.Select(CreateContextHandlerInvocation))
|
||||
.OrderByDescending(h => h.Priority)
|
||||
.ToList();
|
||||
}
|
||||
@ -289,6 +286,29 @@ public class PriorityEvent<T> : IEvent
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将普通事件处理器转换为统一的调用描述。
|
||||
/// </summary>
|
||||
/// <param name="handler">要包装的普通处理器。</param>
|
||||
/// <param name="t">当前触发的事件数据。</param>
|
||||
/// <returns>可与上下文处理器合并排序的统一调用描述。</returns>
|
||||
private static (int Priority, Action? Handler, Action<EventContext<T>>? ContextHandler, bool IsContext)
|
||||
CreateNormalHandlerInvocation(EventHandler handler, T t)
|
||||
{
|
||||
return (handler.Priority, () => handler.Handler.Invoke(t), null, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将上下文事件处理器转换为统一的调用描述。
|
||||
/// </summary>
|
||||
/// <param name="handler">要包装的上下文处理器。</param>
|
||||
/// <returns>可与普通处理器合并排序的统一调用描述。</returns>
|
||||
private static (int Priority, Action? Handler, Action<EventContext<T>>? ContextHandler, bool IsContext)
|
||||
CreateContextHandlerInvocation(ContextEventHandler handler)
|
||||
{
|
||||
return (handler.Priority, null, handler.Handler, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 事件处理器包装类,包含处理器和优先级
|
||||
/// </summary>
|
||||
|
||||
@ -80,7 +80,7 @@ public class PauseStackManager : AbstractContextUtility, IPauseStackManager, IAs
|
||||
// 触发事件
|
||||
try
|
||||
{
|
||||
OnPauseStateChanged?.Invoke(group, false);
|
||||
RaisePauseStateChanged(group, false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -97,7 +97,7 @@ public class PauseStackManager : AbstractContextUtility, IPauseStackManager, IAs
|
||||
/// <summary>
|
||||
/// 暂停状态变化事件,当暂停状态发生改变时触发。
|
||||
/// </summary>
|
||||
public event Action<PauseGroup, bool>? OnPauseStateChanged;
|
||||
public event EventHandler<PauseStateChangedEventArgs>? OnPauseStateChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 推入一个新的暂停请求到指定的暂停组中。
|
||||
@ -488,7 +488,18 @@ public class PauseStackManager : AbstractContextUtility, IPauseStackManager, IAs
|
||||
}
|
||||
|
||||
// 触发事件
|
||||
OnPauseStateChanged?.Invoke(group, isPaused);
|
||||
RaisePauseStateChanged(group, isPaused);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以标准事件模式发布暂停状态变化事件。
|
||||
/// 所有状态变更路径都通过该方法创建统一的事件参数,避免不同调用点出现不一致的载荷。
|
||||
/// </summary>
|
||||
/// <param name="group">发生状态变化的暂停组。</param>
|
||||
/// <param name="isPaused">暂停组变化后的新状态。</param>
|
||||
private void RaisePauseStateChanged(PauseGroup group, bool isPaused)
|
||||
{
|
||||
OnPauseStateChanged?.Invoke(this, new PauseStateChangedEventArgs(group, isPaused));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -23,9 +23,9 @@ public interface ISceneBehavior : IRoute
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取场景的唯一标识符。
|
||||
/// 用于区分不同的场景实例。
|
||||
/// 该成员显式细化了 <see cref="IRoute.Key"/> 在场景路由中的语义,用于区分不同的场景实例。
|
||||
/// </summary>
|
||||
string Key { get; }
|
||||
new string Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取场景的原始对象。
|
||||
|
||||
@ -31,8 +31,9 @@ public interface ISceneRouteGuard : IRouteGuard<ISceneBehavior>
|
||||
|
||||
/// <summary>
|
||||
/// 异步检查是否允许离开指定场景。
|
||||
/// 该成员显式细化了通用路由守卫的离开检查,使场景守卫在 API 文档中保持场景语义。
|
||||
/// </summary>
|
||||
/// <param name="sceneKey">当前场景的唯一标识符。</param>
|
||||
/// <returns>如果允许离开则返回 true,否则返回 false。</returns>
|
||||
ValueTask<bool> CanLeaveAsync(string sceneKey);
|
||||
new ValueTask<bool> CanLeaveAsync(string sceneKey);
|
||||
}
|
||||
@ -48,10 +48,10 @@ public interface IUiPageBehavior : IRoute
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取键值
|
||||
/// 获取页面的唯一键值,并显式细化 <see cref="IRoute.Key"/> 在 UI 路由中的语义。
|
||||
/// </summary>
|
||||
/// <value>返回当前对象的键标识符</value>
|
||||
string Key { get; }
|
||||
new string Key { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -17,9 +17,10 @@ public interface IUiRouteGuard : IRouteGuard<IUiPageBehavior>
|
||||
ValueTask<bool> CanEnterAsync(string uiKey, IUiPageEnterParam? param);
|
||||
|
||||
/// <summary>
|
||||
/// 离开UI前的检查
|
||||
/// 离开UI前的检查。
|
||||
/// 该成员显式细化了通用路由守卫的离开检查,使 UI 守卫在 API 文档中保持 UI 语义。
|
||||
/// </summary>
|
||||
/// <param name="uiKey">当前UI标识符</param>
|
||||
/// <returns>true表示允许离开,false表示拦截</returns>
|
||||
ValueTask<bool> CanLeaveAsync(string uiKey);
|
||||
new ValueTask<bool> CanLeaveAsync(string uiKey);
|
||||
}
|
||||
@ -100,8 +100,8 @@ void ClearAll();
|
||||
void RegisterHandler(IPauseHandler handler);
|
||||
void UnregisterHandler(IPauseHandler handler);
|
||||
|
||||
// 状态变化事件
|
||||
event Action<PauseGroup, bool>? OnPauseStateChanged;
|
||||
// 状态变化事件
|
||||
event EventHandler<PauseStateChangedEventArgs>? OnPauseStateChanged;
|
||||
```
|
||||
|
||||
## 基本用法
|
||||
@ -377,16 +377,16 @@ public partial class PauseIndicator : IController
|
||||
_pauseManager.OnPauseStateChanged += OnPauseStateChanged;
|
||||
}
|
||||
|
||||
private void OnPauseStateChanged(PauseGroup group, bool isPaused)
|
||||
{
|
||||
Console.WriteLine($"暂停状态变化: 组={group}, 暂停={isPaused}");
|
||||
|
||||
if (group == PauseGroup.Global)
|
||||
{
|
||||
if (isPaused)
|
||||
{
|
||||
ShowPauseIndicator();
|
||||
}
|
||||
private void OnPauseStateChanged(object? sender, PauseStateChangedEventArgs e)
|
||||
{
|
||||
Console.WriteLine($"暂停状态变化: 组={e.Group}, 暂停={e.IsPaused}");
|
||||
|
||||
if (e.Group == PauseGroup.Global)
|
||||
{
|
||||
if (e.IsPaused)
|
||||
{
|
||||
ShowPauseIndicator();
|
||||
}
|
||||
else
|
||||
{
|
||||
HidePauseIndicator();
|
||||
@ -705,7 +705,7 @@ public partial class ProperCleanup : IController
|
||||
_pauseManager.OnPauseStateChanged -= OnPauseChanged;
|
||||
}
|
||||
|
||||
private void OnPauseChanged(PauseGroup group, bool isPaused) { }
|
||||
private void OnPauseChanged(object? sender, PauseStateChangedEventArgs e) { }
|
||||
}
|
||||
```
|
||||
|
||||
@ -743,13 +743,13 @@ public partial class PauseMenu : Control
|
||||
|
||||
// 方案 2: 监听暂停事件
|
||||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||||
pauseManager.OnPauseStateChanged += (group, isPaused) =>
|
||||
{
|
||||
if (group == PauseGroup.Global)
|
||||
{
|
||||
Visible = isPaused;
|
||||
}
|
||||
};
|
||||
pauseManager.OnPauseStateChanged += (_, e) =>
|
||||
{
|
||||
if (e.Group == PauseGroup.Global)
|
||||
{
|
||||
Visible = e.IsPaused;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -887,15 +887,15 @@ public class PauseEventBridge : AbstractSystem
|
||||
{
|
||||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||||
|
||||
pauseManager.OnPauseStateChanged += (group, isPaused) =>
|
||||
{
|
||||
// 发送暂停事件
|
||||
this.SendEvent(new GamePausedEvent
|
||||
{
|
||||
Group = group,
|
||||
IsPaused = isPaused
|
||||
});
|
||||
};
|
||||
pauseManager.OnPauseStateChanged += (_, e) =>
|
||||
{
|
||||
// 发送暂停事件
|
||||
this.SendEvent(new GamePausedEvent
|
||||
{
|
||||
Group = e.Group,
|
||||
IsPaused = e.IsPaused
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ public interface IPauseStackManager : IContextUtility
|
||||
int GetPauseDepth(PauseGroup group = PauseGroup.Global);
|
||||
|
||||
// 暂停状态变化事件
|
||||
event Action<PauseGroup, bool>? OnPauseStateChanged;
|
||||
event EventHandler<PauseStateChangedEventArgs>? OnPauseStateChanged;
|
||||
}
|
||||
```
|
||||
|
||||
@ -477,12 +477,12 @@ public partial class PauseIndicator : Label
|
||||
pauseManager.OnPauseStateChanged -= OnPauseStateChanged;
|
||||
}
|
||||
|
||||
private void OnPauseStateChanged(PauseGroup group, bool isPaused)
|
||||
private void OnPauseStateChanged(object? sender, PauseStateChangedEventArgs e)
|
||||
{
|
||||
if (group == PauseGroup.Global)
|
||||
if (e.Group == PauseGroup.Global)
|
||||
{
|
||||
Text = isPaused ? "游戏已暂停" : "游戏运行中";
|
||||
Visible = isPaused;
|
||||
Text = e.IsPaused ? "游戏已暂停" : "游戏运行中";
|
||||
Visible = e.IsPaused;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -502,16 +502,16 @@ public partial class PauseDebugger : Node
|
||||
pauseManager.OnPauseStateChanged += OnPauseStateChanged;
|
||||
}
|
||||
|
||||
private void OnPauseStateChanged(PauseGroup group, bool isPaused)
|
||||
private void OnPauseStateChanged(object? sender, PauseStateChangedEventArgs e)
|
||||
{
|
||||
var pauseManager = this.GetUtility<IPauseStackManager>();
|
||||
|
||||
GD.Print($"=== 暂停状态变化 ===");
|
||||
GD.Print($"组: {group}");
|
||||
GD.Print($"状态: {(isPaused ? "暂停" : "恢复")}");
|
||||
GD.Print($"深度: {pauseManager.GetPauseDepth(group)}");
|
||||
GD.Print($"组: {e.Group}");
|
||||
GD.Print($"状态: {(e.IsPaused ? "暂停" : "恢复")}");
|
||||
GD.Print($"深度: {pauseManager.GetPauseDepth(e.Group)}");
|
||||
|
||||
var reasons = pauseManager.GetPauseReasons(group);
|
||||
var reasons = pauseManager.GetPauseReasons(e.Group);
|
||||
if (reasons.Count > 0)
|
||||
{
|
||||
GD.Print($"原因:");
|
||||
@ -609,9 +609,9 @@ public partial class PauseDebugger : Node
|
||||
|
||||
7. **使用事件监听暂停状态**:实现响应式 UI
|
||||
```csharp
|
||||
pauseManager.OnPauseStateChanged += (group, isPaused) =>
|
||||
pauseManager.OnPauseStateChanged += (_, e) =>
|
||||
{
|
||||
UpdateUI(isPaused);
|
||||
UpdateUI(e.IsPaused);
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user