com.wallstop-studios.dxmessaging 2.0.0-rc27.3.1 → 2.1.0
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/.github/workflows/format-on-demand.yml +2 -2
- package/.github/workflows/json-format-check.yml +1 -1
- package/.github/workflows/markdown-json.yml +1 -1
- package/.github/workflows/markdownlint.yml +1 -1
- package/.github/workflows/npm-publish.yml +1 -1
- package/.github/workflows/prettier-autofix.yml +2 -2
- package/.github/workflows/yaml-format-lint.yml +1 -1
- package/Docs/Advanced.md +26 -1
- package/Docs/Comparisons.md +1352 -141
- package/Docs/Compatibility.md +27 -0
- package/Docs/DesignAndArchitecture.md +41 -34
- package/Docs/EmitShorthands.md +34 -0
- package/Docs/GettingStarted.md +84 -17
- package/Docs/Helpers.md +1 -1
- package/Docs/Index.md +28 -25
- package/Docs/Install.md +29 -6
- package/Docs/Integrations/Reflex.md +292 -0
- package/Docs/Integrations/Reflex.md.meta +7 -0
- package/Docs/Integrations/VContainer.md +324 -0
- package/Docs/Integrations/VContainer.md.meta +7 -0
- package/Docs/Integrations/Zenject.md +333 -0
- package/Docs/Integrations/Zenject.md.meta +7 -0
- package/{Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.pdb.meta → Docs/Integrations.meta} +2 -1
- package/Docs/InterceptorsAndOrdering.md +371 -17
- package/Docs/ListeningPatterns.md +206 -0
- package/Docs/MessageBusProviders.md +496 -0
- package/Docs/MessageBusProviders.md.meta +7 -0
- package/Docs/MessageTypes.md +27 -0
- package/Docs/MigrationGuide.md +45 -0
- package/Docs/Overview.md +114 -20
- package/Docs/Patterns.md +327 -2
- package/Docs/Performance.md +9 -9
- package/Docs/QuickReference.md +31 -0
- package/Docs/RuntimeConfiguration.md +407 -0
- package/Docs/RuntimeConfiguration.md.meta +7 -0
- package/Docs/UnityIntegration.md +3 -1
- package/Docs/VisualGuide.md +281 -167
- package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll +0 -0
- package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +3 -3
- package/Editor/Analyzers/Microsoft.CodeAnalysis.dll +0 -0
- package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +2 -2
- package/Editor/Analyzers/System.Collections.Immutable.dll +0 -0
- package/Editor/Analyzers/System.Reflection.Metadata.dll +0 -0
- package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll +0 -0
- package/Editor/CustomEditors/MessagingComponentEditor.cs +15 -6
- package/README.md +388 -67
- package/Runtime/AssemblyInfo.cs +4 -0
- package/Runtime/Core/Extensions/MessageBusExtensions.cs +253 -0
- package/Runtime/Core/Extensions/MessageBusExtensions.cs.meta +12 -0
- package/Runtime/Core/Extensions/MessageExtensions.cs +137 -89
- package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs +23 -0
- package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +11 -0
- package/Runtime/Core/MessageBus/IMessageBusProvider.cs +14 -0
- package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +11 -0
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs +18 -0
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +11 -0
- package/Runtime/Core/MessageBus/MessageBusRebindMode.cs +26 -0
- package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +11 -0
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +383 -0
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +11 -0
- package/Runtime/Core/MessageHandler.cs +198 -27
- package/Runtime/Core/MessageRegistrationToken.cs +67 -25
- package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs +31 -0
- package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs.meta +12 -0
- package/Runtime/Unity/InitialGlobalMessageBusProvider.cs +38 -0
- package/Runtime/Unity/InitialGlobalMessageBusProvider.cs.meta +12 -0
- package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs +11 -0
- package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs +73 -0
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs.meta +11 -0
- package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef +20 -0
- package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef.meta +7 -0
- package/Runtime/Unity/Integrations/Reflex.meta +8 -0
- package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs +11 -0
- package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs +46 -0
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs.meta +11 -0
- package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef +30 -0
- package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef.meta +7 -0
- package/Runtime/Unity/Integrations/VContainer.meta +8 -0
- package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs +11 -0
- package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef +30 -0
- package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef.meta +7 -0
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs +55 -0
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs.meta +11 -0
- package/Runtime/Unity/Integrations/Zenject.meta +8 -0
- package/Runtime/Unity/Integrations.meta +8 -0
- package/Runtime/Unity/MessageAwareComponent.cs +102 -0
- package/Runtime/Unity/MessageBusProviderHandle.cs +97 -0
- package/Runtime/Unity/MessageBusProviderHandle.cs.meta +12 -0
- package/Runtime/Unity/MessagingComponent.cs +164 -2
- package/Runtime/Unity/MessagingComponentInstaller.cs +120 -0
- package/Runtime/Unity/MessagingComponentInstaller.cs.meta +12 -0
- package/Runtime/Unity/ScriptableMessageBusProvider.cs +14 -0
- package/Runtime/Unity/ScriptableMessageBusProvider.cs.meta +12 -0
- package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab +98 -0
- package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab.meta +7 -0
- package/Samples~/DI/Prefabs.meta +8 -0
- package/Samples~/DI/Providers/GlobalMessageBusProvider.asset +14 -0
- package/Samples~/DI/Providers/GlobalMessageBusProvider.asset.meta +8 -0
- package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset +14 -0
- package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset.meta +8 -0
- package/Samples~/DI/Providers.meta +8 -0
- package/Samples~/DI/README.md +51 -0
- package/Samples~/DI/README.md.meta +7 -0
- package/Samples~/DI/Reflex/SampleInstaller.cs +75 -0
- package/Samples~/DI/Reflex/SampleInstaller.cs.meta +11 -0
- package/Samples~/DI/Reflex.meta +8 -0
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs +81 -0
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +11 -0
- package/Samples~/DI/VContainer.meta +8 -0
- package/Samples~/DI/Zenject/SampleInstaller.cs +67 -0
- package/Samples~/DI/Zenject/SampleInstaller.cs.meta +11 -0
- package/Samples~/DI/Zenject.meta +8 -0
- package/Samples~/DI.meta +8 -0
- package/Samples~/Mini Combat/README.md +86 -28
- package/Samples~/Mini Combat/Walkthrough.md +41 -25
- package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs +12 -2
- package/Samples~/UI Buttons + Inspector/README.md +55 -12
- package/Samples~/UI Buttons + Inspector/README.md.meta +7 -0
- package/Tests/Runtime/Benchmarks/BenchmarkSession.cs +444 -0
- package/Tests/Runtime/Benchmarks/BenchmarkSession.cs.meta +11 -0
- package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs +94 -0
- package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs.meta +11 -0
- package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs +395 -0
- package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs.meta +11 -0
- package/Tests/Runtime/Benchmarks/PerformanceTests.cs +77 -429
- package/Tests/Runtime/Benchmarks/ProviderResolutionBenchmarks.cs +142 -0
- package/Tests/Runtime/Benchmarks/ProviderResolutionBenchmarks.cs.meta +12 -0
- package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef +50 -0
- package/Tests/Runtime/Benchmarks/WallstopStudios.DxMessaging.Tests.Runtime.Benchmarks.asmdef.meta +7 -0
- package/Tests/Runtime/Core/DefaultBusFallbackTests.cs +333 -0
- package/Tests/Runtime/Core/DefaultBusFallbackTests.cs.meta +11 -0
- package/Tests/Runtime/Core/Extensions/MessageBusExtensionsTests.cs +278 -0
- package/Tests/Runtime/Core/Extensions/MessageBusExtensionsTests.cs.meta +11 -0
- package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs +289 -0
- package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs.meta +11 -0
- package/Tests/Runtime/Core/Extensions.meta +8 -0
- package/Tests/Runtime/Core/IntegrationShimSmokeTests.cs +57 -0
- package/Tests/Runtime/Core/IntegrationShimSmokeTests.cs.meta +11 -0
- package/Tests/Runtime/Core/MessageHandlerGlobalBusTests.cs +219 -0
- package/Tests/Runtime/Core/MessageHandlerGlobalBusTests.cs.meta +11 -0
- package/Tests/Runtime/Core/MessageRegistrationBuilderTests.cs +204 -0
- package/Tests/Runtime/Core/MessageRegistrationBuilderTests.cs.meta +11 -0
- package/Tests/Runtime/Core/MessagingTestBase.cs +4 -4
- package/Tests/Runtime/Core/NominalTests.cs +2 -2
- package/Tests/Runtime/Core/SourceGeneratorNestedTests.cs +1 -1
- package/Tests/Runtime/Core/TypedShorthandTests.cs +2 -2
- package/Tests/Runtime/Core/UntargetedEquivalenceTests.cs +1 -1
- package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs +2 -4
- package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs +162 -0
- package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs.meta +11 -0
- package/Tests/Runtime/Integrations/Reflex/Resources/ReflexSettings.asset +16 -0
- package/Tests/Runtime/Integrations/Reflex/Resources/ReflexSettings.asset.meta +8 -0
- package/Tests/Runtime/Integrations/Reflex/Resources.meta +8 -0
- package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef +27 -0
- package/Tests/Runtime/Integrations/Reflex/WallstopStudios.DxMessaging.Tests.Runtime.Reflex.asmdef.meta +7 -0
- package/Tests/Runtime/Integrations/Reflex.meta +8 -0
- package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs +140 -0
- package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs.meta +11 -0
- package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef +37 -0
- package/Tests/Runtime/Integrations/VContainer/WallstopStudios.DxMessaging.Tests.Runtime.VContainer.asmdef.meta +7 -0
- package/Tests/Runtime/Integrations/VContainer.meta +8 -0
- package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef +37 -0
- package/Tests/Runtime/Integrations/Zenject/WallstopStudios.DxMessaging.Tests.Runtime.Zenject.asmdef.meta +7 -0
- package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs +140 -0
- package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs.meta +11 -0
- package/Tests/Runtime/Integrations/Zenject.meta +8 -0
- package/Tests/Runtime/Integrations.meta +8 -0
- package/Tests/Runtime/Scripts/Components/EmptyMessageAwareComponent.cs +1 -1
- package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs +1 -1
- package/Tests/Runtime/Scripts/Components/SimpleMessageAwareComponent.cs +1 -1
- package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs +64 -0
- package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs.meta +12 -0
- package/Tests/Runtime/TestUtilities.meta +9 -0
- package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs +57 -0
- package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs.meta +11 -0
- package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs +107 -0
- package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs.meta +12 -0
- package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs +210 -0
- package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs.meta +12 -0
- package/Tests/Runtime/Unity.meta +9 -0
- package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.asmdef +3 -1
- package/package.json +1 -1
package/Docs/Overview.md
CHANGED
|
@@ -4,22 +4,89 @@
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
DxMessaging is a high
|
|
7
|
+
DxMessaging is a high-performance, type-safe messaging system for Unity that **eliminates the three biggest pain points** of traditional event systems:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
1. **Memory leaks** from forgotten unsubscribes → Automatic lifecycle management
|
|
10
|
+
1. **Tight coupling** creating refactoring nightmares → Full decoupling with no direct references
|
|
11
|
+
1. **Debugging black holes** ("what fired when?") → Built-in Inspector diagnostics
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
- Predictable lifecycle: explicit registration tokens that you enable/disable with Unity components.
|
|
13
|
-
- Ergonomics and performance: struct‑friendly APIs, by‑ref handlers, zero‑boxing patterns.
|
|
14
|
-
- Observability: interceptors, post‑processors, diagnostics buffers, and registration logs.
|
|
15
|
-
- Scalable message taxonomy: Untargeted, Targeted, and Broadcast messages fit most gameplay/UI flows.
|
|
13
|
+
## What Problems Does It Solve?
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
### For Beginners: "I'm calling methods manually everywhere"
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
#### Your code probably looks like this
|
|
18
|
+
|
|
19
|
+
```csharp
|
|
20
|
+
public class Player : MonoBehaviour {
|
|
21
|
+
public HealthBar healthBar;
|
|
22
|
+
public AudioManager audio;
|
|
23
|
+
public AchievementSystem achievements;
|
|
24
|
+
|
|
25
|
+
void TakeDamage(int amount) {
|
|
26
|
+
health -= amount;
|
|
27
|
+
healthBar.UpdateHealth(health); // Manual call
|
|
28
|
+
audio.PlayDamageSound(); // Manual call
|
|
29
|
+
achievements.CheckDamage(amount); // Manual call
|
|
30
|
+
// Add analytics? More manual calls...
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Every new system = another SerializeField + another manual call.** It's exhausting and brittle.
|
|
36
|
+
|
|
37
|
+
##### DxMessaging fixes this
|
|
38
|
+
|
|
39
|
+
```csharp
|
|
40
|
+
void TakeDamage(int amount) {
|
|
41
|
+
health -= amount;
|
|
42
|
+
new TookDamage(amount).EmitComponentBroadcast(this);
|
|
43
|
+
// Done! Everything else reacts automatically.
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### For Intermediate Devs: "I use C# events but they leak"
|
|
48
|
+
|
|
49
|
+
#### You know this pain
|
|
50
|
+
|
|
51
|
+
```csharp
|
|
52
|
+
void OnEnable() { GameManager.OnScoreChanged += UpdateUI; }
|
|
53
|
+
void OnDisable() { /* Forgot this? 💀 LEAK! */ }
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**DxMessaging makes leaks impossible** - automatic cleanup when components die.
|
|
57
|
+
|
|
58
|
+
### For Advanced Devs: "I need observability and control"
|
|
59
|
+
|
|
60
|
+
- ✅ See message history in Inspector (timestamps, payloads, call counts)
|
|
61
|
+
- ✅ Priority-based execution (no more race conditions)
|
|
62
|
+
- ✅ Interceptors (validate/normalize before handlers)
|
|
63
|
+
- ✅ Global observers (track ALL instances of a message type)
|
|
64
|
+
- ✅ Local bus islands (isolated testing, zero global state)
|
|
65
|
+
|
|
66
|
+
## What It Solves (Technical)
|
|
67
|
+
|
|
68
|
+
- **Decoupling without references** - producers/consumers never know about each other
|
|
69
|
+
- **Predictable lifecycle** - explicit tokens tied to Unity component lifecycles
|
|
70
|
+
- **Performance** - struct messages passed by-ref, zero allocations, zero boxing
|
|
71
|
+
- **Observability** - interceptors, post-processors, diagnostics, registration logs
|
|
72
|
+
- **Scalable taxonomy** - three message types (Untargeted/Targeted/Broadcast) cover 99% of use cases
|
|
73
|
+
|
|
74
|
+
## When to Consider DxMessaging
|
|
75
|
+
|
|
76
|
+
### Use it when
|
|
77
|
+
|
|
78
|
+
- You have 3+ systems that need to communicate
|
|
79
|
+
- You've debugged memory leaks from forgotten unsubscribes
|
|
80
|
+
- You're tired of UI depending on 15 different gameplay systems
|
|
81
|
+
- You want to see "what fired when" without setting 50 breakpoints
|
|
82
|
+
- You're building for the long term (months/years, not days)
|
|
83
|
+
|
|
84
|
+
#### Skip it when
|
|
85
|
+
|
|
86
|
+
- Game jam prototype (<1 week)
|
|
87
|
+
- Tiny project (<1000 lines)
|
|
88
|
+
- Single-system communication (just call the method directly)
|
|
89
|
+
- You need synchronous return values (DxMessaging is fire-and-forget)
|
|
23
90
|
|
|
24
91
|
Core ideas
|
|
25
92
|
|
|
@@ -31,15 +98,42 @@ Core ideas
|
|
|
31
98
|
- Pipeline: Interceptors → Handlers → Post‑Processors, with diagnostics optionally enabled.
|
|
32
99
|
- Unity integration: `MessagingComponent` and `MessageAwareComponent` manage lifecycles cleanly.
|
|
33
100
|
|
|
34
|
-
Killer
|
|
101
|
+
## Killer Features (What Makes It Special)
|
|
102
|
+
|
|
103
|
+
### 🚀 Global Observers: The Unique Advantage
|
|
104
|
+
|
|
105
|
+
#### Traditional event systems force you to do this
|
|
106
|
+
|
|
107
|
+
```csharp
|
|
108
|
+
// Subscribe to each entity type separately
|
|
109
|
+
PlayerEvents.OnDamaged += TrackPlayerDamage;
|
|
110
|
+
EnemyEvents.OnDamaged += TrackEnemyDamage;
|
|
111
|
+
NPCEvents.OnDamaged += TrackNPCDamage;
|
|
112
|
+
// Add a new entity type? More subscriptions...
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
##### DxMessaging lets you do this
|
|
116
|
+
|
|
117
|
+
```csharp
|
|
118
|
+
// Subscribe ONCE to ALL damage, regardless of source
|
|
119
|
+
_ = Token.RegisterBroadcastWithoutSource<TookDamage>(
|
|
120
|
+
(InstanceId source, TookDamage msg) => {
|
|
121
|
+
Analytics.Log($"{source} took {msg.amount} damage");
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Real-world impact:** Build achievement systems, combat logs, and analytics that work with ANY entity - even ones that don't exist yet.
|
|
127
|
+
|
|
128
|
+
### Other Killer Features
|
|
35
129
|
|
|
36
|
-
-
|
|
37
|
-
- **
|
|
38
|
-
- **Local bus islands**
|
|
39
|
-
- **
|
|
40
|
-
- **
|
|
41
|
-
- **Unity
|
|
42
|
-
- **
|
|
130
|
+
- **Priority-based ordering** - eliminate race conditions, control execution flow explicitly
|
|
131
|
+
- **Interceptor pipeline** - validate/normalize messages BEFORE handlers run (one validation, all handlers protected)
|
|
132
|
+
- **Local bus islands** - isolated testing with zero global state contamination
|
|
133
|
+
- **Zero-allocation design** - struct messages passed by-ref, no boxing, no GC spikes
|
|
134
|
+
- **Auto-constructor generation** - `[DxAutoConstructor]` eliminates boilerplate while keeping type safety
|
|
135
|
+
- **Unity-first helpers** - `EmitGameObjectTargeted()`, `EmitComponentBroadcast()` feel natural
|
|
136
|
+
- **Inspector diagnostics** - see message history, registrations, call counts in real-time
|
|
43
137
|
|
|
44
138
|
---
|
|
45
139
|
|
package/Docs/Patterns.md
CHANGED
|
@@ -1,10 +1,50 @@
|
|
|
1
|
-
# DxMessaging Patterns
|
|
1
|
+
# DxMessaging Patterns: Real-World Solutions
|
|
2
2
|
|
|
3
3
|
[← Back to Index](Index.md) | [Getting Started](GettingStarted.md) | [Message Types](MessageTypes.md) | [Samples](../Samples~/)
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
**You're here because:** You understand DxMessaging basics, now you want to see "How do I actually build X?"
|
|
8
|
+
|
|
9
|
+
## What you'll find
|
|
10
|
+
|
|
11
|
+
- **Basic Patterns** - Fundamental building blocks (scene transitions, commands, observability)
|
|
12
|
+
- **Advanced Patterns** - Power user techniques (diagnostics, testing, legacy integration)
|
|
13
|
+
- **Scale Patterns** - Production-ready examples (100+ entities, cross-scene systems, large UI)
|
|
14
|
+
|
|
15
|
+
### Reading guide
|
|
16
|
+
|
|
17
|
+
- **New to DxMessaging?** Start with Basic Patterns 1-8
|
|
18
|
+
- **Intermediate user?** Jump to Advanced Patterns 9-12
|
|
19
|
+
- **Building at scale?** Go straight to Real-World Scale Patterns
|
|
20
|
+
- **Specific problem?** Use Ctrl+F / Cmd+F to search
|
|
21
|
+
|
|
22
|
+
**Philosophy:** These aren't toy examples. They're patterns from real games with real problems.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick Links: "I Want To..."
|
|
27
|
+
|
|
28
|
+
### Find your use case, jump to the pattern
|
|
29
|
+
|
|
30
|
+
| I want to... | Go to |
|
|
31
|
+
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
32
|
+
| Make UI react to gameplay | [Pattern 2: Directed Commands](#2-directed-commands-targeted) |
|
|
33
|
+
| Coordinate scene transitions | [Pattern 1: Scene-wide Events](#1-scene-wide-events-untargeted) |
|
|
34
|
+
| Build an achievement system | [Pattern 3: Observability](#3-observability-broadcast) + [Global Accept-All](#10-global-accept-all-handlers) |
|
|
35
|
+
| Validate input/damage before it happens | [Pattern 4: Interceptors](#4-validation-and-normalization-interceptors) |
|
|
36
|
+
| Add analytics without touching gameplay | [Pattern 5: Post-Processors](#5-analyticslogging-post-processors) |
|
|
37
|
+
| Track ALL damage from ANY entity | [Pattern: Managing 100+ Entities](#pattern-managing-100-combat-entities) |
|
|
38
|
+
| Build a large UI system (20+ panels) | [Pattern: Large-Scale UI](#pattern-large-scale-ui-system-20-panels) |
|
|
39
|
+
| Make systems run in a specific order | [Pattern: Priority Ordering](#pattern-priority-ordered-execution-for-complex-systems) |
|
|
40
|
+
| Test in isolation | [Pattern 6: Local Bus Islands](#6-local-bus-islands) |
|
|
41
|
+
| Migrate from C# events | [Pattern 9: Bridging Legacy](#9-bridging-legacy-unity-messaging) |
|
|
42
|
+
| Handle persistent systems across scene loads | [Pattern: Cross-Scene Persistent](#pattern-cross-scene-persistent-systems) |
|
|
43
|
+
| See what's happening (debug message flow) | [Pattern 11: Diagnostics](#11-diagnostics-and-tuning) |
|
|
44
|
+
| Build a battle royale / large multiplayer | [Pattern: Battle Royale Example](#real-world-production-example-battle-royale-game) |
|
|
45
|
+
| Use with Scriptable Object Architecture | [Pattern 14: SOA Compatibility](#14-compatibility-with-scriptable-object-architecture-soa) |
|
|
46
|
+
|
|
47
|
+
---
|
|
8
48
|
|
|
9
49
|
## Table of Contents
|
|
10
50
|
|
|
@@ -25,6 +65,7 @@ This document captures practical patterns for building systems with DxMessaging.
|
|
|
25
65
|
- [Global Accept-All Handlers](#10-global-accept-all-handlers)
|
|
26
66
|
- [Diagnostics and Tuning](#11-diagnostics-and-tuning)
|
|
27
67
|
- [Testing](#12-testing)
|
|
68
|
+
- [Compatibility with Scriptable Object Architecture (SOA)](#14-compatibility-with-scriptable-object-architecture-soa)
|
|
28
69
|
|
|
29
70
|
### Real-World Scale Patterns
|
|
30
71
|
|
|
@@ -729,6 +770,290 @@ public class MatchStats : MessageAwareComponent {
|
|
|
729
770
|
|
|
730
771
|
---
|
|
731
772
|
|
|
773
|
+
## 14) Compatibility with Scriptable Object Architecture (SOA)
|
|
774
|
+
|
|
775
|
+
**Disclaimer:** Scriptable Object Architecture (SOA) is a debated pattern in the Unity community. While it has proponents, there are documented criticisms regarding its scalability and maintainability. See [Anti-ScriptableObject Architecture](https://github.com/cathei/AntiScriptableObjectArchitecture) for a detailed critique. **SOA is not a recommended pattern** for most projects, unless you need designers wiring events. Consider alternatives like dependency injection (Zenject, VContainer), reactive systems (UniRx), or messaging systems (DxMessaging, MessagePipe), as they often provide better long-term maintainability.
|
|
776
|
+
|
|
777
|
+
That said, if your project uses or requires SOA, DxMessaging can work alongside it.
|
|
778
|
+
|
|
779
|
+
### What is Scriptable Object Architecture?
|
|
780
|
+
|
|
781
|
+
**SOA Background:** Popularized by Ryan Hipple's [Unite Austin 2017 talk](https://www.youtube.com/watch?v=raQ3iHhE_Kk), SOA uses ScriptableObject assets as:
|
|
782
|
+
|
|
783
|
+
1. **Shared Variables** - `FloatVariable`, `IntVariable`, etc. (ScriptableObject assets that hold runtime state)
|
|
784
|
+
1. **Event Channels** - `GameEvent` + `GameEventListener` pattern (designer-created events)
|
|
785
|
+
1. **Runtime Sets** - Collections of active game objects (e.g., all enemies)
|
|
786
|
+
|
|
787
|
+
**Core idea:** Systems communicate through serialized SO assets instead of direct references.
|
|
788
|
+
|
|
789
|
+
#### Key resources
|
|
790
|
+
|
|
791
|
+
- [Unite 2017 Talk by Ryan Hipple](https://www.youtube.com/watch?v=raQ3iHhE_Kk)
|
|
792
|
+
- [Official Unity Guide](https://unity.com/how-to/architect-game-code-scriptable-objects)
|
|
793
|
+
- [Reference Implementation](https://github.com/roboryantron/Unite2017)
|
|
794
|
+
- [Community Package](https://github.com/DanielEverland/ScriptableObject-Architecture)
|
|
795
|
+
|
|
796
|
+
### Why SOA is Controversial
|
|
797
|
+
|
|
798
|
+
From [Anti-ScriptableObject Architecture](https://github.com/cathei/AntiScriptableObjectArchitecture), key criticisms include:
|
|
799
|
+
|
|
800
|
+
1. **Wrong Purpose** - ScriptableObjects are designed for immutable design data, not runtime mutable state
|
|
801
|
+
1. **Redundant Complexity** - Standard C# objects achieve the same goals without SO restrictions
|
|
802
|
+
1. **Inspector Dependency** - Binds architecture to Unity's GUI, complicating debugging and maintenance
|
|
803
|
+
1. **Limited Scalability** - Runtime-created variables undermine the pattern; managing numerous assets becomes unwieldy
|
|
804
|
+
1. **Domain Reload Issues** - Disabled domain reloading causes ScriptableObjects to retain values unpredictably
|
|
805
|
+
1. **Testability Concerns** - SO assets persist between tests, requiring manual cleanup
|
|
806
|
+
|
|
807
|
+
#### Recommended alternatives
|
|
808
|
+
|
|
809
|
+
- **Dependency Injection** - Zenject, VContainer, Reflex (see [DxMessaging DI Integrations](Integrations/))
|
|
810
|
+
- **Reactive Systems** - UniRx, UniTask
|
|
811
|
+
- **Messaging** - DxMessaging (this framework), MessagePipe
|
|
812
|
+
- **Configuration Data** - Spreadsheet-based solutions (e.g., BakingSheet)
|
|
813
|
+
|
|
814
|
+
Use ScriptableObjects for their intended purpose: **immutable design-time data** (configs, balance tables, prefab references).
|
|
815
|
+
|
|
816
|
+
### Can DxMessaging Work with SOA?
|
|
817
|
+
|
|
818
|
+
**Yes, but with caveats.** DxMessaging and SOA solve similar problems (decoupling, communication) with different philosophies:
|
|
819
|
+
|
|
820
|
+
| Aspect | SOA | DxMessaging |
|
|
821
|
+
| -------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------- |
|
|
822
|
+
| **Paradigm** | Asset-based, persistent state | Runtime message passing, transient |
|
|
823
|
+
| **Designer-Centric** | ✅ High (create events in Inspector) | ❌ Low (code-driven) |
|
|
824
|
+
| **Type Safety** | ⚠️ Mixed (SO refs typed, but UnityEvent inspector wiring loses compile-time safety) | ✅ Strong (compile-time validation) |
|
|
825
|
+
| **Lifecycle** | ⚠️ Manual (SO assets persist) | ✅ Automatic (tokens clean up) |
|
|
826
|
+
| **Debugging** | ⚠️ Inspector-dependent | ✅ Built-in diagnostics |
|
|
827
|
+
| **Performance** | ⚠️ List iteration, UnityAction overhead | ✅ Zero-allocation structs |
|
|
828
|
+
| **Use Case** | Shared state, designer-driven configs | Event-driven communication, runtime logic |
|
|
829
|
+
| **Testability** | ⚠️ Requires SO asset cleanup | ✅ Isolated buses per test |
|
|
830
|
+
|
|
831
|
+
**Bottom line:** If you're starting fresh, prefer DxMessaging or DI. If you have legacy SOA code, the patterns below show coexistence strategies.
|
|
832
|
+
|
|
833
|
+
### Pattern Overview
|
|
834
|
+
|
|
835
|
+
| Pattern | What it shows | When to use | SOA involvement |
|
|
836
|
+
| ------- | ------------------------------------------------------ | ----------------------------------------------------- | ---------------------------- |
|
|
837
|
+
| **A** | SOA Events (GameEvent) forwarding to DxMessaging | Designer-created event assets, modern code downstream | ✅ Yes - SOA Event pattern |
|
|
838
|
+
| **B** | ScriptableObjects for configs + DxMessaging for events | New projects / best practice | ❌ No - proper SO usage only |
|
|
839
|
+
|
|
840
|
+
### Pattern A: SOA → DxMessaging (Event Forwarding)
|
|
841
|
+
|
|
842
|
+
**Use case:** Designer-created SOA events, but you want DxMessaging benefits downstream.
|
|
843
|
+
|
|
844
|
+
**Strategy:** SOA GameEventListener forwards to DxMessaging.
|
|
845
|
+
|
|
846
|
+
> **This uses the SOA GameEvent pattern:** If you're NOT using designer-created GameEvent assets
|
|
847
|
+
> with `Raise()`/listener management, you don't need this pattern. For immutable config data,
|
|
848
|
+
> see Pattern B instead.
|
|
849
|
+
|
|
850
|
+
#### Example: Scene Transitions
|
|
851
|
+
|
|
852
|
+
```csharp
|
|
853
|
+
using DxMessaging.Core.Messages;
|
|
854
|
+
using DxMessaging.Core.Attributes;
|
|
855
|
+
using DxMessaging.Core.Extensions;
|
|
856
|
+
using UnityEngine;
|
|
857
|
+
using UnityEngine.Events;
|
|
858
|
+
|
|
859
|
+
// Traditional SOA event
|
|
860
|
+
[CreateAssetMenu(menuName = "Events/Game Event")]
|
|
861
|
+
public class GameEvent : ScriptableObject
|
|
862
|
+
{
|
|
863
|
+
private readonly List<UnityAction> listeners = new();
|
|
864
|
+
|
|
865
|
+
public void Raise()
|
|
866
|
+
{
|
|
867
|
+
for (int i = listeners.Count - 1; i >= 0; i--)
|
|
868
|
+
listeners[i]?.Invoke();
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
public void RegisterListener(UnityAction listener) => listeners.Add(listener);
|
|
872
|
+
public void UnregisterListener(UnityAction listener) => listeners.Remove(listener);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// DxMessaging message (modern, type-safe)
|
|
876
|
+
[DxUntargetedMessage]
|
|
877
|
+
public readonly struct SceneTransitionRequested { }
|
|
878
|
+
|
|
879
|
+
// Bridge: SOA Event → DxMessaging
|
|
880
|
+
public class SOAEventBridge : MonoBehaviour
|
|
881
|
+
{
|
|
882
|
+
[SerializeField] private GameEvent onSceneTransitionSO; // Designer-created asset
|
|
883
|
+
|
|
884
|
+
void OnEnable()
|
|
885
|
+
{
|
|
886
|
+
onSceneTransitionSO.RegisterListener(OnSOAEvent);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
void OnDisable()
|
|
890
|
+
{
|
|
891
|
+
onSceneTransitionSO.UnregisterListener(OnSOAEvent);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
void OnSOAEvent()
|
|
895
|
+
{
|
|
896
|
+
// Forward to DxMessaging
|
|
897
|
+
var message = new SceneTransitionRequested();
|
|
898
|
+
message.Emit();
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// Modern DxMessaging listeners (no SO dependency)
|
|
903
|
+
public class AudioSystem : MessageAwareComponent
|
|
904
|
+
{
|
|
905
|
+
protected override void RegisterMessageHandlers()
|
|
906
|
+
{
|
|
907
|
+
base.RegisterMessageHandlers();
|
|
908
|
+
_ = Token.RegisterUntargeted<SceneTransitionRequested>(OnTransition);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
void OnTransition(ref SceneTransitionRequested msg)
|
|
912
|
+
{
|
|
913
|
+
FadeOutMusic(); // Type-safe, debuggable via DxMessaging Inspector
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
##### Benefits
|
|
919
|
+
|
|
920
|
+
- ✅ Designers create events in Inspector (SOA workflow preserved)
|
|
921
|
+
- ✅ Code uses DxMessaging (type-safe, lifecycle-safe)
|
|
922
|
+
|
|
923
|
+
###### Drawbacks
|
|
924
|
+
|
|
925
|
+
- ⚠️ Bridge boilerplate for each SOA event
|
|
926
|
+
- ⚠️ Double registration (SOA listener + DxMessaging handler)
|
|
927
|
+
|
|
928
|
+
### Pattern B: Proper ScriptableObject Usage (Recommended)
|
|
929
|
+
|
|
930
|
+
**Use case:** ScriptableObjects for immutable config data, DxMessaging for runtime events.
|
|
931
|
+
|
|
932
|
+
**Strategy:** Use each tool for its intended purpose; avoid bridging.
|
|
933
|
+
|
|
934
|
+
> **Important:** This pattern uses ScriptableObjects CORRECTLY (immutable design data),
|
|
935
|
+
> NOT as SOA (mutable runtime state). This is standard Unity best practice, not SOA.
|
|
936
|
+
> If you're only using SOs for config data like this, you don't need SOA patterns at all.
|
|
937
|
+
|
|
938
|
+
#### Example: Combat with Designer-Tunable Data
|
|
939
|
+
|
|
940
|
+
```csharp
|
|
941
|
+
using DxMessaging.Core.Messages;
|
|
942
|
+
using DxMessaging.Core.Attributes;
|
|
943
|
+
using DxMessaging.Unity;
|
|
944
|
+
using UnityEngine;
|
|
945
|
+
|
|
946
|
+
// ScriptableObject: Designer-tunable balance data (immutable at runtime)
|
|
947
|
+
// This is CORRECT SO usage, NOT SOA
|
|
948
|
+
[CreateAssetMenu(menuName = "Config/Weapon Stats")]
|
|
949
|
+
public class WeaponStats : ScriptableObject
|
|
950
|
+
{
|
|
951
|
+
public int baseDamage = 10; // Designer tweaks in Inspector
|
|
952
|
+
public float critMultiplier = 2f;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// DxMessaging: Runtime event (code-driven)
|
|
956
|
+
[DxBroadcastMessage]
|
|
957
|
+
[DxAutoConstructor]
|
|
958
|
+
public readonly partial struct DamageDealt
|
|
959
|
+
{
|
|
960
|
+
public readonly int amount;
|
|
961
|
+
public readonly bool wasCrit;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// Combat system: Reads immutable SO data, emits DxMessaging events
|
|
965
|
+
public class Weapon : MessageAwareComponent
|
|
966
|
+
{
|
|
967
|
+
[SerializeField] private WeaponStats stats; // Immutable config (correct SO usage)
|
|
968
|
+
|
|
969
|
+
public void Fire()
|
|
970
|
+
{
|
|
971
|
+
bool crit = Random.value < 0.1f;
|
|
972
|
+
int damage = Mathf.RoundToInt(stats.baseDamage * (crit ? stats.critMultiplier : 1f));
|
|
973
|
+
|
|
974
|
+
var msg = new DamageDealt(damage, crit);
|
|
975
|
+
msg.EmitComponentBroadcast(this); // Runtime event via DxMessaging
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// Analytics: Pure DxMessaging (no SOA dependency)
|
|
980
|
+
public class CombatAnalytics : MessageAwareComponent
|
|
981
|
+
{
|
|
982
|
+
protected override void RegisterMessageHandlers()
|
|
983
|
+
{
|
|
984
|
+
base.RegisterMessageHandlers();
|
|
985
|
+
_ = Token.RegisterBroadcastWithoutSource<DamageDealt>(OnDamage);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
void OnDamage(InstanceId source, DamageDealt msg)
|
|
989
|
+
{
|
|
990
|
+
Debug.Log($"{source} dealt {msg.amount} damage (crit: {msg.wasCrit})");
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
##### Benefits
|
|
996
|
+
|
|
997
|
+
- ✅ **Best of both worlds** - ScriptableObjects for static configs, DxMessaging for runtime events
|
|
998
|
+
- ✅ No bridging overhead
|
|
999
|
+
- ✅ Uses each system correctly: SOs for their intended purpose (immutable design data), messaging for runtime communication
|
|
1000
|
+
- ✅ This is NOT SOA - it's proper Unity architecture
|
|
1001
|
+
|
|
1002
|
+
###### This is the recommended pattern for all projects
|
|
1003
|
+
|
|
1004
|
+
### When to Use Each Pattern
|
|
1005
|
+
|
|
1006
|
+
| Pattern | Use When | Complexity | Performance |
|
|
1007
|
+
| --------------------------- | ------------------------------------------------------- | ---------- | ----------- |
|
|
1008
|
+
| **A: SOA → DxMessaging** | Designers create SOA events, modern code uses messaging | Medium | ⚠️ Medium |
|
|
1009
|
+
| **B: Proper SO Usage** | Immutable configs only, messaging for events | Low | ✅ Good |
|
|
1010
|
+
| **None (Pure DxMessaging)** | Greenfield project or full SOA migration | Lowest | ✅ Best |
|
|
1011
|
+
|
|
1012
|
+
### Migration Path: SOA → DxMessaging
|
|
1013
|
+
|
|
1014
|
+
If you're moving away from SOA:
|
|
1015
|
+
|
|
1016
|
+
1. **Phase 1:** Identify SOA event usage (GameEvent/GameEventListener patterns)
|
|
1017
|
+
1. **Phase 2:** Create equivalent DxMessaging messages (Untargeted/Broadcast)
|
|
1018
|
+
1. **Phase 3:** Add bridges (Pattern A or B) to maintain compatibility
|
|
1019
|
+
1. **Phase 4:** Migrate listeners to DxMessaging incrementally
|
|
1020
|
+
1. **Phase 5:** Remove bridges and SOA assets once all references gone
|
|
1021
|
+
|
|
1022
|
+
For SOA variables:
|
|
1023
|
+
|
|
1024
|
+
1. Convert read-only SO configs → Keep as-is (correct SO usage) or move to JSON/ScriptableObjects for data
|
|
1025
|
+
1. Convert mutable SO variables → DxMessaging messages or DI-injected services
|
|
1026
|
+
1. Convert RuntimeSets → DxMessaging global observers (`RegisterBroadcastWithoutSource`)
|
|
1027
|
+
|
|
1028
|
+
### Final Recommendations
|
|
1029
|
+
|
|
1030
|
+
#### If you're using SOA
|
|
1031
|
+
|
|
1032
|
+
- ✅ **Do:** Use Pattern B (Proper SO Usage) - SOs for immutable configs ONLY, DxMessaging for runtime events
|
|
1033
|
+
- ✅ **Do:** Use Pattern A to bridge existing SOA GameEvent assets to DxMessaging during migration
|
|
1034
|
+
- ✅ **Do:** Read [Anti-ScriptableObject Architecture](https://github.com/cathei/AntiScriptableObjectArchitecture) to understand risks
|
|
1035
|
+
- ✅ **Do:** Consider gradual migration to DxMessaging or DI frameworks
|
|
1036
|
+
- ❌ **Don't:** Use SOs for mutable runtime state (health, scores, etc.)
|
|
1037
|
+
- ❌ **Don't:** Create new SOA event assets—use DxMessaging messages instead
|
|
1038
|
+
|
|
1039
|
+
##### If you're starting fresh
|
|
1040
|
+
|
|
1041
|
+
- ✅ **Do:** Use DxMessaging for all messaging/events
|
|
1042
|
+
- ✅ **Do:** Use ScriptableObjects ONLY for immutable design data (weapon stats, level configs)
|
|
1043
|
+
- ✅ **Do:** Consider DI frameworks (Zenject/VContainer) for service dependencies
|
|
1044
|
+
- ❌ **Don't:** Adopt SOA's GameEvent/Variable patterns—they're superseded by better tools
|
|
1045
|
+
|
|
1046
|
+
###### Resources
|
|
1047
|
+
|
|
1048
|
+
- [Anti-ScriptableObject Architecture](https://github.com/cathei/AntiScriptableObjectArchitecture) - Detailed critique
|
|
1049
|
+
- [Ryan Hipple Unite 2017 Talk](https://www.youtube.com/watch?v=raQ3iHhE_Kk) - Original SOA presentation
|
|
1050
|
+
- [Unity Official Guide](https://unity.com/how-to/architect-game-code-scriptable-objects) - Unity's perspective
|
|
1051
|
+
- [DxMessaging DI Integrations](Integrations/) - Better alternatives for dependency management
|
|
1052
|
+
- [Zenject](https://github.com/modesttree/Zenject) - Recommended DI framework
|
|
1053
|
+
- [VContainer](https://github.com/hadashiA/VContainer) - Lightweight DI alternative
|
|
1054
|
+
|
|
1055
|
+
---
|
|
1056
|
+
|
|
732
1057
|
## Related Documentation
|
|
733
1058
|
|
|
734
1059
|
### Learn the Basics First?
|
package/Docs/Performance.md
CHANGED
|
@@ -14,15 +14,15 @@ See also: `Docs/DesignAndArchitecture.md#performance-optimizations` for design d
|
|
|
14
14
|
|
|
15
15
|
| Message Tech | Operations / Second | Allocations? |
|
|
16
16
|
| ---------------------------------- | ------------------- | ------------ |
|
|
17
|
-
| Unity | 2,
|
|
18
|
-
| DxMessaging (GameObject) - Normal | 8,
|
|
19
|
-
| DxMessaging (Component) - Normal | 8,
|
|
20
|
-
| DxMessaging (GameObject) - No-Copy | 9,
|
|
21
|
-
| DxMessaging (Component) - No-Copy | 9,
|
|
22
|
-
| DxMessaging (Untargeted) - No-Copy | 14,
|
|
23
|
-
| Reflexive (One Argument) | 2,
|
|
24
|
-
| Reflexive (Two Arguments) | 2,
|
|
25
|
-
| Reflexive (Three Arguments) | 2,
|
|
17
|
+
| Unity | 2,490,000 | Yes |
|
|
18
|
+
| DxMessaging (GameObject) - Normal | 8,520,000 | No |
|
|
19
|
+
| DxMessaging (Component) - Normal | 8,542,000 | No |
|
|
20
|
+
| DxMessaging (GameObject) - No-Copy | 9,426,000 | No |
|
|
21
|
+
| DxMessaging (Component) - No-Copy | 9,552,000 | No |
|
|
22
|
+
| DxMessaging (Untargeted) - No-Copy | 14,900,000 | No |
|
|
23
|
+
| Reflexive (One Argument) | 2,832,000 | No |
|
|
24
|
+
| Reflexive (Two Arguments) | 2,348,000 | No |
|
|
25
|
+
| Reflexive (Three Arguments) | 2,364,000 | No |
|
|
26
26
|
|
|
27
27
|
## macOS
|
|
28
28
|
|
package/Docs/QuickReference.md
CHANGED
|
@@ -9,6 +9,7 @@ Do’s
|
|
|
9
9
|
- Use GameObject/Component emit helpers (no manual `InstanceId`).
|
|
10
10
|
- Register once; enable/disable with component state.
|
|
11
11
|
- Prefer named handler methods over inline lambdas for reuse and clarity.
|
|
12
|
+
- When using DI, inject `IMessageRegistrationBuilder` instead of newing `MessageHandler`s manually.
|
|
12
13
|
|
|
13
14
|
Don’ts
|
|
14
15
|
|
|
@@ -77,6 +78,36 @@ _ = token.RegisterBroadcastWithoutSource<TookDamage>(OnAnyDamage);
|
|
|
77
78
|
void OnAnyDamage(ref InstanceId src, ref TookDamage m) { /* ... */ }
|
|
78
79
|
```
|
|
79
80
|
|
|
81
|
+
Register (DI / services)
|
|
82
|
+
|
|
83
|
+
```csharp
|
|
84
|
+
using DxMessaging.Core.MessageBus;
|
|
85
|
+
|
|
86
|
+
public sealed class DamageSystem : IStartable, IDisposable
|
|
87
|
+
{
|
|
88
|
+
private readonly MessageRegistrationLease lease;
|
|
89
|
+
|
|
90
|
+
public DamageSystem(IMessageRegistrationBuilder registrationBuilder)
|
|
91
|
+
{
|
|
92
|
+
lease = registrationBuilder.Build(new MessageRegistrationBuildOptions
|
|
93
|
+
{
|
|
94
|
+
Configure = token =>
|
|
95
|
+
{
|
|
96
|
+
_ = token.RegisterUntargeted<TookDamage>(OnDamage);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public void Start() => lease.Activate();
|
|
102
|
+
|
|
103
|
+
public void Dispose() => lease.Dispose();
|
|
104
|
+
|
|
105
|
+
private static void OnDamage(ref TookDamage message) { /* respond */ }
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Tip: Define `ZENJECT_PRESENT`, `VCONTAINER_PRESENT`, or `REFLEX_PRESENT` to enable the optional shims under `Runtime/Unity/Integrations/` that bind the builder automatically for those containers.
|
|
110
|
+
|
|
80
111
|
Interceptors and post‑processors
|
|
81
112
|
|
|
82
113
|
```csharp
|