com.wallstop-studios.dxmessaging 2.2.0 → 3.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/CHANGELOG.md +315 -67
- package/CHANGELOG.md.meta +7 -7
- package/Editor/Analyzers/BaseCallIlInspector.cs +277 -0
- package/Editor/Analyzers/BaseCallIlInspector.cs.meta +11 -0
- package/Editor/Analyzers/BaseCallLogMessageParser.cs +295 -0
- package/Editor/Analyzers/BaseCallLogMessageParser.cs.meta +11 -0
- package/Editor/Analyzers/BaseCallReportAggregator.cs +308 -0
- package/Editor/Analyzers/BaseCallReportAggregator.cs.meta +11 -0
- package/Editor/Analyzers/BaseCallTypeScanner.cs +110 -0
- package/Editor/Analyzers/BaseCallTypeScanner.cs.meta +11 -0
- package/Editor/Analyzers/BaseCallTypeScannerCore.cs +562 -0
- package/Editor/Analyzers/BaseCallTypeScannerCore.cs.meta +11 -0
- package/Editor/Analyzers/DxMessagingConsoleHarvester.cs +1129 -0
- package/Editor/Analyzers/DxMessagingConsoleHarvester.cs.meta +11 -0
- package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +44 -44
- package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +44 -44
- package/Editor/Analyzers/System.Collections.Immutable.dll.meta +44 -44
- package/Editor/Analyzers/System.Reflection.Metadata.dll.meta +44 -44
- package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll.meta +44 -44
- package/Editor/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll +0 -0
- package/Editor/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll.meta +46 -0
- package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
- package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll.meta +72 -72
- package/Editor/Analyzers.meta +8 -8
- package/Editor/AssemblyInfo.cs.meta +11 -3
- package/Editor/CustomEditors/MessageAwareComponentFallbackEditor.cs +81 -0
- package/Editor/CustomEditors/MessageAwareComponentFallbackEditor.cs.meta +11 -0
- package/Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs +429 -0
- package/Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs.meta +11 -0
- package/Editor/CustomEditors/MessagingComponentEditor.cs +1 -1
- package/Editor/CustomEditors/MessagingComponentEditor.cs.meta +11 -3
- package/Editor/CustomEditors.meta +2 -2
- package/Editor/DxMessagingEditorIdle.cs +62 -0
- package/Editor/DxMessagingEditorIdle.cs.meta +11 -0
- package/Editor/DxMessagingEditorInitializer.cs +112 -15
- package/Editor/DxMessagingEditorInitializer.cs.meta +11 -3
- package/Editor/DxMessagingEditorLog.cs +32 -0
- package/Editor/DxMessagingEditorLog.cs.meta +11 -0
- package/Editor/DxMessagingMenu.cs.meta +11 -11
- package/Editor/DxMessagingSceneBuildProcessor.cs.meta +11 -11
- package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs +313 -0
- package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs.meta +11 -0
- package/Editor/Settings/DxMessagingSettings.cs +261 -11
- package/Editor/Settings/DxMessagingSettings.cs.meta +11 -3
- package/Editor/Settings/DxMessagingSettingsProvider.cs +50 -33
- package/Editor/Settings/DxMessagingSettingsProvider.cs.meta +11 -3
- package/Editor/Settings.meta +2 -2
- package/Editor/SetupCscRsp.cs +406 -39
- package/Editor/SetupCscRsp.cs.meta +11 -3
- package/Editor/Testing/MessagingComponentEditorHarness.cs +2 -2
- package/Editor/Testing/MessagingComponentEditorHarness.cs.meta +11 -3
- package/Editor/Testing.meta +3 -3
- package/Editor/WallstopStudios.DxMessaging.Editor.asmdef +14 -14
- package/Editor/WallstopStudios.DxMessaging.Editor.asmdef.meta +7 -7
- package/Editor.meta +8 -8
- package/LICENSE.md +9 -9
- package/LICENSE.md.meta +7 -7
- package/README.md +940 -900
- package/README.md.meta +7 -7
- package/Runtime/AssemblyInfo.cs +4 -0
- package/Runtime/AssemblyInfo.cs.meta +11 -3
- package/Runtime/Core/Attributes/DxAutoConstructorAttribute.cs.meta +11 -3
- package/Runtime/Core/Attributes/DxBroadcastMessageAttribute.cs.meta +11 -3
- package/Runtime/Core/Attributes/DxIgnoreMissingBaseCallAttribute.cs +26 -0
- package/Runtime/Core/Attributes/DxIgnoreMissingBaseCallAttribute.cs.meta +11 -0
- package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs +2 -4
- package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs.meta +11 -3
- package/Runtime/Core/Attributes/DxTargetedMessageAttribute.cs.meta +11 -3
- package/Runtime/Core/Attributes/DxUntargetedMessageAttribute.cs.meta +11 -3
- package/Runtime/Core/Attributes/Il2CppSetOptionAttribute.cs +56 -0
- package/Runtime/Core/Attributes/Il2CppSetOptionAttribute.cs.meta +11 -0
- package/Runtime/Core/Attributes.meta +2 -2
- package/Runtime/Core/Configuration/DxMessagingRuntimeSettings.cs +195 -0
- package/Runtime/Core/Configuration/DxMessagingRuntimeSettings.cs.meta +11 -0
- package/Runtime/Core/Configuration/DxMessagingRuntimeSettingsProvider.cs +179 -0
- package/Runtime/Core/Configuration/DxMessagingRuntimeSettingsProvider.cs.meta +11 -0
- package/Runtime/Core/Configuration.meta +9 -0
- package/Runtime/Core/DataStructure/CyclicBuffer.cs +46 -28
- package/Runtime/Core/DataStructure/CyclicBuffer.cs.meta +11 -3
- package/Runtime/Core/DataStructure.meta +2 -2
- package/Runtime/Core/Diagnostics/MessageEmissionData.cs.meta +11 -3
- package/Runtime/Core/Diagnostics/MessageRegistrationData.cs.meta +11 -3
- package/Runtime/Core/Diagnostics/MessageRegistrationType.cs.meta +11 -3
- package/Runtime/Core/Diagnostics.meta +2 -2
- package/Runtime/Core/DxMessagingStaticState.cs +19 -0
- package/Runtime/Core/DxMessagingStaticState.cs.meta +11 -11
- package/Runtime/Core/Extensions/EnumExtensions.cs +6 -5
- package/Runtime/Core/Extensions/EnumExtensions.cs.meta +11 -3
- package/Runtime/Core/Extensions/IListExtensions.cs.meta +11 -3
- package/Runtime/Core/Extensions/MessageBusExtensions.cs.meta +12 -12
- package/Runtime/Core/Extensions/MessageExtensions.cs +0 -60
- package/Runtime/Core/Extensions/MessageExtensions.cs.meta +11 -11
- package/Runtime/Core/Extensions.meta +8 -8
- package/Runtime/Core/Helper/MessageCache.cs +32 -0
- package/Runtime/Core/Helper/MessageCache.cs.meta +11 -3
- package/Runtime/Core/Helper/MessageHelperIndexer.cs.meta +11 -3
- package/Runtime/Core/Helper.meta +2 -2
- package/Runtime/Core/IMessage.cs +3 -3
- package/Runtime/Core/IMessage.cs.meta +11 -11
- package/Runtime/Core/InstanceId.cs +25 -1
- package/Runtime/Core/InstanceId.cs.meta +11 -11
- package/Runtime/Core/Internal/DxUnsafe.cs +60 -0
- package/Runtime/Core/Internal/DxUnsafe.cs.meta +11 -0
- package/Runtime/Core/Internal/FlatDispatch.cs +198 -0
- package/Runtime/Core/Internal/FlatDispatch.cs.meta +11 -0
- package/Runtime/Core/Internal/TypedGlobalSlotIndex.cs +38 -0
- package/Runtime/Core/Internal/TypedGlobalSlotIndex.cs.meta +11 -0
- package/Runtime/Core/Internal/TypedSlotIndex.cs +81 -0
- package/Runtime/Core/Internal/TypedSlotIndex.cs.meta +11 -0
- package/Runtime/Core/Internal/TypedSlots.cs +597 -0
- package/Runtime/Core/Internal/TypedSlots.cs.meta +11 -0
- package/Runtime/Core/Internal.meta +9 -0
- package/Runtime/Core/MessageBus/DiagnosticsTarget.cs.meta +11 -11
- package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +11 -11
- package/Runtime/Core/MessageBus/IMessageBus.cs +189 -15
- package/Runtime/Core/MessageBus/IMessageBus.cs.meta +11 -11
- package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +11 -11
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs +1 -0
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +11 -11
- package/Runtime/Core/MessageBus/Internal/BusContextIndex.cs +16 -0
- package/Runtime/Core/MessageBus/Internal/BusContextIndex.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/BusSinkIndex.cs +40 -0
- package/Runtime/Core/MessageBus/Internal/BusSinkIndex.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/BusSlots.cs +719 -0
- package/Runtime/Core/MessageBus/Internal/BusSlots.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/DispatchKind.cs +38 -0
- package/Runtime/Core/MessageBus/Internal/DispatchKind.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/DispatchPhase.cs +20 -0
- package/Runtime/Core/MessageBus/Internal/DispatchPhase.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/DispatchVariant.cs +28 -0
- package/Runtime/Core/MessageBus/Internal/DispatchVariant.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/IEvictableSlot.cs +48 -0
- package/Runtime/Core/MessageBus/Internal/IEvictableSlot.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/ISweepable.cs +15 -0
- package/Runtime/Core/MessageBus/Internal/ISweepable.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/RegistrationMethodAxes.cs +222 -0
- package/Runtime/Core/MessageBus/Internal/RegistrationMethodAxes.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal/SlotKey.cs +192 -0
- package/Runtime/Core/MessageBus/Internal/SlotKey.cs.meta +11 -0
- package/Runtime/Core/MessageBus/Internal.meta +9 -0
- package/Runtime/Core/MessageBus/MessageBus.cs +5366 -3838
- package/Runtime/Core/MessageBus/MessageBus.cs.meta +11 -11
- package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +11 -11
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +187 -14
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +11 -11
- package/Runtime/Core/MessageBus/MessagingRegistration.cs.meta +11 -11
- package/Runtime/Core/MessageBus/RegistrationLog.cs.meta +11 -11
- package/Runtime/Core/MessageBus.meta +8 -8
- package/Runtime/Core/MessageHandler.cs +2399 -1042
- package/Runtime/Core/MessageHandler.cs.meta +11 -11
- package/Runtime/Core/MessageRegistrationHandle.cs.meta +11 -11
- package/Runtime/Core/MessageRegistrationToken.cs +429 -44
- package/Runtime/Core/MessageRegistrationToken.cs.meta +11 -11
- package/Runtime/Core/Messages/GlobalStringMessage.cs.meta +11 -3
- package/Runtime/Core/Messages/IBroadcastMessage.cs.meta +11 -11
- package/Runtime/Core/Messages/ITargetedMessage.cs.meta +11 -11
- package/Runtime/Core/Messages/IUntargetedMessage.cs.meta +11 -11
- package/Runtime/Core/Messages/ReflexiveMessage.cs.meta +11 -3
- package/Runtime/Core/Messages/SourcedStringMessage.cs.meta +11 -11
- package/Runtime/Core/Messages/StringMessage.cs.meta +11 -3
- package/Runtime/Core/Messages.meta +8 -8
- package/Runtime/Core/MessagingDebug.cs.meta +11 -11
- package/Runtime/Core/Pooling/CollectionPool.cs +266 -0
- package/Runtime/Core/Pooling/CollectionPool.cs.meta +11 -0
- package/Runtime/Core/Pooling/CollectionPoolDiagnostics.cs +30 -0
- package/Runtime/Core/Pooling/CollectionPoolDiagnostics.cs.meta +11 -0
- package/Runtime/Core/Pooling/DxPools.cs +157 -0
- package/Runtime/Core/Pooling/DxPools.cs.meta +11 -0
- package/Runtime/Core/Pooling/EvictionPlayerLoopHook.cs +106 -0
- package/Runtime/Core/Pooling/EvictionPlayerLoopHook.cs.meta +11 -0
- package/Runtime/Core/Pooling/IDxMessagingClock.cs +18 -0
- package/Runtime/Core/Pooling/IDxMessagingClock.cs.meta +11 -0
- package/Runtime/Core/Pooling/PoolDiagnosticsSnapshot.cs +55 -0
- package/Runtime/Core/Pooling/PoolDiagnosticsSnapshot.cs.meta +11 -0
- package/Runtime/Core/Pooling/StopwatchClock.cs +27 -0
- package/Runtime/Core/Pooling/StopwatchClock.cs.meta +11 -0
- package/Runtime/Core/Pooling/UnityRealtimeClock.cs +31 -0
- package/Runtime/Core/Pooling/UnityRealtimeClock.cs.meta +11 -0
- package/Runtime/Core/Pooling.meta +9 -0
- package/Runtime/Core.meta +8 -8
- package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs.meta +12 -12
- package/Runtime/Unity/DxMessagingRuntimeInitializer.cs.meta +11 -11
- package/Runtime/Unity/InitialGlobalMessageBusProvider.cs.meta +12 -12
- package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs.meta +11 -3
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs +73 -0
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs.meta +11 -11
- package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef +20 -20
- package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef.meta +7 -7
- package/Runtime/Unity/Integrations/Reflex.meta +8 -8
- package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs.meta +11 -3
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs +109 -1
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs.meta +11 -11
- package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef +30 -30
- package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef.meta +7 -7
- package/Runtime/Unity/Integrations/VContainer.meta +8 -8
- package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs.meta +11 -3
- package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef +30 -30
- package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef.meta +7 -7
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs +79 -1
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs.meta +11 -11
- package/Runtime/Unity/Integrations/Zenject.meta +8 -8
- package/Runtime/Unity/Integrations.meta +8 -8
- package/Runtime/Unity/MessageAwareComponent.cs +74 -0
- package/Runtime/Unity/MessageAwareComponent.cs.meta +11 -11
- package/Runtime/Unity/MessageBusProviderHandle.cs.meta +12 -12
- package/Runtime/Unity/MessagingComponent.cs +43 -10
- package/Runtime/Unity/MessagingComponent.cs.meta +11 -11
- package/Runtime/Unity/MessagingComponentInstaller.cs.meta +12 -12
- package/Runtime/Unity/ScriptableMessageBusProvider.cs.meta +12 -12
- package/Runtime/Unity.meta +8 -8
- package/Runtime/WallstopStudios.DxMessaging.asmdef +14 -14
- package/Runtime/WallstopStudios.DxMessaging.asmdef.meta +7 -7
- package/Runtime.meta +8 -8
- package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab +98 -98
- package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab.meta +7 -7
- package/Samples~/DI/Prefabs.meta +8 -8
- package/Samples~/DI/Providers/GlobalMessageBusProvider.asset +14 -14
- package/Samples~/DI/Providers/GlobalMessageBusProvider.asset.meta +8 -8
- package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset +14 -14
- package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset.meta +8 -8
- package/Samples~/DI/Providers.meta +8 -8
- package/Samples~/DI/README.md +51 -51
- package/Samples~/DI/README.md.meta +7 -7
- package/Samples~/DI/Reflex/SampleInstaller.cs +7 -0
- package/Samples~/DI/Reflex/SampleInstaller.cs.meta +11 -11
- package/Samples~/DI/Reflex.meta +8 -8
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs +6 -1
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +11 -11
- package/Samples~/DI/VContainer.meta +8 -8
- package/Samples~/DI/Zenject/SampleInstaller.cs +8 -0
- package/Samples~/DI/Zenject/SampleInstaller.cs.meta +11 -11
- package/Samples~/DI/Zenject.meta +8 -8
- package/Samples~/DI.meta +8 -8
- package/Samples~/Mini Combat/Boot.cs.meta +11 -11
- package/Samples~/Mini Combat/Enemy.cs.meta +11 -11
- package/Samples~/Mini Combat/Messages.cs.meta +11 -11
- package/Samples~/Mini Combat/Player.cs.meta +11 -11
- package/Samples~/Mini Combat/README.md +324 -323
- package/Samples~/Mini Combat/README.md.meta +7 -7
- package/Samples~/Mini Combat/UIOverlay.cs.meta +11 -11
- package/Samples~/Mini Combat/Walkthrough.md +430 -430
- package/Samples~/Mini Combat/Walkthrough.md.meta +7 -7
- package/Samples~/Mini Combat/WallstopStudios.DxMessaging.MiniCombat.Sample.asmdef +13 -13
- package/Samples~/Mini Combat/WallstopStudios.DxMessaging.MiniCombat.Sample.asmdef.meta +7 -7
- package/Samples~/Mini Combat.meta +8 -8
- package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs.meta +11 -11
- package/Samples~/UI Buttons + Inspector/Messages.cs.meta +11 -11
- package/Samples~/UI Buttons + Inspector/MessagingObserver.cs.meta +11 -11
- package/Samples~/UI Buttons + Inspector/README.md +210 -209
- package/Samples~/UI Buttons + Inspector/README.md.meta +7 -7
- package/Samples~/UI Buttons + Inspector/UIButtonEmitter.cs.meta +11 -11
- package/Samples~/UI Buttons + Inspector/WallstopStudios.DxMessaging.UIButtons.Sample.asmdef +13 -13
- package/Samples~/UI Buttons + Inspector/WallstopStudios.DxMessaging.UIButtons.Sample.asmdef.meta +7 -7
- package/Samples~/UI Buttons + Inspector.meta +8 -8
- package/SourceGenerators/Directory.Build.props +50 -3
- package/SourceGenerators/Directory.Build.props.meta +7 -7
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs +96 -63
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs.meta +11 -11
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs +745 -87
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs.meta +11 -3
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj +39 -46
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj.meta +7 -7
- package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.meta +8 -8
- package/SourceGenerators/global.json +7 -0
- package/SourceGenerators/global.json.meta +7 -0
- package/SourceGenerators.meta +8 -8
- package/Third Party Notices.md +3 -3
- package/Third Party Notices.md.meta +7 -7
- package/package.json +102 -92
- package/package.json.meta +7 -7
package/README.md
CHANGED
|
@@ -1,900 +1,940 @@
|
|
|
1
|
-
# DxMessaging for Unity
|
|
2
|
-
|
|
3
|
-
<p align="center">
|
|
4
|
-
<img src="docs/images/DxMessaging-banner.svg" alt="DxMessaging - Type-safe messaging system for Unity" width="800"/>
|
|
5
|
-
</p>
|
|
6
|
-
|
|
7
|
-
<p align="center">
|
|
8
|
-
<a href="https://
|
|
9
|
-
<img src="https://img.shields.io/badge
|
|
10
|
-
</a>
|
|
11
|
-
</p>
|
|
12
|
-
|
|
13
|
-
[](https://unity.com/releases/editor)<br/>
|
|
14
|
-
[](LICENSE.md)<br/>
|
|
15
|
-
[](https://openupm.com/packages/com.wallstop-studios.dxmessaging/)<br/>
|
|
16
|
-
[](https://www.npmjs.com/package/com.wallstop-studios.dxmessaging)<br/>
|
|
17
|
-
[ for how to choose the right type.
|
|
75
|
-
|
|
76
|
-
**One line:** It's a type-safe messaging system with automatic lifecycle management and built-in inspection tools.
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## Mental Model: How to Think About DxMessaging
|
|
81
|
-
|
|
82
|
-
### The Core Idea
|
|
83
|
-
|
|
84
|
-
DxMessaging is built around one principle: **it gets out of your way**.
|
|
85
|
-
|
|
86
|
-
You have data. You need to pass it around. That's the problem. DxMessaging provides fast, simple primitives as building blocks. You model changes as message types with optional context, using game primitives (GameObjects, components) as that context.
|
|
87
|
-
|
|
88
|
-
**You don't build your game INTO the messaging system.** It's opt-in and optional
|
|
89
|
-
|
|
90
|
-
### The Three Message Types: Real-World Analogies
|
|
91
|
-
|
|
92
|
-
> 💡 _Diagrams below require Mermaid support. If they don't render, try viewing this file directly on [GitHub](https://github.com/
|
|
93
|
-
|
|
94
|
-
Each message type maps to a real-world communication pattern:
|
|
95
|
-
|
|
96
|
-
#### 1. Untargeted = PA System
|
|
97
|
-
|
|
98
|
-
```mermaid
|
|
99
|
-
flowchart LR
|
|
100
|
-
S[Someone] -->|announces| PA[
|
|
101
|
-
PA --> L1[Listener A]
|
|
102
|
-
PA --> L2[Listener B]
|
|
103
|
-
PA --> L3[Listener C]
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
Announcements with no specific recipient. Everyone who cares can hear it.
|
|
107
|
-
|
|
108
|
-
**Examples:** "The game is paused", "Settings changed", "Scene finished loading"
|
|
109
|
-
|
|
110
|
-
#### 2. Targeted = Addressed Letter
|
|
111
|
-
|
|
112
|
-
```mermaid
|
|
113
|
-
flowchart LR
|
|
114
|
-
S[Sender] -->|"To: Player"| Letter[
|
|
115
|
-
Letter --> Player[Player receives]
|
|
116
|
-
Other1[Enemy A] -.->|ignores| Letter
|
|
117
|
-
Other2[Enemy B] -.->|ignores| Letter
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
Commands to a specific recipient. Only that entity receives them.
|
|
121
|
-
|
|
122
|
-
**Examples:** "Player, heal for 10 HP", "Door #7, open", "This enemy, take 25 damage"
|
|
123
|
-
|
|
124
|
-
#### 3. Broadcast = Radio Station
|
|
125
|
-
|
|
126
|
-
```mermaid
|
|
127
|
-
flowchart LR
|
|
128
|
-
Source[Enemy] -->|"I took damage!"| Radio[
|
|
129
|
-
Radio --> L1[Damage Numbers UI]
|
|
130
|
-
Radio --> L2[Achievement Tracker]
|
|
131
|
-
Radio --> L3[Analytics]
|
|
132
|
-
Radio --> L4[Combat Log]
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
Facts emitted by a specific source. No intended recipient
|
|
136
|
-
|
|
137
|
-
**Examples:** "This enemy took 25 damage", "The player picked up item X", "This chest opened"
|
|
138
|
-
|
|
139
|
-
### Choosing the Right Message Type
|
|
140
|
-
|
|
141
|
-
```mermaid
|
|
142
|
-
flowchart TD
|
|
143
|
-
Start([I need to send a message])
|
|
144
|
-
Start --> Q1{Does it matter<br/>WHO sent it?}
|
|
145
|
-
|
|
146
|
-
Q1 -->|No| Q2{Does it matter<br/>WHO receives it?}
|
|
147
|
-
Q2 -->|No| Untargeted[Use UNTARGETED<br/>Global announcement]
|
|
148
|
-
Q2 -->|Yes| Targeted[Use TARGETED<br/>Directed command]
|
|
149
|
-
|
|
150
|
-
Q1 -->|Yes| Q3{Am I commanding<br/>someone to act?}
|
|
151
|
-
Q3 -->|Yes| Targeted
|
|
152
|
-
Q3 -->|No| Broadcast[Use BROADCAST<br/>Observable fact]
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
| Question | Untargeted | Targeted | Broadcast |
|
|
156
|
-
| ----------------------------------- | :--------: | :------: | :-------: |
|
|
157
|
-
| Has a specific sender that matters? |
|
|
158
|
-
| Has a specific recipient? |
|
|
159
|
-
| Is it a command? |
|
|
160
|
-
| Is it an observable fact? | Maybe |
|
|
161
|
-
| Is it a global announcement? |
|
|
162
|
-
|
|
163
|
-
>
|
|
164
|
-
>
|
|
165
|
-
> - **Forgetting to enable the token**
|
|
166
|
-
> - **Targeting Component when you meant GameObject**
|
|
167
|
-
> - **Using Broadcast when you need Targeted**
|
|
168
|
-
> - **Missing `[Dx*Message]` attribute**
|
|
169
|
-
>
|
|
170
|
-
> 📖 See [Troubleshooting](docs/reference/troubleshooting.md) for solutions to these and other issues.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## Quick Start (5 Minutes)
|
|
179
|
-
|
|
180
|
-
**New to messaging?** Start with the [Visual Guide](docs/getting-started/visual-guide.md) (5 min) for a beginner-friendly introduction!
|
|
181
|
-
|
|
182
|
-
### 1. Install
|
|
183
|
-
|
|
184
|
-
#### Via OpenUPM (Recommended)
|
|
185
|
-
|
|
186
|
-
```bash
|
|
187
|
-
openupm add com.wallstop-studios.dxmessaging
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
#### Or via Git URL
|
|
191
|
-
|
|
192
|
-
```bash
|
|
193
|
-
# Unity Package Manager > Add package from git URL...
|
|
194
|
-
https://github.com/
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
See the [Install Guide](docs/getting-started/install.md) for all options including NPM scoped registries and local tarballs.
|
|
198
|
-
|
|
199
|
-
### 2. Define Your First Message
|
|
200
|
-
|
|
201
|
-
```csharp
|
|
202
|
-
using DxMessaging.Core.Attributes;
|
|
203
|
-
|
|
204
|
-
[DxTargetedMessage]
|
|
205
|
-
[DxAutoConstructor] // Auto-generates constructor
|
|
206
|
-
public readonly partial struct OpenChest {
|
|
207
|
-
public readonly int chestId;
|
|
208
|
-
[DxOptionalParameter(true)] // Optional with custom default
|
|
209
|
-
public readonly bool playSound;
|
|
210
|
-
}
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### 3. Listen for It
|
|
214
|
-
|
|
215
|
-
```csharp
|
|
216
|
-
using DxMessaging.Unity;
|
|
217
|
-
|
|
218
|
-
public class ChestController : MessageAwareComponent {
|
|
219
|
-
protected override void RegisterMessageHandlers() {
|
|
220
|
-
base.RegisterMessageHandlers();
|
|
221
|
-
_ = Token.RegisterComponentTargeted<OpenChest>(this, OnOpen);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
void OnOpen(ref OpenChest msg) {
|
|
225
|
-
Debug.Log($"Opening chest {msg.chestId}");
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
- **
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
- [
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
- **
|
|
302
|
-
- **You
|
|
303
|
-
- **
|
|
304
|
-
- **You
|
|
305
|
-
- **
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
- **
|
|
312
|
-
- **
|
|
313
|
-
- **
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
- **
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
Q1
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
Q2
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
Q3
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
[SerializeField] private
|
|
368
|
-
[SerializeField] private
|
|
369
|
-
[SerializeField] private
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
- **
|
|
399
|
-
- **
|
|
400
|
-
- **
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
_ = Token.RegisterUntargeted<
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
[12:34:
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
-
|
|
487
|
-
-
|
|
488
|
-
-
|
|
489
|
-
-
|
|
490
|
-
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
//
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
//
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
//
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
**
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
);
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
-
|
|
565
|
-
|
|
566
|
-
- **
|
|
567
|
-
- **
|
|
568
|
-
|
|
569
|
-
**
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
**
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
-
|
|
602
|
-
|
|
603
|
-
-
|
|
604
|
-
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
**
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
-
|
|
618
|
-
-
|
|
619
|
-
-
|
|
620
|
-
|
|
621
|
-
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
-
|
|
632
|
-
|
|
633
|
-
- "
|
|
634
|
-
- "
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
**
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
var
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
-
|
|
668
|
-
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
- **[
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
- **
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
- [
|
|
687
|
-
- [
|
|
688
|
-
- [
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
- [
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
- If you
|
|
702
|
-
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
|
737
|
-
|
|
|
738
|
-
| **
|
|
739
|
-
| **
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
-
|
|
747
|
-
-
|
|
748
|
-
-
|
|
749
|
-
-
|
|
750
|
-
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
>
|
|
758
|
-
>
|
|
759
|
-
>
|
|
760
|
-
>
|
|
761
|
-
> -
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
- [
|
|
769
|
-
- [
|
|
770
|
-
- [
|
|
771
|
-
- [
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
- **
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
|
841
|
-
|
|
|
842
|
-
| **
|
|
843
|
-
| **
|
|
844
|
-
| **
|
|
845
|
-
| **
|
|
846
|
-
| **
|
|
847
|
-
| **
|
|
848
|
-
| **
|
|
849
|
-
| **
|
|
850
|
-
| **
|
|
851
|
-
| **
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
|
859
|
-
|
|
|
860
|
-
| **
|
|
861
|
-
| **
|
|
862
|
-
| **
|
|
863
|
-
| **
|
|
864
|
-
| **
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
-
|
|
899
|
-
|
|
900
|
-
|
|
1
|
+
# DxMessaging for Unity
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="docs/images/DxMessaging-banner.svg" alt="DxMessaging - Type-safe messaging system for Unity" width="800"/>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://ambiguous-interactive.github.io/DxMessaging/">
|
|
9
|
+
<img src="https://img.shields.io/badge/Full_Documentation-Visit_the_Docs_Site-2ea44f?style=for-the-badge" alt="Full Documentation" />
|
|
10
|
+
</a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
[](https://unity.com/releases/editor/archive)<br/>
|
|
14
|
+
[](LICENSE.md)<br/>
|
|
15
|
+
[](https://openupm.com/packages/com.wallstop-studios.dxmessaging/)<br/>
|
|
16
|
+
[](https://www.npmjs.com/package/com.wallstop-studios.dxmessaging)<br/>
|
|
17
|
+
[-blueviolet.svg>)](docs/architecture/performance.md)<br/>
|
|
18
|
+
[](https://github.com/Ambiguous-Interactive/DxMessaging/actions/workflows/markdown-link-validity.yml)
|
|
19
|
+
|
|
20
|
+
> **🤖 AI Assistance Disclosure:**
|
|
21
|
+
>
|
|
22
|
+
> This project has been actively developed and maintained by human authors for over a decade. Recent versions have utilized AI assistance for documentation, test coverage, and performance optimizations.
|
|
23
|
+
|
|
24
|
+
**DxMessaging is a type-safe messaging system** that replaces sprawling C# events, brittle UnityEvents, and global static event buses with an observable and lifecycle-managed communication pattern.
|
|
25
|
+
|
|
26
|
+
Think of it as: A messaging system designed for decoupled game systems.
|
|
27
|
+
|
|
28
|
+
Need install instructions? Try [OpenUPM](https://openupm.com/packages/com.wallstop-studios.dxmessaging/) (recommended) or see the [Install Guide](docs/getting-started/install.md) for Git URLs, scoped registries, and more.
|
|
29
|
+
|
|
30
|
+
## Table of Contents
|
|
31
|
+
|
|
32
|
+
- [30-Second Elevator Pitch](#30-second-elevator-pitch)
|
|
33
|
+
- [Mental Model: How to Think About DxMessaging](#mental-model-how-to-think-about-dxmessaging)
|
|
34
|
+
- [Quick Start (5 Minutes)](#quick-start-5-minutes)
|
|
35
|
+
- [Dependency Injection (DI) Compatible](#dependency-injection-di-compatible)
|
|
36
|
+
- [Is DxMessaging Right for You?](#is-dxmessaging-right-for-you)
|
|
37
|
+
- [Why DxMessaging](#why-dxmessaging)
|
|
38
|
+
- [Key Features](#key-features)
|
|
39
|
+
- [The DxMessaging Solution](#the-dxmessaging-solution)
|
|
40
|
+
- [Real-World Examples](#real-world-examples)
|
|
41
|
+
- [Performance](#performance)
|
|
42
|
+
- [Comparison Table](#comparison-table)
|
|
43
|
+
- [Samples](#samples)
|
|
44
|
+
- [Documentation](#documentation)
|
|
45
|
+
- [Requirements](#requirements)
|
|
46
|
+
- [Contributing](#contributing)
|
|
47
|
+
- [Links](#links)
|
|
48
|
+
- [AI Agent Integration](#ai-agent-integration)
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 30-Second Elevator Pitch
|
|
53
|
+
|
|
54
|
+
### If you've ever
|
|
55
|
+
|
|
56
|
+
- Forgotten to unsubscribe from an event and spent hours debugging memory leaks
|
|
57
|
+
- Had UI code tangled with 15 different game systems
|
|
58
|
+
- Wondered "which event fired when?" with no way to see message flow
|
|
59
|
+
- Copy-pasted event boilerplate dozens of times
|
|
60
|
+
|
|
61
|
+
#### Then DxMessaging can help address these challenges
|
|
62
|
+
|
|
63
|
+
- **Automatic lifecycle management** - manages subscription lifecycle automatically, no manual unsubscribe
|
|
64
|
+
- **Zero coupling** - systems communicate without knowing each other exist
|
|
65
|
+
- **Full visibility** - see every message in the Inspector with timestamps and payloads
|
|
66
|
+
- **Complete control** - priority-based ordering, validation, and interception
|
|
67
|
+
|
|
68
|
+
##### Three simple message types
|
|
69
|
+
|
|
70
|
+
1. **Untargeted** - Global announcements
|
|
71
|
+
1. **Targeted** - Commands to specific entities
|
|
72
|
+
1. **Broadcast** - Observable facts from a source
|
|
73
|
+
|
|
74
|
+
See [Mental Model](#mental-model-how-to-think-about-dxmessaging) for how to choose the right type.
|
|
75
|
+
|
|
76
|
+
**One line:** It's a type-safe messaging system with automatic lifecycle management and built-in inspection tools.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Mental Model: How to Think About DxMessaging
|
|
81
|
+
|
|
82
|
+
### The Core Idea
|
|
83
|
+
|
|
84
|
+
DxMessaging is built around one principle: **it gets out of your way**.
|
|
85
|
+
|
|
86
|
+
You have data. You need to pass it around. That's the problem. DxMessaging provides fast, simple primitives as building blocks. You model changes as message types with optional context, using game primitives (GameObjects, components) as that context.
|
|
87
|
+
|
|
88
|
+
**You don't build your game INTO the messaging system.** It's opt-in and optional -- a tool you reach for when it helps.
|
|
89
|
+
|
|
90
|
+
### The Three Message Types: Real-World Analogies
|
|
91
|
+
|
|
92
|
+
> 💡 _Diagrams below require Mermaid support. If they don't render, try viewing this file directly on [GitHub](https://github.com/Ambiguous-Interactive/DxMessaging)._
|
|
93
|
+
|
|
94
|
+
Each message type maps to a real-world communication pattern:
|
|
95
|
+
|
|
96
|
+
#### 1. Untargeted = PA System
|
|
97
|
+
|
|
98
|
+
```mermaid
|
|
99
|
+
flowchart LR
|
|
100
|
+
S[Someone] -->|announces| PA[PA System]
|
|
101
|
+
PA --> L1[Listener A]
|
|
102
|
+
PA --> L2[Listener B]
|
|
103
|
+
PA --> L3[Listener C]
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Announcements with no specific recipient. Everyone who cares can hear it.
|
|
107
|
+
|
|
108
|
+
**Examples:** "The game is paused", "Settings changed", "Scene finished loading"
|
|
109
|
+
|
|
110
|
+
#### 2. Targeted = Addressed Letter
|
|
111
|
+
|
|
112
|
+
```mermaid
|
|
113
|
+
flowchart LR
|
|
114
|
+
S[Sender] -->|"To: Player"| Letter[Message Bus]
|
|
115
|
+
Letter --> Player[Player receives]
|
|
116
|
+
Other1[Enemy A] -.->|ignores| Letter
|
|
117
|
+
Other2[Enemy B] -.->|ignores| Letter
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Commands to a specific recipient. Only that entity receives them.
|
|
121
|
+
|
|
122
|
+
**Examples:** "Player, heal for 10 HP", "Door #7, open", "This enemy, take 25 damage"
|
|
123
|
+
|
|
124
|
+
#### 3. Broadcast = Radio Station
|
|
125
|
+
|
|
126
|
+
```mermaid
|
|
127
|
+
flowchart LR
|
|
128
|
+
Source[Enemy] -->|"I took damage!"| Radio[Message Bus]
|
|
129
|
+
Radio --> L1[Damage Numbers UI]
|
|
130
|
+
Radio --> L2[Achievement Tracker]
|
|
131
|
+
Radio --> L3[Analytics]
|
|
132
|
+
Radio --> L4[Combat Log]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Facts emitted by a specific source. No intended recipient -- just an origin. Anyone can tune in.
|
|
136
|
+
|
|
137
|
+
**Examples:** "This enemy took 25 damage", "The player picked up item X", "This chest opened"
|
|
138
|
+
|
|
139
|
+
### Choosing the Right Message Type
|
|
140
|
+
|
|
141
|
+
```mermaid
|
|
142
|
+
flowchart TD
|
|
143
|
+
Start([I need to send a message])
|
|
144
|
+
Start --> Q1{Does it matter<br/>WHO sent it?}
|
|
145
|
+
|
|
146
|
+
Q1 -->|No| Q2{Does it matter<br/>WHO receives it?}
|
|
147
|
+
Q2 -->|No| Untargeted[Use UNTARGETED<br/>Global announcement]
|
|
148
|
+
Q2 -->|Yes| Targeted[Use TARGETED<br/>Directed command]
|
|
149
|
+
|
|
150
|
+
Q1 -->|Yes| Q3{Am I commanding<br/>someone to act?}
|
|
151
|
+
Q3 -->|Yes| Targeted
|
|
152
|
+
Q3 -->|No| Broadcast[Use BROADCAST<br/>Observable fact]
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
| Question | Untargeted | Targeted | Broadcast |
|
|
156
|
+
| ----------------------------------- | :--------: | :------: | :-------: |
|
|
157
|
+
| Has a specific sender that matters? | No | No | Yes |
|
|
158
|
+
| Has a specific recipient? | No | Yes | No |
|
|
159
|
+
| Is it a command? | No | Yes | No |
|
|
160
|
+
| Is it an observable fact? | Maybe | No | Yes |
|
|
161
|
+
| Is it a global announcement? | Yes | No | No |
|
|
162
|
+
|
|
163
|
+
> **Common Mistakes:**
|
|
164
|
+
>
|
|
165
|
+
> - **Forgetting to enable the token** -- Messages won't be received. Use `MessageAwareComponent` (auto-enables) or call `Token.Enable()` manually.
|
|
166
|
+
> - **Targeting Component when you meant GameObject** -- These are distinct registration paths. Component-targeted messages won't reach GameObject-level handlers.
|
|
167
|
+
> - **Using Broadcast when you need Targeted** -- Broadcasts have no recipient, just an origin. Use Targeted when commanding a specific entity.
|
|
168
|
+
> - **Missing `[Dx*Message]` attribute** -- The source generator won't process the struct without the marker attribute.
|
|
169
|
+
>
|
|
170
|
+
> 📖 See [Troubleshooting](docs/reference/troubleshooting.md) for solutions to these and other issues.
|
|
171
|
+
|
|
172
|
+
**Want more depth?** See the full [Mental Model documentation](docs/concepts/mental-model.md) for detailed examples, lifecycle patterns, and edge cases.
|
|
173
|
+
|
|
174
|
+
**Ready to code?** Jump to [Quick Start](#quick-start-5-minutes) to send your first message!
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Quick Start (5 Minutes)
|
|
179
|
+
|
|
180
|
+
**New to messaging?** Start with the [Visual Guide](docs/getting-started/visual-guide.md) (5 min) for a beginner-friendly introduction!
|
|
181
|
+
|
|
182
|
+
### 1. Install
|
|
183
|
+
|
|
184
|
+
#### Via OpenUPM (Recommended)
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
openupm add com.wallstop-studios.dxmessaging
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
#### Or via Git URL
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# Unity Package Manager > Add package from git URL...
|
|
194
|
+
https://github.com/Ambiguous-Interactive/DxMessaging.git
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
See the [Install Guide](docs/getting-started/install.md) for all options including NPM scoped registries and local tarballs.
|
|
198
|
+
|
|
199
|
+
### 2. Define Your First Message
|
|
200
|
+
|
|
201
|
+
```csharp
|
|
202
|
+
using DxMessaging.Core.Attributes;
|
|
203
|
+
|
|
204
|
+
[DxTargetedMessage]
|
|
205
|
+
[DxAutoConstructor] // Auto-generates constructor
|
|
206
|
+
public readonly partial struct OpenChest {
|
|
207
|
+
public readonly int chestId;
|
|
208
|
+
[DxOptionalParameter(true)] // Optional with custom default
|
|
209
|
+
public readonly bool playSound;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 3. Listen for It
|
|
214
|
+
|
|
215
|
+
```csharp
|
|
216
|
+
using DxMessaging.Unity;
|
|
217
|
+
|
|
218
|
+
public class ChestController : MessageAwareComponent {
|
|
219
|
+
protected override void RegisterMessageHandlers() {
|
|
220
|
+
base.RegisterMessageHandlers();
|
|
221
|
+
_ = Token.RegisterComponentTargeted<OpenChest>(this, OnOpen);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
void OnOpen(ref OpenChest msg) {
|
|
225
|
+
Debug.Log($"Opening chest {msg.chestId}");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
> **Heads-up:** When you override `Awake`, `OnEnable`, `OnDisable`, `OnDestroy`, or `RegisterMessageHandlers`, call the base method first or handlers fail silently. See [DXMSG006](docs/reference/analyzers.md#dxmsg006-missing-base-call).
|
|
231
|
+
|
|
232
|
+
### 4. Send It
|
|
233
|
+
|
|
234
|
+
```csharp
|
|
235
|
+
// From anywhere:
|
|
236
|
+
var msg = new OpenChest(chestId: 42);
|
|
237
|
+
msg.EmitComponentTargeted(chestComponent);
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
No manual unsubscribe needed. Subscriptions are type-safe and lifecycle-managed.
|
|
241
|
+
|
|
242
|
+
**Stuck?** See [Troubleshooting](docs/reference/troubleshooting.md) or [FAQ](docs/reference/faq.md)
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Dependency Injection (DI) Compatible
|
|
247
|
+
|
|
248
|
+
**Using Zenject, VContainer, or Reflex?** DxMessaging is fully DI-compatible out of the box!
|
|
249
|
+
|
|
250
|
+
```csharp
|
|
251
|
+
// Inject IMessageBus in any class
|
|
252
|
+
public class PlayerService : IInitializable, IDisposable
|
|
253
|
+
{
|
|
254
|
+
private readonly MessageRegistrationLease _lease;
|
|
255
|
+
|
|
256
|
+
public PlayerService(IMessageRegistrationBuilder builder)
|
|
257
|
+
{
|
|
258
|
+
// Builder automatically resolves your container-managed bus
|
|
259
|
+
_lease = builder.Build(new MessageRegistrationBuildOptions
|
|
260
|
+
{
|
|
261
|
+
Configure = token => token.RegisterUntargeted<PlayerSpawned>(OnSpawn)
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
public void Initialize() => _lease.Activate();
|
|
266
|
+
public void Dispose() => _lease.Dispose();
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Why use DI + Messaging?
|
|
271
|
+
|
|
272
|
+
- **DI for construction** -- Inject services, repositories, managers via constructors
|
|
273
|
+
- **Messaging for events** -- Reactive, decoupled communication for gameplay events
|
|
274
|
+
- **Combined approach** -- Clean architecture with testable, isolated buses
|
|
275
|
+
|
|
276
|
+
#### Automatic integration for
|
|
277
|
+
|
|
278
|
+
- [x] **Zenject/Extenject** -- Full-featured DI with extensive Unity support
|
|
279
|
+
- [x] **VContainer** -- Lightweight, high-performance DI with scoped lifetimes
|
|
280
|
+
- [x] **Reflex** -- Minimal API, high-performance dependency injection
|
|
281
|
+
|
|
282
|
+
##### Get started
|
|
283
|
+
|
|
284
|
+
- [Zenject Integration Guide](docs/integrations/zenject.md) -- Complete setup with examples
|
|
285
|
+
- [VContainer Integration Guide](docs/integrations/vcontainer.md) -- Scoped buses for scene isolation
|
|
286
|
+
- [Reflex Integration Guide](docs/integrations/reflex.md) -- Minimal, lightweight patterns
|
|
287
|
+
|
|
288
|
+
##### Core DI concepts
|
|
289
|
+
|
|
290
|
+
- [Runtime Configuration](docs/advanced/runtime-configuration.md) -- Setting message buses at runtime, re-binding registrations
|
|
291
|
+
- [Message Bus Providers](docs/advanced/message-bus-providers.md) -- Provider system for design-time and runtime bus configuration
|
|
292
|
+
|
|
293
|
+
**Not using DI?** No problem. DxMessaging works standalone with zero dependencies.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Is DxMessaging Right for You?
|
|
298
|
+
|
|
299
|
+
### Use DxMessaging When
|
|
300
|
+
|
|
301
|
+
- **You have cross-system communication** - UI needs to react to gameplay, achievements track events, analytics observe everything
|
|
302
|
+
- **You're building for scale** - 10+ systems that need to communicate, or growing from prototype to production
|
|
303
|
+
- **Memory leaks are a concern** - You've been bitten by forgotten event unsubscribes before
|
|
304
|
+
- **You value observability** - Need to debug "what fired when?" or track message flow
|
|
305
|
+
- **Teams/long-term maintenance** - Multiple developers, or you'll maintain this code for years
|
|
306
|
+
- **You want decoupling** - When UI classes need references to many game systems
|
|
307
|
+
- **You're using DI frameworks** - Compatible with Zenject/VContainer/Reflex (see [DI Compatible](#dependency-injection-di-compatible))
|
|
308
|
+
|
|
309
|
+
### Don't Use DxMessaging When
|
|
310
|
+
|
|
311
|
+
- **Tiny prototypes/game jams** - If your game is <1000 lines and will be done in a week, C# events are fine
|
|
312
|
+
- **Simple, local communication** - A single button calling a single method? Just use UnityEvents or direct references
|
|
313
|
+
- **Performance is THE constraint** - Building a physics engine or ECS with millions of events/frame? Raw delegates are faster
|
|
314
|
+
- **Team is unfamiliar** - Learning curve exists; if the team isn't on board, it won't be used correctly
|
|
315
|
+
- **You need synchronous return values** - DxMessaging is fire-and-forget; if you need bidirectional request/response, consider other patterns
|
|
316
|
+
|
|
317
|
+
### Maybe Use DxMessaging (Start Small)
|
|
318
|
+
|
|
319
|
+
- **Existing large codebase** - Migrate incrementally: start with new features, refactor old code gradually (see [Migration Guide](docs/guides/migration-guide.md))
|
|
320
|
+
- **Small team learning** - Try it for one system (e.g., achievements) before going all-in
|
|
321
|
+
- **Mid-size projects (5-20k lines)** - Evaluate after trying it for one complex interaction (e.g., combat or scene transitions)
|
|
322
|
+
|
|
323
|
+
### Decision Flow
|
|
324
|
+
|
|
325
|
+
```mermaid
|
|
326
|
+
flowchart TD
|
|
327
|
+
Q1{Does your project have 3+<br/>systems that need to talk to each other?}
|
|
328
|
+
Q1 -->|NO| A1[Stick with C# events or direct references]
|
|
329
|
+
Q1 -->|YES| Q2
|
|
330
|
+
|
|
331
|
+
Q2{Are you okay with a small<br/>upfront learning investment?}
|
|
332
|
+
Q2 -->|NO| A2[Stick with what you know]
|
|
333
|
+
Q2 -->|YES| Q3
|
|
334
|
+
|
|
335
|
+
Q3{Do you need observable, decoupled,<br/>lifecycle-safe messaging?}
|
|
336
|
+
Q3 -->|YES| A3[" Use DxMessaging"]
|
|
337
|
+
Q3 -->|NO| A4[" Keep it simple"]
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Rule of thumb:** If decoupling, lifecycle leaks, or handler-ordering bugs match what you're hitting today, DxMessaging fits. If none of those describe your project, start with the [Visual Guide](docs/getting-started/visual-guide.md) or stick with simpler patterns.
|
|
341
|
+
|
|
342
|
+
Looking for hard numbers? See the Standalone IL2CPP dispatch and library-comparison [Performance Benchmarks](docs/architecture/performance.md).
|
|
343
|
+
|
|
344
|
+
## Why DxMessaging
|
|
345
|
+
|
|
346
|
+
### The Problems You've Probably Hit
|
|
347
|
+
|
|
348
|
+
#### Scenario 1: The Memory Leak Nightmare
|
|
349
|
+
|
|
350
|
+
You write this innocent-looking code:
|
|
351
|
+
|
|
352
|
+
```csharp
|
|
353
|
+
public class GameUI : MonoBehaviour {
|
|
354
|
+
void OnEnable() {
|
|
355
|
+
GameManager.Instance.OnScoreChanged += UpdateScore;
|
|
356
|
+
}
|
|
357
|
+
// Oops, forgot OnDisable... leak!
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Months later: "Why is our game using 2GB of RAM after an hour?"
|
|
362
|
+
|
|
363
|
+
#### Scenario 2: The Spaghetti Mess
|
|
364
|
+
|
|
365
|
+
```csharp
|
|
366
|
+
public class GameUI : MonoBehaviour {
|
|
367
|
+
[SerializeField] private Player player;
|
|
368
|
+
[SerializeField] private EnemySpawner spawner;
|
|
369
|
+
[SerializeField] private InventorySystem inventory;
|
|
370
|
+
[SerializeField] private QuestSystem quests;
|
|
371
|
+
[SerializeField] private AudioManager audio;
|
|
372
|
+
// ... 15 more SerializeFields ...
|
|
373
|
+
|
|
374
|
+
void Awake() {
|
|
375
|
+
player.OnHealthChanged += UpdateHealth;
|
|
376
|
+
spawner.OnWaveStart += ShowWave;
|
|
377
|
+
inventory.OnItemAdded += RefreshInventory;
|
|
378
|
+
quests.OnQuestCompleted += ShowQuestNotification;
|
|
379
|
+
// ... 20 more subscriptions ...
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**Your UI now depends on many systems.** Refactoring becomes more difficult.
|
|
385
|
+
|
|
386
|
+
#### Scenario 3: The Debugging Black Hole
|
|
387
|
+
|
|
388
|
+
Player reports: "My health bar didn't update!"
|
|
389
|
+
|
|
390
|
+
You think: "Okay, which of the 47 events touching health failed? And in what order?"
|
|
391
|
+
|
|
392
|
+
**30 minutes later:** Still setting breakpoints everywhere...
|
|
393
|
+
|
|
394
|
+
### Common Challenges
|
|
395
|
+
|
|
396
|
+
Some developers encounter these challenges when working with traditional event systems:
|
|
397
|
+
|
|
398
|
+
- **Memory leaks** from forgotten unsubscribes
|
|
399
|
+
- **Tight coupling** making refactoring difficult
|
|
400
|
+
- **No execution order control** leading to unpredictable behavior
|
|
401
|
+
- **Limited debugging visibility** for tracking message flow
|
|
402
|
+
- **Boilerplate code** when managing many event subscriptions
|
|
403
|
+
|
|
404
|
+
### The DxMessaging Solution
|
|
405
|
+
|
|
406
|
+
#### Same scenarios, simplified handling
|
|
407
|
+
|
|
408
|
+
##### Scenario 1: No More Memory Leaks
|
|
409
|
+
|
|
410
|
+
```csharp
|
|
411
|
+
public class GameUI : MessageAwareComponent {
|
|
412
|
+
protected override void RegisterMessageHandlers() {
|
|
413
|
+
base.RegisterMessageHandlers();
|
|
414
|
+
_ = Token.RegisterUntargeted<ScoreChanged>(UpdateScore);
|
|
415
|
+
}
|
|
416
|
+
// No manual cleanup needed.
|
|
417
|
+
// Token automatically handles OnEnable/OnDisable/OnDestroy
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
###### Automatic lifecycle = leaks are prevented by default
|
|
422
|
+
|
|
423
|
+
##### Scenario 2: No More Coupling
|
|
424
|
+
|
|
425
|
+
```csharp
|
|
426
|
+
public class GameUI : MessageAwareComponent {
|
|
427
|
+
// Zero SerializeFields! Zero references!
|
|
428
|
+
|
|
429
|
+
protected override void RegisterMessageHandlers() {
|
|
430
|
+
base.RegisterMessageHandlers();
|
|
431
|
+
_ = Token.RegisterUntargeted<HealthChanged>(OnHealth);
|
|
432
|
+
_ = Token.RegisterUntargeted<WaveStarted>(OnWave);
|
|
433
|
+
_ = Token.RegisterUntargeted<ItemAdded>(OnItem);
|
|
434
|
+
// Listen to anything, from anywhere, no coupling
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Your UI is now independent.** Swapping systems no longer requires updating UI references.
|
|
440
|
+
|
|
441
|
+
##### Scenario 3: Debugging is Built In
|
|
442
|
+
|
|
443
|
+
Open any `MessageAwareComponent` in the Inspector:
|
|
444
|
+
|
|
445
|
+
```text
|
|
446
|
+
Message History (last 50):
|
|
447
|
+
[12:34:56] HealthChanged (amount: 25) -> Priority: 0
|
|
448
|
+
[12:34:55] ItemAdded (id: 42, count: 1) -> Priority: 5
|
|
449
|
+
[12:34:54] WaveStarted (wave: 3) -> Priority: 0
|
|
450
|
+
|
|
451
|
+
Active Registrations:
|
|
452
|
+
HealthChanged (5 handlers)
|
|
453
|
+
ItemAdded (2 handlers)
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**See exactly what fired, when, and who handled it.** No guesswork.
|
|
457
|
+
|
|
458
|
+
### How It Transforms Your Code
|
|
459
|
+
|
|
460
|
+
```csharp
|
|
461
|
+
// 1. Define messages (typed, discoverable)
|
|
462
|
+
[DxTargetedMessage]
|
|
463
|
+
[DxAutoConstructor]
|
|
464
|
+
public readonly partial struct Heal { public readonly int amount; }
|
|
465
|
+
|
|
466
|
+
// 2. Listen (automatic lifecycle - prevents leaks)
|
|
467
|
+
public class Player : MessageAwareComponent {
|
|
468
|
+
protected override void RegisterMessageHandlers() {
|
|
469
|
+
base.RegisterMessageHandlers();
|
|
470
|
+
_ = Token.RegisterComponentTargeted<Heal>(this, OnHeal);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
void OnHeal(ref Heal m) {
|
|
474
|
+
health += m.amount;
|
|
475
|
+
Debug.Log($"Healed {m.amount}!");
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// 3. Send (from anywhere - zero coupling)
|
|
480
|
+
var heal = new Heal(50);
|
|
481
|
+
heal.EmitComponentTargeted(playerComponent);
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
#### What you get
|
|
485
|
+
|
|
486
|
+
- [x] **Automatic cleanup** - tokens clean up when components are destroyed
|
|
487
|
+
- [x] **Zero coupling** - no SerializeFields, no GetComponent, no direct references
|
|
488
|
+
- [x] **Full visibility** - see message flow in Inspector with timestamps and payloads
|
|
489
|
+
- [x] **Predictable order** - priority-based execution (no more mystery race conditions)
|
|
490
|
+
- [x] **Type-safe** - compile-time guarantees, refactor with confidence
|
|
491
|
+
- [x] **Intercept & validate** - enforce rules before handlers run (clamp damage, block invalid input)
|
|
492
|
+
- [x] **Extension points everywhere** - interceptors, handlers, post-processors with priorities
|
|
493
|
+
|
|
494
|
+
## Key Features
|
|
495
|
+
|
|
496
|
+
What DxMessaging offers:
|
|
497
|
+
|
|
498
|
+
### Performance: Zero-Allocation Design
|
|
499
|
+
|
|
500
|
+
**The problem with normal events:** Boxing allocations, GC spikes, memory leaks from forgotten unsubscribes.
|
|
501
|
+
|
|
502
|
+
#### DxMessaging solution
|
|
503
|
+
|
|
504
|
+
```csharp
|
|
505
|
+
void OnDamage(ref TookDamage msg) { // Pass by ref = zero allocations
|
|
506
|
+
health -= msg.amount; // No boxing, no GC pressure
|
|
507
|
+
}
|
|
508
|
+
// Automatic cleanup prevents common leak patterns
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Note:** Struct messages passed by ref avoid GC allocations, which is standard behavior for value types in C#.
|
|
512
|
+
|
|
513
|
+
### Three Message Types
|
|
514
|
+
|
|
515
|
+
Most event systems force you into one pattern. DxMessaging gives you the right tool for each job:
|
|
516
|
+
|
|
517
|
+
```csharp
|
|
518
|
+
// Untargeted: "Everyone, listen up!" (global announcements)
|
|
519
|
+
[DxUntargetedMessage]
|
|
520
|
+
public struct GamePaused { }
|
|
521
|
+
// -> Perfect for: settings, scene transitions, global state
|
|
522
|
+
|
|
523
|
+
// Targeted: "Hey Player, do this!" (commands to specific entities)
|
|
524
|
+
[DxTargetedMessage]
|
|
525
|
+
public struct Heal { public int amount; }
|
|
526
|
+
// -> Perfect for: UI actions, direct commands, player input
|
|
527
|
+
|
|
528
|
+
// Broadcast: "I took damage!" (events others can observe)
|
|
529
|
+
[DxBroadcastMessage]
|
|
530
|
+
public struct TookDamage { public int amount; }
|
|
531
|
+
// -> Perfect for: achievements, analytics, UI updates from entities
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**Why this matters:** You're not forcing everything through one generic "Event<T>" pattern. Each message type has clear semantics.
|
|
535
|
+
|
|
536
|
+
### The Message Pipeline
|
|
537
|
+
|
|
538
|
+
Every message flows through 3 stages with priority control:
|
|
539
|
+
|
|
540
|
+
```mermaid
|
|
541
|
+
flowchart LR
|
|
542
|
+
P[Producer] --> I[Interceptors<br/>validate/mutate]
|
|
543
|
+
I --> H[Handlers<br/>main logic]
|
|
544
|
+
H --> PP[Post-Processors<br/>analytics/logging]
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### Global Observers: Listen to All Events
|
|
548
|
+
|
|
549
|
+
**The problem with normal events:** To track all player damage, enemy damage, and NPC damage, you need 3 separate event subscriptions.
|
|
550
|
+
|
|
551
|
+
**DxMessaging approach:** Subscribe once to a message type, receive all instances with source information:
|
|
552
|
+
|
|
553
|
+
```csharp
|
|
554
|
+
// Track ALL damage from ANY source (players, enemies, NPCs, environment)
|
|
555
|
+
_ = token.RegisterBroadcastWithoutSource<TookDamage>(
|
|
556
|
+
(InstanceId source, TookDamage msg) => {
|
|
557
|
+
Debug.Log($"{source} took {msg.amount} damage!");
|
|
558
|
+
Analytics.LogDamage(source, msg.amount);
|
|
559
|
+
CheckAchievements(source, msg.amount);
|
|
560
|
+
}
|
|
561
|
+
);
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
#### Real-world use cases
|
|
565
|
+
|
|
566
|
+
- **Achievement system:** Track all kills, deaths, damage across the entire game
|
|
567
|
+
- **Combat log:** "Player took 25 damage, Enemy3 took 50 damage, Boss took 100 damage"
|
|
568
|
+
- **Analytics:** Aggregate stats from all entities without knowing about them upfront
|
|
569
|
+
- **Debug tools:** Watch ALL messages in the Inspector without instrumenting code
|
|
570
|
+
|
|
571
|
+
**How this differs:** Some event bus patterns require subscribing to each entity type separately. DxMessaging allows observing all instances of a message type in one registration.
|
|
572
|
+
|
|
573
|
+
### Interceptors: Validate Before Execution
|
|
574
|
+
|
|
575
|
+
**The problem with normal events:** Validation logic duplicated in every handler, or bugs when you forget.
|
|
576
|
+
|
|
577
|
+
**DxMessaging solution:** Validate ONCE before ANY handler runs:
|
|
578
|
+
|
|
579
|
+
```csharp
|
|
580
|
+
// ONE interceptor protects ALL handlers
|
|
581
|
+
_ = token.RegisterBroadcastInterceptor<TookDamage>(
|
|
582
|
+
(ref InstanceId src, ref TookDamage msg) => {
|
|
583
|
+
if (msg.amount <= 0) return false; // Cancel invalid
|
|
584
|
+
if (msg.amount > 999) {
|
|
585
|
+
msg = new TookDamage(999); // Clamp excessive
|
|
586
|
+
}
|
|
587
|
+
if (IsGodModeActive(src)) return false; // Block damage
|
|
588
|
+
return true;
|
|
589
|
+
},
|
|
590
|
+
priority: -100 // Run FIRST
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
// Now ALL handlers receive clean, validated data
|
|
594
|
+
_ = token.RegisterComponentTargeted<TookDamage>(player, OnDamage);
|
|
595
|
+
void OnDamage(ref TookDamage msg) {
|
|
596
|
+
// No validation needed - interceptor guarantees validity!
|
|
597
|
+
health -= msg.amount;
|
|
598
|
+
}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
#### Real-world use cases
|
|
602
|
+
|
|
603
|
+
- Clamp/normalize values (damage, healing, speeds)
|
|
604
|
+
- Enforce game rules ("can't heal above max health")
|
|
605
|
+
- Block messages during cutscenes
|
|
606
|
+
- Log/audit sensitive actions
|
|
607
|
+
|
|
608
|
+
### Built-in Inspector Diagnostics
|
|
609
|
+
|
|
610
|
+
**The problem with normal events:** "Which event fired? When? Who handled it? In what order?" = unknown
|
|
611
|
+
|
|
612
|
+
**DxMessaging solution:** Click any `MessageAwareComponent` in the Inspector:
|
|
613
|
+
|
|
614
|
+
#### Message History (last 50)
|
|
615
|
+
|
|
616
|
+
- `[12:34:56.123] HealthChanged`
|
|
617
|
+
- amount: 25
|
|
618
|
+
- priority: 0
|
|
619
|
+
- handlers: 3
|
|
620
|
+
- `[12:34:55.987] ItemAdded`
|
|
621
|
+
- itemId: 42, count: 1
|
|
622
|
+
- priority: 5
|
|
623
|
+
- handlers: 2
|
|
624
|
+
|
|
625
|
+
##### Active Registrations
|
|
626
|
+
|
|
627
|
+
- [x] HealthChanged (priority: 0, called: 847 times)
|
|
628
|
+
- [x] ItemAdded (priority: 5, called: 23 times)
|
|
629
|
+
- [x] TookDamage (priority: 10, called: 1,203 times)
|
|
630
|
+
|
|
631
|
+
#### Real-world debugging scenarios
|
|
632
|
+
|
|
633
|
+
- "Did my message fire?" -> Check history, see timestamp
|
|
634
|
+
- "Why didn't my handler run?" -> Check registrations, see if it's active
|
|
635
|
+
- "What's firing too often?" -> Sort by call count
|
|
636
|
+
- "What's the execution order?" -> Sort by priority
|
|
637
|
+
|
|
638
|
+
**No more:** Setting 50 breakpoints and stepping through code for 30 minutes.
|
|
639
|
+
|
|
640
|
+
### Local Bus Islands for Testing
|
|
641
|
+
|
|
642
|
+
**The problem with normal events:** Global static events contaminate tests. Mock complexity. Flaky tests.
|
|
643
|
+
|
|
644
|
+
**DxMessaging solution:** Each test gets its own isolated message bus:
|
|
645
|
+
|
|
646
|
+
```csharp
|
|
647
|
+
[Test]
|
|
648
|
+
public void TestAchievementSystem() {
|
|
649
|
+
// Create isolated bus - zero global state
|
|
650
|
+
var testBus = new MessageBus();
|
|
651
|
+
var handler = new MessageHandler(new InstanceId(1), testBus) { active = true };
|
|
652
|
+
var token = MessageRegistrationToken.Create(handler, testBus);
|
|
653
|
+
|
|
654
|
+
// Test in isolation
|
|
655
|
+
_ = token.RegisterBroadcastWithoutSource<EnemyKilled>(achievements.OnKill);
|
|
656
|
+
|
|
657
|
+
var msg = new EnemyKilled("Boss");
|
|
658
|
+
msg.EmitGameObjectBroadcast(enemy, testBus); // Only this test sees it
|
|
659
|
+
|
|
660
|
+
Assert.IsTrue(achievements.Unlocked("BossSlayer"));
|
|
661
|
+
}
|
|
662
|
+
// Bus destroyed, zero cleanup needed
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
#### Why this matters
|
|
666
|
+
|
|
667
|
+
- Tests don't interfere with each other
|
|
668
|
+
- No "arrange/act/cleanup" boilerplate
|
|
669
|
+
- No mocking frameworks needed
|
|
670
|
+
- Parallel test execution is supported
|
|
671
|
+
|
|
672
|
+
## Documentation
|
|
673
|
+
|
|
674
|
+
- **[Documentation Site](https://ambiguous-interactive.github.io/DxMessaging/)** - Full searchable documentation
|
|
675
|
+
- **[Wiki](https://github.com/Ambiguous-Interactive/DxMessaging/wiki)** - Quick reference wiki
|
|
676
|
+
- **[Changelog](CHANGELOG.md)** - Version history
|
|
677
|
+
|
|
678
|
+
### Learn
|
|
679
|
+
|
|
680
|
+
- **New here?** Start with [Getting Started Guide](docs/getting-started/getting-started.md) (10 min read)
|
|
681
|
+
- **Want patterns?** See [Common Patterns](docs/guides/patterns.md)
|
|
682
|
+
- **Deep dive?** Read [Design & Architecture](docs/architecture/design-and-architecture.md)
|
|
683
|
+
|
|
684
|
+
### Core Concepts
|
|
685
|
+
|
|
686
|
+
- [Overview](docs/getting-started/overview.md) -- What and why
|
|
687
|
+
- [Quick Start](docs/getting-started/quick-start.md) -- First message in 5 minutes
|
|
688
|
+
- [Message Types](docs/concepts/message-types.md) -- When to use Untargeted/Targeted/Broadcast
|
|
689
|
+
- [Interceptors & Ordering](docs/concepts/interceptors-and-ordering.md) -- Control execution flow
|
|
690
|
+
- [Listening Patterns](docs/concepts/listening-patterns.md) -- All the ways to receive messages
|
|
691
|
+
|
|
692
|
+
### Unity Integration
|
|
693
|
+
|
|
694
|
+
- [Unity Integration](docs/guides/unity-integration.md) -- MessagingComponent deep dive
|
|
695
|
+
- [Targeting & Context](docs/concepts/targeting-and-context.md) -- GameObject vs Component
|
|
696
|
+
- [Diagnostics](docs/guides/diagnostics.md) -- Inspector tools and debugging
|
|
697
|
+
- [Memory Reclamation](docs/guides/memory-reclamation.md) -- idle eviction, explicit Trim, and tuning the runtime settings asset
|
|
698
|
+
|
|
699
|
+
Important: Inheritance with MessageAwareComponent
|
|
700
|
+
|
|
701
|
+
- If you override lifecycle or registration hooks, call the base method.
|
|
702
|
+
- Use `base.RegisterMessageHandlers()` to keep default string-message registrations.
|
|
703
|
+
- Use `base.OnEnable()` / `base.OnDisable()` to preserve token enable/disable.
|
|
704
|
+
- If you need to opt out of string demos, override `RegisterForStringMessages => false` instead of skipping the base call.
|
|
705
|
+
- Don't hide Unity methods with `new` (e.g., `new void OnEnable()`); always `override` and call `base.*`.
|
|
706
|
+
|
|
707
|
+
### DI Framework Integrations
|
|
708
|
+
|
|
709
|
+
DxMessaging works standalone (zero dependencies) or with any major DI framework. For detailed setup guides and code examples:
|
|
710
|
+
|
|
711
|
+
- **[Zenject Integration Guide](docs/integrations/zenject.md)** -- Full-featured DI with extensive Unity support
|
|
712
|
+
- **[VContainer Integration Guide](docs/integrations/vcontainer.md)** -- Lightweight DI with scoped lifetimes for scene isolation
|
|
713
|
+
- **[Reflex Integration Guide](docs/integrations/reflex.md)** -- Minimal API, high-performance DI
|
|
714
|
+
|
|
715
|
+
#### Core DI concepts
|
|
716
|
+
|
|
717
|
+
- **[Runtime Configuration](docs/advanced/runtime-configuration.md)** -- Setting and overriding message buses at runtime, re-binding registrations
|
|
718
|
+
- **[Message Bus Providers](docs/advanced/message-bus-providers.md)** -- Provider system and MessageBusProviderHandle for flexible bus configuration
|
|
719
|
+
|
|
720
|
+
Each guide includes:
|
|
721
|
+
|
|
722
|
+
- [x] Complete setup instructions with installers
|
|
723
|
+
- [x] Multiple usage patterns (plain classes, MonoBehaviours, direct injection)
|
|
724
|
+
- [x] Testing examples with isolated buses
|
|
725
|
+
- [x] Advanced patterns (pooling, scene scopes, signal bridges)
|
|
726
|
+
|
|
727
|
+
See the [DI Compatible section](#dependency-injection-di-compatible) above for a quick overview.
|
|
728
|
+
|
|
729
|
+
### Comparisons
|
|
730
|
+
|
|
731
|
+
- [Compare with Other Unity Messaging Frameworks](docs/architecture/comparisons.md) -- In-depth comparison with UniRx, MessagePipe, Zenject Signals, C# events, UnityEvents, and more
|
|
732
|
+
- [Scriptable Object Architecture (SOA) Compatibility](docs/guides/patterns.md#14-compatibility-with-scriptable-object-architecture-soa) -- Migration patterns and interoperability with SOA
|
|
733
|
+
|
|
734
|
+
#### Quick Framework Comparison
|
|
735
|
+
|
|
736
|
+
| Framework | Best For | Key Strength | Unity Support | Learning Curve |
|
|
737
|
+
| ------------------- | --------------------------------- | -------------------------------- | --------------- | -------------- |
|
|
738
|
+
| **DxMessaging** | Unity pub/sub with lifecycle mgmt | Inspector debugging + control | Built for Unity | Moderate |
|
|
739
|
+
| **UniRx** | Complex event stream transforms | Reactive operators (LINQ) | Built for Unity | Easy |
|
|
740
|
+
| **MessagePipe** | High-performance DI messaging | Highest throughput (74M ops/sec) | Built for Unity | Steep |
|
|
741
|
+
| **Zenject Signals** | DI-integrated messaging | Zenject ecosystem | Built for Unity | Easy |
|
|
742
|
+
| **C# Events** | Simple, local communication | Minimal overhead | Native C# | Steepest |
|
|
743
|
+
|
|
744
|
+
##### Choose DxMessaging when you want
|
|
745
|
+
|
|
746
|
+
- Unity-first design with GameObject/Component targeting
|
|
747
|
+
- Automatic lifecycle management (prevents common memory leaks)
|
|
748
|
+
- Inspector debugging to see message flow and history
|
|
749
|
+
- Execution order control (priority-based handlers)
|
|
750
|
+
- Message validation/interception pipeline
|
|
751
|
+
- Global observers (listen to all message instances)
|
|
752
|
+
- Post-processing stage (analytics, logging after handlers)
|
|
753
|
+
- No dependencies, plug-and-play setup
|
|
754
|
+
|
|
755
|
+
See [full comparison](docs/architecture/comparisons.md) for detailed analysis with code examples, performance benchmarks, and decision guides.
|
|
756
|
+
|
|
757
|
+
> **📦 Using Scriptable Object Architecture (SOA)?**
|
|
758
|
+
>
|
|
759
|
+
> DxMessaging can work alongside or replace SOA patterns. See [SOA Compatibility Guide](docs/guides/patterns.md#14-compatibility-with-scriptable-object-architecture-soa) for:
|
|
760
|
+
>
|
|
761
|
+
> - Fair comparison of SOA vs. DxMessaging
|
|
762
|
+
> - Migration patterns from GameEvent/FloatVariable to DxMessaging
|
|
763
|
+
> - How to use both systems together (SOs for configs, DxMessaging for events)
|
|
764
|
+
> - When to keep using ScriptableObjects (immutable design data)
|
|
765
|
+
|
|
766
|
+
### Reference
|
|
767
|
+
|
|
768
|
+
- [Install Guide](docs/getting-started/install.md) -- All install options (OpenUPM, Git URL, scoped registry, tarball)
|
|
769
|
+
- [Glossary](docs/reference/glossary.md) -- All terms explained in plain English
|
|
770
|
+
- [Quick Reference](docs/reference/quick-reference.md) -- Cheat sheet
|
|
771
|
+
- [API Reference](docs/reference/reference.md) -- Complete API
|
|
772
|
+
- [Helpers](docs/reference/helpers.md) -- Source generators and utilities
|
|
773
|
+
- [FAQ](docs/reference/faq.md) -- Common questions
|
|
774
|
+
- [Troubleshooting](docs/reference/troubleshooting.md)
|
|
775
|
+
|
|
776
|
+
### Full Documentation
|
|
777
|
+
|
|
778
|
+
Browse all docs: [Documentation Hub](docs/getting-started/index.md)
|
|
779
|
+
|
|
780
|
+
## Real-World Examples
|
|
781
|
+
|
|
782
|
+
### Scene Transitions
|
|
783
|
+
|
|
784
|
+
```csharp
|
|
785
|
+
[DxUntargetedMessage]
|
|
786
|
+
[DxAutoConstructor]
|
|
787
|
+
public readonly partial struct SceneTransition {
|
|
788
|
+
public readonly string sceneName;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// Multiple systems react independently
|
|
792
|
+
public class AudioSystem : MessageAwareComponent {
|
|
793
|
+
protected override void RegisterMessageHandlers() {
|
|
794
|
+
base.RegisterMessageHandlers();
|
|
795
|
+
_ = Token.RegisterUntargeted<SceneTransition>(OnScene, priority: 0);
|
|
796
|
+
}
|
|
797
|
+
void OnScene(ref SceneTransition m) => FadeOutMusic();
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
public class SaveSystem : MessageAwareComponent {
|
|
801
|
+
protected override void RegisterMessageHandlers() {
|
|
802
|
+
base.RegisterMessageHandlers();
|
|
803
|
+
_ = Token.RegisterUntargeted<SceneTransition>(OnScene, priority: 0);
|
|
804
|
+
}
|
|
805
|
+
void OnScene(ref SceneTransition m) => SaveGame();
|
|
806
|
+
}
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
### Achievement System
|
|
810
|
+
|
|
811
|
+
```csharp
|
|
812
|
+
// Listen to ALL events for achievement tracking
|
|
813
|
+
public class AchievementTracker : MessageAwareComponent {
|
|
814
|
+
protected override void RegisterMessageHandlers() {
|
|
815
|
+
base.RegisterMessageHandlers();
|
|
816
|
+
_ = Token.RegisterGlobalAcceptAll(
|
|
817
|
+
acceptAllUntargeted: m => Check(m),
|
|
818
|
+
acceptAllTargeted: (t, m) => Check(m),
|
|
819
|
+
acceptAllBroadcast: (s, m) => Check(m)
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
## Performance
|
|
826
|
+
|
|
827
|
+
- **Zero GC allocations** for struct messages
|
|
828
|
+
- **~10ns overhead** per handler (compared to C# events)
|
|
829
|
+
- **Type-indexed caching** for O(1) lookups
|
|
830
|
+
- **Optimized for hot paths** with aggressive inlining
|
|
831
|
+
|
|
832
|
+
See [Design & Architecture](docs/architecture/design-and-architecture.md#performance-optimizations) for details.
|
|
833
|
+
|
|
834
|
+
For live, CI-generated Standalone IL2CPP dispatch tables and a cross-library comparison matrix, see [Performance Benchmarks](docs/architecture/performance.md). Those numbers are auto-generated on every push with the .NET Standard 2.1 profile and a Release build; the comparison table below is a static summary, not the live data.
|
|
835
|
+
|
|
836
|
+
## Comparison Table
|
|
837
|
+
|
|
838
|
+
### Comparison with Unity Messaging Frameworks
|
|
839
|
+
|
|
840
|
+
| Feature | DxMessaging | UniRx | MessagePipe | Zenject Signals |
|
|
841
|
+
| ------------------------ | --------------- | --------------- | --------------- | --------------- |
|
|
842
|
+
| **Unity Compatibility** | Built for Unity | Built for Unity | Built for Unity | Built for Unity |
|
|
843
|
+
| **Decoupling** | Full | Full | Full | Full |
|
|
844
|
+
| **Lifecycle Safety** | Auto | Manual | Manual | DI-managed |
|
|
845
|
+
| **Execution Order** | Priority | None | None | None |
|
|
846
|
+
| **Type Safety** | Strong | Strong | Strong | Strong |
|
|
847
|
+
| **Inspector Debug** | Built-in | No | No | No |
|
|
848
|
+
| **GameObject Targeting** | Yes | No | No | No |
|
|
849
|
+
| **Global Observers** | Yes | No | No | No |
|
|
850
|
+
| **Interceptors** | Pipeline | No | Filters | No |
|
|
851
|
+
| **Post-Processing** | Dedicated | No | Filters | No |
|
|
852
|
+
| **Stream Operators** | No | Extensive | No | With UniRx |
|
|
853
|
+
| **Performance** | Good (27M) | Moderate (4M) | High (74M) | Moderate (2M) |
|
|
854
|
+
| **Dependencies** | None | UniTask | None | Zenject |
|
|
855
|
+
|
|
856
|
+
### Comparison with Traditional Approaches
|
|
857
|
+
|
|
858
|
+
| Feature | DxMessaging | C# Events | UnityEvents | Static Event Bus |
|
|
859
|
+
| ---------------------- | ----------- | --------- | ----------- | ---------------- |
|
|
860
|
+
| **Decoupling** | Full | Tight | Hidden | Yes |
|
|
861
|
+
| **Lifecycle Safety** | Auto | Manual | Unity-only | Manual |
|
|
862
|
+
| **Execution Order** | Priority | Undefined | Undefined | Undefined |
|
|
863
|
+
| **Type Safety** | Strong | Strong | Weak | Weak |
|
|
864
|
+
| **Context (Who/What)** | Rich | None | None | None |
|
|
865
|
+
| **Interception** | Yes | No | No | No |
|
|
866
|
+
| **Observability** | Built-in | No | No | No |
|
|
867
|
+
| **Performance** | Zero-alloc | Good | Boxing | Good |
|
|
868
|
+
|
|
869
|
+
## Samples
|
|
870
|
+
|
|
871
|
+
Import samples from Package Manager:
|
|
872
|
+
|
|
873
|
+
- **[Mini Combat](Samples~/Mini%20Combat/README.md)** -- Simple combat with Heal/Damage messages
|
|
874
|
+
- **[UI Buttons + Inspector](Samples~/UI%20Buttons%20%2B%20Inspector/README.md)** -- Interactive diagnostics demo
|
|
875
|
+
|
|
876
|
+
## Requirements
|
|
877
|
+
|
|
878
|
+
- Unity 2021.3 or later
|
|
879
|
+
- .NET Standard 2.1
|
|
880
|
+
- Works with all render pipelines (URP, HDRP, Built-in)
|
|
881
|
+
|
|
882
|
+
See [Compatibility](docs/reference/compatibility.md) for details.
|
|
883
|
+
|
|
884
|
+
## Contributing
|
|
885
|
+
|
|
886
|
+
Contributions welcome! See [Contributing](CONTRIBUTING.md).
|
|
887
|
+
|
|
888
|
+
## License
|
|
889
|
+
|
|
890
|
+
MIT License - see [License](LICENSE.md)
|
|
891
|
+
|
|
892
|
+
## Credits
|
|
893
|
+
|
|
894
|
+
Created and maintained by [wallstop studios](https://wallstopstudios.com)
|
|
895
|
+
|
|
896
|
+
## Links
|
|
897
|
+
|
|
898
|
+
- [Package on GitHub](https://github.com/Ambiguous-Interactive/DxMessaging)
|
|
899
|
+
- [Report Issues](https://github.com/Ambiguous-Interactive/DxMessaging/issues)
|
|
900
|
+
- [Documentation Site](https://ambiguous-interactive.github.io/DxMessaging/)
|
|
901
|
+
- [Wiki](https://github.com/Ambiguous-Interactive/DxMessaging/wiki)
|
|
902
|
+
|
|
903
|
+
## AI Agent Integration
|
|
904
|
+
|
|
905
|
+
DxMessaging publishes machine-readable context for AI agents through [llms.txt](llms.txt), following the [llmstxt.org](https://llmstxt.org/) standard. The file collects the project overview, API surface, conventions, and links into one document.
|
|
906
|
+
|
|
907
|
+
### For AI Agents
|
|
908
|
+
|
|
909
|
+
- **[llms.txt](llms.txt)** -- Complete project overview, API reference, and context in a single file
|
|
910
|
+
- **[Repository Guidelines](.llm/context.md)** -- Coding standards and development workflows
|
|
911
|
+
- **[AI Agent Skills](.llm/skills/)** -- 155+ specialized skill documents covering documentation, testing, GitHub Actions, and more
|
|
912
|
+
|
|
913
|
+
The `llms.txt` file is automatically updated via CI/CD to stay current with project changes. It includes:
|
|
914
|
+
|
|
915
|
+
- Project overview and quick facts
|
|
916
|
+
- Core concepts and architecture
|
|
917
|
+
- Complete documentation links
|
|
918
|
+
- Development commands and standards
|
|
919
|
+
- Common pitfalls and solutions
|
|
920
|
+
- Performance characteristics
|
|
921
|
+
- Code examples and patterns
|
|
922
|
+
|
|
923
|
+
### Keeping llms.txt Updated
|
|
924
|
+
|
|
925
|
+
The automation script ensures llms.txt stays current:
|
|
926
|
+
|
|
927
|
+
```bash
|
|
928
|
+
# Update llms.txt
|
|
929
|
+
npm run update:llms-txt
|
|
930
|
+
|
|
931
|
+
# Verify llms.txt is current
|
|
932
|
+
npm run check:llms-txt
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
GitHub Actions automatically validates and updates llms.txt:
|
|
936
|
+
|
|
937
|
+
- **Validation:** Runs on PRs to ensure llms.txt is up-to-date
|
|
938
|
+
- **Auto-update:** Runs weekly and on relevant file changes
|
|
939
|
+
|
|
940
|
+
---
|