com.wallstop-studios.dxmessaging 2.0.0-rc27.3 → 2.0.0-rc27.3.1
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/Runtime/Core/MessageBus/MessageBus.cs +13 -0
- package/Runtime/Core/MessageHandler.cs +27 -33
- package/Runtime/Core/MessageRegistrationToken.cs +12 -21
- package/Runtime/Unity/MessageAwareComponent.cs +6 -0
- package/Runtime/Unity/MessagingComponent.cs +24 -0
- package/Tests/Runtime/Core/MessagingComponentLifecycleTests.cs +89 -0
- package/Tests/Runtime/Core/MessagingComponentLifecycleTests.cs.meta +11 -0
- package/Tests/Runtime/Core/ReflexiveMessageWarningTests.cs +86 -0
- package/Tests/Runtime/Core/ReflexiveMessageWarningTests.cs.meta +11 -0
- package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs +116 -0
- package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs.meta +11 -0
- package/Tests/Runtime/Scripts/Components/ReflexiveReceiverComponent.cs +14 -0
- package/Tests/Runtime/Scripts/Components/ReflexiveReceiverComponent.cs.meta +11 -0
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
7
7
|
using System.Runtime.CompilerServices;
|
|
8
8
|
using DataStructure;
|
|
9
9
|
using Diagnostics;
|
|
10
|
+
using DxMessaging.Core;
|
|
10
11
|
using Extensions;
|
|
11
12
|
using Helper;
|
|
12
13
|
using Messages;
|
|
@@ -177,6 +178,7 @@ namespace DxMessaging.Core.MessageBus
|
|
|
177
178
|
);
|
|
178
179
|
|
|
179
180
|
private bool _diagnosticsMode = GlobalDiagnosticsMode;
|
|
181
|
+
private bool _loggedReflexiveWarning;
|
|
180
182
|
|
|
181
183
|
public Action RegisterUntargeted<T>(MessageHandler messageHandler, int priority = 0)
|
|
182
184
|
where T : IUntargetedMessage
|
|
@@ -1131,6 +1133,17 @@ namespace DxMessaging.Core.MessageBus
|
|
|
1131
1133
|
|
|
1132
1134
|
if (typeof(TMessage) == typeof(ReflexiveMessage))
|
|
1133
1135
|
{
|
|
1136
|
+
if (!_loggedReflexiveWarning)
|
|
1137
|
+
{
|
|
1138
|
+
_loggedReflexiveWarning = true;
|
|
1139
|
+
if (MessagingDebug.enabled)
|
|
1140
|
+
{
|
|
1141
|
+
MessagingDebug.Log(
|
|
1142
|
+
LogLevel.Warn,
|
|
1143
|
+
"ReflexiveMessage dispatch traverses the Unity hierarchy and is significantly slower than typed messages. Prefer targeted or broadcast messages where possible."
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1134
1147
|
#if UNITY_2017_1_OR_NEWER
|
|
1135
1148
|
ref ReflexiveMessage reflexiveMessage = ref Unsafe.As<TMessage, ReflexiveMessage>(
|
|
1136
1149
|
ref typedMessage
|
|
@@ -1782,6 +1782,7 @@ namespace DxMessaging.Core
|
|
|
1782
1782
|
public long version;
|
|
1783
1783
|
public long lastSeenVersion = -1;
|
|
1784
1784
|
public long lastSeenEmissionId;
|
|
1785
|
+
internal int prefreezeInvocationCount;
|
|
1785
1786
|
}
|
|
1786
1787
|
|
|
1787
1788
|
/// <summary>
|
|
@@ -1895,39 +1896,16 @@ namespace DxMessaging.Core
|
|
|
1895
1896
|
/// <param name="priority">Priority at which to run the handlers.</param>
|
|
1896
1897
|
public void HandleUntargeted(ref T message, int priority, long emissionId)
|
|
1897
1898
|
{
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
)
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
&& _untargetedPostProcessingHandlers.TryGetValue(priority, out var up)
|
|
1909
|
-
)
|
|
1910
|
-
{
|
|
1911
|
-
_ = GetOrAddNewHandlerStack(up, emissionId);
|
|
1912
|
-
}
|
|
1913
|
-
// Pre-freeze post-processors for this emission/priority
|
|
1914
|
-
if (
|
|
1915
|
-
_untargetedPostProcessingFastHandlers != null
|
|
1916
|
-
&& _untargetedPostProcessingFastHandlers.TryGetValue(
|
|
1917
|
-
priority,
|
|
1918
|
-
out var fastCache
|
|
1919
|
-
)
|
|
1920
|
-
)
|
|
1921
|
-
{
|
|
1922
|
-
_ = GetOrAddNewHandlerStack(fastCache, emissionId);
|
|
1923
|
-
}
|
|
1924
|
-
if (
|
|
1925
|
-
_untargetedPostProcessingHandlers != null
|
|
1926
|
-
&& _untargetedPostProcessingHandlers.TryGetValue(priority, out var cache)
|
|
1927
|
-
)
|
|
1928
|
-
{
|
|
1929
|
-
_ = GetOrAddNewHandlerStack(cache, emissionId);
|
|
1930
|
-
}
|
|
1899
|
+
PrefreezeHandlersForEmission(
|
|
1900
|
+
_untargetedPostProcessingFastHandlers,
|
|
1901
|
+
priority,
|
|
1902
|
+
emissionId
|
|
1903
|
+
);
|
|
1904
|
+
PrefreezeHandlersForEmission(
|
|
1905
|
+
_untargetedPostProcessingHandlers,
|
|
1906
|
+
priority,
|
|
1907
|
+
emissionId
|
|
1908
|
+
);
|
|
1931
1909
|
|
|
1932
1910
|
RunFastHandlers(_untargetedFastHandlers, ref message, priority, emissionId);
|
|
1933
1911
|
RunHandlers(_untargetedHandlers, ref message, priority, emissionId);
|
|
@@ -3535,6 +3513,22 @@ namespace DxMessaging.Core
|
|
|
3535
3513
|
return actionCache.cache;
|
|
3536
3514
|
}
|
|
3537
3515
|
|
|
3516
|
+
private static void PrefreezeHandlersForEmission<THandler>(
|
|
3517
|
+
Dictionary<int, HandlerActionCache<THandler>> handlers,
|
|
3518
|
+
int priority,
|
|
3519
|
+
long emissionId
|
|
3520
|
+
)
|
|
3521
|
+
{
|
|
3522
|
+
if (
|
|
3523
|
+
handlers != null
|
|
3524
|
+
&& handlers.TryGetValue(priority, out HandlerActionCache<THandler> cache)
|
|
3525
|
+
)
|
|
3526
|
+
{
|
|
3527
|
+
cache.prefreezeInvocationCount++;
|
|
3528
|
+
_ = GetOrAddNewHandlerStack(cache, emissionId);
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
|
|
3538
3532
|
private static Action AddHandler<TU>(
|
|
3539
3533
|
InstanceId context,
|
|
3540
3534
|
ref Dictionary<
|
|
@@ -59,6 +59,7 @@ namespace DxMessaging.Core
|
|
|
59
59
|
|
|
60
60
|
private readonly Dictionary<MessageRegistrationHandle, Action> _registrations = new();
|
|
61
61
|
private readonly Dictionary<MessageRegistrationHandle, Action> _deregistrations = new();
|
|
62
|
+
private readonly List<Action> _deregistrationQueue = new();
|
|
62
63
|
internal readonly Dictionary<
|
|
63
64
|
MessageRegistrationHandle,
|
|
64
65
|
MessageRegistrationMetadata
|
|
@@ -1878,13 +1879,11 @@ namespace DxMessaging.Core
|
|
|
1878
1879
|
|
|
1879
1880
|
if (_deregistrations is { Count: > 0 })
|
|
1880
1881
|
{
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
>.ValueCollection.Enumerator enumerator = _deregistrations.Values.GetEnumerator();
|
|
1885
|
-
while (enumerator.MoveNext())
|
|
1882
|
+
_deregistrationQueue.Clear();
|
|
1883
|
+
_deregistrationQueue.AddRange(_deregistrations.Values);
|
|
1884
|
+
foreach (Action deregistration in _deregistrationQueue)
|
|
1886
1885
|
{
|
|
1887
|
-
|
|
1886
|
+
deregistration?.Invoke();
|
|
1888
1887
|
}
|
|
1889
1888
|
}
|
|
1890
1889
|
|
|
@@ -1905,15 +1904,13 @@ namespace DxMessaging.Core
|
|
|
1905
1904
|
/// </example>
|
|
1906
1905
|
public void UnregisterAll()
|
|
1907
1906
|
{
|
|
1908
|
-
if (
|
|
1907
|
+
if (_deregistrations is { Count: > 0 })
|
|
1909
1908
|
{
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
>.ValueCollection.Enumerator enumerator = _deregistrations.Values.GetEnumerator();
|
|
1914
|
-
while (enumerator.MoveNext())
|
|
1909
|
+
_deregistrationQueue.Clear();
|
|
1910
|
+
_deregistrationQueue.AddRange(_deregistrations.Values);
|
|
1911
|
+
foreach (Action deregistration in _deregistrationQueue)
|
|
1915
1912
|
{
|
|
1916
|
-
|
|
1913
|
+
deregistration?.Invoke();
|
|
1917
1914
|
}
|
|
1918
1915
|
}
|
|
1919
1916
|
|
|
@@ -1934,16 +1931,10 @@ namespace DxMessaging.Core
|
|
|
1934
1931
|
/// </example>
|
|
1935
1932
|
public void RemoveRegistration(MessageRegistrationHandle handle)
|
|
1936
1933
|
{
|
|
1937
|
-
if (
|
|
1938
|
-
_deregistrations != null
|
|
1939
|
-
&& _deregistrations.TryGetValue(handle, out Action deregistrationAction)
|
|
1940
|
-
)
|
|
1934
|
+
if (_deregistrations?.Remove(handle, out Action deregistrationAction) == true)
|
|
1941
1935
|
{
|
|
1942
|
-
deregistrationAction();
|
|
1943
|
-
_ = _deregistrations.Remove(handle);
|
|
1936
|
+
deregistrationAction?.Invoke();
|
|
1944
1937
|
}
|
|
1945
|
-
|
|
1946
|
-
_ = _registrations?.Remove(handle);
|
|
1947
1938
|
}
|
|
1948
1939
|
|
|
1949
1940
|
/// <summary>
|
|
@@ -124,8 +124,14 @@ namespace DxMessaging.Unity
|
|
|
124
124
|
/// </summary>
|
|
125
125
|
protected virtual void OnDestroy()
|
|
126
126
|
{
|
|
127
|
+
if (_messagingComponent != null)
|
|
128
|
+
{
|
|
129
|
+
_messagingComponent.Release(this);
|
|
130
|
+
}
|
|
131
|
+
|
|
127
132
|
_messageRegistrationToken?.Disable();
|
|
128
133
|
_messageRegistrationToken = null;
|
|
134
|
+
_messagingComponent = null;
|
|
129
135
|
}
|
|
130
136
|
|
|
131
137
|
/// <summary>
|
|
@@ -73,6 +73,30 @@ namespace DxMessaging.Unity
|
|
|
73
73
|
return createdToken;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/// <summary>
|
|
77
|
+
/// Releases the registration token previously created for <paramref name="listener"/>.
|
|
78
|
+
/// </summary>
|
|
79
|
+
/// <param name="listener">Listener whose token should be released.</param>
|
|
80
|
+
/// <remarks>
|
|
81
|
+
/// Invokes <see cref="MessageRegistrationToken.Disable"/> and removes the listener from the internal cache.
|
|
82
|
+
/// Safe to call multiple times.
|
|
83
|
+
/// </remarks>
|
|
84
|
+
public bool Release(MonoBehaviour listener)
|
|
85
|
+
{
|
|
86
|
+
if (listener is null)
|
|
87
|
+
{
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (_registeredListeners.Remove(listener, out MessageRegistrationToken token))
|
|
92
|
+
{
|
|
93
|
+
token?.Disable();
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
76
100
|
/// <summary>
|
|
77
101
|
/// Ensures the underlying <see cref="Core.MessageHandler"/> exists.
|
|
78
102
|
/// </summary>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
namespace DxMessaging.Tests.Runtime.Core
|
|
2
|
+
{
|
|
3
|
+
using System.Collections;
|
|
4
|
+
using DxMessaging.Core;
|
|
5
|
+
using DxMessaging.Tests.Runtime.Scripts.Components;
|
|
6
|
+
using DxMessaging.Unity;
|
|
7
|
+
using NUnit.Framework;
|
|
8
|
+
using UnityEngine;
|
|
9
|
+
using UnityEngine.TestTools;
|
|
10
|
+
|
|
11
|
+
public sealed class MessagingComponentLifecycleTests : MessagingTestBase
|
|
12
|
+
{
|
|
13
|
+
[UnityTest]
|
|
14
|
+
public IEnumerator ReleasesListenerOnDestroy()
|
|
15
|
+
{
|
|
16
|
+
GameObject go = new(
|
|
17
|
+
"Lifecycle",
|
|
18
|
+
typeof(MessagingComponent),
|
|
19
|
+
typeof(SimpleMessageAwareComponent)
|
|
20
|
+
);
|
|
21
|
+
_spawned.Add(go);
|
|
22
|
+
|
|
23
|
+
MessagingComponent messaging = go.GetComponent<MessagingComponent>();
|
|
24
|
+
SimpleMessageAwareComponent listener = go.GetComponent<SimpleMessageAwareComponent>();
|
|
25
|
+
|
|
26
|
+
yield return null;
|
|
27
|
+
|
|
28
|
+
Assert.AreEqual(
|
|
29
|
+
1,
|
|
30
|
+
messaging._registeredListeners.Count,
|
|
31
|
+
"Expected initial listener registration."
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
Object.Destroy(listener);
|
|
35
|
+
yield return null;
|
|
36
|
+
|
|
37
|
+
Assert.AreEqual(
|
|
38
|
+
0,
|
|
39
|
+
messaging._registeredListeners.Count,
|
|
40
|
+
"Listener dictionary should be cleared after destroy."
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
SimpleMessageAwareComponent replacement =
|
|
44
|
+
go.AddComponent<SimpleMessageAwareComponent>();
|
|
45
|
+
yield return null;
|
|
46
|
+
|
|
47
|
+
Assert.AreEqual(
|
|
48
|
+
1,
|
|
49
|
+
messaging._registeredListeners.Count,
|
|
50
|
+
"Replacement listener should be tracked."
|
|
51
|
+
);
|
|
52
|
+
Assert.IsTrue(messaging._registeredListeners.ContainsKey(replacement));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
[UnityTest]
|
|
56
|
+
public IEnumerator ManualReleaseRemovesListenerAndDisablesToken()
|
|
57
|
+
{
|
|
58
|
+
GameObject go = new(
|
|
59
|
+
"ManualRelease",
|
|
60
|
+
typeof(MessagingComponent),
|
|
61
|
+
typeof(ManualListenerComponent)
|
|
62
|
+
);
|
|
63
|
+
_spawned.Add(go);
|
|
64
|
+
|
|
65
|
+
MessagingComponent messaging = go.GetComponent<MessagingComponent>();
|
|
66
|
+
ManualListenerComponent listener = go.GetComponent<ManualListenerComponent>();
|
|
67
|
+
|
|
68
|
+
MessageRegistrationToken token = listener.RequestToken(messaging);
|
|
69
|
+
Assert.AreEqual(
|
|
70
|
+
1,
|
|
71
|
+
messaging._registeredListeners.Count,
|
|
72
|
+
"Token request should register listener."
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
token.Enable();
|
|
76
|
+
Assert.IsTrue(token.Enabled, "Token should enable successfully.");
|
|
77
|
+
|
|
78
|
+
messaging.Release(listener);
|
|
79
|
+
yield return null;
|
|
80
|
+
|
|
81
|
+
Assert.AreEqual(
|
|
82
|
+
0,
|
|
83
|
+
messaging._registeredListeners.Count,
|
|
84
|
+
"Manual release should remove listener."
|
|
85
|
+
);
|
|
86
|
+
Assert.IsFalse(token.Enabled, "Released token should be disabled.");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
namespace DxMessaging.Tests.Runtime.Core
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections;
|
|
5
|
+
using System.Collections.Generic;
|
|
6
|
+
using System.Linq;
|
|
7
|
+
using DxMessaging.Core;
|
|
8
|
+
using DxMessaging.Core.MessageBus;
|
|
9
|
+
using DxMessaging.Core.Messages;
|
|
10
|
+
using DxMessaging.Tests.Runtime.Scripts.Components;
|
|
11
|
+
using NUnit.Framework;
|
|
12
|
+
using UnityEngine;
|
|
13
|
+
using UnityEngine.TestTools;
|
|
14
|
+
|
|
15
|
+
public sealed class ReflexiveMessageWarningTests : MessagingTestBase
|
|
16
|
+
{
|
|
17
|
+
[UnityTest]
|
|
18
|
+
public IEnumerator LogsWarningOncePerBus()
|
|
19
|
+
{
|
|
20
|
+
List<(LogLevel level, string message)> logs = new();
|
|
21
|
+
var previousLogFunction = MessagingDebug.LogFunction;
|
|
22
|
+
try
|
|
23
|
+
{
|
|
24
|
+
MessagingDebug.LogFunction = (level, message) => logs.Add((level, message));
|
|
25
|
+
MessagingDebug.enabled = true;
|
|
26
|
+
logs.Clear();
|
|
27
|
+
|
|
28
|
+
GameObject go = new("ReflexiveReceiver", typeof(ReflexiveReceiverComponent));
|
|
29
|
+
_spawned.Add(go);
|
|
30
|
+
ReflexiveReceiverComponent receiver = go.GetComponent<ReflexiveReceiverComponent>();
|
|
31
|
+
|
|
32
|
+
MessageBus bus = new();
|
|
33
|
+
ReflexiveMessage message = new("OnReflexive", ReflexiveSendMode.Flat);
|
|
34
|
+
|
|
35
|
+
int warningsBefore = CountWarnings(logs);
|
|
36
|
+
InstanceId target = receiver;
|
|
37
|
+
bus.TargetedBroadcast(ref target, ref message);
|
|
38
|
+
Assert.AreEqual(1, receiver.InvocationCount);
|
|
39
|
+
int warningsAfter = CountWarnings(logs);
|
|
40
|
+
Assert.Greater(
|
|
41
|
+
warningsAfter,
|
|
42
|
+
warningsBefore,
|
|
43
|
+
"First reflexive dispatch should log a warning."
|
|
44
|
+
);
|
|
45
|
+
StringAssert.Contains("ReflexiveMessage", logs[^1].message);
|
|
46
|
+
|
|
47
|
+
warningsBefore = warningsAfter;
|
|
48
|
+
target = receiver;
|
|
49
|
+
bus.TargetedBroadcast(ref target, ref message);
|
|
50
|
+
Assert.AreEqual(2, receiver.InvocationCount);
|
|
51
|
+
warningsAfter = CountWarnings(logs);
|
|
52
|
+
Assert.AreEqual(
|
|
53
|
+
warningsBefore,
|
|
54
|
+
warningsAfter,
|
|
55
|
+
"Second dispatch on the same bus should not emit additional warnings."
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
MessageBus secondBus = new();
|
|
59
|
+
warningsBefore = warningsAfter;
|
|
60
|
+
target = receiver;
|
|
61
|
+
secondBus.TargetedBroadcast(ref target, ref message);
|
|
62
|
+
Assert.AreEqual(3, receiver.InvocationCount);
|
|
63
|
+
warningsAfter = CountWarnings(logs);
|
|
64
|
+
Assert.AreEqual(
|
|
65
|
+
warningsBefore + 1,
|
|
66
|
+
warningsAfter,
|
|
67
|
+
"A new bus should emit its own warning."
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
finally
|
|
71
|
+
{
|
|
72
|
+
MessagingDebug.LogFunction = previousLogFunction;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
yield break;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private static int CountWarnings(List<(LogLevel level, string message)> logs)
|
|
79
|
+
{
|
|
80
|
+
return logs.Count(entry =>
|
|
81
|
+
entry.level == LogLevel.Warn
|
|
82
|
+
&& entry.message.IndexOf("ReflexiveMessage dispatch", StringComparison.Ordinal) >= 0
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
namespace DxMessaging.Tests.Runtime.Core
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
using System.Reflection;
|
|
6
|
+
using DxMessaging.Core;
|
|
7
|
+
using DxMessaging.Core.Helper;
|
|
8
|
+
using DxMessaging.Core.MessageBus;
|
|
9
|
+
using DxMessaging.Tests.Runtime.Scripts.Messages;
|
|
10
|
+
using NUnit.Framework;
|
|
11
|
+
|
|
12
|
+
public sealed class UntargetedPrefreezeTests
|
|
13
|
+
{
|
|
14
|
+
[Test]
|
|
15
|
+
public void PrefreezeRunsOncePerEmission()
|
|
16
|
+
{
|
|
17
|
+
MessageHandler handler = new(new InstanceId(123)) { active = true };
|
|
18
|
+
MessageBus messageBus = new();
|
|
19
|
+
MessageRegistrationToken token = MessageRegistrationToken.Create(handler, messageBus);
|
|
20
|
+
|
|
21
|
+
int postProcessCount = 0;
|
|
22
|
+
_ = token.RegisterUntargeted<SimpleUntargetedMessage>(
|
|
23
|
+
(ref SimpleUntargetedMessage _) => { }
|
|
24
|
+
);
|
|
25
|
+
_ = token.RegisterUntargetedPostProcessor<SimpleUntargetedMessage>(
|
|
26
|
+
(ref SimpleUntargetedMessage _) => postProcessCount++,
|
|
27
|
+
priority: 0
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
token.Enable();
|
|
31
|
+
|
|
32
|
+
object cache = GetUntargetedPostProcessingFastCache(
|
|
33
|
+
handler,
|
|
34
|
+
messageBus,
|
|
35
|
+
typeof(SimpleUntargetedMessage),
|
|
36
|
+
priority: 0
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
SimpleUntargetedMessage message = new();
|
|
40
|
+
messageBus.UntargetedBroadcast(ref message);
|
|
41
|
+
Assert.AreEqual(1, postProcessCount);
|
|
42
|
+
Assert.AreEqual(1, GetPrefreezeInvocationCount(cache));
|
|
43
|
+
|
|
44
|
+
messageBus.UntargetedBroadcast(ref message);
|
|
45
|
+
Assert.AreEqual(2, postProcessCount);
|
|
46
|
+
Assert.AreEqual(2, GetPrefreezeInvocationCount(cache));
|
|
47
|
+
|
|
48
|
+
token.Disable();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private static object GetUntargetedPostProcessingFastCache(
|
|
52
|
+
MessageHandler handler,
|
|
53
|
+
MessageBus messageBus,
|
|
54
|
+
Type messageType,
|
|
55
|
+
int priority
|
|
56
|
+
)
|
|
57
|
+
{
|
|
58
|
+
FieldInfo handlersField = typeof(MessageHandler).GetField(
|
|
59
|
+
"_handlersByTypeByMessageBus",
|
|
60
|
+
BindingFlags.NonPublic | BindingFlags.Instance
|
|
61
|
+
);
|
|
62
|
+
Assert.IsNotNull(handlersField);
|
|
63
|
+
var handlersByBus = (List<MessageCache<object>>)handlersField.GetValue(handler);
|
|
64
|
+
Assert.IsNotNull(handlersByBus);
|
|
65
|
+
|
|
66
|
+
MessageCache<object> cacheByType = handlersByBus[
|
|
67
|
+
messageBus.RegisteredGlobalSequentialIndex
|
|
68
|
+
];
|
|
69
|
+
MethodInfo getOrAddMethod = typeof(MessageCache<object>)
|
|
70
|
+
.GetMethod(nameof(MessageCache<object>.GetOrAdd))
|
|
71
|
+
?.MakeGenericMethod(messageType);
|
|
72
|
+
Assert.IsNotNull(getOrAddMethod);
|
|
73
|
+
|
|
74
|
+
object typedHandler = getOrAddMethod.Invoke(cacheByType, null);
|
|
75
|
+
Assert.IsNotNull(typedHandler);
|
|
76
|
+
|
|
77
|
+
FieldInfo fastHandlersField = typedHandler
|
|
78
|
+
.GetType()
|
|
79
|
+
.GetField(
|
|
80
|
+
"_untargetedPostProcessingFastHandlers",
|
|
81
|
+
BindingFlags.NonPublic | BindingFlags.Instance
|
|
82
|
+
);
|
|
83
|
+
Assert.IsNotNull(fastHandlersField);
|
|
84
|
+
|
|
85
|
+
object fastHandlers = fastHandlersField.GetValue(typedHandler);
|
|
86
|
+
Assert.IsNotNull(fastHandlers);
|
|
87
|
+
|
|
88
|
+
return GetDictionaryValue(fastHandlers, priority);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private static object GetDictionaryValue(object dictionary, int key)
|
|
92
|
+
{
|
|
93
|
+
MethodInfo tryGetValue = dictionary
|
|
94
|
+
.GetType()
|
|
95
|
+
.GetMethod("TryGetValue", BindingFlags.Public | BindingFlags.Instance);
|
|
96
|
+
Assert.IsNotNull(tryGetValue);
|
|
97
|
+
|
|
98
|
+
object[] args = { key, null };
|
|
99
|
+
bool found = (bool)tryGetValue.Invoke(dictionary, args);
|
|
100
|
+
Assert.IsTrue(found, $"Failed to locate cache for priority {key}.");
|
|
101
|
+
return args[1];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private static int GetPrefreezeInvocationCount(object handlerCache)
|
|
105
|
+
{
|
|
106
|
+
FieldInfo countField = handlerCache
|
|
107
|
+
.GetType()
|
|
108
|
+
.GetField(
|
|
109
|
+
"prefreezeInvocationCount",
|
|
110
|
+
BindingFlags.NonPublic | BindingFlags.Instance
|
|
111
|
+
);
|
|
112
|
+
Assert.IsNotNull(countField);
|
|
113
|
+
return (int)countField.GetValue(handlerCache);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
namespace DxMessaging.Tests.Runtime.Scripts.Components
|
|
2
|
+
{
|
|
3
|
+
using UnityEngine;
|
|
4
|
+
|
|
5
|
+
public sealed class ReflexiveReceiverComponent : MonoBehaviour
|
|
6
|
+
{
|
|
7
|
+
public int InvocationCount { get; private set; }
|
|
8
|
+
|
|
9
|
+
public void OnReflexive()
|
|
10
|
+
{
|
|
11
|
+
InvocationCount++;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|