com.wallstop-studios.dxmessaging 1.0.0-rc8
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.
- package/.gitattributes +63 -0
- package/CHANGELOG.md +0 -0
- package/CHANGELOG.md.meta +7 -0
- package/Editor.meta +8 -0
- package/LICENSE.md +7 -0
- package/LICENSE.md.meta +7 -0
- package/README.md +76 -0
- package/README.md.meta +7 -0
- package/Runtime/Core/Extensions/MessageExtensions.cs +275 -0
- package/Runtime/Core/Extensions/MessageExtensions.cs.meta +11 -0
- package/Runtime/Core/Extensions.meta +8 -0
- package/Runtime/Core/IMessage.cs +12 -0
- package/Runtime/Core/IMessage.cs.meta +11 -0
- package/Runtime/Core/InstanceId.cs +117 -0
- package/Runtime/Core/InstanceId.cs.meta +11 -0
- package/Runtime/Core/MessageBus/IMessageBus.cs +249 -0
- package/Runtime/Core/MessageBus/IMessageBus.cs.meta +11 -0
- package/Runtime/Core/MessageBus/MessageBus.cs +961 -0
- package/Runtime/Core/MessageBus/MessageBus.cs.meta +11 -0
- package/Runtime/Core/MessageBus/MessagingRegistration.cs +100 -0
- package/Runtime/Core/MessageBus/MessagingRegistration.cs.meta +11 -0
- package/Runtime/Core/MessageBus/RegistrationLog.cs +111 -0
- package/Runtime/Core/MessageBus/RegistrationLog.cs.meta +11 -0
- package/Runtime/Core/MessageBus.meta +8 -0
- package/Runtime/Core/MessageHandler.cs +1589 -0
- package/Runtime/Core/MessageHandler.cs.meta +11 -0
- package/Runtime/Core/MessageRegistrationHandle.cs +55 -0
- package/Runtime/Core/MessageRegistrationHandle.cs.meta +11 -0
- package/Runtime/Core/MessageRegistrationToken.cs +885 -0
- package/Runtime/Core/MessageRegistrationToken.cs.meta +11 -0
- package/Runtime/Core/Messages/IBroadcastMessage.cs +27 -0
- package/Runtime/Core/Messages/IBroadcastMessage.cs.meta +11 -0
- package/Runtime/Core/Messages/ITargetedMessage.cs +26 -0
- package/Runtime/Core/Messages/ITargetedMessage.cs.meta +11 -0
- package/Runtime/Core/Messages/IUntargetedMessage.cs +26 -0
- package/Runtime/Core/Messages/IUntargetedMessage.cs.meta +11 -0
- package/Runtime/Core/Messages.meta +8 -0
- package/Runtime/Core/MessagingDebug.cs +71 -0
- package/Runtime/Core/MessagingDebug.cs.meta +11 -0
- package/Runtime/Core.meta +8 -0
- package/Runtime/Unity/MessageAwareComponent.cs +77 -0
- package/Runtime/Unity/MessageAwareComponent.cs.meta +11 -0
- package/Runtime/Unity/MessagingComponent.cs +73 -0
- package/Runtime/Unity/MessagingComponent.cs.meta +11 -0
- package/Runtime/Unity.meta +8 -0
- package/Runtime/WallstopStudios.DxMessaging.asmdef +18 -0
- package/Runtime/WallstopStudios.DxMessaging.asmdef.meta +7 -0
- package/Runtime.meta +8 -0
- package/Tests/Editor/WallstopStudios.DxMessaging.Tests.Editor.asmdef +23 -0
- package/Tests/Editor/WallstopStudios.DxMessaging.Tests.Editor.asmdef.meta +7 -0
- package/Tests/Editor.meta +8 -0
- package/Tests/Runtime/Benchmarks/PerformanceTests.cs +196 -0
- package/Tests/Runtime/Benchmarks/PerformanceTests.cs.meta +11 -0
- package/Tests/Runtime/Benchmarks.meta +8 -0
- package/Tests/Runtime/Core/BroadcastTests.cs +600 -0
- package/Tests/Runtime/Core/BroadcastTests.cs.meta +11 -0
- package/Tests/Runtime/Core/GlobalAcceptAllTests.cs +169 -0
- package/Tests/Runtime/Core/GlobalAcceptAllTests.cs.meta +11 -0
- package/Tests/Runtime/Core/MessagingTestBase.cs +164 -0
- package/Tests/Runtime/Core/MessagingTestBase.cs.meta +11 -0
- package/Tests/Runtime/Core/NominalTests.cs +1468 -0
- package/Tests/Runtime/Core/NominalTests.cs.meta +11 -0
- package/Tests/Runtime/Core/PostProcessorTests.cs +849 -0
- package/Tests/Runtime/Core/PostProcessorTests.cs.meta +11 -0
- package/Tests/Runtime/Core/RegistrationTests.cs +1045 -0
- package/Tests/Runtime/Core/RegistrationTests.cs.meta +11 -0
- package/Tests/Runtime/Core/TargetedTests.cs +596 -0
- package/Tests/Runtime/Core/TargetedTests.cs.meta +11 -0
- package/Tests/Runtime/Core/UntargetedTests.cs +149 -0
- package/Tests/Runtime/Core/UntargetedTests.cs.meta +11 -0
- package/Tests/Runtime/Core.meta +8 -0
- package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs +9 -0
- package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs.meta +11 -0
- package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs +140 -0
- package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs.meta +11 -0
- package/Tests/Runtime/Scripts/Components.meta +8 -0
- package/Tests/Runtime/Scripts/Messages/ComplexTargetedMessage.cs +28 -0
- package/Tests/Runtime/Scripts/Messages/ComplexTargetedMessage.cs.meta +11 -0
- package/Tests/Runtime/Scripts/Messages/SimpleBroadcastMessage.cs +8 -0
- package/Tests/Runtime/Scripts/Messages/SimpleBroadcastMessage.cs.meta +11 -0
- package/Tests/Runtime/Scripts/Messages/SimpleTargetedMessage.cs +8 -0
- package/Tests/Runtime/Scripts/Messages/SimpleTargetedMessage.cs.meta +11 -0
- package/Tests/Runtime/Scripts/Messages/SimpleUntargetedMessage.cs +8 -0
- package/Tests/Runtime/Scripts/Messages/SimpleUntargetedMessage.cs.meta +11 -0
- package/Tests/Runtime/Scripts/Messages.meta +8 -0
- package/Tests/Runtime/Scripts.meta +8 -0
- package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef +22 -0
- package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef.meta +7 -0
- package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.csproj +1 -0
- package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.csproj.meta +7 -0
- package/Tests/Runtime.meta +8 -0
- package/Tests.meta +8 -0
- package/Third Party Notices.md +1 -0
- package/Third Party Notices.md.meta +7 -0
- package/package.json +33 -0
- package/package.json.meta +7 -0
|
@@ -0,0 +1,961 @@
|
|
|
1
|
+
namespace DxMessaging.Core.MessageBus
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
using System.Linq;
|
|
6
|
+
using System.Reflection;
|
|
7
|
+
using Messages;
|
|
8
|
+
using static IMessageBus;
|
|
9
|
+
|
|
10
|
+
/// <summary>
|
|
11
|
+
/// Instanced MessageBus for use cases where you want distinct islands of MessageBuses.
|
|
12
|
+
/// </summary>
|
|
13
|
+
public sealed class MessageBus : IMessageBus
|
|
14
|
+
{
|
|
15
|
+
public int RegisteredTargeted => _targetedSinks.Select(kvp => kvp.Value.Count).Sum();
|
|
16
|
+
public int RegisteredBroadcast => _broadcastSinks.Select(kvp => kvp.Value.Count).Sum();
|
|
17
|
+
public int RegisteredUntargeted => _sinks.Select(kvp => kvp.Value.Count).Sum();
|
|
18
|
+
|
|
19
|
+
private static readonly Type MessageBusType = typeof(MessageBus);
|
|
20
|
+
// For use with re-broadcasting to generic methods
|
|
21
|
+
private static readonly object[] ReflectionMethodArgumentsCache = new object[2];
|
|
22
|
+
|
|
23
|
+
private const BindingFlags ReflectionHelperBindingFlags = BindingFlags.Static | BindingFlags.NonPublic;
|
|
24
|
+
|
|
25
|
+
private delegate void FastUntargetedBroadcast<T>(ref T message) where T : IUntargetedMessage;
|
|
26
|
+
private delegate void FastTargetedBroadcast<T>(ref InstanceId target, ref T message) where T : ITargetedMessage;
|
|
27
|
+
private delegate void FastSourcedBroadcast<T>(ref InstanceId target, ref T message) where T : IBroadcastMessage;
|
|
28
|
+
|
|
29
|
+
public RegistrationLog Log => _log;
|
|
30
|
+
|
|
31
|
+
private readonly Dictionary<Type, Dictionary<MessageHandler, int>> _sinks = new();
|
|
32
|
+
private readonly Dictionary<Type, Dictionary<InstanceId, Dictionary<MessageHandler, int>>> _targetedSinks = new();
|
|
33
|
+
private readonly Dictionary<Type, Dictionary<InstanceId, Dictionary<MessageHandler, int>>> _broadcastSinks = new();
|
|
34
|
+
private readonly Dictionary<Type, Dictionary<MessageHandler, int>> _postProcessingSinks = new();
|
|
35
|
+
private readonly Dictionary<Type, Dictionary<InstanceId, Dictionary<MessageHandler, int>>> _postProcessingTargetedSinks = new();
|
|
36
|
+
private readonly Dictionary<Type, Dictionary<InstanceId, Dictionary<MessageHandler, int>>> _postProcessingBroadcastSinks = new();
|
|
37
|
+
private readonly Dictionary<Type, Dictionary<MessageHandler, int>> _postProcessingTargetedWithoutTargetingSinks = new();
|
|
38
|
+
private readonly Dictionary<Type, Dictionary<MessageHandler, int>> _postProcessingBroadcastWithoutSourceSinks = new();
|
|
39
|
+
private readonly Dictionary<MessageHandler, int> _globalSinks = new();
|
|
40
|
+
private readonly Dictionary<Type, SortedDictionary<int, List<object>>> _interceptsByType = new();
|
|
41
|
+
private readonly Dictionary<object, Dictionary<int, int>> _uniqueInterceptorsAndPriorities = new();
|
|
42
|
+
|
|
43
|
+
private readonly Dictionary<Type, object> _broadcastMethodsByType = new();
|
|
44
|
+
|
|
45
|
+
private readonly RegistrationLog _log = new();
|
|
46
|
+
|
|
47
|
+
// These are used so we aren't allocating as much every time we send messages
|
|
48
|
+
private readonly Stack<List<MessageHandler>> _messageHandlers = new();
|
|
49
|
+
private readonly Stack<List<object>> _interceptors = new();
|
|
50
|
+
private readonly Stack<List<int>> _interceptorKeys = new();
|
|
51
|
+
|
|
52
|
+
public Action RegisterUntargeted<T>(MessageHandler messageHandler) where T : IUntargetedMessage
|
|
53
|
+
{
|
|
54
|
+
return InternalRegisterUntargeted<T>(messageHandler, _sinks, RegistrationMethod.Untargeted);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public Action RegisterTargeted<T>(InstanceId target, MessageHandler messageHandler) where T : ITargetedMessage
|
|
58
|
+
{
|
|
59
|
+
return InternalRegisterWithContext<T>(target, messageHandler, _targetedSinks, RegistrationMethod.Targeted);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public Action RegisterSourcedBroadcast<T>(InstanceId source, MessageHandler messageHandler) where T : IBroadcastMessage
|
|
63
|
+
{
|
|
64
|
+
return InternalRegisterWithContext<T>(source, messageHandler, _broadcastSinks, RegistrationMethod.Broadcast);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public Action RegisterSourcedBroadcastWithoutSource<T>(MessageHandler messageHandler) where T : IBroadcastMessage
|
|
68
|
+
{
|
|
69
|
+
return InternalRegisterUntargeted<T>(messageHandler, _sinks, RegistrationMethod.BroadcastWithoutSource);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public Action RegisterTargetedWithoutTargeting<T>(MessageHandler messageHandler) where T : ITargetedMessage
|
|
73
|
+
{
|
|
74
|
+
return InternalRegisterUntargeted<T>(messageHandler, _sinks, RegistrationMethod.TargetedWithoutTargeting);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public Action RegisterGlobalAcceptAll(MessageHandler messageHandler)
|
|
78
|
+
{
|
|
79
|
+
if (!_globalSinks.TryGetValue(messageHandler, out int count))
|
|
80
|
+
{
|
|
81
|
+
count = 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
Type type = typeof(IMessage);
|
|
85
|
+
_globalSinks[messageHandler] = count + 1;
|
|
86
|
+
_log.Log(new MessagingRegistration(messageHandler.owner, type, RegistrationType.Register, RegistrationMethod.GlobalAcceptAll));
|
|
87
|
+
|
|
88
|
+
return () =>
|
|
89
|
+
{
|
|
90
|
+
_log.Log(new MessagingRegistration(messageHandler.owner, type, RegistrationType.Deregister, RegistrationMethod.GlobalAcceptAll));
|
|
91
|
+
if (!_globalSinks.TryGetValue(messageHandler, out count))
|
|
92
|
+
{
|
|
93
|
+
MessagingDebug.Log(LogLevel.Error,
|
|
94
|
+
"Received over-deregistration of GlobalAcceptAll for MessageHandler {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
95
|
+
messageHandler);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (count <= 1)
|
|
100
|
+
{
|
|
101
|
+
_ = _globalSinks.Remove(messageHandler);
|
|
102
|
+
}
|
|
103
|
+
else
|
|
104
|
+
{
|
|
105
|
+
_globalSinks[messageHandler] = count - 1;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public Action RegisterUntargetedInterceptor<T>(UntargetedInterceptor<T> interceptor, int priority = 0) where T : IUntargetedMessage
|
|
111
|
+
{
|
|
112
|
+
return RegisterInterceptor<T>(interceptor, priority);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public Action RegisterTargetedInterceptor<T>(TargetedInterceptor<T> interceptor, int priority = 0) where T : ITargetedMessage
|
|
116
|
+
{
|
|
117
|
+
return RegisterInterceptor<T>(interceptor, priority);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public Action RegisterBroadcastInterceptor<T>(BroadcastInterceptor<T> interceptor, int priority = 0) where T : IBroadcastMessage
|
|
121
|
+
{
|
|
122
|
+
return RegisterInterceptor<T>(interceptor, priority);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public Action RegisterUntargetedPostProcessor<T>(MessageHandler messageHandler) where T : IUntargetedMessage
|
|
126
|
+
{
|
|
127
|
+
return InternalRegisterUntargeted<T>(messageHandler, _postProcessingSinks, RegistrationMethod.UntargetedPostProcessor);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public Action RegisterTargetedPostProcessor<T>(InstanceId target, MessageHandler messageHandler) where T : ITargetedMessage
|
|
131
|
+
{
|
|
132
|
+
return InternalRegisterWithContext<T>(target, messageHandler, _postProcessingTargetedSinks, RegistrationMethod.TargetedPostProcessor);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public Action RegisterTargetedWithoutTargetingPostProcessor<T>(MessageHandler messageHandler) where T : ITargetedMessage
|
|
136
|
+
{
|
|
137
|
+
return InternalRegisterUntargeted<T>(messageHandler, _postProcessingTargetedWithoutTargetingSinks, RegistrationMethod.TargetedWithoutTargetingPostProcessor);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public Action RegisterBroadcastPostProcessor<T>(InstanceId source, MessageHandler messageHandler) where T : IBroadcastMessage
|
|
141
|
+
{
|
|
142
|
+
return InternalRegisterWithContext<T>(source, messageHandler, _postProcessingBroadcastSinks, RegistrationMethod.BroadcastPostProcessor);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public Action RegisterBroadcastWithoutSourcePostProcessor<T>(MessageHandler messageHandler) where T : IBroadcastMessage
|
|
146
|
+
{
|
|
147
|
+
return InternalRegisterUntargeted<T>(messageHandler, _postProcessingBroadcastWithoutSourceSinks, RegistrationMethod.BroadcastWithoutSourcePostProcessor);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private Action RegisterInterceptor<T>(object interceptor, int priority) where T : IMessage
|
|
151
|
+
{
|
|
152
|
+
Type type = typeof(T);
|
|
153
|
+
if (!_interceptsByType.TryGetValue(type, out SortedDictionary<int, List<object>> prioritizedInterceptors))
|
|
154
|
+
{
|
|
155
|
+
prioritizedInterceptors = new SortedDictionary<int, List<object>>();
|
|
156
|
+
_interceptsByType[type] = prioritizedInterceptors;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!prioritizedInterceptors.TryGetValue(priority, out List<object> interceptors))
|
|
160
|
+
{
|
|
161
|
+
interceptors = new List<object>();
|
|
162
|
+
prioritizedInterceptors[priority] = interceptors;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!_uniqueInterceptorsAndPriorities.TryGetValue(interceptor, out Dictionary<int, int> priorityCount))
|
|
166
|
+
{
|
|
167
|
+
priorityCount = new Dictionary<int, int>();
|
|
168
|
+
_uniqueInterceptorsAndPriorities[interceptor] = priorityCount;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!priorityCount.TryGetValue(priority, out int count))
|
|
172
|
+
{
|
|
173
|
+
count = 0;
|
|
174
|
+
interceptors.Add(interceptor);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
priorityCount[priority] = count + 1;
|
|
178
|
+
|
|
179
|
+
_log.Log(new MessagingRegistration(InstanceId.EmptyId, type, RegistrationType.Register, RegistrationMethod.Interceptor));
|
|
180
|
+
|
|
181
|
+
return () =>
|
|
182
|
+
{
|
|
183
|
+
_log.Log(new MessagingRegistration(InstanceId.EmptyId, type, RegistrationType.Deregister, RegistrationMethod.Interceptor));
|
|
184
|
+
bool removed = false;
|
|
185
|
+
if (_uniqueInterceptorsAndPriorities.TryGetValue(interceptor, out priorityCount))
|
|
186
|
+
{
|
|
187
|
+
if (priorityCount.TryGetValue(priority, out count))
|
|
188
|
+
{
|
|
189
|
+
if (1 < count)
|
|
190
|
+
{
|
|
191
|
+
priorityCount[priority] = count - 1;
|
|
192
|
+
}
|
|
193
|
+
else
|
|
194
|
+
{
|
|
195
|
+
removed = true;
|
|
196
|
+
_ = priorityCount.Remove(priority);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (priorityCount.Count <= 0)
|
|
201
|
+
{
|
|
202
|
+
_uniqueInterceptorsAndPriorities.Remove(interceptor);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else
|
|
206
|
+
{
|
|
207
|
+
MessagingDebug.Log(LogLevel.Error,
|
|
208
|
+
"Received over-deregistration of Interceptor {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
209
|
+
interceptor);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
bool complete = false;
|
|
213
|
+
if (removed)
|
|
214
|
+
{
|
|
215
|
+
if (_interceptsByType.TryGetValue(type, out prioritizedInterceptors))
|
|
216
|
+
{
|
|
217
|
+
if (prioritizedInterceptors.TryGetValue(priority, out interceptors))
|
|
218
|
+
{
|
|
219
|
+
complete = interceptors.Remove(interceptor);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!complete)
|
|
224
|
+
{
|
|
225
|
+
MessagingDebug.Log(LogLevel.Error,
|
|
226
|
+
"Received over-deregistration of Interceptor {0}. Check to make sure you're not calling (de)registration multiple times.",
|
|
227
|
+
interceptor);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
public void UntypedUntargetedBroadcast(IUntargetedMessage typedMessage)
|
|
235
|
+
{
|
|
236
|
+
Type messageType = typedMessage.MessageType;
|
|
237
|
+
if (!_broadcastMethodsByType.TryGetValue(messageType, out object untargetedMethod))
|
|
238
|
+
{
|
|
239
|
+
// ReSharper disable once PossibleNullReferenceException
|
|
240
|
+
MethodInfo broadcastMethod = MessageBusType.GetMethod(nameof(UntargetedBroadcast)).MakeGenericMethod(messageType);
|
|
241
|
+
// ReSharper disable once PossibleNullReferenceException
|
|
242
|
+
MethodInfo helperMethod = MessageBusType.GetMethod(nameof(UntargetedBroadcastReflectionHelper), ReflectionHelperBindingFlags).MakeGenericMethod(messageType);
|
|
243
|
+
|
|
244
|
+
ReflectionMethodArgumentsCache[0] = this;
|
|
245
|
+
ReflectionMethodArgumentsCache[1] = broadcastMethod;
|
|
246
|
+
untargetedMethod = helperMethod.Invoke(null, ReflectionMethodArgumentsCache);
|
|
247
|
+
_broadcastMethodsByType[messageType] = untargetedMethod;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
Action<IUntargetedMessage> broadcast = (Action<IUntargetedMessage>)untargetedMethod;
|
|
251
|
+
broadcast.Invoke(typedMessage);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
public void UntargetedBroadcast<TMessage>(ref TMessage typedMessage) where TMessage : IUntargetedMessage
|
|
256
|
+
{
|
|
257
|
+
Type type = typedMessage.MessageType;
|
|
258
|
+
if (!RunUntargetedInterceptors(type, ref typedMessage))
|
|
259
|
+
{
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (0 < _globalSinks.Count)
|
|
264
|
+
{
|
|
265
|
+
IUntargetedMessage untargetedMessage = typedMessage;
|
|
266
|
+
BroadcastGlobalUntargeted(ref untargetedMessage);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
bool foundAnyHandlers = InternalUntargetedBroadcast(ref typedMessage, type);
|
|
270
|
+
|
|
271
|
+
if (_postProcessingSinks.TryGetValue(type, out Dictionary<MessageHandler, int> handlers) && 0 < handlers.Count)
|
|
272
|
+
{
|
|
273
|
+
foundAnyHandlers = true;
|
|
274
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(handlers.Keys);
|
|
275
|
+
try
|
|
276
|
+
{
|
|
277
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
278
|
+
{
|
|
279
|
+
handler.HandleUntargetedPostProcessing(ref typedMessage, this);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
finally
|
|
283
|
+
{
|
|
284
|
+
_messageHandlers.Push(messageHandlers);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (!foundAnyHandlers)
|
|
289
|
+
{
|
|
290
|
+
MessagingDebug.Log(LogLevel.Info, "Could not find a matching untargeted broadcast handler for Message: {0}.", typedMessage);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
public void UntypedTargetedBroadcast(InstanceId target, ITargetedMessage typedMessage)
|
|
295
|
+
{
|
|
296
|
+
Type messageType = typedMessage.MessageType;
|
|
297
|
+
if (!_broadcastMethodsByType.TryGetValue(messageType, out object targetedMethod))
|
|
298
|
+
{
|
|
299
|
+
// ReSharper disable once PossibleNullReferenceException
|
|
300
|
+
MethodInfo broadcastMethod = MessageBusType.GetMethod(nameof(TargetedBroadcast)).MakeGenericMethod(messageType);
|
|
301
|
+
// ReSharper disable once PossibleNullReferenceException
|
|
302
|
+
MethodInfo helperMethod = MessageBusType.GetMethod(nameof(TargetedBroadcastReflectionHelper), ReflectionHelperBindingFlags).MakeGenericMethod(messageType);
|
|
303
|
+
|
|
304
|
+
ReflectionMethodArgumentsCache[0] = this;
|
|
305
|
+
ReflectionMethodArgumentsCache[1] = broadcastMethod;
|
|
306
|
+
targetedMethod = helperMethod.Invoke(null, ReflectionMethodArgumentsCache);
|
|
307
|
+
_broadcastMethodsByType[messageType] = targetedMethod;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
Action<InstanceId, ITargetedMessage> broadcast = (Action<InstanceId, ITargetedMessage>)targetedMethod;
|
|
311
|
+
broadcast.Invoke(target, typedMessage);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
public void TargetedBroadcast<TMessage>(ref InstanceId target, ref TMessage typedMessage) where TMessage : ITargetedMessage
|
|
316
|
+
{
|
|
317
|
+
Type type = typedMessage.MessageType;
|
|
318
|
+
if (!RunTargetedInterceptors(type, ref typedMessage, ref target))
|
|
319
|
+
{
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (0 < _globalSinks.Count)
|
|
324
|
+
{
|
|
325
|
+
ITargetedMessage targetedMessage = typedMessage;
|
|
326
|
+
BroadcastGlobalTargeted(ref target, ref targetedMessage);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
bool foundAnyHandlers = false;
|
|
330
|
+
if (_targetedSinks.TryGetValue(type, out Dictionary<InstanceId, Dictionary<MessageHandler, int>> targetedHandlers)
|
|
331
|
+
&& targetedHandlers.TryGetValue(target, out Dictionary<MessageHandler, int> handlers)
|
|
332
|
+
&& 0 < handlers.Count)
|
|
333
|
+
{
|
|
334
|
+
foundAnyHandlers = true;
|
|
335
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(handlers.Keys);
|
|
336
|
+
try
|
|
337
|
+
{
|
|
338
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
339
|
+
{
|
|
340
|
+
handler.HandleTargeted(ref target, ref typedMessage, this);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
finally
|
|
344
|
+
{
|
|
345
|
+
_messageHandlers.Push(messageHandlers);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
_ = InternalTargetedWithoutTargetingBroadcast(ref target, ref typedMessage, type);
|
|
350
|
+
|
|
351
|
+
if (_postProcessingTargetedSinks.TryGetValue(type, out targetedHandlers) && targetedHandlers.TryGetValue(target, out handlers) && 0 < handlers.Count)
|
|
352
|
+
{
|
|
353
|
+
foundAnyHandlers = true;
|
|
354
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(handlers.Keys);
|
|
355
|
+
try
|
|
356
|
+
{
|
|
357
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
358
|
+
{
|
|
359
|
+
handler.HandleTargetedPostProcessing(ref target, ref typedMessage, this);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
finally
|
|
363
|
+
{
|
|
364
|
+
_messageHandlers.Push(messageHandlers);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (_postProcessingTargetedWithoutTargetingSinks.TryGetValue(type, out handlers) && 0 < handlers.Count)
|
|
369
|
+
{
|
|
370
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(handlers.Keys);
|
|
371
|
+
try
|
|
372
|
+
{
|
|
373
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
374
|
+
{
|
|
375
|
+
handler.HandleTargetedWithoutTargetingPostProcessing(ref target, ref typedMessage, this);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
finally
|
|
379
|
+
{
|
|
380
|
+
_messageHandlers.Push(messageHandlers);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (!foundAnyHandlers)
|
|
385
|
+
{
|
|
386
|
+
MessagingDebug.Log(LogLevel.Info, "Could not find a matching targeted broadcast handler for Id: {0}, Message: {1}.", target,
|
|
387
|
+
typedMessage);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
public void UntypedSourcedBroadcast(InstanceId source, IBroadcastMessage typedMessage)
|
|
392
|
+
{
|
|
393
|
+
Type messageType = typedMessage.MessageType;
|
|
394
|
+
if (!_broadcastMethodsByType.TryGetValue(messageType, out object sourcedBroadcastMethod))
|
|
395
|
+
{
|
|
396
|
+
// ReSharper disable once PossibleNullReferenceException
|
|
397
|
+
MethodInfo broadcastMethod = MessageBusType.GetMethod(nameof(SourcedBroadcast)).MakeGenericMethod(messageType);
|
|
398
|
+
// ReSharper disable once PossibleNullReferenceException
|
|
399
|
+
MethodInfo helperMethod = MessageBusType.GetMethod(nameof(SourcedBroadcastReflectionHelper), ReflectionHelperBindingFlags).MakeGenericMethod(messageType);
|
|
400
|
+
|
|
401
|
+
ReflectionMethodArgumentsCache[0] = this;
|
|
402
|
+
ReflectionMethodArgumentsCache[1] = broadcastMethod;
|
|
403
|
+
sourcedBroadcastMethod = helperMethod.Invoke(null, ReflectionMethodArgumentsCache);
|
|
404
|
+
|
|
405
|
+
_broadcastMethodsByType[messageType] = sourcedBroadcastMethod;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
Action<InstanceId, IBroadcastMessage> broadcast = (Action<InstanceId, IBroadcastMessage>)sourcedBroadcastMethod;
|
|
409
|
+
broadcast.Invoke(source, typedMessage);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
public void SourcedBroadcast<TMessage>(ref InstanceId source, ref TMessage typedMessage) where TMessage : IBroadcastMessage
|
|
413
|
+
{
|
|
414
|
+
Type type = typedMessage.MessageType;
|
|
415
|
+
if (!RunBroadcastInterceptors(type, ref typedMessage, ref source))
|
|
416
|
+
{
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (0 < _globalSinks.Count)
|
|
421
|
+
{
|
|
422
|
+
IBroadcastMessage broadcastMessage = typedMessage;
|
|
423
|
+
BroadcastGlobalSourcedBroadcast(ref source, ref broadcastMessage);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
bool foundAnyHandlers = false;
|
|
427
|
+
if (_broadcastSinks.TryGetValue(type, out Dictionary<InstanceId, Dictionary<MessageHandler, int>> broadcastHandlers)
|
|
428
|
+
&& broadcastHandlers.TryGetValue(source, out Dictionary<MessageHandler, int> handlers)
|
|
429
|
+
&& 0 < handlers.Count)
|
|
430
|
+
{
|
|
431
|
+
foundAnyHandlers = true;
|
|
432
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(handlers.Keys);
|
|
433
|
+
try
|
|
434
|
+
{
|
|
435
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
436
|
+
{
|
|
437
|
+
handler.HandleSourcedBroadcast(ref source, ref typedMessage, this);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
finally
|
|
441
|
+
{
|
|
442
|
+
_messageHandlers.Push(messageHandlers);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
_ = InternalBroadcastWithoutSource(ref source, ref typedMessage, type);
|
|
447
|
+
|
|
448
|
+
if (_postProcessingBroadcastSinks.TryGetValue(type, out broadcastHandlers) && broadcastHandlers.TryGetValue(source, out handlers) && 0 < handlers.Count)
|
|
449
|
+
{
|
|
450
|
+
foundAnyHandlers = true;
|
|
451
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(handlers.Keys);
|
|
452
|
+
try
|
|
453
|
+
{
|
|
454
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
455
|
+
{
|
|
456
|
+
handler.HandleSourcedBroadcastPostProcessing(ref source, ref typedMessage, this);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
finally
|
|
460
|
+
{
|
|
461
|
+
_messageHandlers.Push(messageHandlers);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (_postProcessingBroadcastWithoutSourceSinks.TryGetValue(type, out handlers) && 0 < handlers.Count)
|
|
466
|
+
{
|
|
467
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(handlers.Keys);
|
|
468
|
+
try
|
|
469
|
+
{
|
|
470
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
471
|
+
{
|
|
472
|
+
handler.HandleSourcedBroadcastWithoutSourcePostProcessing(ref source, ref typedMessage, this);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
finally
|
|
476
|
+
{
|
|
477
|
+
_messageHandlers.Push(messageHandlers);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (!foundAnyHandlers)
|
|
482
|
+
{
|
|
483
|
+
MessagingDebug.Log(LogLevel.Info, "Could not find a matching sourced broadcast handler for Id: {0}, Message: {1}.",
|
|
484
|
+
source, typedMessage);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
private void BroadcastGlobalUntargeted(ref IUntargetedMessage message)
|
|
489
|
+
{
|
|
490
|
+
if (_globalSinks.Count <= 0)
|
|
491
|
+
{
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(_globalSinks.Keys);
|
|
496
|
+
try
|
|
497
|
+
{
|
|
498
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
499
|
+
{
|
|
500
|
+
handler.HandleGlobalUntargetedMessage(ref message, this);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
finally
|
|
504
|
+
{
|
|
505
|
+
_messageHandlers.Push(messageHandlers);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
private void BroadcastGlobalTargeted(ref InstanceId target, ref ITargetedMessage message)
|
|
510
|
+
{
|
|
511
|
+
if (_globalSinks.Count <= 0)
|
|
512
|
+
{
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(_globalSinks.Keys);
|
|
517
|
+
try
|
|
518
|
+
{
|
|
519
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
520
|
+
{
|
|
521
|
+
handler.HandleGlobalTargetedMessage(ref target, ref message, this);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
finally
|
|
525
|
+
{
|
|
526
|
+
_messageHandlers.Push(messageHandlers);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
private void BroadcastGlobalSourcedBroadcast(ref InstanceId source, ref IBroadcastMessage message)
|
|
531
|
+
{
|
|
532
|
+
if (_globalSinks.Count <= 0)
|
|
533
|
+
{
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(_globalSinks.Keys);
|
|
538
|
+
try
|
|
539
|
+
{
|
|
540
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
541
|
+
{
|
|
542
|
+
handler.HandleGlobalSourcedBroadcastMessage(ref source, ref message, this);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
finally
|
|
546
|
+
{
|
|
547
|
+
_messageHandlers.Push(messageHandlers);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
private bool TryGetInterceptorCaches(Type type, out SortedDictionary<int, List<object>> interceptors, out List<int> interceptorKeys, out List<object> interceptorStack)
|
|
552
|
+
{
|
|
553
|
+
if (!_interceptsByType.TryGetValue(type, out interceptors) || interceptors.Count <= 0)
|
|
554
|
+
{
|
|
555
|
+
interceptorKeys = default;
|
|
556
|
+
interceptorStack = default;
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (!_interceptors.TryPop(out interceptorStack))
|
|
561
|
+
{
|
|
562
|
+
interceptorStack = new List<object>();
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (!_interceptorKeys.TryPop(out interceptorKeys))
|
|
566
|
+
{
|
|
567
|
+
interceptorKeys = new List<int>();
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
private bool RunUntargetedInterceptors<T>(Type type, ref T message) where T : IUntargetedMessage
|
|
574
|
+
{
|
|
575
|
+
if (!TryGetInterceptorCaches(
|
|
576
|
+
type,
|
|
577
|
+
out SortedDictionary<int, List<object>> interceptors,
|
|
578
|
+
out List<int> interceptorKeys,
|
|
579
|
+
out List<object> interceptorStack))
|
|
580
|
+
{
|
|
581
|
+
return true;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
try
|
|
585
|
+
{
|
|
586
|
+
interceptorKeys.Clear();
|
|
587
|
+
interceptorKeys.AddRange(interceptors.Keys);
|
|
588
|
+
foreach (int priority in interceptorKeys)
|
|
589
|
+
{
|
|
590
|
+
if (!interceptors.TryGetValue(priority, out List<object> untypedInterceptors) || untypedInterceptors.Count <= 0)
|
|
591
|
+
{
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
interceptorStack.Clear();
|
|
596
|
+
interceptorStack.AddRange(untypedInterceptors);
|
|
597
|
+
|
|
598
|
+
foreach (object transformer in interceptorStack)
|
|
599
|
+
{
|
|
600
|
+
if (transformer is not UntargetedInterceptor<T> typedTransformer)
|
|
601
|
+
{
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (!typedTransformer(ref message))
|
|
606
|
+
{
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
finally
|
|
613
|
+
{
|
|
614
|
+
_interceptors.Push(interceptorStack);
|
|
615
|
+
_interceptorKeys.Push(interceptorKeys);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return true;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
private bool RunTargetedInterceptors<T>(Type type, ref T message, ref InstanceId target) where T : ITargetedMessage
|
|
622
|
+
{
|
|
623
|
+
if (!TryGetInterceptorCaches(
|
|
624
|
+
type,
|
|
625
|
+
out SortedDictionary<int, List<object>> interceptors,
|
|
626
|
+
out List<int> interceptorKeys,
|
|
627
|
+
out List<object> interceptorStack))
|
|
628
|
+
{
|
|
629
|
+
return true;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
try
|
|
633
|
+
{
|
|
634
|
+
interceptorKeys.Clear();
|
|
635
|
+
interceptorKeys.AddRange(interceptors.Keys);
|
|
636
|
+
foreach (int priority in interceptorKeys)
|
|
637
|
+
{
|
|
638
|
+
if (!interceptors.TryGetValue(priority, out List<object> untypedInterceptors) || untypedInterceptors.Count <= 0)
|
|
639
|
+
{
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
interceptorStack.Clear();
|
|
644
|
+
interceptorStack.AddRange(untypedInterceptors);
|
|
645
|
+
|
|
646
|
+
foreach (object transformer in interceptorStack)
|
|
647
|
+
{
|
|
648
|
+
if (transformer is not TargetedInterceptor<T> typedTransformer)
|
|
649
|
+
{
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
if (!typedTransformer(ref target, ref message))
|
|
654
|
+
{
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
finally
|
|
661
|
+
{
|
|
662
|
+
_interceptors.Push(interceptorStack);
|
|
663
|
+
_interceptorKeys.Push(interceptorKeys);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
return true;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
private bool RunBroadcastInterceptors<T>(Type type, ref T message, ref InstanceId source) where T : IBroadcastMessage
|
|
670
|
+
{
|
|
671
|
+
if (!TryGetInterceptorCaches(
|
|
672
|
+
type,
|
|
673
|
+
out SortedDictionary<int, List<object>> interceptors,
|
|
674
|
+
out List<int> interceptorKeys,
|
|
675
|
+
out List<object> interceptorStack))
|
|
676
|
+
{
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
try
|
|
681
|
+
{
|
|
682
|
+
interceptorKeys.Clear();
|
|
683
|
+
interceptorKeys.AddRange(interceptors.Keys);
|
|
684
|
+
foreach (int priority in interceptorKeys)
|
|
685
|
+
{
|
|
686
|
+
if (!interceptors.TryGetValue(priority, out List<object> untypedInterceptors) || untypedInterceptors.Count <= 0)
|
|
687
|
+
{
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
interceptorStack.Clear();
|
|
692
|
+
interceptorStack.AddRange(untypedInterceptors);
|
|
693
|
+
|
|
694
|
+
foreach (object transformer in interceptorStack)
|
|
695
|
+
{
|
|
696
|
+
if (transformer is not BroadcastInterceptor<T> typedTransformer)
|
|
697
|
+
{
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
if (!typedTransformer(ref source, ref message))
|
|
702
|
+
{
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
finally
|
|
709
|
+
{
|
|
710
|
+
_interceptors.Push(interceptorStack);
|
|
711
|
+
_interceptorKeys.Push(interceptorKeys);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return true;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
private bool InternalUntargetedBroadcast<TMessage>(ref TMessage message, Type type) where TMessage : IMessage
|
|
718
|
+
{
|
|
719
|
+
if (!_sinks.TryGetValue(type, out Dictionary<MessageHandler, int> handlers) || handlers.Count <= 0)
|
|
720
|
+
{
|
|
721
|
+
return false;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(handlers.Keys);
|
|
725
|
+
try
|
|
726
|
+
{
|
|
727
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
728
|
+
{
|
|
729
|
+
handler.HandleUntargetedMessage(ref message, this);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
finally
|
|
733
|
+
{
|
|
734
|
+
_messageHandlers.Push(messageHandlers);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
return true;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
private bool InternalTargetedWithoutTargetingBroadcast<TMessage>(
|
|
741
|
+
ref InstanceId target, ref TMessage message, Type type) where TMessage : ITargetedMessage
|
|
742
|
+
{
|
|
743
|
+
if (!_sinks.TryGetValue(type, out Dictionary<MessageHandler, int> handlers) || handlers.Count <= 0)
|
|
744
|
+
{
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(handlers.Keys);
|
|
749
|
+
try
|
|
750
|
+
{
|
|
751
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
752
|
+
{
|
|
753
|
+
handler.HandleTargetedWithoutTargeting(ref target, ref message, this);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
finally
|
|
757
|
+
{
|
|
758
|
+
_messageHandlers.Push(messageHandlers);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
return true;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
private bool InternalBroadcastWithoutSource<TMessage>(
|
|
765
|
+
ref InstanceId target, ref TMessage message, Type type) where TMessage : IBroadcastMessage
|
|
766
|
+
{
|
|
767
|
+
if (!_sinks.TryGetValue(type, out Dictionary<MessageHandler, int> handlers) || handlers.Count <= 0)
|
|
768
|
+
{
|
|
769
|
+
return false;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
List<MessageHandler> messageHandlers = GetOrAddMessageHandlerStack(handlers.Keys);
|
|
773
|
+
try
|
|
774
|
+
{
|
|
775
|
+
foreach (MessageHandler handler in messageHandlers)
|
|
776
|
+
{
|
|
777
|
+
handler.HandleSourcedBroadcastWithoutSource(ref target, ref message, this);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
finally
|
|
781
|
+
{
|
|
782
|
+
_messageHandlers.Push(messageHandlers);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
return true;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
private Action InternalRegisterUntargeted<T>(MessageHandler messageHandler, Dictionary<Type, Dictionary<MessageHandler, int>> sinks, RegistrationMethod registrationMethod) where T : IMessage
|
|
789
|
+
{
|
|
790
|
+
if (messageHandler == null)
|
|
791
|
+
{
|
|
792
|
+
throw new ArgumentNullException(nameof(messageHandler));
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
InstanceId handlerOwnerId = messageHandler.owner;
|
|
796
|
+
Type type = typeof(T);
|
|
797
|
+
|
|
798
|
+
if (!sinks.TryGetValue(type, out Dictionary<MessageHandler, int> handlers))
|
|
799
|
+
{
|
|
800
|
+
handlers = new Dictionary<MessageHandler, int>();
|
|
801
|
+
sinks[type] = handlers;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
if (!handlers.TryGetValue(messageHandler, out int count))
|
|
805
|
+
{
|
|
806
|
+
count = 0;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
handlers[messageHandler] = count + 1;
|
|
810
|
+
_log.Log(new MessagingRegistration(handlerOwnerId, type, RegistrationType.Register, registrationMethod));
|
|
811
|
+
|
|
812
|
+
return () =>
|
|
813
|
+
{
|
|
814
|
+
_log.Log(new MessagingRegistration(handlerOwnerId, type, RegistrationType.Deregister, registrationMethod));
|
|
815
|
+
if (!sinks.TryGetValue(type, out handlers) || !handlers.TryGetValue(messageHandler, out count))
|
|
816
|
+
{
|
|
817
|
+
MessagingDebug.Log(LogLevel.Error,
|
|
818
|
+
"Received over-deregistration of {0} for {1}. Check to make sure you're not calling (de)registration multiple times.",
|
|
819
|
+
type, messageHandler);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (count <= 1)
|
|
824
|
+
{
|
|
825
|
+
bool complete = handlers.Remove(messageHandler);
|
|
826
|
+
bool trulyComplete = true;
|
|
827
|
+
if (handlers.Count <= 0)
|
|
828
|
+
{
|
|
829
|
+
trulyComplete = sinks.Remove(type);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
if (!complete || !trulyComplete)
|
|
833
|
+
{
|
|
834
|
+
MessagingDebug.Log(LogLevel.Error,
|
|
835
|
+
"Received over-deregistration of {0} for {1}. Check to make sure you're not calling (de)registration multiple times.",
|
|
836
|
+
type, messageHandler);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
else
|
|
840
|
+
{
|
|
841
|
+
handlers[messageHandler] = count - 1;
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
private Action InternalRegisterWithContext<T>(InstanceId context, MessageHandler messageHandler, Dictionary<Type, Dictionary<InstanceId, Dictionary<MessageHandler, int>>> sinks, RegistrationMethod registrationMethod)
|
|
847
|
+
{
|
|
848
|
+
if (messageHandler == null)
|
|
849
|
+
{
|
|
850
|
+
throw new ArgumentNullException(nameof(messageHandler));
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
Type type = typeof(T);
|
|
854
|
+
if (!sinks.TryGetValue(type, out Dictionary<InstanceId, Dictionary<MessageHandler, int>> broadcastHandlers))
|
|
855
|
+
{
|
|
856
|
+
broadcastHandlers = new Dictionary<InstanceId, Dictionary<MessageHandler, int>>();
|
|
857
|
+
sinks[type] = broadcastHandlers;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
if (!broadcastHandlers.TryGetValue(context, out Dictionary<MessageHandler, int> handlers))
|
|
861
|
+
{
|
|
862
|
+
handlers = new Dictionary<MessageHandler, int>();
|
|
863
|
+
broadcastHandlers[context] = handlers;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
if (!handlers.TryGetValue(messageHandler, out int count))
|
|
867
|
+
{
|
|
868
|
+
count = 0;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
handlers[messageHandler] = count + 1;
|
|
872
|
+
_log.Log(new MessagingRegistration(context, type, RegistrationType.Register, registrationMethod));
|
|
873
|
+
|
|
874
|
+
return () =>
|
|
875
|
+
{
|
|
876
|
+
_log.Log(new MessagingRegistration(context, type, RegistrationType.Deregister, registrationMethod));
|
|
877
|
+
if (!sinks.TryGetValue(type, out broadcastHandlers) || !broadcastHandlers.TryGetValue(context, out handlers) || !handlers.TryGetValue(messageHandler, out count))
|
|
878
|
+
{
|
|
879
|
+
MessagingDebug.Log(LogLevel.Error,
|
|
880
|
+
"Received over-deregistration of {0} for {1}. Check to make sure you're not calling (de)registration multiple times.",
|
|
881
|
+
type, messageHandler);
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (count <= 1)
|
|
886
|
+
{
|
|
887
|
+
bool complete = handlers.Remove(messageHandler);
|
|
888
|
+
if (handlers.Count <= 0)
|
|
889
|
+
{
|
|
890
|
+
_ = broadcastHandlers.Remove(context);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
if (broadcastHandlers.Count <= 0)
|
|
894
|
+
{
|
|
895
|
+
_ = sinks.Remove(type);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
if (!complete)
|
|
899
|
+
{
|
|
900
|
+
MessagingDebug.Log(LogLevel.Error,
|
|
901
|
+
"Received over-deregistration of {0} for {1}. Check to make sure you're not calling (de)registration multiple times.",
|
|
902
|
+
type, messageHandler);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
else
|
|
906
|
+
{
|
|
907
|
+
handlers[messageHandler] = count - 1;
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
private List<MessageHandler> GetOrAddMessageHandlerStack(IEnumerable<MessageHandler> handlers)
|
|
913
|
+
{
|
|
914
|
+
if (!_messageHandlers.TryPop(out List<MessageHandler> messageHandlers))
|
|
915
|
+
{
|
|
916
|
+
return new List<MessageHandler>(handlers);
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
messageHandlers.Clear();
|
|
920
|
+
messageHandlers.AddRange(handlers);
|
|
921
|
+
return messageHandlers;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// https://blogs.msmvps.com/jonskeet/2008/08/09/making-reflection-fly-and-exploring-delegates/
|
|
925
|
+
private static Action<IUntargetedMessage> UntargetedBroadcastReflectionHelper<T>(IMessageBus messageBus, MethodInfo methodInfo) where T : IUntargetedMessage
|
|
926
|
+
{
|
|
927
|
+
FastUntargetedBroadcast<T> untargetedBroadcast = (FastUntargetedBroadcast<T>) Delegate.CreateDelegate(typeof(FastUntargetedBroadcast<T>), messageBus, methodInfo);
|
|
928
|
+
void UntypedBroadcast(IUntargetedMessage message)
|
|
929
|
+
{
|
|
930
|
+
T typedMessage = (T) message;
|
|
931
|
+
untargetedBroadcast(ref typedMessage);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
return UntypedBroadcast;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
private static Action<InstanceId, ITargetedMessage> TargetedBroadcastReflectionHelper<T>(IMessageBus messageBus, MethodInfo methodInfo) where T : ITargetedMessage
|
|
938
|
+
{
|
|
939
|
+
FastTargetedBroadcast<T> targetedBroadcast = (FastTargetedBroadcast<T>) Delegate.CreateDelegate(typeof(FastTargetedBroadcast<T>), messageBus, methodInfo);
|
|
940
|
+
void UntypedBroadcast(InstanceId target, ITargetedMessage message)
|
|
941
|
+
{
|
|
942
|
+
T typedMessage = (T) message;
|
|
943
|
+
targetedBroadcast(ref target, ref typedMessage);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
return UntypedBroadcast;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
private static Action<InstanceId, IBroadcastMessage> SourcedBroadcastReflectionHelper<T>(IMessageBus messageBus, MethodInfo methodInfo) where T : IBroadcastMessage
|
|
950
|
+
{
|
|
951
|
+
FastSourcedBroadcast<T> sourcedBroadcast = (FastSourcedBroadcast<T>)Delegate.CreateDelegate(typeof(FastSourcedBroadcast<T>), messageBus, methodInfo);
|
|
952
|
+
void UntypedBroadcast(InstanceId target, IBroadcastMessage message)
|
|
953
|
+
{
|
|
954
|
+
T typedMessage = (T)message;
|
|
955
|
+
sourcedBroadcast(ref target, ref typedMessage);
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
return UntypedBroadcast;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|