com.wallstop-studios.dxmessaging 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.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 +1229 -146
- package/Docs/Compatibility.md +27 -0
- package/Docs/DesignAndArchitecture.md +41 -34
- package/Docs/EmitShorthands.md +34 -0
- package/Docs/Helpers.md +91 -76
- package/Docs/Index.md +28 -25
- package/Docs/Install.md +29 -6
- package/Docs/Integrations/Reflex.md +292 -0
- package/{package-lock.json.meta → Docs/Integrations/Reflex.md.meta} +1 -1
- 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/Patterns.md +286 -0
- package/Docs/Performance.md +9 -9
- package/Docs/QuickReference.md +31 -0
- package/Docs/QuickStart.md +1 -2
- package/Docs/RuntimeConfiguration.md +407 -0
- package/Docs/RuntimeConfiguration.md.meta +7 -0
- package/Docs/UnityIntegration.md +3 -1
- package/Docs/VisualGuide.md +206 -157
- package/Editor/CustomEditors/MessagingComponentEditor.cs +15 -6
- package/README.md +148 -26
- package/Runtime/AssemblyInfo.cs +4 -0
- package/Runtime/Core/Attributes/DxAutoConstructorAttribute.cs +1 -1
- package/Runtime/Core/Attributes/DxBroadcastMessageAttribute.cs +1 -1
- package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs +1 -1
- package/Runtime/Core/Attributes/DxTargetedMessageAttribute.cs +1 -1
- package/Runtime/Core/Attributes/DxUntargetedMessageAttribute.cs +1 -1
- 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/Core/Messages/IBroadcastMessage.cs +1 -1
- package/Runtime/Core/Messages/ITargetedMessage.cs +1 -1
- package/Runtime/Core/Messages/IUntargetedMessage.cs +1 -1
- 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 +175 -9
- 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 +79 -0
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +11 -0
- package/Samples~/DI/VContainer.meta +8 -0
- package/Samples~/DI/Zenject/SampleInstaller.cs +65 -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 +5 -7
- package/Samples~/Mini Combat/Walkthrough.md +18 -24
- package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs +12 -2
- 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/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
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
# Message Bus Providers
|
|
2
|
+
|
|
3
|
+
DxMessaging provides a flexible provider system that lets you configure which message bus drives your components. This works both at design time (with ScriptableObject providers) and at runtime (with provider handles).
|
|
4
|
+
|
|
5
|
+
This guide covers:
|
|
6
|
+
|
|
7
|
+
- The `IMessageBusProvider` interface
|
|
8
|
+
- Built-in ScriptableObject providers
|
|
9
|
+
- The `MessageBusProviderHandle` system
|
|
10
|
+
- How to create custom providers
|
|
11
|
+
- Practical usage patterns
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Table of Contents
|
|
16
|
+
|
|
17
|
+
- [Overview](#overview)
|
|
18
|
+
- [IMessageBusProvider Interface](#imessagebusprovider-interface)
|
|
19
|
+
- [Built-in Providers](#built-in-providers)
|
|
20
|
+
- [Current Global Message Bus Provider](#current-global-message-bus-provider)
|
|
21
|
+
- [Initial Global Message Bus Provider](#initial-global-message-bus-provider)
|
|
22
|
+
- [MessageBusProviderHandle](#messagebusproviderhandle)
|
|
23
|
+
- [Using Providers with Components](#using-providers-with-components)
|
|
24
|
+
- [Creating Custom Providers](#creating-custom-providers)
|
|
25
|
+
- [Common Patterns](#common-patterns)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Overview
|
|
30
|
+
|
|
31
|
+
Providers abstract away the details of how a message bus is resolved. This lets you:
|
|
32
|
+
|
|
33
|
+
- **Swap buses at design time** — Change a ScriptableObject reference without modifying code
|
|
34
|
+
- **Integrate with DI containers** — Resolve buses from your container
|
|
35
|
+
- **Support runtime reconfiguration** — Change which bus a component uses dynamically
|
|
36
|
+
- **Isolate scenes or features** — Use different buses for different parts of your game
|
|
37
|
+
|
|
38
|
+
If you're using the default global bus everywhere, you probably don't need providers. They're most useful when you need flexibility or are integrating with DI frameworks.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## IMessageBusProvider Interface
|
|
43
|
+
|
|
44
|
+
All providers implement this simple interface:
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
public interface IMessageBusProvider
|
|
48
|
+
{
|
|
49
|
+
IMessageBus Resolve();
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
When a component needs a bus, it calls `Resolve()` on its provider. The provider returns the appropriate bus instance.
|
|
54
|
+
|
|
55
|
+
**Key insight:** By abstracting bus resolution behind this interface, components don't need to know whether they're using the global bus, a container-managed bus, or something completely custom.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Built-in Providers
|
|
60
|
+
|
|
61
|
+
DxMessaging ships with two ScriptableObject-based providers. These are assets you can create in the editor and reference in your scenes.
|
|
62
|
+
|
|
63
|
+
### Current Global Message Bus Provider
|
|
64
|
+
|
|
65
|
+
`CurrentGlobalMessageBusProvider` returns whatever bus is currently set as the global bus via `MessageHandler.MessageBus`. If you override the global bus at runtime, this provider reflects that change.
|
|
66
|
+
|
|
67
|
+
#### Creating the asset
|
|
68
|
+
|
|
69
|
+
Right-click in the Project window:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
Create > Wallstop Studios > DxMessaging > Message Bus Providers > Current Global Message Bus
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### When to use this
|
|
76
|
+
|
|
77
|
+
- When you want components to follow the global bus, even if it changes
|
|
78
|
+
- In DI scenarios where the global bus is replaced during bootstrap
|
|
79
|
+
- For components that should always use the "active" bus
|
|
80
|
+
|
|
81
|
+
#### Example
|
|
82
|
+
|
|
83
|
+
```csharp
|
|
84
|
+
using DxMessaging.Core.MessageBus;
|
|
85
|
+
using DxMessaging.Unity;
|
|
86
|
+
using UnityEngine;
|
|
87
|
+
|
|
88
|
+
[RequireComponent(typeof(MessagingComponent))]
|
|
89
|
+
public sealed class MessagingComponentConfigurator : MonoBehaviour
|
|
90
|
+
{
|
|
91
|
+
[SerializeField]
|
|
92
|
+
private CurrentGlobalMessageBusProvider provider;
|
|
93
|
+
|
|
94
|
+
private void Awake()
|
|
95
|
+
{
|
|
96
|
+
MessagingComponent component = GetComponent<MessagingComponent>();
|
|
97
|
+
component.Configure(provider, MessageBusRebindMode.RebindActive);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Initial Global Message Bus Provider
|
|
103
|
+
|
|
104
|
+
`InitialGlobalMessageBusProvider` always returns the original startup bus that was created during static initialization. It ignores any calls to `SetGlobalMessageBus()` or `OverrideGlobalMessageBus()`.
|
|
105
|
+
|
|
106
|
+
#### Creating the asset
|
|
107
|
+
|
|
108
|
+
Right-click in the Project window:
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
Create > Wallstop Studios > DxMessaging > Message Bus Providers > Initial Global Message Bus
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### When to use this
|
|
115
|
+
|
|
116
|
+
- In diagnostic tools that need a stable reference point
|
|
117
|
+
- When testing with temporary bus overrides but need access to the original
|
|
118
|
+
- For debugging scenarios where you want to compare against the startup bus
|
|
119
|
+
|
|
120
|
+
#### Example
|
|
121
|
+
|
|
122
|
+
```csharp
|
|
123
|
+
using DxMessaging.Core;
|
|
124
|
+
using DxMessaging.Core.MessageBus;
|
|
125
|
+
using UnityEngine;
|
|
126
|
+
|
|
127
|
+
public class DiagnosticLogger : MonoBehaviour
|
|
128
|
+
{
|
|
129
|
+
[SerializeField]
|
|
130
|
+
private InitialGlobalMessageBusProvider initialProvider;
|
|
131
|
+
|
|
132
|
+
private void Start()
|
|
133
|
+
{
|
|
134
|
+
// Always logs to the original bus, even if global bus is overridden
|
|
135
|
+
IMessageBus startupBus = initialProvider.Resolve();
|
|
136
|
+
|
|
137
|
+
// Can compare with current global bus
|
|
138
|
+
bool busWasReplaced = startupBus != MessageHandler.MessageBus;
|
|
139
|
+
Debug.Log($"Bus replaced: {busWasReplaced}");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## MessageBusProviderHandle
|
|
147
|
+
|
|
148
|
+
`MessageBusProviderHandle` is a serializable struct that can reference either:
|
|
149
|
+
|
|
150
|
+
- A ScriptableObject provider (design-time configuration)
|
|
151
|
+
- A runtime provider instance (runtime configuration)
|
|
152
|
+
|
|
153
|
+
This gives you the best of both worlds: editor-friendly assets and runtime flexibility.
|
|
154
|
+
|
|
155
|
+
### Key Methods
|
|
156
|
+
|
|
157
|
+
```csharp
|
|
158
|
+
// Create from a runtime provider
|
|
159
|
+
MessageBusProviderHandle handle = MessageBusProviderHandle.FromProvider(myProvider);
|
|
160
|
+
|
|
161
|
+
// Associate a runtime provider with an existing handle
|
|
162
|
+
handle = handle.WithRuntimeProvider(myRuntimeProvider);
|
|
163
|
+
|
|
164
|
+
// Resolve the provider (runtime takes precedence over asset)
|
|
165
|
+
if (handle.TryGetProvider(out IMessageBusProvider provider))
|
|
166
|
+
{
|
|
167
|
+
IMessageBus bus = provider.Resolve();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Or resolve the bus directly
|
|
171
|
+
IMessageBus bus = handle.ResolveBus();
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### How It Works
|
|
175
|
+
|
|
176
|
+
The handle has two fields:
|
|
177
|
+
|
|
178
|
+
1. `Provider` — A serialized reference to a ScriptableObject provider (visible in Inspector)
|
|
179
|
+
1. A runtime provider instance (not serialized)
|
|
180
|
+
|
|
181
|
+
When you call `TryGetProvider()` or `ResolveBus()`, it checks:
|
|
182
|
+
|
|
183
|
+
1. Is there a runtime provider? Use that first.
|
|
184
|
+
1. Otherwise, use the serialized ScriptableObject provider.
|
|
185
|
+
1. If neither exists, return null or the global default.
|
|
186
|
+
|
|
187
|
+
**Why this matters:** You can design your prefabs with ScriptableObject references, then override them at runtime with DI-provided buses. No code changes needed.
|
|
188
|
+
|
|
189
|
+
### Example: Design Time Configuration
|
|
190
|
+
|
|
191
|
+
```csharp
|
|
192
|
+
using DxMessaging.Unity;
|
|
193
|
+
using UnityEngine;
|
|
194
|
+
|
|
195
|
+
public class PlayerController : MessageAwareComponent
|
|
196
|
+
{
|
|
197
|
+
[SerializeField]
|
|
198
|
+
private MessageBusProviderHandle providerHandle;
|
|
199
|
+
|
|
200
|
+
protected override void Awake()
|
|
201
|
+
{
|
|
202
|
+
// Configure with the handle before base.Awake()
|
|
203
|
+
if (providerHandle.TryGetProvider(out var provider))
|
|
204
|
+
{
|
|
205
|
+
ConfigureMessageBus(provider, MessageBusRebindMode.RebindActive);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
base.Awake();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
In the Inspector, you can drag a `CurrentGlobalMessageBusProvider` or `InitialGlobalMessageBusProvider` asset onto the `providerHandle` field.
|
|
214
|
+
|
|
215
|
+
### Example: Runtime Override
|
|
216
|
+
|
|
217
|
+
```csharp
|
|
218
|
+
using DxMessaging.Core.MessageBus;
|
|
219
|
+
using DxMessaging.Unity;
|
|
220
|
+
|
|
221
|
+
public class DynamicConfigurator
|
|
222
|
+
{
|
|
223
|
+
public void ConfigureWithRuntimeBus(MessageAwareComponent component, IMessageBus runtimeBus)
|
|
224
|
+
{
|
|
225
|
+
// Create a runtime provider
|
|
226
|
+
var provider = new RuntimeMessageBusProvider(runtimeBus);
|
|
227
|
+
|
|
228
|
+
// Wrap it in a handle
|
|
229
|
+
var handle = MessageBusProviderHandle.FromProvider(provider);
|
|
230
|
+
|
|
231
|
+
// Configure the component
|
|
232
|
+
component.ConfigureMessageBus(handle, MessageBusRebindMode.RebindActive);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Simple runtime provider implementation
|
|
237
|
+
public class RuntimeMessageBusProvider : IMessageBusProvider
|
|
238
|
+
{
|
|
239
|
+
private readonly IMessageBus _bus;
|
|
240
|
+
|
|
241
|
+
public RuntimeMessageBusProvider(IMessageBus bus)
|
|
242
|
+
{
|
|
243
|
+
_bus = bus;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public IMessageBus Resolve() => _bus;
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Using Providers with Components
|
|
253
|
+
|
|
254
|
+
### MessagingComponent
|
|
255
|
+
|
|
256
|
+
`MessagingComponent` has three `Configure()` overloads:
|
|
257
|
+
|
|
258
|
+
```csharp
|
|
259
|
+
// Direct bus reference
|
|
260
|
+
component.Configure(messageBus, MessageBusRebindMode.RebindActive);
|
|
261
|
+
|
|
262
|
+
// Provider interface
|
|
263
|
+
component.Configure(provider, MessageBusRebindMode.RebindActive);
|
|
264
|
+
|
|
265
|
+
// Provider handle (design-time or runtime)
|
|
266
|
+
component.Configure(providerHandle, MessageBusRebindMode.RebindActive);
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### MessageAwareComponent
|
|
270
|
+
|
|
271
|
+
`MessageAwareComponent` exposes `ConfigureMessageBus()` with the same three overloads:
|
|
272
|
+
|
|
273
|
+
```csharp
|
|
274
|
+
// Direct bus
|
|
275
|
+
ConfigureMessageBus(messageBus, MessageBusRebindMode.RebindActive);
|
|
276
|
+
|
|
277
|
+
// Provider
|
|
278
|
+
ConfigureMessageBus(provider, MessageBusRebindMode.RebindActive);
|
|
279
|
+
|
|
280
|
+
// Handle
|
|
281
|
+
ConfigureMessageBus(providerHandle, MessageBusRebindMode.RebindActive);
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Best practice:** Call `ConfigureMessageBus()` in `Awake()` before calling `base.Awake()` to ensure the bus is set before message handlers are registered.
|
|
285
|
+
|
|
286
|
+
### MessagingComponentInstaller
|
|
287
|
+
|
|
288
|
+
`MessagingComponentInstaller` configures all `MessagingComponent` descendants in a hierarchy:
|
|
289
|
+
|
|
290
|
+
```csharp
|
|
291
|
+
using DxMessaging.Core.MessageBus;
|
|
292
|
+
using DxMessaging.Unity;
|
|
293
|
+
using UnityEngine;
|
|
294
|
+
|
|
295
|
+
public class SceneSetup : MonoBehaviour
|
|
296
|
+
{
|
|
297
|
+
[SerializeField]
|
|
298
|
+
private MessagingComponentInstaller installer;
|
|
299
|
+
|
|
300
|
+
[SerializeField]
|
|
301
|
+
private CurrentGlobalMessageBusProvider provider;
|
|
302
|
+
|
|
303
|
+
private void Awake()
|
|
304
|
+
{
|
|
305
|
+
// Configure installer with provider
|
|
306
|
+
installer.SetProvider(MessageBusProviderHandle.FromProvider(provider));
|
|
307
|
+
|
|
308
|
+
// Apply to all child MessagingComponents
|
|
309
|
+
installer.ApplyConfiguration();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
This is useful when you want to configure an entire prefab hierarchy or scene section with a single provider.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Creating Custom Providers
|
|
319
|
+
|
|
320
|
+
You can create your own providers for advanced scenarios:
|
|
321
|
+
|
|
322
|
+
### Example: Container-Managed Provider
|
|
323
|
+
|
|
324
|
+
```csharp
|
|
325
|
+
using DxMessaging.Core.MessageBus;
|
|
326
|
+
|
|
327
|
+
public class ContainerMessageBusProvider : IMessageBusProvider
|
|
328
|
+
{
|
|
329
|
+
private readonly IDependencyContainer _container;
|
|
330
|
+
|
|
331
|
+
public ContainerMessageBusProvider(IDependencyContainer container)
|
|
332
|
+
{
|
|
333
|
+
_container = container;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
public IMessageBus Resolve()
|
|
337
|
+
{
|
|
338
|
+
// Resolve from container each time
|
|
339
|
+
return _container.Resolve<IMessageBus>();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Example: ScriptableObject Provider for Specific Bus
|
|
345
|
+
|
|
346
|
+
```csharp
|
|
347
|
+
using DxMessaging.Core.MessageBus;
|
|
348
|
+
using UnityEngine;
|
|
349
|
+
|
|
350
|
+
[CreateAssetMenu(menuName = "Game/Messaging/Custom Bus Provider")]
|
|
351
|
+
public class CustomBusProvider : ScriptableObject, IMessageBusProvider
|
|
352
|
+
{
|
|
353
|
+
[SerializeField]
|
|
354
|
+
private bool useTestBus;
|
|
355
|
+
|
|
356
|
+
private static IMessageBus _testBus;
|
|
357
|
+
private static IMessageBus _productionBus;
|
|
358
|
+
|
|
359
|
+
public IMessageBus Resolve()
|
|
360
|
+
{
|
|
361
|
+
if (useTestBus)
|
|
362
|
+
{
|
|
363
|
+
return _testBus ??= new MessageBus();
|
|
364
|
+
}
|
|
365
|
+
return _productionBus ??= new MessageBus();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Example: Lazy-Initialized Provider
|
|
371
|
+
|
|
372
|
+
```csharp
|
|
373
|
+
using DxMessaging.Core.MessageBus;
|
|
374
|
+
|
|
375
|
+
public class LazyMessageBusProvider : IMessageBusProvider
|
|
376
|
+
{
|
|
377
|
+
private IMessageBus _cachedBus;
|
|
378
|
+
|
|
379
|
+
public IMessageBus Resolve()
|
|
380
|
+
{
|
|
381
|
+
// Only create the bus when first requested
|
|
382
|
+
return _cachedBus ??= new MessageBus();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Common Patterns
|
|
390
|
+
|
|
391
|
+
### Pattern 1: Design-Time Configuration
|
|
392
|
+
|
|
393
|
+
Set up providers in the editor, no code needed:
|
|
394
|
+
|
|
395
|
+
1. Create a `CurrentGlobalMessageBusProvider` asset in your project
|
|
396
|
+
1. Add a `MessagingComponent` to your prefab
|
|
397
|
+
1. Add a `MessagingComponentConfigurator` script that references the provider
|
|
398
|
+
1. In Awake, call `component.Configure(provider, ...)`
|
|
399
|
+
|
|
400
|
+
This lets designers swap providers without touching code.
|
|
401
|
+
|
|
402
|
+
### Pattern 2: DI Container Integration
|
|
403
|
+
|
|
404
|
+
Use a provider to resolve buses from your container:
|
|
405
|
+
|
|
406
|
+
```csharp
|
|
407
|
+
// In your DI installer
|
|
408
|
+
container.RegisterInstance<IMessageBus>(new MessageBus());
|
|
409
|
+
|
|
410
|
+
// In a bootstrap script
|
|
411
|
+
var provider = new ContainerMessageBusProvider(container);
|
|
412
|
+
MessageHandler.SetGlobalMessageBus(provider.Resolve());
|
|
413
|
+
|
|
414
|
+
// Now all components use the container bus
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Pattern 3: Scene-Scoped Buses
|
|
418
|
+
|
|
419
|
+
Create a provider that returns a scene-specific bus:
|
|
420
|
+
|
|
421
|
+
```csharp
|
|
422
|
+
public class SceneMessageBusManager : MonoBehaviour
|
|
423
|
+
{
|
|
424
|
+
private IMessageBus _sceneBus;
|
|
425
|
+
|
|
426
|
+
private void Awake()
|
|
427
|
+
{
|
|
428
|
+
// Create scene-local bus
|
|
429
|
+
_sceneBus = new MessageBus();
|
|
430
|
+
|
|
431
|
+
// Configure all components in this scene
|
|
432
|
+
var components = GetComponentsInChildren<MessagingComponent>();
|
|
433
|
+
var provider = new RuntimeMessageBusProvider(_sceneBus);
|
|
434
|
+
|
|
435
|
+
foreach (var component in components)
|
|
436
|
+
{
|
|
437
|
+
component.Configure(provider, MessageBusRebindMode.RebindActive);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
Messages sent in this scene stay in this scene.
|
|
444
|
+
|
|
445
|
+
### Pattern 4: Runtime Provider Override
|
|
446
|
+
|
|
447
|
+
Start with a design-time provider, override at runtime:
|
|
448
|
+
|
|
449
|
+
```csharp
|
|
450
|
+
public class RuntimeReconfiguration : MonoBehaviour
|
|
451
|
+
{
|
|
452
|
+
[SerializeField]
|
|
453
|
+
private MessageAwareComponent component;
|
|
454
|
+
|
|
455
|
+
[SerializeField]
|
|
456
|
+
private MessageBusProviderHandle designTimeHandle; // Set in Inspector
|
|
457
|
+
|
|
458
|
+
private void Start()
|
|
459
|
+
{
|
|
460
|
+
// Use design-time provider initially
|
|
461
|
+
component.ConfigureMessageBus(designTimeHandle, MessageBusRebindMode.RebindActive);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
public void SwitchToRuntimeBus(IMessageBus runtimeBus)
|
|
465
|
+
{
|
|
466
|
+
// Override with runtime provider
|
|
467
|
+
var runtimeProvider = new RuntimeMessageBusProvider(runtimeBus);
|
|
468
|
+
var handle = MessageBusProviderHandle.FromProvider(runtimeProvider);
|
|
469
|
+
component.ConfigureMessageBus(handle, MessageBusRebindMode.RebindActive);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Quick Reference
|
|
477
|
+
|
|
478
|
+
| Type | Purpose | Use Case |
|
|
479
|
+
| -------------------------------------- | --------------------------------------------- | --------------------------------- |
|
|
480
|
+
| `IMessageBusProvider` | Interface for bus resolution | Create custom providers |
|
|
481
|
+
| `CurrentGlobalMessageBusProvider` | ScriptableObject returning current global bus | Follow the active global bus |
|
|
482
|
+
| `InitialGlobalMessageBusProvider` | ScriptableObject returning startup bus | Diagnostics, stable reference |
|
|
483
|
+
| `MessageBusProviderHandle` | Serializable wrapper for providers | Design-time + runtime flexibility |
|
|
484
|
+
| `handle.FromProvider(provider)` | Create handle from runtime provider | Runtime configuration |
|
|
485
|
+
| `handle.WithRuntimeProvider(provider)` | Add runtime provider to handle | Override design-time config |
|
|
486
|
+
| `handle.TryGetProvider(out provider)` | Resolve provider from handle | Get the actual provider |
|
|
487
|
+
| `handle.ResolveBus()` | Resolve bus directly | Shortcut to get bus |
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## See Also
|
|
492
|
+
|
|
493
|
+
- **[Runtime Configuration](RuntimeConfiguration.md)** — Setting and overriding global buses, re-binding registrations
|
|
494
|
+
- **[DI Integration Guides](Integrations/)** — Zenject, VContainer, and Reflex integration patterns
|
|
495
|
+
- **[Unity Integration](UnityIntegration.md)** — MessagingComponent and MessageAwareComponent deep dive
|
|
496
|
+
- **[Back to Documentation Hub](Index.md)** — Browse all docs
|
package/Docs/MessageTypes.md
CHANGED
|
@@ -12,6 +12,33 @@ This guide introduces the three message categories in DxMessaging with concepts,
|
|
|
12
12
|
- Targeted: directed at one recipient (e.g., heal Player by 10).
|
|
13
13
|
- Broadcast: emitted from a source for anyone to observe (e.g., Enemy took 5 damage).
|
|
14
14
|
|
|
15
|
+
### Quick Decision Guide
|
|
16
|
+
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart TD
|
|
19
|
+
Start([Choose Message Type])
|
|
20
|
+
|
|
21
|
+
Start --> Q1{Is it a global<br/>announcement?}
|
|
22
|
+
|
|
23
|
+
Q1 -->|Yes<br/>e.g., game paused,<br/>settings changed| Untargeted[✅ Use UNTARGETED<br/>Everyone listens]
|
|
24
|
+
|
|
25
|
+
Q1 -->|No| Q2{Are you commanding<br/>a specific entity?}
|
|
26
|
+
|
|
27
|
+
Q2 -->|Yes<br/>e.g., heal Player,<br/>open Chest #3| Targeted[✅ Use TARGETED<br/>One recipient]
|
|
28
|
+
|
|
29
|
+
Q2 -->|No| Q3{Is an entity announcing<br/>something happened?}
|
|
30
|
+
|
|
31
|
+
Q3 -->|Yes<br/>e.g., Enemy died,<br/>Chest opened| Broadcast[✅ Use BROADCAST<br/>Anyone can observe]
|
|
32
|
+
|
|
33
|
+
Q3 -->|No| Rethink[🤔 Rethink your<br/>message design]
|
|
34
|
+
|
|
35
|
+
style Untargeted fill:#91d5ff,stroke:#096dd9,stroke-width:3px,color:#000
|
|
36
|
+
style Targeted fill:#ffd591,stroke:#d46b08,stroke-width:3px,color:#000
|
|
37
|
+
style Broadcast fill:#95de64,stroke:#237804,stroke-width:3px,color:#000
|
|
38
|
+
style Rethink fill:#ffa39e,stroke:#cf1322,stroke-width:2px,color:#000
|
|
39
|
+
style Start fill:#f0f0f0,stroke:#595959,stroke-width:2px,color:#000
|
|
40
|
+
```
|
|
41
|
+
|
|
15
42
|
## Untargeted Messages
|
|
16
43
|
|
|
17
44
|
- Use for cross‑cutting notifications: settings changed, scene loaded, world regenerated.
|
package/Docs/MigrationGuide.md
CHANGED
|
@@ -431,6 +431,51 @@ Phase them out gradually:
|
|
|
431
431
|
1. Migrate listeners
|
|
432
432
|
1. Remove references in next refactor pass
|
|
433
433
|
|
|
434
|
+
### Adopt the DI Registration Builder
|
|
435
|
+
|
|
436
|
+
Once the bus/provider abstractions are in place, wire listeners through the registration builder instead of hand-rolling handler lifecycles. Benefits:
|
|
437
|
+
|
|
438
|
+
- Container-managed lifetimes (`IDisposable`, `IInitializable`, `IStartable`, etc.) automatically enable/disable registrations.
|
|
439
|
+
- Centralises diagnostics toggles and message bus selection.
|
|
440
|
+
- Keeps MonoBehaviours and pure C# services on the same path.
|
|
441
|
+
|
|
442
|
+
```csharp
|
|
443
|
+
public sealed class InventoryService : IStartable, IDisposable
|
|
444
|
+
{
|
|
445
|
+
private readonly MessageRegistrationLease lease;
|
|
446
|
+
|
|
447
|
+
public InventoryService(IMessageRegistrationBuilder registrationBuilder)
|
|
448
|
+
{
|
|
449
|
+
lease = registrationBuilder.Build(new MessageRegistrationBuildOptions
|
|
450
|
+
{
|
|
451
|
+
Configure = token =>
|
|
452
|
+
{
|
|
453
|
+
_ = token.RegisterUntargeted<InventoryChanged>(OnInventoryChanged);
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
public void Start()
|
|
459
|
+
{
|
|
460
|
+
lease.Activate();
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
public void Dispose()
|
|
464
|
+
{
|
|
465
|
+
lease.Dispose();
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
private static void OnInventoryChanged(ref InventoryChanged message)
|
|
469
|
+
{
|
|
470
|
+
// respond to updates
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
- **Unity scene code:** Call `MessagingComponent.CreateRegistrationBuilder()` during dependency injection and share the lease across helper services or pooled objects.
|
|
476
|
+
- **Container shims:** Define `ZENJECT_PRESENT`, `VCONTAINER_PRESENT`, or `REFLEX_PRESENT` to enable the built-in installers/extensions that register the builder automatically when those frameworks are present.
|
|
477
|
+
- **Tests:** Prefer the builder to create isolated tokens tied to the test fixture lifecycle.
|
|
478
|
+
|
|
434
479
|
### "Should we migrate tests?"
|
|
435
480
|
|
|
436
481
|
Yes! Tests benefit from isolated message buses:
|