com.wallstop-studios.dxmessaging 1.0.0-rc10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/.gitattributes +63 -0
  2. package/CHANGELOG.md +0 -0
  3. package/CHANGELOG.md.meta +7 -0
  4. package/Editor.meta +8 -0
  5. package/LICENSE.md +7 -0
  6. package/LICENSE.md.meta +7 -0
  7. package/README.md +76 -0
  8. package/README.md.meta +7 -0
  9. package/Runtime/Core/Extensions/MessageExtensions.cs +275 -0
  10. package/Runtime/Core/Extensions/MessageExtensions.cs.meta +11 -0
  11. package/Runtime/Core/Extensions.meta +8 -0
  12. package/Runtime/Core/IMessage.cs +12 -0
  13. package/Runtime/Core/IMessage.cs.meta +11 -0
  14. package/Runtime/Core/InstanceId.cs +117 -0
  15. package/Runtime/Core/InstanceId.cs.meta +11 -0
  16. package/Runtime/Core/MessageBus/IMessageBus.cs +249 -0
  17. package/Runtime/Core/MessageBus/IMessageBus.cs.meta +11 -0
  18. package/Runtime/Core/MessageBus/MessageBus.cs +961 -0
  19. package/Runtime/Core/MessageBus/MessageBus.cs.meta +11 -0
  20. package/Runtime/Core/MessageBus/MessagingRegistration.cs +100 -0
  21. package/Runtime/Core/MessageBus/MessagingRegistration.cs.meta +11 -0
  22. package/Runtime/Core/MessageBus/RegistrationLog.cs +111 -0
  23. package/Runtime/Core/MessageBus/RegistrationLog.cs.meta +11 -0
  24. package/Runtime/Core/MessageBus.meta +8 -0
  25. package/Runtime/Core/MessageHandler.cs +1589 -0
  26. package/Runtime/Core/MessageHandler.cs.meta +11 -0
  27. package/Runtime/Core/MessageRegistrationHandle.cs +55 -0
  28. package/Runtime/Core/MessageRegistrationHandle.cs.meta +11 -0
  29. package/Runtime/Core/MessageRegistrationToken.cs +885 -0
  30. package/Runtime/Core/MessageRegistrationToken.cs.meta +11 -0
  31. package/Runtime/Core/Messages/IBroadcastMessage.cs +27 -0
  32. package/Runtime/Core/Messages/IBroadcastMessage.cs.meta +11 -0
  33. package/Runtime/Core/Messages/ITargetedMessage.cs +26 -0
  34. package/Runtime/Core/Messages/ITargetedMessage.cs.meta +11 -0
  35. package/Runtime/Core/Messages/IUntargetedMessage.cs +26 -0
  36. package/Runtime/Core/Messages/IUntargetedMessage.cs.meta +11 -0
  37. package/Runtime/Core/Messages.meta +8 -0
  38. package/Runtime/Core/MessagingDebug.cs +71 -0
  39. package/Runtime/Core/MessagingDebug.cs.meta +11 -0
  40. package/Runtime/Core.meta +8 -0
  41. package/Runtime/Unity/MessageAwareComponent.cs +77 -0
  42. package/Runtime/Unity/MessageAwareComponent.cs.meta +11 -0
  43. package/Runtime/Unity/MessagingComponent.cs +73 -0
  44. package/Runtime/Unity/MessagingComponent.cs.meta +11 -0
  45. package/Runtime/Unity.meta +8 -0
  46. package/Runtime/WallstopStudios.DxMessaging.asmdef +18 -0
  47. package/Runtime/WallstopStudios.DxMessaging.asmdef.meta +7 -0
  48. package/Runtime.meta +8 -0
  49. package/Tests/Editor/WallstopStudios.DxMessaging.Tests.Editor.asmdef +23 -0
  50. package/Tests/Editor/WallstopStudios.DxMessaging.Tests.Editor.asmdef.meta +7 -0
  51. package/Tests/Editor.meta +8 -0
  52. package/Tests/Runtime/Benchmarks/PerformanceTests.cs +196 -0
  53. package/Tests/Runtime/Benchmarks/PerformanceTests.cs.meta +11 -0
  54. package/Tests/Runtime/Benchmarks.meta +8 -0
  55. package/Tests/Runtime/Core/BroadcastTests.cs +600 -0
  56. package/Tests/Runtime/Core/BroadcastTests.cs.meta +11 -0
  57. package/Tests/Runtime/Core/GlobalAcceptAllTests.cs +169 -0
  58. package/Tests/Runtime/Core/GlobalAcceptAllTests.cs.meta +11 -0
  59. package/Tests/Runtime/Core/MessagingTestBase.cs +164 -0
  60. package/Tests/Runtime/Core/MessagingTestBase.cs.meta +11 -0
  61. package/Tests/Runtime/Core/NominalTests.cs +1468 -0
  62. package/Tests/Runtime/Core/NominalTests.cs.meta +11 -0
  63. package/Tests/Runtime/Core/PostProcessorTests.cs +849 -0
  64. package/Tests/Runtime/Core/PostProcessorTests.cs.meta +11 -0
  65. package/Tests/Runtime/Core/RegistrationTests.cs +1045 -0
  66. package/Tests/Runtime/Core/RegistrationTests.cs.meta +11 -0
  67. package/Tests/Runtime/Core/TargetedTests.cs +596 -0
  68. package/Tests/Runtime/Core/TargetedTests.cs.meta +11 -0
  69. package/Tests/Runtime/Core/UntargetedTests.cs +149 -0
  70. package/Tests/Runtime/Core/UntargetedTests.cs.meta +11 -0
  71. package/Tests/Runtime/Core.meta +8 -0
  72. package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs +9 -0
  73. package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs.meta +11 -0
  74. package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs +140 -0
  75. package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs.meta +11 -0
  76. package/Tests/Runtime/Scripts/Components.meta +8 -0
  77. package/Tests/Runtime/Scripts/Messages/ComplexTargetedMessage.cs +28 -0
  78. package/Tests/Runtime/Scripts/Messages/ComplexTargetedMessage.cs.meta +11 -0
  79. package/Tests/Runtime/Scripts/Messages/SimpleBroadcastMessage.cs +8 -0
  80. package/Tests/Runtime/Scripts/Messages/SimpleBroadcastMessage.cs.meta +11 -0
  81. package/Tests/Runtime/Scripts/Messages/SimpleTargetedMessage.cs +8 -0
  82. package/Tests/Runtime/Scripts/Messages/SimpleTargetedMessage.cs.meta +11 -0
  83. package/Tests/Runtime/Scripts/Messages/SimpleUntargetedMessage.cs +8 -0
  84. package/Tests/Runtime/Scripts/Messages/SimpleUntargetedMessage.cs.meta +11 -0
  85. package/Tests/Runtime/Scripts/Messages.meta +8 -0
  86. package/Tests/Runtime/Scripts.meta +8 -0
  87. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef +22 -0
  88. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef.meta +7 -0
  89. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.csproj +1 -0
  90. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.csproj.meta +7 -0
  91. package/Tests/Runtime.meta +8 -0
  92. package/Tests.meta +8 -0
  93. package/Third Party Notices.md +1 -0
  94. package/Third Party Notices.md.meta +7 -0
  95. package/package.json +36 -0
  96. package/package.json.meta +7 -0
@@ -0,0 +1,1589 @@
1
+ namespace DxMessaging.Core
2
+ {
3
+ using MessageBus;
4
+ using System;
5
+ using System.Collections.Generic;
6
+ using System.Linq;
7
+ using System.Runtime.CompilerServices;
8
+ using Messages;
9
+
10
+ /// <summary>
11
+ /// Abstraction layer for immediate-mode Message passing. An instance of this handles all
12
+ /// kinds of types to trigger functions that are registered with it.
13
+ /// </summary>
14
+ public sealed class MessageHandler
15
+ {
16
+ public delegate void FastHandler<TMessage>(ref TMessage message) where TMessage : IMessage;
17
+ public delegate void FastHandlerWithContext<TMessage>(ref InstanceId context, ref TMessage message) where TMessage : IMessage;
18
+
19
+ /// <summary>
20
+ /// MessageBus for all MessageHandlers to use. Currently immutable, but may change in the future.
21
+ /// </summary>
22
+ public static readonly MessageBus.MessageBus MessageBus = new();
23
+
24
+ /// <summary>
25
+ /// Maps Types to the corresponding Handler of that type.
26
+ /// </summary>
27
+ /// <note>
28
+ /// Ideally, this would be something like a Dictionary[T,Handler[T]], but that can't be done with C#s type system.
29
+ /// </note>
30
+ private readonly Dictionary<IMessageBus, Dictionary<Type, object>> _handlersByTypeByMessageBus;
31
+
32
+ /// <summary>
33
+ /// Whether or not this MessageHandler will process messages.
34
+ /// </summary>
35
+ public bool active;
36
+
37
+ /// <summary>
38
+ /// The Id of the GameObject that owns us.
39
+ /// </summary>
40
+ public readonly InstanceId owner;
41
+
42
+ public MessageHandler(InstanceId owner)
43
+ {
44
+ this.owner = owner;
45
+ _handlersByTypeByMessageBus = new Dictionary<IMessageBus, Dictionary<Type, object>>();
46
+ }
47
+
48
+ /// <summary>
49
+ /// Callback from the MessageBus for handling UntargetedMessages - user code should generally never use this.
50
+ /// </summary>
51
+ /// <note>
52
+ /// In this case, "UntargetedMessage" refers to Targeted without targeting, and UntargetedMessages, hence T : AbstractMessage.
53
+ /// </note>
54
+ /// <param name="message">Message to handle.</param>
55
+ /// <param name="messageBus">The specific MessageBus to use.</param>
56
+ public void HandleUntargetedMessage<TMessage>(ref TMessage message, IMessageBus messageBus) where TMessage : IMessage
57
+ {
58
+ if (!active)
59
+ {
60
+ return;
61
+ }
62
+
63
+ if (GetHandlerForType(message.MessageType, messageBus, out TypedHandler<TMessage> handler))
64
+ {
65
+ handler.HandleUntargeted(ref message);
66
+ }
67
+ }
68
+
69
+ /// <summary>
70
+ /// Callback from the MessageBus for handling UntargetedMessages - user code should generally never use this.
71
+ /// </summary>
72
+ /// <note>
73
+ /// In this case, "UntargetedMessage" refers to Targeted without targeting, and UntargetedMessages, hence T : AbstractMessage.
74
+ /// </note>
75
+ /// <param name="message">Message to handle.</param>
76
+ /// <param name="messageBus">The specific MessageBus to use.</param>
77
+ public void HandleUntargetedPostProcessing<TMessage>(ref TMessage message, IMessageBus messageBus) where TMessage : IUntargetedMessage
78
+ {
79
+ if (!active)
80
+ {
81
+ return;
82
+ }
83
+
84
+ if (GetHandlerForType(message.MessageType, messageBus, out TypedHandler<TMessage> handler))
85
+ {
86
+ handler.HandleUntargetedPostProcessing(ref message);
87
+ }
88
+ }
89
+
90
+ /// <summary>
91
+ /// Callback from the MessageBus for handling TargetedMessages when this MessageHandler has subscribed - user code should generally never use this.
92
+ /// </summary>
93
+ /// <note>
94
+ /// TargetedMessage refers to those that are intended for the GameObject that owns this MessageHandler.
95
+ /// </note>
96
+ /// <param name="target">Target Id the message is for.</param>
97
+ /// <param name="message">Message to handle.</param>
98
+ /// <param name="messageBus">The specific MessageBus to use.</param>
99
+ public void HandleTargeted<TMessage>(ref InstanceId target, ref TMessage message, IMessageBus messageBus) where TMessage : ITargetedMessage
100
+ {
101
+ if (!active)
102
+ {
103
+ return;
104
+ }
105
+
106
+ if (GetHandlerForType(message.MessageType, messageBus, out TypedHandler<TMessage> handler))
107
+ {
108
+ handler.HandleTargeted(ref target, ref message);
109
+ }
110
+ }
111
+
112
+ /// <summary>
113
+ /// Callback from the MessageBus for handling TargetedMessages without targeting when this MessageHandler has subscribed - user code should generally never use this.
114
+ /// </summary>
115
+ /// <note>
116
+ /// Any TargetedMessage.
117
+ /// </note>
118
+ /// <param name="target">Target Id the message is for.</param>
119
+ /// <param name="message">Message to handle.</param>
120
+ /// <param name="messageBus">The specific MessageBus to use.</param>
121
+
122
+ public void HandleTargetedWithoutTargeting<TMessage>(ref InstanceId target, ref TMessage message, IMessageBus messageBus) where TMessage : ITargetedMessage
123
+ {
124
+ if (!active)
125
+ {
126
+ return;
127
+ }
128
+
129
+ if (GetHandlerForType(message.MessageType, messageBus, out TypedHandler<TMessage> handler))
130
+ {
131
+ handler.HandleTargetedWithoutTargeting(ref target, ref message);
132
+ }
133
+ }
134
+
135
+ /// <summary>
136
+ /// Callback from the MessageBus for post processing TargetedMessages when this MessageHandler has subscribed - user code should generally never use this.
137
+ /// </summary>
138
+ /// <note>
139
+ /// TargetedMessage refers to those that are intended for the GameObject that owns this MessageHandler.
140
+ /// </note>
141
+ /// <param name="target">Target Id the message is for.</param>
142
+ /// <param name="message">Message to handle.</param>
143
+ /// <param name="messageBus">The specific MessageBus to use.</param>
144
+
145
+ public void HandleTargetedPostProcessing<TMessage>(ref InstanceId target, ref TMessage message, IMessageBus messageBus) where TMessage : ITargetedMessage
146
+ {
147
+ if (!active)
148
+ {
149
+ return;
150
+ }
151
+
152
+ if (GetHandlerForType(message.MessageType, messageBus, out TypedHandler<TMessage> handler))
153
+ {
154
+ handler.HandleTargetedPostProcessing(ref target, ref message);
155
+ }
156
+ }
157
+
158
+ /// <summary>
159
+ /// Callback from the MessageBus for post processing TargetedMessages when this MessageHandler has subscribed - user code should generally never use this.
160
+ /// </summary>
161
+ /// <note>
162
+ /// TargetedMessage refers to those that are intended for the GameObject that owns this MessageHandler.
163
+ /// </note>
164
+ /// <param name="target">Target Id the message is for.</param>
165
+ /// <param name="message">Message to handle.</param>
166
+ /// <param name="messageBus">The specific MessageBus to use.</param>
167
+
168
+ public void HandleTargetedWithoutTargetingPostProcessing<TMessage>(ref InstanceId target, ref TMessage message, IMessageBus messageBus) where TMessage : ITargetedMessage
169
+ {
170
+ if (!active)
171
+ {
172
+ return;
173
+ }
174
+
175
+ if (GetHandlerForType(message.MessageType, messageBus, out TypedHandler<TMessage> handler))
176
+ {
177
+ handler.HandleTargetedWithoutTargetingPostProcessing(ref target, ref message);
178
+ }
179
+ }
180
+
181
+ /// <summary>
182
+ /// Callback from the MessageBus for handling SourcedBroadcastMessages - user code should generally never use this.
183
+ /// </summary>
184
+ /// <note>
185
+ /// SourcedBroadcastMessages generally refer to those that are sourced from the GameObject that owns this MessageHandler.
186
+ /// </note>
187
+ /// <param name="source">Source Id the broadcast message is from.</param>
188
+ /// <param name="message">Message to handle</param>
189
+ /// <param name="messageBus">The specific MessageBus to use.</param>
190
+ public void HandleSourcedBroadcast<TMessage>(ref InstanceId source, ref TMessage message, IMessageBus messageBus) where TMessage : IBroadcastMessage
191
+ {
192
+ if (!active)
193
+ {
194
+ return;
195
+ }
196
+
197
+ if (GetHandlerForType(message.MessageType, messageBus, out TypedHandler<TMessage> handler))
198
+ {
199
+ handler.HandleSourcedBroadcast(ref source, ref message);
200
+ }
201
+ }
202
+
203
+ /// <summary>
204
+ /// Callback from the MessageBus for handling SourcedBroadcastMessages without source - user code should generally never use this.
205
+ /// </summary>
206
+ /// <note>
207
+ /// Any SourcedBroadcastMessages.
208
+ /// </note>
209
+ /// <param name="source">Source Id the broadcast message is from.</param>
210
+ /// <param name="message">Message to handle</param>
211
+ /// <param name="messageBus">The specific MessageBus to use.</param>
212
+ public void HandleSourcedBroadcastWithoutSource<TMessage>(ref InstanceId source, ref TMessage message, IMessageBus messageBus) where TMessage : IBroadcastMessage
213
+ {
214
+ if (!active)
215
+ {
216
+ return;
217
+ }
218
+
219
+ if (GetHandlerForType(message.MessageType, messageBus, out TypedHandler<TMessage> handler))
220
+ {
221
+ handler.HandleSourcedBroadcastWithoutSource(ref source, ref message);
222
+ }
223
+ }
224
+
225
+ /// <summary>
226
+ /// Callback from the MessageBus for handling SourcedBroadcastPostProcessing - user code should generally never use this.
227
+ /// </summary>
228
+ /// <note>
229
+ /// SourcedBroadcastMessages generally refer to those that are sourced from the GameObject that owns this MessageHandler.
230
+ /// </note>
231
+ /// <param name="source">Source Id the broadcast message is from.</param>
232
+ /// <param name="message">Message to handle</param>
233
+ /// <param name="messageBus">The specific MessageBus to use.</param>
234
+ public void HandleSourcedBroadcastPostProcessing<TMessage>(ref InstanceId source, ref TMessage message, IMessageBus messageBus) where TMessage :IBroadcastMessage
235
+ {
236
+ if (!active)
237
+ {
238
+ return;
239
+ }
240
+
241
+ if (GetHandlerForType(message.MessageType, messageBus, out TypedHandler<TMessage> handler))
242
+ {
243
+ handler.HandleSourcedBroadcastPostProcessing(ref source, ref message);
244
+ }
245
+ }
246
+
247
+ /// <summary>
248
+ /// Callback from the MessageBus for handling SourcedBroadcastPostProcessing - user code should generally never use this.
249
+ /// </summary>
250
+ /// <note>
251
+ /// SourcedBroadcastMessages generally refer to those that are sourced from the GameObject that owns this MessageHandler.
252
+ /// </note>
253
+ /// <param name="source">Source Id the broadcast message is from.</param>
254
+ /// <param name="message">Message to handle</param>
255
+ /// <param name="messageBus">The specific MessageBus to use.</param>
256
+ public void HandleSourcedBroadcastWithoutSourcePostProcessing<TMessage>(ref InstanceId source, ref TMessage message, IMessageBus messageBus) where TMessage : IBroadcastMessage
257
+ {
258
+ if (!active)
259
+ {
260
+ return;
261
+ }
262
+
263
+ if (GetHandlerForType(message.MessageType, messageBus, out TypedHandler<TMessage> handler))
264
+ {
265
+ handler.HandleBroadcastWithoutSourcePostProcessing(ref source, ref message);
266
+ }
267
+ }
268
+
269
+ /// <summary>
270
+ /// Callback from the MessageBus for handling Messages when this MessageHandler has subscribed to GlobalAcceptAll - user code should generally never use this.
271
+ /// </summary>
272
+ /// <param name="message">Message to handle.</param>
273
+ /// <param name="messageBus">The specific MessageBus to use.</param>
274
+ public void HandleGlobalUntargetedMessage(ref IUntargetedMessage message, IMessageBus messageBus)
275
+ {
276
+ if (!active)
277
+ {
278
+ return;
279
+ }
280
+
281
+ // Use the "IMessage" explicitly to indicate global messages, allowing us to multi-purpose a single dictionary
282
+ if (GetHandlerForType(typeof(IMessage), messageBus, out TypedHandler<IMessage> handler))
283
+ {
284
+ handler.HandleGlobalUntargeted(ref message);
285
+ }
286
+ }
287
+
288
+ /// <summary>
289
+ /// Callback from the MessageBus for handling Messages when this MessageHandler has subscribed to GlobalAcceptAll - user code should generally never use this.
290
+ /// </summary>
291
+ /// <param name="target">Target of the message.</param>
292
+ /// <param name="message">Message to handle.</param>
293
+ /// <param name="messageBus">The specific MessageBus to use.</param>
294
+ public void HandleGlobalTargetedMessage(ref InstanceId target, ref ITargetedMessage message, IMessageBus messageBus)
295
+ {
296
+ if (!active)
297
+ {
298
+ return;
299
+ }
300
+
301
+ // Use the "IMessage" explicitly to indicate global messages, allowing us to multi-purpose a single dictionary
302
+ if (GetHandlerForType(typeof(IMessage), messageBus, out TypedHandler<IMessage> handler))
303
+ {
304
+ handler.HandleGlobalTargeted(ref target, ref message);
305
+ }
306
+ }
307
+
308
+ /// <summary>
309
+ /// Callback from the MessageBus for handling Messages when this MessageHandler has subscribed to GlobalAcceptAll - user code should generally never use this.
310
+ /// </summary>
311
+ /// <param name="source">Source that this message is from.</param>
312
+ /// <param name="message">Message to handle.</param>
313
+ /// <param name="messageBus">The specific MessageBus to use.</param>
314
+ public void HandleGlobalSourcedBroadcastMessage(ref InstanceId source, ref IBroadcastMessage message, IMessageBus messageBus)
315
+ {
316
+ if (!active)
317
+ {
318
+ return;
319
+ }
320
+
321
+ // Use the "IMessage" explicitly to indicate global messages, allowing us to multi-purpose a single dictionary
322
+ if (GetHandlerForType(typeof(IMessage), messageBus, out TypedHandler<IMessage> handler))
323
+ {
324
+ handler.HandleGlobalBroadcast(ref source, ref message);
325
+ }
326
+ }
327
+
328
+ /// <summary>
329
+ /// Registers this MessageHandler to Globally Accept All Messages via the MessageBus, properly handling de-registration.
330
+ /// </summary>
331
+ /// <param name="untargetedMessageHandler">MessageHandler to accept all UntargetedMessages.</param>
332
+ /// <param name="broadcastMessageHandler">MessageHandler to accept all TargetedMessages for all entities.</param>
333
+ /// <param name="targetedMessageHandler">MessageHandler to accept all BroadcastMessages for all entities.</param>
334
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
335
+ /// <returns>The de-registration action.</returns>
336
+ public Action RegisterGlobalAcceptAll(Action<IUntargetedMessage> untargetedMessageHandler, Action<InstanceId, ITargetedMessage> targetedMessageHandler, Action<InstanceId, IBroadcastMessage> broadcastMessageHandler, IMessageBus messageBus = null)
337
+ {
338
+ messageBus ??= MessageBus;
339
+ Action messageBusDeregistration = messageBus.RegisterGlobalAcceptAll(this);
340
+ TypedHandler<IMessage> typedHandler = GetOrCreateHandlerForType<IMessage>(messageBus);
341
+
342
+ void NullDeregistration()
343
+ {
344
+
345
+ }
346
+ Action untargetedDeregistration = typedHandler.AddGlobalUntargetedHandler(untargetedMessageHandler, NullDeregistration);
347
+ Action targetedDeregistration = typedHandler.AddGlobalTargetedHandler(targetedMessageHandler, NullDeregistration);
348
+ Action broadcastDeregistration = typedHandler.AddGlobalBroadcastHandler(broadcastMessageHandler, NullDeregistration);
349
+
350
+ return () =>
351
+ {
352
+ untargetedDeregistration();
353
+ targetedDeregistration();
354
+ broadcastDeregistration();
355
+ messageBusDeregistration?.Invoke();
356
+ };
357
+ }
358
+
359
+ /// <summary>
360
+ /// Registers this MessageHandler to Globally Accept All Messages via the MessageBus, properly handling de-registration.
361
+ /// </summary>
362
+ /// <param name="untargetedMessageHandler">MessageHandler to accept all UntargetedMessages.</param>
363
+ /// <param name="broadcastMessageHandler">MessageHandler to accept all TargetedMessages for all entities.</param>
364
+ /// <param name="targetedMessageHandler">MessageHandler to accept all BroadcastMessages for all entities.</param>
365
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
366
+ /// <returns>The de-registration action.</returns>
367
+ public Action RegisterGlobalAcceptAll(FastHandler<IUntargetedMessage> untargetedMessageHandler, FastHandlerWithContext<ITargetedMessage> targetedMessageHandler, FastHandlerWithContext<IBroadcastMessage> broadcastMessageHandler, IMessageBus messageBus = null)
368
+ {
369
+ messageBus ??= MessageBus;
370
+ Action messageBusDeregistration = messageBus.RegisterGlobalAcceptAll(this);
371
+ TypedHandler<IMessage> typedHandler = GetOrCreateHandlerForType<IMessage>(messageBus);
372
+
373
+ void NullDeregistration()
374
+ {
375
+
376
+ }
377
+ Action untargetedDeregistration = typedHandler.AddGlobalUntargetedHandler(untargetedMessageHandler, NullDeregistration);
378
+ Action targetedDeregistration = typedHandler.AddGlobalTargetedHandler(targetedMessageHandler, NullDeregistration);
379
+ Action broadcastDeregistration = typedHandler.AddGlobalBroadcastHandler(broadcastMessageHandler, NullDeregistration);
380
+
381
+ return () =>
382
+ {
383
+ untargetedDeregistration();
384
+ targetedDeregistration();
385
+ broadcastDeregistration();
386
+ messageBusDeregistration?.Invoke();
387
+ };
388
+ }
389
+
390
+ /// <summary>
391
+ /// Registers this MessageHandler to accept TargetedMessages via the MessageBus, properly handling de-registration.
392
+ /// </summary>
393
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
394
+ /// <param name="target">Target Id of TargetedMessages to listen for.</param>
395
+ /// <param name="messageHandler">Function that actually handles the message.</param>
396
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
397
+ /// <returns>The de-registration action.</returns>
398
+ public Action RegisterTargetedMessageHandler<T>(InstanceId target, Action<T> messageHandler, IMessageBus messageBus = null) where T : ITargetedMessage
399
+ {
400
+ messageBus ??= MessageBus;
401
+ Action messageBusDeregistration = messageBus.RegisterTargeted<T>(target, this);
402
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
403
+ return typedHandler.AddTargetedHandler(target, messageHandler, messageBusDeregistration);
404
+ }
405
+
406
+ /// <summary>
407
+ /// Registers this MessageHandler to accept fast TargetedMessages via the MessageBus, properly handling de-registration.
408
+ /// </summary>
409
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
410
+ /// <param name="target">Target Id of TargetedMessages to listen for.</param>
411
+ /// <param name="messageHandler">Function that actually handles the message.</param>
412
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
413
+ /// <returns>The de-registration action.</returns>
414
+ public Action RegisterTargetedMessageHandler<T>(InstanceId target, FastHandler<T> messageHandler, IMessageBus messageBus = null) where T : ITargetedMessage
415
+ {
416
+ messageBus ??= MessageBus;
417
+ Action messageBusDeregistration = messageBus.RegisterTargeted<T>(target, this);
418
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
419
+ return typedHandler.AddTargetedHandler(target, messageHandler, messageBusDeregistration);
420
+ }
421
+
422
+ /// <summary>
423
+ /// Registers this MessageHandler to post process TargetedMessages via the MessageBus, properly handling de-registration.
424
+ /// </summary>
425
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
426
+ /// <param name="target">Target Id of TargetedMessages to listen for.</param>
427
+ /// <param name="messageHandler">Function that actually handles the message.</param>
428
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
429
+ /// <returns>The de-registration action.</returns>
430
+ public Action RegisterTargetedPostProcessor<T>(InstanceId target, Action<T> messageHandler, IMessageBus messageBus = null) where T : ITargetedMessage
431
+ {
432
+ messageBus ??= MessageBus;
433
+ Action messageBusDeregistration = messageBus.RegisterTargetedPostProcessor<T>(target, this);
434
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
435
+ return typedHandler.AddTargetedPostProcessor(target, messageHandler, messageBusDeregistration);
436
+ }
437
+
438
+ /// <summary>
439
+ /// Registers this MessageHandler to post process fast TargetedMessages via the MessageBus, properly handling de-registration.
440
+ /// </summary>
441
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
442
+ /// <param name="target">Target Id of TargetedMessages to listen for.</param>
443
+ /// <param name="messageHandler">Function that actually handles the message.</param>
444
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
445
+ /// <returns>The de-registration action.</returns>
446
+ public Action RegisterTargetedPostProcessor<T>(InstanceId target, FastHandler<T> messageHandler, IMessageBus messageBus = null) where T : ITargetedMessage
447
+ {
448
+ messageBus ??= MessageBus;
449
+ Action messageBusDeregistration = messageBus.RegisterTargetedPostProcessor<T>(target, this);
450
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
451
+ return typedHandler.AddTargetedPostProcessor(target, messageHandler, messageBusDeregistration);
452
+ }
453
+
454
+ /// <summary>
455
+ /// Registers this MessageHandler to post process TargetedMessages for all messages of the provided type via the MessageBus, properly handling de-registration.
456
+ /// </summary>
457
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
458
+ /// <param name="messageHandler">Function that actually handles the message.</param>
459
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
460
+ /// <returns>The de-registration action.</returns>
461
+ public Action RegisterTargetedWithoutTargetingPostProcessor<T>(Action<InstanceId, T> messageHandler, IMessageBus messageBus = null) where T : ITargetedMessage
462
+ {
463
+ messageBus ??= MessageBus;
464
+ Action messageBusDeregistration = messageBus.RegisterTargetedWithoutTargetingPostProcessor<T>(this);
465
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
466
+ return typedHandler.AddTargetedWithoutTargetingPostProcessor(messageHandler, messageBusDeregistration);
467
+ }
468
+
469
+ /// <summary>
470
+ /// Registers this MessageHandler to post process fast TargetedMessages for all messages of the provided type via the MessageBus, properly handling de-registration.
471
+ /// </summary>
472
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
473
+ /// <param name="messageHandler">Function that actually handles the message.</param>
474
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
475
+ /// <returns>The de-registration action.</returns>
476
+ public Action RegisterTargetedWithoutTargetingPostProcessor<T>(FastHandlerWithContext<T> messageHandler, IMessageBus messageBus = null) where T : ITargetedMessage
477
+ {
478
+ messageBus ??= MessageBus;
479
+ Action messageBusDeregistration = messageBus.RegisterTargetedWithoutTargetingPostProcessor<T>(this);
480
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
481
+ return typedHandler.AddTargetedWithoutTargetingPostProcessor(messageHandler, messageBusDeregistration);
482
+ }
483
+
484
+ /// <summary>
485
+ /// Registers this MessageHandler to accept TargetedMessages without Targeting via the MessageBus, properly handling de-registration.
486
+ /// </summary>
487
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
488
+ /// <param name="messageHandler">Function that actually handles the message.</param>
489
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
490
+ /// <returns>The de-registration action.</returns>
491
+ public Action RegisterTargetedWithoutTargeting<T>(Action<InstanceId, T> messageHandler, IMessageBus messageBus = null) where T : ITargetedMessage
492
+ {
493
+ messageBus ??= MessageBus;
494
+ Action messageBusDeregistration = messageBus.RegisterTargetedWithoutTargeting<T>(this);
495
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
496
+ return typedHandler.AddTargetedWithoutTargetingHandler(messageHandler, messageBusDeregistration);
497
+ }
498
+
499
+ /// <summary>
500
+ /// Registers this MessageHandler to accept fast TargetedMessages without Targeting via the MessageBus, properly handling de-registration.
501
+ /// </summary>
502
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
503
+ /// <param name="messageHandler">Function that actually handles the message.</param>
504
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
505
+ /// <returns>The de-registration action.</returns>
506
+ public Action RegisterTargetedWithoutTargeting<T>(FastHandlerWithContext<T> messageHandler, IMessageBus messageBus = null) where T : ITargetedMessage
507
+ {
508
+ messageBus ??= MessageBus;
509
+ Action messageBusDeregistration = messageBus.RegisterTargetedWithoutTargeting<T>(this);
510
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
511
+ return typedHandler.AddTargetedWithoutTargetingHandler(messageHandler, messageBusDeregistration);
512
+ }
513
+
514
+ /// <summary>
515
+ /// Registers this MessageHandler to accept UntargetedMessages via the MessageBus, properly handling de-registration.
516
+ /// </summary>
517
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
518
+ /// <param name="messageHandler">Function that actually handles the message.</param>
519
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
520
+ /// <returns>The de-registration action.</returns>
521
+ public Action RegisterUntargetedMessageHandler<T>(Action<T> messageHandler, IMessageBus messageBus = null) where T : IUntargetedMessage
522
+ {
523
+ messageBus ??= MessageBus;
524
+ Action messageBusDeregistration = messageBus.RegisterUntargeted<T>(this);
525
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
526
+ return typedHandler.AddUntargetedHandler(messageHandler, messageBusDeregistration);
527
+ }
528
+
529
+ /// <summary>
530
+ /// Registers this MessageHandler to accept fast UntargetedMessages via the MessageBus, properly handling de-registration.
531
+ /// </summary>
532
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
533
+ /// <param name="messageHandler">Function that actually handles the message.</param>
534
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
535
+ /// <returns>The de-registration action.</returns>
536
+ public Action RegisterUntargetedMessageHandler<T>(FastHandler<T> messageHandler, IMessageBus messageBus = null) where T : IUntargetedMessage
537
+ {
538
+ messageBus ??= MessageBus;
539
+ Action messageBusDeregistration = messageBus.RegisterUntargeted<T>(this);
540
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
541
+ return typedHandler.AddUntargetedHandler(messageHandler, messageBusDeregistration);
542
+ }
543
+
544
+ /// <summary>
545
+ /// Registers this MessageHandler to post process UntargetedMessages via the MessageBus, properly handling de-registration.
546
+ /// </summary>
547
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
548
+ /// <param name="messageHandler">Function that actually handles the message.</param>
549
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
550
+ /// <returns>The de-registration action.</returns>
551
+ public Action RegisterUntargetedPostProcessor<T>(Action<T> messageHandler, IMessageBus messageBus = null) where T : IUntargetedMessage
552
+ {
553
+ messageBus ??= MessageBus;
554
+ Action messageBusDeregistration = messageBus.RegisterUntargetedPostProcessor<T>(this);
555
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
556
+ return typedHandler.AddUntargetedPostProcessor(messageHandler, messageBusDeregistration);
557
+ }
558
+
559
+ /// <summary>
560
+ /// Registers this MessageHandler to post process fast UntargetedMessages via the MessageBus, properly handling de-registration.
561
+ /// </summary>
562
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
563
+ /// <param name="messageHandler">Function that actually handles the message.</param>
564
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
565
+ /// <returns>The de-registration action.</returns>
566
+ public Action RegisterUntargetedPostProcessor<T>(FastHandler<T> messageHandler, IMessageBus messageBus = null) where T : IUntargetedMessage
567
+ {
568
+ messageBus ??= MessageBus;
569
+ Action messageBusDeregistration = messageBus.RegisterUntargetedPostProcessor<T>(this);
570
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
571
+ return typedHandler.AddUntargetedPostProcessor(messageHandler, messageBusDeregistration);
572
+ }
573
+
574
+ /// <summary>
575
+ /// Registers this MessageHandler to accept BroadcastMessages via their MessageBus, properly handling de-registration.
576
+ /// </summary>
577
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
578
+ /// <param name="source">Source Id of BroadcastMessages to listen for.</param>
579
+ /// <param name="messageHandler">Function that actually handles the message.</param>
580
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
581
+ /// <returns>The de-registration action.</returns>
582
+ public Action RegisterSourcedBroadcastMessageHandler<T>(InstanceId source, Action<T> messageHandler, IMessageBus messageBus = null)
583
+ where T : IBroadcastMessage
584
+ {
585
+ messageBus ??= MessageBus;
586
+ Action messageBusDeregistration = messageBus.RegisterSourcedBroadcast<T>(source, this);
587
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);;
588
+ return typedHandler.AddSourcedBroadcastHandler(source, messageHandler, messageBusDeregistration);
589
+ }
590
+
591
+ /// <summary>
592
+ /// Registers this MessageHandler to accept fast BroadcastMessages via their MessageBus, properly handling de-registration.
593
+ /// </summary>
594
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
595
+ /// <param name="source">Source Id of BroadcastMessages to listen for.</param>
596
+ /// <param name="messageHandler">Function that actually handles the message.</param>
597
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
598
+ /// <returns>The de-registration action.</returns>
599
+ public Action RegisterSourcedBroadcastMessageHandler<T>(InstanceId source, FastHandler<T> messageHandler, IMessageBus messageBus = null)
600
+ where T : IBroadcastMessage
601
+ {
602
+ messageBus ??= MessageBus;
603
+ Action messageBusDeregistration = messageBus.RegisterSourcedBroadcast<T>(source, this);
604
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus); ;
605
+ return typedHandler.AddSourcedBroadcastHandler(source, messageHandler, messageBusDeregistration);
606
+ }
607
+
608
+ /// <summary>
609
+ /// Registers this MessageHandler to accept BroadcastMessage regardless of source via their MessageBus, properly handling de-registration.
610
+ /// </summary>
611
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
612
+ /// <param name="messageHandler">Function that actually handles the message.</param>
613
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
614
+ /// <returns>The de-registration action.</returns>
615
+ public Action RegisterSourcedBroadcastWithoutSource<T>(Action<InstanceId, T> messageHandler, IMessageBus messageBus = null) where T : IBroadcastMessage
616
+ {
617
+ messageBus ??= MessageBus;
618
+ Action messageBusDeregistration = messageBus.RegisterSourcedBroadcastWithoutSource<T>(this);
619
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
620
+ return typedHandler.AddSourcedBroadcastWithoutSourceHandler(messageHandler, messageBusDeregistration);
621
+ }
622
+
623
+ /// <summary>
624
+ /// Registers this MessageHandler to accept fast BroadcastMessage regardless of source via their MessageBus, properly handling de-registration.
625
+ /// </summary>
626
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
627
+ /// <param name="messageHandler">Function that actually handles the message.</param>
628
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
629
+ /// <returns>The de-registration action.</returns>
630
+ public Action RegisterSourcedBroadcastWithoutSource<T>(FastHandlerWithContext<T> messageHandler, IMessageBus messageBus = null) where T : IBroadcastMessage
631
+ {
632
+ messageBus ??= MessageBus;
633
+ Action messageBusDeregistration = messageBus.RegisterSourcedBroadcastWithoutSource<T>(this);
634
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
635
+ return typedHandler.AddSourcedBroadcastWithoutSourceHandler(messageHandler, messageBusDeregistration);
636
+ }
637
+
638
+ /// <summary>
639
+ /// Registers this MessageHandler to post processes BroadcastMessage messages.
640
+ /// </summary>
641
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
642
+ /// <param name="source">Source object to listen for BroadcastMessages on.</param>
643
+ /// <param name="messageHandler">Function that actually handles the message.</param>
644
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
645
+ /// <returns>The de-registration action.</returns>
646
+ public Action RegisterSourcedBroadcastPostProcessor<T>(InstanceId source, Action<T> messageHandler, IMessageBus messageBus = null) where T : IBroadcastMessage
647
+ {
648
+ messageBus ??= MessageBus;
649
+ Action messageBusDeregistration = messageBus.RegisterBroadcastPostProcessor<T>(source, this);
650
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
651
+ return typedHandler.AddBroadcastPostProcessor(source, messageHandler, messageBusDeregistration);
652
+ }
653
+
654
+ /// <summary>
655
+ /// Registers this MessageHandler to post processes fast BroadcastMessage messages.
656
+ /// </summary>
657
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
658
+ /// <param name="source">Source object to listen for BroadcastMessages on.</param>
659
+ /// <param name="messageHandler">Function that actually handles the message.</param>
660
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
661
+ /// <returns>The de-registration action.</returns>
662
+ public Action RegisterSourcedBroadcastPostProcessor<T>(InstanceId source, FastHandler<T> messageHandler, IMessageBus messageBus = null) where T : IBroadcastMessage
663
+ {
664
+ messageBus ??= MessageBus;
665
+ Action messageBusDeregistration = messageBus.RegisterBroadcastPostProcessor<T>(source, this);
666
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
667
+ return typedHandler.AddBroadcastPostProcessor(source, messageHandler, messageBusDeregistration);
668
+ }
669
+
670
+ /// <summary>
671
+ /// Registers this MessageHandler to post processes BroadcastMessage messages for all messages of the provided type.
672
+ /// </summary>
673
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
674
+ /// <param name="messageHandler">Function that actually handles the message.</param>
675
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
676
+ /// <returns>The de-registration action.</returns>
677
+ public Action RegisterSourcedBroadcastWithoutSourcePostProcessor<T>(Action<InstanceId, T> messageHandler, IMessageBus messageBus = null) where T : IBroadcastMessage
678
+ {
679
+ messageBus ??= MessageBus;
680
+ Action messageBusDeregistration = messageBus.RegisterBroadcastWithoutSourcePostProcessor<T>(this);
681
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
682
+ return typedHandler.AddBroadcastWithoutSourcePostProcessor(messageHandler, messageBusDeregistration);
683
+ }
684
+
685
+ /// <summary>
686
+ /// Registers this MessageHandler to post processes fast BroadcastMessage messages for all messages of the provided type.
687
+ /// </summary>
688
+ /// <typeparam name="T">Type of Message to be handled.</typeparam>
689
+ /// <param name="messageHandler">Function that actually handles the message.</param>
690
+ /// <param name="messageBus">IMessageBus override to register with, if any. Null/not provided defaults to the GlobalMessageBus.</param>
691
+ /// <returns>The de-registration action.</returns>
692
+ public Action RegisterSourcedBroadcastWithoutSourcePostProcessor<T>(FastHandlerWithContext<T> messageHandler, IMessageBus messageBus = null) where T : IBroadcastMessage
693
+ {
694
+ messageBus ??= MessageBus;
695
+ Action messageBusDeregistration = messageBus.RegisterBroadcastWithoutSourcePostProcessor<T>(this);
696
+ TypedHandler<T> typedHandler = GetOrCreateHandlerForType<T>(messageBus);
697
+ return typedHandler.AddBroadcastWithoutSourcePostProcessor(messageHandler, messageBusDeregistration);
698
+ }
699
+
700
+ /// <summary>
701
+ /// Registers an UntargetedInterceptor for messages of the provided type at the provided priority.
702
+ /// </summary>
703
+ /// <typeparam name="T">Type of the UntargetedMessage to intercept.</typeparam>
704
+ /// <param name="interceptor">Interceptor to register.</param>
705
+ /// <param name="priority">Priority to register the interceptor at (interceptors are ran from low -> high priority)</param>
706
+ /// <param name="messageBus">Message bus to register the interceptor on.</param>
707
+ /// <returns>The de-registration action.</returns>
708
+ public Action RegisterUntargetedInterceptor<T>(IMessageBus.UntargetedInterceptor<T> interceptor, int priority = 0, IMessageBus messageBus = null) where T : IUntargetedMessage
709
+ {
710
+ return (messageBus ?? MessageBus).RegisterUntargetedInterceptor(interceptor, priority);
711
+ }
712
+
713
+ /// <summary>
714
+ /// Registers a BroadcastInterceptor for messages of the provided type at the provided priority.
715
+ /// </summary>
716
+ /// <typeparam name="T">Type of the BroadcastMessage to intercept.</typeparam>
717
+ /// <param name="interceptor">Interceptor to register.</param>
718
+ /// <param name="priority">Priority to register the interceptor at (interceptors are ran from low -> high priority)</param>
719
+ /// <param name="messageBus">Message bus to register the interceptor on.</param>
720
+ /// <returns>The de-registration action.</returns>
721
+ public Action RegisterBroadcastInterceptor<T>(IMessageBus.BroadcastInterceptor<T> interceptor, int priority = 0, IMessageBus messageBus = null) where T : IBroadcastMessage
722
+ {
723
+ return (messageBus ?? MessageBus).RegisterBroadcastInterceptor(interceptor, priority);
724
+ }
725
+
726
+ /// <summary>
727
+ /// Registers a TargetedInterceptor for messages of the provided type at the provided priority.
728
+ /// </summary>
729
+ /// <typeparam name="T">Type of the TargetedMessage to intercept.</typeparam>
730
+ /// <param name="interceptor">Interceptor to register.</param>
731
+ /// <param name="priority">Priority to register the interceptor at (interceptors are ran from low -> high priority)</param>
732
+ /// <param name="messageBus">Message bus to register the interceptor on.</param>
733
+ /// <returns>The de-registration action.</returns>
734
+ public Action RegisterTargetedInterceptor<T>(IMessageBus.TargetedInterceptor<T> interceptor, int priority = 0, IMessageBus messageBus = null) where T : ITargetedMessage
735
+ {
736
+ return (messageBus ?? MessageBus).RegisterTargetedInterceptor(interceptor, priority);
737
+ }
738
+
739
+ public override string ToString()
740
+ {
741
+ return new
742
+ {
743
+ OwnerId = owner,
744
+ HandlerTypes = string.Join(",",
745
+ _handlersByTypeByMessageBus.Values
746
+ .SelectMany(handlers => handlers.Keys)
747
+ .Distinct()
748
+ .Select(type => type.Name)
749
+ .OrderBy(_ => _))
750
+ }.ToString();
751
+ }
752
+
753
+ /// <summary>
754
+ /// Retrieves an existing Handler for the specific type, if it exists, or creates a new Handler, if none exist.
755
+ /// </summary>
756
+ /// <typeparam name="T">Type of Message to retrieve a Handler for.</typeparam>
757
+ /// <returns>Non-Null Handler for the specific type.</returns>
758
+ private TypedHandler<T> GetOrCreateHandlerForType<T>(IMessageBus messageBus) where T : IMessage
759
+ {
760
+ Type type = typeof(T);
761
+
762
+ if (!_handlersByTypeByMessageBus.TryGetValue(messageBus, out Dictionary<Type, object> handlersByType))
763
+ {
764
+ handlersByType = new Dictionary<Type, object>();
765
+ _handlersByTypeByMessageBus[messageBus] = handlersByType;
766
+ }
767
+
768
+ if (handlersByType.TryGetValue(type, out object existingTypedHandler))
769
+ {
770
+ return (TypedHandler<T>) existingTypedHandler;
771
+ }
772
+
773
+ TypedHandler<T> newTypedHandler = new();
774
+ handlersByType[type] = newTypedHandler;
775
+ return newTypedHandler;
776
+ }
777
+
778
+ /// <summary>
779
+ /// Gets an existing Handler for the specific type, if it exists.
780
+ /// </summary>
781
+ /// <param name="type">Message type to get the handler for.</param>
782
+ /// <param name="messageBus">The specific MessageBus to use.</param>
783
+ /// <param name="existingTypedHandler">Existing typed message handler, if one exists.</param>
784
+ /// <returns>Existing handler for the specific type, or null if none exists..</returns>
785
+ private bool GetHandlerForType<T>(Type type, IMessageBus messageBus, out TypedHandler<T> existingTypedHandler) where T : IMessage
786
+ {
787
+ if (_handlersByTypeByMessageBus.TryGetValue(messageBus, out Dictionary<Type, object> handlersByType) && handlersByType.TryGetValue(type, out object untypedHandler))
788
+ {
789
+ existingTypedHandler = (TypedHandler<T>) untypedHandler;
790
+ return true;
791
+ }
792
+
793
+ existingTypedHandler = default;
794
+ return false;
795
+ }
796
+
797
+ private abstract class TypedHandler
798
+ {
799
+ protected static readonly Stack<List<Action<IUntargetedMessage>>> GlobalUntargetedHandlersStack = new();
800
+ protected static readonly Stack<List<Action<InstanceId, ITargetedMessage>>> GlobalTargetedHandlersStack = new();
801
+ protected static readonly Stack<List<Action<InstanceId, IBroadcastMessage>>> GlobalBroadcastHandlersStack = new();
802
+ protected static readonly Stack<List<FastHandler<IUntargetedMessage>>> GlobalUntargetedFastHandlersStack = new();
803
+ protected static readonly Stack<List<FastHandlerWithContext<ITargetedMessage>>> GlobalTargetedFastHandlersStack = new();
804
+ protected static readonly Stack<List<FastHandlerWithContext<IBroadcastMessage>>> GlobalBroadcastFastHandlersStack = new();
805
+ }
806
+
807
+ /// <summary>
808
+ /// One-size-fits-all wrapper around all possible Messaging sinks for a particular MessageHandler & MessageType.
809
+ /// </summary>
810
+ /// <typeparam name="T">Message type that this Handler exists to serve.</typeparam>
811
+ private sealed class TypedHandler<T> : TypedHandler where T: IMessage
812
+ {
813
+ // Buffers so we don't allocate memory as often
814
+ private static Stack<List<Action<T>>> HandlersStack;
815
+ private static Stack<List<Action<InstanceId, T>>> HandlersWithoutContextStack;
816
+ private static Stack<List<FastHandler<T>>> FastHandlersStack;
817
+ private static Stack<List<FastHandlerWithContext<T>>> FastHandlersWithContextStack;
818
+
819
+ private Dictionary<InstanceId, Dictionary<Action<T>, int>> _targetedHandlers;
820
+ private Dictionary<Action<T>, int> _untargetedHandlers;
821
+ private Dictionary<InstanceId, Dictionary<Action<T>, int>> _broadcastHandlers;
822
+ private Dictionary<InstanceId, Dictionary<Action<T>, int>> _targetedPostProcessingHandlers;
823
+ private Dictionary<Action<T>, int> _untargetedPostProcessingHandlers;
824
+ private Dictionary<InstanceId, Dictionary<Action<T>, int>> _broadcastPostProcessingHandlers;
825
+ private Dictionary<InstanceId, Dictionary<FastHandler<T>, int>> _targetedFastHandlers;
826
+ private Dictionary<FastHandler<T>, int> _untargetedFastHandlers;
827
+ private Dictionary<InstanceId, Dictionary<FastHandler<T>, int>> _broadcastFastHandlers;
828
+ private Dictionary<InstanceId, Dictionary<FastHandler<T>, int>> _targetedPostProcessingFastHandlers;
829
+ private Dictionary<FastHandler<T>, int> _untargetedPostProcessingFastHandlers;
830
+ private Dictionary<InstanceId, Dictionary<FastHandler<T>, int>> _broadcastPostProcessingFastHandlers;
831
+ private Dictionary<Action<IUntargetedMessage>, int> _globalUntargetedHandlers;
832
+ private Dictionary<Action<InstanceId, ITargetedMessage>, int> _globalTargetedHandlers;
833
+ private Dictionary<Action<InstanceId, IBroadcastMessage>, int> _globalBroadcastHandlers;
834
+ private Dictionary<FastHandler<IUntargetedMessage>, int> _globalUntargetedFastHandlers;
835
+ private Dictionary<FastHandlerWithContext<ITargetedMessage>, int> _globalTargetedFastHandlers;
836
+ private Dictionary<FastHandlerWithContext<IBroadcastMessage>, int> _globalBroadcastFastHandlers;
837
+ private Dictionary<Action<InstanceId, T>, int> _targetedWithoutTargetingHandlers;
838
+ private Dictionary<FastHandlerWithContext<T>, int> _fastTargetedWithoutTargetingHandlers;
839
+ private Dictionary<Action<InstanceId, T>, int> _broadcastWithoutSourceHandlers;
840
+ private Dictionary<FastHandlerWithContext<T>, int> _fastBroadcastWithoutSourceHandlers;
841
+ private Dictionary<Action<InstanceId, T>, int> _targetedWithoutTargetingPostProcessingHandlers;
842
+ private Dictionary<FastHandlerWithContext<T>, int> _fastTargetedWithoutTargetingPostProcessingHandlers;
843
+ private Dictionary<Action<InstanceId, T>, int> _broadcastWithoutSourcePostProcessingHandlers;
844
+ private Dictionary<FastHandlerWithContext<T>, int> _fastBroadcastWithoutSourcePostProcessingHandlers;
845
+
846
+ /// <summary>
847
+ /// Emits the UntargetedMessage to all subscribed listeners.
848
+ /// </summary>
849
+ /// <param name="message">Message to emit.</param>
850
+ public void HandleUntargeted(ref T message)
851
+ {
852
+ RunFastHandlers(_untargetedFastHandlers, ref message);
853
+ RunHandlers(_untargetedHandlers, ref message);
854
+ }
855
+
856
+ /// <summary>
857
+ /// Emits the TargetedMessage to all subscribed listeners.
858
+ /// </summary>
859
+ /// <param name="target">Target the message is for.</param>
860
+ /// <param name="message">Message to emit.</param>
861
+ public void HandleTargeted(ref InstanceId target, ref T message)
862
+ {
863
+ RunFastHandlersWithContext(ref target, _targetedFastHandlers, ref message);
864
+ RunHandlersWithContext(ref target, _targetedHandlers, ref message);
865
+ }
866
+
867
+ /// <summary>
868
+ /// Emits the TargetedMessage without targeting to all subscribed listeners.
869
+ /// </summary>
870
+ /// <param name="target">Target the message is for.</param>
871
+ /// <param name="message">Message to emit.</param>
872
+ public void HandleTargetedWithoutTargeting(ref InstanceId target, ref T message)
873
+ {
874
+ RunFastHandlers(ref target, ref FastHandlersWithContextStack, _fastTargetedWithoutTargetingHandlers, ref message);
875
+ RunHandlers(ref target, _targetedWithoutTargetingHandlers, ref message);
876
+ }
877
+
878
+ /// <summary>
879
+ /// Emits the BroadcastMessage to all subscribed listeners.
880
+ /// </summary>
881
+ /// <param name="source">Source the message is from.</param>
882
+ /// <param name="message">Message to emit.</param>
883
+ public void HandleSourcedBroadcast(ref InstanceId source, ref T message)
884
+ {
885
+ RunFastHandlersWithContext(ref source, _broadcastFastHandlers, ref message);
886
+ RunHandlersWithContext(ref source, _broadcastHandlers, ref message);
887
+ }
888
+
889
+ /// <summary>
890
+ /// Emits the BroadcastMessage without source to all subscribed listeners.
891
+ /// </summary>
892
+ /// <param name="source">Source the message is from.</param>
893
+ /// <param name="message">Message to emit.</param>
894
+ public void HandleSourcedBroadcastWithoutSource(ref InstanceId source, ref T message)
895
+ {
896
+ RunFastHandlers(ref source, ref FastHandlersWithContextStack, _fastBroadcastWithoutSourceHandlers, ref message);
897
+ RunHandlers(ref source, _broadcastWithoutSourceHandlers, ref message);
898
+ }
899
+
900
+ /// <summary>
901
+ /// Emits the UntargetedMessage to all global listeners.
902
+ /// </summary>
903
+ /// <param name="message">Message to emit.</param>
904
+ public void HandleGlobalUntargeted(ref IUntargetedMessage message)
905
+ {
906
+ RunFastHandlers(GlobalUntargetedFastHandlersStack, _globalUntargetedFastHandlers, ref message);
907
+
908
+ if (_globalUntargetedHandlers is not { Count: > 0 })
909
+ {
910
+ return;
911
+ }
912
+
913
+ if (GlobalUntargetedHandlersStack.TryPop(out List<Action<IUntargetedMessage>> handlers))
914
+ {
915
+ handlers.Clear();
916
+ handlers.AddRange(_globalUntargetedHandlers.Keys);
917
+ }
918
+ else
919
+ {
920
+ handlers = new List<Action<IUntargetedMessage>>(_globalUntargetedHandlers.Keys);
921
+ }
922
+
923
+ try
924
+ {
925
+ foreach (Action<IUntargetedMessage> handler in handlers)
926
+ {
927
+ handler(message);
928
+ }
929
+ }
930
+ finally
931
+ {
932
+ GlobalUntargetedHandlersStack.Push(handlers);
933
+ }
934
+ }
935
+
936
+ /// <summary>
937
+ /// Emits the TargetedMessage to all global listeners.
938
+ /// </summary>
939
+ /// <param name="target">Target that this message is intended for.</param>
940
+ /// <param name="message">Message to emit.</param>
941
+ public void HandleGlobalTargeted(ref InstanceId target, ref ITargetedMessage message)
942
+ {
943
+ RunFastHandlers(ref target, GlobalTargetedFastHandlersStack, _globalTargetedFastHandlers, ref message);
944
+
945
+ if (_globalTargetedHandlers is not { Count: > 0 })
946
+ {
947
+ return;
948
+ }
949
+
950
+ if (GlobalTargetedHandlersStack.TryPop(out List<Action<InstanceId, ITargetedMessage>> handlers))
951
+ {
952
+ handlers.Clear();
953
+ handlers.AddRange(_globalTargetedHandlers.Keys);
954
+ }
955
+ else
956
+ {
957
+ handlers = new List<Action<InstanceId, ITargetedMessage>>(_globalTargetedHandlers.Keys);
958
+ }
959
+
960
+ try
961
+ {
962
+ foreach (Action<InstanceId, ITargetedMessage> handler in handlers)
963
+ {
964
+ handler(target, message);
965
+ }
966
+ }
967
+ finally
968
+ {
969
+ GlobalTargetedHandlersStack.Push(handlers);
970
+ }
971
+ }
972
+
973
+ /// <summary>
974
+ /// Emits the BroadcastMessage to all global listeners.
975
+ /// </summary>
976
+ /// <param name="source">Source that this message is from.</param>
977
+ /// <param name="message">Message to emit.</param>
978
+ public void HandleGlobalBroadcast(ref InstanceId source, ref IBroadcastMessage message)
979
+ {
980
+ RunFastHandlers(ref source, GlobalBroadcastFastHandlersStack, _globalBroadcastFastHandlers, ref message);
981
+
982
+ if (_globalBroadcastHandlers is not { Count: > 0 })
983
+ {
984
+ return;
985
+ }
986
+
987
+ if (GlobalBroadcastHandlersStack.TryPop(out List<Action<InstanceId, IBroadcastMessage>> handlers))
988
+ {
989
+ handlers.Clear();
990
+ handlers.AddRange(_globalBroadcastHandlers.Keys);
991
+ }
992
+ else
993
+ {
994
+ handlers = new List<Action<InstanceId, IBroadcastMessage>>(_globalBroadcastHandlers.Keys);
995
+ }
996
+
997
+ try
998
+ {
999
+ foreach (Action<InstanceId, IBroadcastMessage> handler in handlers)
1000
+ {
1001
+ handler(source, message);
1002
+ }
1003
+ }
1004
+ finally
1005
+ {
1006
+ GlobalBroadcastHandlersStack.Push(handlers);
1007
+ }
1008
+ }
1009
+
1010
+ public void HandleUntargetedPostProcessing(ref T message)
1011
+ {
1012
+ RunFastHandlers(_untargetedPostProcessingFastHandlers, ref message);
1013
+ RunHandlers(_untargetedPostProcessingHandlers, ref message);
1014
+ }
1015
+
1016
+ public void HandleTargetedPostProcessing(ref InstanceId target, ref T message)
1017
+ {
1018
+ RunFastHandlersWithContext(ref target, _targetedPostProcessingFastHandlers, ref message);
1019
+ RunHandlersWithContext(ref target, _targetedPostProcessingHandlers, ref message);
1020
+ }
1021
+
1022
+ public void HandleTargetedWithoutTargetingPostProcessing(ref InstanceId target, ref T message)
1023
+ {
1024
+ RunFastHandlersWithContext(ref target, _fastTargetedWithoutTargetingPostProcessingHandlers, ref message);
1025
+ RunHandlers(ref target, _targetedWithoutTargetingPostProcessingHandlers, ref message);
1026
+ }
1027
+
1028
+ public void HandleSourcedBroadcastPostProcessing(ref InstanceId source, ref T message)
1029
+ {
1030
+ RunFastHandlersWithContext(ref source, _broadcastPostProcessingFastHandlers, ref message);
1031
+ RunHandlersWithContext(ref source, _broadcastPostProcessingHandlers, ref message);
1032
+ }
1033
+
1034
+ public void HandleBroadcastWithoutSourcePostProcessing(ref InstanceId source, ref T message)
1035
+ {
1036
+ RunFastHandlersWithContext(ref source, _fastBroadcastWithoutSourcePostProcessingHandlers, ref message);
1037
+ RunHandlers(ref source, _broadcastWithoutSourcePostProcessingHandlers, ref message);
1038
+ }
1039
+
1040
+ /// <summary>
1041
+ /// Adds a TargetedHandler to listen to Messages of the given type, returning a de-registration action.
1042
+ /// </summary>
1043
+ /// <param name="target">Target the handler is for.</param>
1044
+ /// <param name="handler">Relevant MessageHandler.</param>
1045
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1046
+ /// <returns>De-registration action to un-register the handler.</returns>
1047
+ public Action AddTargetedHandler(InstanceId target, Action<T> handler, Action deregistration)
1048
+ {
1049
+ return AddHandler(target, ref _targetedHandlers, handler, deregistration);
1050
+ }
1051
+
1052
+ /// <summary>
1053
+ /// Adds a fast TargetedHandler to listen to Messages of the given type, returning a de-registration action.
1054
+ /// </summary>
1055
+ /// <param name="target">Target the handler is for.</param>
1056
+ /// <param name="handler">Relevant MessageHandler.</param>
1057
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1058
+ /// <returns>De-registration action to un-register the handler.</returns>
1059
+ public Action AddTargetedHandler(InstanceId target, FastHandler<T> handler, Action deregistration)
1060
+ {
1061
+ return AddHandler(target, ref _targetedFastHandlers, handler, deregistration);
1062
+ }
1063
+
1064
+ /// <summary>
1065
+ /// Adds a TargetedWithoutTargetingHandler to listen to Messages of the given type, returning a de-registration action.
1066
+ /// </summary>
1067
+ /// <param name="handler">Relevant MessageHandler.</param>
1068
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1069
+ /// <returns>De-registration action to un-register the handler.</returns>
1070
+ public Action AddTargetedWithoutTargetingHandler(Action<InstanceId, T> handler, Action deregistration)
1071
+ {
1072
+ return AddHandler(ref _targetedWithoutTargetingHandlers, handler, deregistration);
1073
+ }
1074
+
1075
+ /// <summary>
1076
+ /// Adds a fast TargetedWithoutTargetingHandler to listen to Messages of the given type, returning a de-registration action.
1077
+ /// </summary>
1078
+ /// <param name="handler">Relevant MessageHandler.</param>
1079
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1080
+ /// <returns>De-registration action to un-register the handler.</returns>
1081
+ public Action AddTargetedWithoutTargetingHandler(FastHandlerWithContext<T> handler, Action deregistration)
1082
+ {
1083
+ return AddHandler(ref _fastTargetedWithoutTargetingHandlers, handler, deregistration);
1084
+ }
1085
+
1086
+ /// <summary>
1087
+ /// Adds a UntargetedHandler to listen to Messages of the given type, returning a de-registration action.
1088
+ /// </summary>
1089
+ /// <param name="handler">Relevant MessageHandler.</param>
1090
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1091
+ /// <returns>De-registration action to un-register the handler.</returns>
1092
+ public Action AddUntargetedHandler(Action<T> handler, Action deregistration)
1093
+ {
1094
+ return AddHandler(ref _untargetedHandlers, handler, deregistration);
1095
+ }
1096
+
1097
+ /// <summary>
1098
+ /// Adds a fast UntargetedHandler to listen to Messages of the given type, returning a de-registration action.
1099
+ /// </summary>
1100
+ /// <param name="handler">Relevant MessageHandler.</param>
1101
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1102
+ /// <returns>De-registration action to un-register the handler.</returns>
1103
+
1104
+ public Action AddUntargetedHandler(FastHandler<T> handler, Action deregistration)
1105
+ {
1106
+ return AddHandler(ref _untargetedFastHandlers, handler, deregistration);
1107
+ }
1108
+
1109
+ /// <summary>
1110
+ /// Adds a SourcedBroadcastHandler to listen to Messages of the given type from an entity, returning a de-registration action.
1111
+ /// </summary>
1112
+ /// <param name="source">Source of the handler is for.</param>
1113
+ /// <param name="handler">Relevant MessageHandler.</param>
1114
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1115
+ /// <returns>De-registration action to un-register the handler.</returns>
1116
+ public Action AddSourcedBroadcastHandler(InstanceId source, Action<T> handler, Action deregistration)
1117
+ {
1118
+ return AddHandler(source, ref _broadcastHandlers, handler, deregistration);
1119
+ }
1120
+
1121
+ /// <summary>
1122
+ /// Adds a fast SourcedBroadcastHandler to listen to Messages of the given type from an entity, returning a de-registration action.
1123
+ /// </summary>
1124
+ /// <param name="source">Source of the handler is for.</param>
1125
+ /// <param name="handler">Relevant MessageHandler.</param>
1126
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1127
+ /// <returns>De-registration action to un-register the handler.</returns>
1128
+ public Action AddSourcedBroadcastHandler(InstanceId source, FastHandler<T> handler, Action deregistration)
1129
+ {
1130
+ return AddHandler(source, ref _broadcastFastHandlers, handler, deregistration);
1131
+ }
1132
+
1133
+ /// <summary>
1134
+ /// Adds a SourcedBroadcastWithoutSourceHandler to listen to Messages of the given type from an entity, returning a de-registration action.
1135
+ /// </summary>
1136
+ /// <param name="handler">Relevant MessageHandler.</param>
1137
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1138
+ /// <returns>De-registration action to un-register the handler.</returns>
1139
+ public Action AddSourcedBroadcastWithoutSourceHandler(Action<InstanceId, T> handler, Action deregistration)
1140
+ {
1141
+ return AddHandler(ref _broadcastWithoutSourceHandlers, handler, deregistration);
1142
+ }
1143
+
1144
+ /// <summary>
1145
+ /// Adds a fast SourcedBroadcastWithoutSourceHandler to listen to Messages of the given type from an entity, returning a de-registration action.
1146
+ /// </summary>
1147
+ /// <param name="handler">Relevant MessageHandler.</param>
1148
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1149
+ /// <returns>De-registration action to un-register the handler.</returns>
1150
+ public Action AddSourcedBroadcastWithoutSourceHandler(FastHandlerWithContext<T> handler, Action deregistration)
1151
+ {
1152
+ return AddHandler(ref _fastBroadcastWithoutSourceHandlers, handler, deregistration);
1153
+ }
1154
+
1155
+ /// <summary>
1156
+ /// Adds a Global UntargetedHandler to listen to all Untargeted Messages of all types, returning the de-registration action.
1157
+ /// </summary>
1158
+ /// <param name="handler">Relevant MessageHandler.</param>
1159
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1160
+ /// <returns>De-registration action to un-register the handler.</returns>
1161
+ public Action AddGlobalUntargetedHandler(Action<IUntargetedMessage> handler, Action deregistration)
1162
+ {
1163
+ return AddHandler(ref _globalUntargetedHandlers, handler, deregistration);
1164
+ }
1165
+
1166
+ /// <summary>
1167
+ /// Adds a Global fast UntargetedHandler to listen to all Untargeted Messages of all types, returning the de-registration action.
1168
+ /// </summary>
1169
+ /// <param name="handler">Relevant MessageHandler.</param>
1170
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1171
+ /// <returns>De-registration action to un-register the handler.</returns>
1172
+
1173
+ public Action AddGlobalUntargetedHandler(FastHandler<IUntargetedMessage> handler, Action deregistration)
1174
+ {
1175
+ return AddHandler(ref _globalUntargetedFastHandlers, handler, deregistration);
1176
+ }
1177
+
1178
+ /// <summary>
1179
+ /// Adds a Global TargetedHandler to listen to all Targeted Messages of all types for all entities, returning the de-registration action.
1180
+ /// </summary>
1181
+ /// <param name="handler">Relevant MessageHandler.</param>
1182
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1183
+ /// <returns>De-registration action to un-register the handler.</returns>
1184
+ public Action AddGlobalTargetedHandler(Action<InstanceId, ITargetedMessage> handler, Action deregistration)
1185
+ {
1186
+ return AddHandler(ref _globalTargetedHandlers, handler, deregistration);
1187
+ }
1188
+
1189
+ /// <summary>
1190
+ /// Adds a Global fast TargetedHandler to listen to all Targeted Messages of all types for all entities (along with the target instance id), returning the de-registration action.
1191
+ /// </summary>
1192
+ /// <param name="handler">Relevant MessageHandler.</param>
1193
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1194
+ /// <returns>De-registration action to un-register the handler.</returns>
1195
+
1196
+ public Action AddGlobalTargetedHandler(FastHandlerWithContext<ITargetedMessage> handler, Action deregistration)
1197
+ {
1198
+ return AddHandler(ref _globalTargetedFastHandlers, handler, deregistration);
1199
+ }
1200
+
1201
+ /// <summary>
1202
+ /// Adds a Global BroadcastHandler to listen to all Targeted Messages of all types for all entities, returning the de-registration action.
1203
+ /// </summary>
1204
+ /// <param name="handler">Relevant MessageHandler.</param>
1205
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1206
+ /// <returns>De-registration action to un-register the handler.</returns>
1207
+ public Action AddGlobalBroadcastHandler(Action<InstanceId, IBroadcastMessage> handler, Action deregistration)
1208
+ {
1209
+ return AddHandler(ref _globalBroadcastHandlers, handler, deregistration);
1210
+ }
1211
+
1212
+ /// <summary>
1213
+ /// Adds a Global fast BroadcastHandler to listen to all Targeted Messages of all types for all entities (along with the source instance id), returning the de-registration action.
1214
+ /// </summary>
1215
+ /// <param name="handler">Relevant MessageHandler.</param>
1216
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1217
+ /// <returns>De-registration action to un-register the handler.</returns>
1218
+ public Action AddGlobalBroadcastHandler(FastHandlerWithContext<IBroadcastMessage> handler, Action deregistration)
1219
+ {
1220
+ return AddHandler(ref _globalBroadcastFastHandlers, handler, deregistration);
1221
+ }
1222
+
1223
+ /// <summary>
1224
+ /// Adds an Untargeted post processor to be called after all other handlers have been called.
1225
+ /// </summary>
1226
+ /// <param name="handler">Relevant MessageHandler.</param>
1227
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1228
+ /// <returns>De-registration action to un-register the handler.</returns>
1229
+ public Action AddUntargetedPostProcessor(Action<T> handler, Action deregistration)
1230
+ {
1231
+ return AddHandler(ref _untargetedPostProcessingHandlers, handler, deregistration);
1232
+ }
1233
+
1234
+ /// <summary>
1235
+ /// Adds a fast Untargeted post processor to be called after all other handlers have been called.
1236
+ /// </summary>
1237
+ /// <param name="handler">Relevant MessageHandler.</param>
1238
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1239
+ /// <returns>De-registration action to un-register the handler.</returns>
1240
+ public Action AddUntargetedPostProcessor(FastHandler<T> handler, Action deregistration)
1241
+ {
1242
+ return AddHandler(ref _untargetedPostProcessingFastHandlers, handler, deregistration);
1243
+ }
1244
+
1245
+ /// <summary>
1246
+ /// Adds an Targeted post processor to be called after all other handlers have been called.
1247
+ /// </summary>
1248
+ /// <param name="target">Target the handler is for.</param>
1249
+ /// <param name="handler">Relevant MessageHandler.</param>
1250
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1251
+ /// <returns>De-registration action to un-register the handler.</returns>
1252
+ public Action AddTargetedPostProcessor(InstanceId target, Action<T> handler, Action deregistration)
1253
+ {
1254
+ return AddHandler(target, ref _targetedPostProcessingHandlers, handler, deregistration);
1255
+ }
1256
+
1257
+ /// <summary>
1258
+ /// Adds a Targeted post processor to be called after all other handlers have been called.
1259
+ /// </summary>
1260
+ /// <param name="target">Target the handler is for.</param>
1261
+ /// <param name="handler">Relevant MessageHandler.</param>
1262
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1263
+ /// <returns>De-registration action to un-register the handler.</returns>
1264
+ public Action AddTargetedPostProcessor(InstanceId target, FastHandler<T> handler, Action deregistration)
1265
+ {
1266
+ return AddHandler(target, ref _targetedPostProcessingFastHandlers, handler, deregistration);
1267
+ }
1268
+
1269
+ /// <summary>
1270
+ /// Adds a Targeted post processor to be called after all other handlers have been called after every message of the given type.
1271
+ /// </summary>
1272
+ /// <param name="handler">Relevant MessageHandler.</param>
1273
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1274
+ /// <returns>De-registration action to un-register the handler.</returns>
1275
+ public Action AddTargetedWithoutTargetingPostProcessor(Action<InstanceId, T> handler, Action deregistration)
1276
+ {
1277
+ return AddHandler(ref _targetedWithoutTargetingPostProcessingHandlers, handler, deregistration);
1278
+ }
1279
+
1280
+ /// <summary>
1281
+ /// Adds a Targeted post processor to be called after all other handlers have been called after every message of the given type.
1282
+ /// </summary>
1283
+ /// <param name="handler">Relevant MessageHandler.</param>
1284
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1285
+ /// <returns>De-registration action to un-register the handler.</returns>
1286
+ public Action AddTargetedWithoutTargetingPostProcessor(FastHandlerWithContext<T> handler, Action deregistration)
1287
+ {
1288
+ return AddHandler(ref _fastTargetedWithoutTargetingPostProcessingHandlers, handler, deregistration);
1289
+ }
1290
+
1291
+ /// <summary>
1292
+ /// Adds a Broadcast post processor to be called after all other handlers have been called.
1293
+ /// </summary>
1294
+ /// <param name="source">Source the handler is for.</param>
1295
+ /// <param name="handler">Relevant MessageHandler.</param>
1296
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1297
+ /// <returns>De-registration action to un-register the handler.</returns>
1298
+ public Action AddBroadcastPostProcessor(InstanceId source, Action<T> handler, Action deregistration)
1299
+ {
1300
+ return AddHandler(source, ref _broadcastPostProcessingHandlers, handler, deregistration);
1301
+ }
1302
+
1303
+ /// <summary>
1304
+ /// Adds a fast Broadcast post processor to be called after all other handlers have been called.
1305
+ /// </summary>
1306
+ /// <param name="source">Source the handler is for.</param>
1307
+ /// <param name="handler">Relevant MessageHandler.</param>
1308
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1309
+ /// <returns>De-registration action to un-register the handler.</returns>
1310
+ public Action AddBroadcastPostProcessor(InstanceId source, FastHandler<T> handler, Action deregistration)
1311
+ {
1312
+ return AddHandler(source, ref _broadcastPostProcessingFastHandlers, handler, deregistration);
1313
+ }
1314
+
1315
+ /// <summary>
1316
+ /// Adds a Broadcast post processor to be called after all other handlers have been called for every message of the given type.
1317
+ /// </summary>
1318
+ /// <param name="handler">Relevant MessageHandler.</param>
1319
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1320
+ /// <returns>De-registration action to un-register the handler.</returns>
1321
+ public Action AddBroadcastWithoutSourcePostProcessor(Action<InstanceId, T> handler, Action deregistration)
1322
+ {
1323
+ return AddHandler(ref _broadcastWithoutSourcePostProcessingHandlers, handler, deregistration);
1324
+ }
1325
+
1326
+ /// <summary>
1327
+ /// Adds a fast Broadcast post processor to be called after all other handlers have been called.
1328
+ /// </summary>
1329
+ /// <param name="source">Source the handler is for.</param>
1330
+ /// <param name="handler">Relevant MessageHandler.</param>
1331
+ /// <param name="deregistration">Deregistration action for the handler.</param>
1332
+ /// <returns>De-registration action to un-register the handler.</returns>
1333
+ public Action AddBroadcastWithoutSourcePostProcessor(FastHandlerWithContext<T> handler, Action deregistration)
1334
+ {
1335
+ return AddHandler(ref _fastBroadcastWithoutSourcePostProcessingHandlers, handler, deregistration);
1336
+ }
1337
+
1338
+ private static void RunFastHandlersWithContext<TMessage>(ref InstanceId context, Dictionary<FastHandlerWithContext<T>, int> fastHandlersByContext, ref TMessage message) where TMessage : IMessage
1339
+ {
1340
+ if (fastHandlersByContext is not { Count: > 0 })
1341
+ {
1342
+ return;
1343
+ }
1344
+
1345
+ RunFastHandlers(ref context, ref FastHandlersWithContextStack, fastHandlersByContext, ref message);
1346
+ }
1347
+
1348
+ private static void RunFastHandlersWithContext<TMessage>(ref InstanceId context, Dictionary<InstanceId, Dictionary<FastHandler<T>, int>> fastHandlersByContext, ref TMessage message) where TMessage : IMessage
1349
+ {
1350
+ if (fastHandlersByContext is not { Count: > 0 } || !fastHandlersByContext.TryGetValue(context, out Dictionary<FastHandler<T>, int> fastHandlers))
1351
+ {
1352
+ return;
1353
+ }
1354
+
1355
+ RunFastHandlers(fastHandlers, ref message);
1356
+ }
1357
+
1358
+ private static void RunFastHandlers<TMessage>(Dictionary<FastHandler<T>, int> fastHandlers, ref TMessage message) where TMessage : IMessage
1359
+ {
1360
+ if (fastHandlers is not { Count: > 0 })
1361
+ {
1362
+ return;
1363
+ }
1364
+
1365
+ ref T typedMessage = ref Unsafe.As<TMessage, T>(ref message);
1366
+
1367
+ List<FastHandler<T>> handlers = GetOrAddNewHandlerStack(ref FastHandlersStack, fastHandlers.Keys);
1368
+ try
1369
+ {
1370
+ foreach (FastHandler<T> fastHandler in handlers)
1371
+ {
1372
+ fastHandler(ref typedMessage);
1373
+ }
1374
+ }
1375
+ finally
1376
+ {
1377
+ FastHandlersStack.Push(handlers);
1378
+ }
1379
+ }
1380
+
1381
+ private static void RunFastHandlers<TMessage, U>(Stack<List<FastHandler<U>>> stack, Dictionary<FastHandler<U>, int> fastHandlers, ref TMessage message) where TMessage : IMessage where U : IMessage
1382
+ {
1383
+ if (fastHandlers is not { Count: > 0 })
1384
+ {
1385
+ return;
1386
+ }
1387
+
1388
+ ref U typedMessage = ref Unsafe.As<TMessage, U>(ref message);
1389
+
1390
+ List<FastHandler<U>> handlers = GetOrAddNewHandlerStack(ref stack, fastHandlers.Keys);
1391
+ try
1392
+ {
1393
+ foreach (FastHandler<U> fastHandler in handlers)
1394
+ {
1395
+ fastHandler(ref typedMessage);
1396
+ }
1397
+ }
1398
+ finally
1399
+ {
1400
+ stack.Push(handlers);
1401
+ }
1402
+ }
1403
+
1404
+ private static void RunFastHandlers<TMessage, U>(
1405
+ ref InstanceId context, Stack<List<FastHandlerWithContext<U>>> stack,
1406
+ Dictionary<FastHandlerWithContext<U>, int> fastHandlers, ref TMessage message)
1407
+ where TMessage : IMessage where U : IMessage
1408
+ {
1409
+ RunFastHandlers(ref context, ref stack, fastHandlers, ref message);
1410
+ }
1411
+
1412
+ private static void RunFastHandlers<TMessage, U>(ref InstanceId context, ref Stack<List<FastHandlerWithContext<U>>> stack, Dictionary<FastHandlerWithContext<U>, int> fastHandlers, ref TMessage message) where TMessage : IMessage where U : IMessage
1413
+ {
1414
+ if (fastHandlers is not { Count: > 0 })
1415
+ {
1416
+ return;
1417
+ }
1418
+
1419
+ ref U typedMessage = ref Unsafe.As<TMessage, U>(ref message);
1420
+
1421
+ List<FastHandlerWithContext<U>> handlers = GetOrAddNewHandlerStack(ref stack, fastHandlers.Keys);
1422
+ try
1423
+ {
1424
+ foreach (FastHandlerWithContext<U> fastHandler in handlers)
1425
+ {
1426
+ fastHandler(ref context, ref typedMessage);
1427
+ }
1428
+ }
1429
+ finally
1430
+ {
1431
+ stack.Push(handlers);
1432
+ }
1433
+ }
1434
+
1435
+ private static void RunHandlersWithContext<TMessage>(ref InstanceId context, Dictionary<InstanceId, Dictionary<Action<T>, int>> handlersByContext, ref TMessage message) where TMessage : IMessage
1436
+ {
1437
+ if (handlersByContext is not { Count: > 0 } || !handlersByContext.TryGetValue(context, out Dictionary<Action<T>, int> handlers))
1438
+ {
1439
+ return;
1440
+ }
1441
+
1442
+ RunHandlers(handlers, ref message);
1443
+ }
1444
+
1445
+ private static void RunHandlers<TMessage>(Dictionary<Action<T>, int> handlers, ref TMessage message) where TMessage : IMessage
1446
+ {
1447
+ if (handlers is not { Count: > 0 })
1448
+ {
1449
+ return;
1450
+ }
1451
+
1452
+ List<Action<T>> typedHandlers = GetOrAddNewHandlerStack(ref HandlersStack, handlers.Keys);
1453
+ try
1454
+ {
1455
+ ref T typedMessage = ref Unsafe.As<TMessage, T>(ref message);
1456
+
1457
+ foreach (Action<T> handler in typedHandlers)
1458
+ {
1459
+ handler(typedMessage);
1460
+ }
1461
+ }
1462
+ finally
1463
+ {
1464
+ HandlersStack.Push(typedHandlers);
1465
+ }
1466
+ }
1467
+
1468
+ private static void RunHandlers<TMessage>(ref InstanceId context, Dictionary<Action<InstanceId, T>, int> handlers, ref TMessage message) where TMessage : IMessage
1469
+ {
1470
+ if (handlers is not { Count: > 0 })
1471
+ {
1472
+ return;
1473
+ }
1474
+
1475
+ List<Action<InstanceId, T>> typedHandlers = GetOrAddNewHandlerStack(ref HandlersWithoutContextStack, handlers.Keys);
1476
+ try
1477
+ {
1478
+ ref T typedMessage = ref Unsafe.As<TMessage, T>(ref message);
1479
+
1480
+ foreach (Action<InstanceId, T> handler in typedHandlers)
1481
+ {
1482
+ handler(context, typedMessage);
1483
+ }
1484
+ }
1485
+ finally
1486
+ {
1487
+ HandlersWithoutContextStack.Push(typedHandlers);
1488
+ }
1489
+ }
1490
+
1491
+ private static List<U> GetOrAddNewHandlerStack<U>(ref Stack<List<U>> stack, IEnumerable<U> handlers)
1492
+ {
1493
+ stack ??= new Stack<List<U>>();
1494
+ if (stack.TryPop(out List<U> typedHandlerStack))
1495
+ {
1496
+ typedHandlerStack.Clear();
1497
+ typedHandlerStack.AddRange(handlers);
1498
+ return typedHandlerStack;
1499
+ }
1500
+
1501
+ return new List<U>(handlers);
1502
+ }
1503
+
1504
+ private static Action AddHandler<U>(InstanceId context, ref Dictionary<InstanceId, Dictionary<U, int>> handlersByContext, U handler, Action deregistration)
1505
+ {
1506
+ handlersByContext ??= new Dictionary<InstanceId, Dictionary<U, int>>();
1507
+
1508
+ if (!handlersByContext.TryGetValue(context, out Dictionary<U, int> handlers))
1509
+ {
1510
+ handlers = new Dictionary<U, int>();
1511
+ handlersByContext[context] = handlers;
1512
+ }
1513
+
1514
+ if (!handlers.TryGetValue(handler, out int count))
1515
+ {
1516
+ count = 0;
1517
+ }
1518
+
1519
+ handlers[handler] = count + 1;
1520
+
1521
+ Dictionary<InstanceId, Dictionary<U, int>> localHandlersByContext = handlersByContext;
1522
+ return () =>
1523
+ {
1524
+ if (!localHandlersByContext.TryGetValue(context, out handlers))
1525
+ {
1526
+ return;
1527
+ }
1528
+
1529
+ if (!handlers.TryGetValue(handler, out count))
1530
+ {
1531
+ return;
1532
+ }
1533
+
1534
+ // Always invoke deregistration action, as MessageBus dedupes this as well
1535
+ deregistration?.Invoke();
1536
+
1537
+ if (count <= 1)
1538
+ {
1539
+ _ = handlers.Remove(handler);
1540
+ return;
1541
+ }
1542
+
1543
+ handlers[handler] = count - 1;
1544
+
1545
+ if (handlers.Count <= 0)
1546
+ {
1547
+ _ = localHandlersByContext.Remove(context);
1548
+ }
1549
+ };
1550
+ }
1551
+
1552
+ private static Action AddHandler<U>(ref Dictionary<U, int> handlers, U handler, Action deregistration)
1553
+ {
1554
+ int count;
1555
+ if (handlers == null)
1556
+ {
1557
+ handlers = new Dictionary<U, int>();
1558
+ count = 0;
1559
+ }
1560
+ else if (!handlers.TryGetValue(handler, out count))
1561
+ {
1562
+ count = 0;
1563
+ }
1564
+
1565
+ handlers[handler] = count + 1;
1566
+
1567
+ Dictionary<U, int> localHandlers = handlers;
1568
+
1569
+ return () =>
1570
+ {
1571
+ if (!localHandlers.TryGetValue(handler, out count))
1572
+ {
1573
+ return;
1574
+ }
1575
+
1576
+ // Always invoke deregistration action, as MessageBus dedupes this as well
1577
+ deregistration?.Invoke();
1578
+ if (count <= 1)
1579
+ {
1580
+ _ = localHandlers.Remove(handler);
1581
+ return;
1582
+ }
1583
+
1584
+ localHandlers[handler] = count - 1;
1585
+ };
1586
+ }
1587
+ }
1588
+ }
1589
+ }