Skip to content

Commit 18fbc02

Browse files
committed
feat(ModelCloneRegistry): add model-clone listener registry functionality
- Introduced `ModelCloneRegistry` for per-mod registration of model clone listeners, enhancing modularity and organization. - Implemented methods for creating and managing listener registrations, including support for custom predicates. - Updated documentation to reflect changes and improve clarity on usage within the framework.
1 parent 9331b0b commit 18fbc02

2 files changed

Lines changed: 65 additions & 48 deletions

File tree

Models/ModelCloneRegistry.cs

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,69 @@
33
namespace STS2RitsuLib.Models
44
{
55
/// <summary>
6-
/// Global listeners for vanilla model clone operations.
7-
/// 原版模型复制操作的全局监听器
6+
/// Per-mod registration surface for vanilla model clone listeners.
7+
/// 原版模型复制监听器的按 mod 注册入口
88
/// </summary>
9-
public static class ModelCloneRegistry
9+
public sealed class ModelCloneRegistry
1010
{
1111
private static readonly Lock SyncRoot = new();
12+
13+
private static readonly Dictionary<string, ModelCloneRegistry> Registries =
14+
new(StringComparer.OrdinalIgnoreCase);
15+
1216
private static readonly Dictionary<(string ModId, string ListenerId), ListenerEntry> Listeners = [];
1317
private static long _nextRegistrationOrder;
1418

19+
private readonly string _modId;
20+
21+
private ModelCloneRegistry(string modId)
22+
{
23+
_modId = modId;
24+
}
25+
1526
/// <summary>
16-
/// Registers or replaces a listener for <paramref name="modId" /> that receives every completed
17-
/// <see cref="AbstractModel.MutableClone" />.
18-
/// 为 <paramref name="modId" /> 注册或替换一个监听器,以接收每次完成的
19-
/// <see cref="AbstractModel.MutableClone" />。
27+
/// Returns the singleton clone registry for <paramref name="modId" />, creating it on first use.
28+
/// 返回 <paramref name="modId" /> 对应的单例复制注册表,并在首次使用时创建。
29+
/// </summary>
30+
public static ModelCloneRegistry For(string modId)
31+
{
32+
ArgumentException.ThrowIfNullOrWhiteSpace(modId);
33+
34+
lock (SyncRoot)
35+
{
36+
if (Registries.TryGetValue(modId, out var existing))
37+
return existing;
38+
39+
var created = new ModelCloneRegistry(modId);
40+
Registries[modId] = created;
41+
return created;
42+
}
43+
}
44+
45+
/// <summary>
46+
/// Registers or replaces a listener that receives every completed <see cref="AbstractModel.MutableClone" />.
47+
/// 注册或替换一个监听器,以接收每次完成的 <see cref="AbstractModel.MutableClone" />。
2048
/// </summary>
21-
/// <param name="modId">
22-
/// Owning mod identifier.
23-
/// 所属 mod 标识符。
24-
/// </param>
2549
/// <param name="listenerId">
26-
/// Unique listener id within the mod.
27-
/// 此监听器在 mod 内的唯一标识符。
50+
/// Unique listener id within this registry's mod.
51+
/// 此监听器在当前注册表 mod 内的唯一标识符。
2852
/// </param>
2953
/// <param name="listener">
3054
/// Listener invoked after the clone has been created and initialized.
3155
/// 在复制体创建并初始化后调用的监听器。
3256
/// </param>
33-
public static void Register(string modId, string listenerId, Action<ModelCloneContext> listener)
57+
public void Register(string listenerId, Action<ModelCloneContext> listener)
3458
{
35-
Register(modId, listenerId, _ => true, listener);
59+
Register(listenerId, _ => true, listener);
3660
}
3761

3862
/// <summary>
39-
/// Registers or replaces a listener with a custom predicate for <paramref name="modId" />.
40-
/// 为 <paramref name="modId" /> 注册或替换一个带自定义谓词的监听器。
63+
/// Registers or replaces a listener with a custom predicate.
64+
/// 注册或替换一个带自定义谓词的监听器。
4165
/// </summary>
42-
/// <param name="modId">
43-
/// Owning mod identifier.
44-
/// 所属 mod 标识符。
45-
/// </param>
4666
/// <param name="listenerId">
47-
/// Unique listener id within the mod.
48-
/// 此监听器在 mod 内的唯一标识符。
67+
/// Unique listener id within this registry's mod.
68+
/// 此监听器在当前注册表 mod 内的唯一标识符。
4969
/// </param>
5070
/// <param name="predicate">
5171
/// Predicate used to select clone operations for this listener.
@@ -55,69 +75,57 @@ public static void Register(string modId, string listenerId, Action<ModelCloneCo
5575
/// Listener invoked after the clone has been created and initialized.
5676
/// 在复制体创建并初始化后调用的监听器。
5777
/// </param>
58-
public static void Register(
59-
string modId,
78+
public void Register(
6079
string listenerId,
6180
Func<ModelCloneContext, bool> predicate,
6281
Action<ModelCloneContext> listener)
6382
{
64-
ArgumentException.ThrowIfNullOrWhiteSpace(modId);
6583
ArgumentException.ThrowIfNullOrWhiteSpace(listenerId);
6684
ArgumentNullException.ThrowIfNull(predicate);
6785
ArgumentNullException.ThrowIfNull(listener);
6886

6987
lock (SyncRoot)
7088
{
71-
var key = (modId, listenerId);
89+
var key = (_modId, listenerId);
7290
var registrationOrder = Listeners.TryGetValue(key, out var existing)
7391
? existing.RegistrationOrder
7492
: _nextRegistrationOrder++;
7593

76-
Listeners[key] = new(modId, listenerId, predicate, listener, registrationOrder);
94+
Listeners[key] = new(_modId, listenerId, predicate, listener, registrationOrder);
7795
}
7896
}
7997

8098
/// <summary>
81-
/// Registers or replaces a typed listener for a model family, including vanilla model types, for
82-
/// <paramref name="modId" />.
83-
/// 为 <paramref name="modId" /> 注册或替换某个模型族的类型化监听器,包括原版模型类型。
99+
/// Registers or replaces a typed listener for a model family, including vanilla model types.
100+
/// 注册或替换某个模型族的类型化监听器,包括原版模型类型。
84101
/// </summary>
85102
/// <typeparam name="TModel">
86103
/// Model base or concrete type to listen for.
87104
/// 要监听的模型基类或具体类型。
88105
/// </typeparam>
89-
/// <param name="modId">
90-
/// Owning mod identifier.
91-
/// 所属 mod 标识符。
92-
/// </param>
93106
/// <param name="listenerId">
94-
/// Unique listener id within the mod.
95-
/// 此监听器在 mod 内的唯一标识符。
107+
/// Unique listener id within this registry's mod.
108+
/// 此监听器在当前注册表 mod 内的唯一标识符。
96109
/// </param>
97110
/// <param name="listener">
98111
/// Typed listener invoked when both prototype and cloned model are <typeparamref name="TModel" />.
99112
/// 当原型和复制体均为 <typeparamref name="TModel" /> 时调用的类型化监听器。
100113
/// </param>
101-
public static void Register<TModel>(string modId, string listenerId, Action<TModel, TModel> listener)
114+
public void Register<TModel>(string listenerId, Action<TModel, TModel> listener)
102115
where TModel : AbstractModel
103116
{
104117
ArgumentNullException.ThrowIfNull(listener);
105118

106119
Register(
107-
modId,
108120
listenerId,
109121
context => context is { Prototype: TModel, ClonedModel: TModel },
110122
context => listener((TModel)context.Prototype, (TModel)context.ClonedModel));
111123
}
112124

113125
/// <summary>
114-
/// Removes a previously registered listener.
115-
/// 移除先前注册的监听器。
126+
/// Removes a previously registered listener from this registry's mod.
127+
/// 从当前注册表 mod 移除先前注册的监听器。
116128
/// </summary>
117-
/// <param name="modId">
118-
/// Mod identifier used at registration.
119-
/// 注册时使用的 mod 标识符。
120-
/// </param>
121129
/// <param name="listenerId">
122130
/// Listener id used at registration.
123131
/// 注册时使用的监听器标识符。
@@ -126,14 +134,13 @@ public static void Register<TModel>(string modId, string listenerId, Action<TMod
126134
/// <see langword="true" /> if an entry was removed.
127135
/// 如果移除了条目,则为 <see langword="true" />。
128136
/// </returns>
129-
public static bool Unregister(string modId, string listenerId)
137+
public bool Unregister(string listenerId)
130138
{
131-
ArgumentException.ThrowIfNullOrWhiteSpace(modId);
132139
ArgumentException.ThrowIfNullOrWhiteSpace(listenerId);
133140

134141
lock (SyncRoot)
135142
{
136-
return Listeners.Remove((modId, listenerId));
143+
return Listeners.Remove((_modId, listenerId));
137144
}
138145
}
139146

RitsuLibFramework.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using STS2RitsuLib.Keywords;
2222
using STS2RitsuLib.Localization;
2323
using STS2RitsuLib.Localization.SmartFormat;
24+
using STS2RitsuLib.Models;
2425
using STS2RitsuLib.Patching.Core;
2526
using STS2RitsuLib.Platform;
2627
using STS2RitsuLib.RunData;
@@ -564,6 +565,15 @@ public static ModUnlockRegistry GetUnlockRegistry(string modId)
564565
return ModUnlockRegistry.For(modId);
565566
}
566567

568+
/// <summary>
569+
/// Returns the model-clone listener registry for <paramref name="modId" />.
570+
/// 返回 <paramref name="modId" /> 的模型复制监听器注册表。
571+
/// </summary>
572+
public static ModelCloneRegistry GetModelCloneRegistry(string modId)
573+
{
574+
return ModelCloneRegistry.For(modId);
575+
}
576+
567577
/// <summary>
568578
/// Registers a non-power health bar forecast source type through the framework.
569579
/// 通过框架注册非能力生命条预测来源类型。

0 commit comments

Comments
 (0)