com.wallstop-studios.dxmessaging 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/format-on-demand.yml +2 -2
- package/.github/workflows/json-format-check.yml +1 -1
- package/.github/workflows/markdown-json.yml +1 -1
- package/.github/workflows/markdownlint.yml +1 -1
- package/.github/workflows/npm-publish.yml +1 -1
- package/.github/workflows/prettier-autofix.yml +2 -2
- package/.github/workflows/yaml-format-lint.yml +1 -1
- package/Docs/Advanced.md +26 -1
- package/Docs/Comparisons.md +1229 -146
- package/Docs/Compatibility.md +27 -0
- package/Docs/DesignAndArchitecture.md +41 -34
- package/Docs/EmitShorthands.md +34 -0
- package/Docs/Helpers.md +1 -1
- package/Docs/Index.md +28 -25
- package/Docs/Install.md +29 -6
- package/Docs/Integrations/Reflex.md +292 -0
- package/Docs/Integrations/Reflex.md.meta +7 -0
- package/Docs/Integrations/VContainer.md +324 -0
- package/Docs/Integrations/VContainer.md.meta +7 -0
- package/Docs/Integrations/Zenject.md +333 -0
- package/Docs/Integrations/Zenject.md.meta +7 -0
- package/{Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.pdb.meta → Docs/Integrations.meta} +2 -1
- package/Docs/InterceptorsAndOrdering.md +371 -17
- package/Docs/ListeningPatterns.md +206 -0
- package/Docs/MessageBusProviders.md +496 -0
- package/Docs/MessageBusProviders.md.meta +7 -0
- package/Docs/MessageTypes.md +27 -0
- package/Docs/MigrationGuide.md +45 -0
- package/Docs/Patterns.md +286 -0
- package/Docs/Performance.md +9 -9
- package/Docs/QuickReference.md +31 -0
- package/Docs/RuntimeConfiguration.md +407 -0
- package/Docs/RuntimeConfiguration.md.meta +7 -0
- package/Docs/UnityIntegration.md +3 -1
- package/Docs/VisualGuide.md +206 -157
- package/Editor/CustomEditors/MessagingComponentEditor.cs +15 -6
- package/README.md +148 -26
- package/Runtime/AssemblyInfo.cs +4 -0
- package/Runtime/Core/Extensions/MessageBusExtensions.cs +253 -0
- package/Runtime/Core/Extensions/MessageBusExtensions.cs.meta +12 -0
- package/Runtime/Core/Extensions/MessageExtensions.cs +137 -89
- package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs +23 -0
- package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +11 -0
- package/Runtime/Core/MessageBus/IMessageBusProvider.cs +14 -0
- package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +11 -0
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs +18 -0
- package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +11 -0
- package/Runtime/Core/MessageBus/MessageBusRebindMode.cs +26 -0
- package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +11 -0
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +383 -0
- package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +11 -0
- package/Runtime/Core/MessageHandler.cs +198 -27
- package/Runtime/Core/MessageRegistrationToken.cs +67 -25
- package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs +31 -0
- package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs.meta +12 -0
- package/Runtime/Unity/InitialGlobalMessageBusProvider.cs +38 -0
- package/Runtime/Unity/InitialGlobalMessageBusProvider.cs.meta +12 -0
- package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs +11 -0
- package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs +73 -0
- package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs.meta +11 -0
- package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef +20 -0
- package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef.meta +7 -0
- package/Runtime/Unity/Integrations/Reflex.meta +8 -0
- package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs +11 -0
- package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs +46 -0
- package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs.meta +11 -0
- package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef +30 -0
- package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef.meta +7 -0
- package/Runtime/Unity/Integrations/VContainer.meta +8 -0
- package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs +11 -0
- package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef +30 -0
- package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef.meta +7 -0
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs +55 -0
- package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs.meta +11 -0
- package/Runtime/Unity/Integrations/Zenject.meta +8 -0
- package/Runtime/Unity/Integrations.meta +8 -0
- package/Runtime/Unity/MessageAwareComponent.cs +102 -0
- package/Runtime/Unity/MessageBusProviderHandle.cs +97 -0
- package/Runtime/Unity/MessageBusProviderHandle.cs.meta +12 -0
- package/Runtime/Unity/MessagingComponent.cs +164 -2
- package/Runtime/Unity/MessagingComponentInstaller.cs +120 -0
- package/Runtime/Unity/MessagingComponentInstaller.cs.meta +12 -0
- package/Runtime/Unity/ScriptableMessageBusProvider.cs +14 -0
- package/Runtime/Unity/ScriptableMessageBusProvider.cs.meta +12 -0
- package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab +98 -0
- package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab.meta +7 -0
- package/Samples~/DI/Prefabs.meta +8 -0
- package/Samples~/DI/Providers/GlobalMessageBusProvider.asset +14 -0
- package/Samples~/DI/Providers/GlobalMessageBusProvider.asset.meta +8 -0
- package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset +14 -0
- package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset.meta +8 -0
- package/Samples~/DI/Providers.meta +8 -0
- package/Samples~/DI/README.md +51 -0
- package/Samples~/DI/README.md.meta +7 -0
- package/Samples~/DI/Reflex/SampleInstaller.cs +75 -0
- package/Samples~/DI/Reflex/SampleInstaller.cs.meta +11 -0
- package/Samples~/DI/Reflex.meta +8 -0
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs +81 -0
- package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +11 -0
- package/Samples~/DI/VContainer.meta +8 -0
- package/Samples~/DI/Zenject/SampleInstaller.cs +67 -0
- package/Samples~/DI/Zenject/SampleInstaller.cs.meta +11 -0
- package/Samples~/DI/Zenject.meta +8 -0
- package/Samples~/DI.meta +8 -0
- package/Samples~/Mini Combat/README.md +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
package/Docs/Patterns.md
CHANGED
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
| Handle persistent systems across scene loads | [Pattern: Cross-Scene Persistent](#pattern-cross-scene-persistent-systems) |
|
|
43
43
|
| See what's happening (debug message flow) | [Pattern 11: Diagnostics](#11-diagnostics-and-tuning) |
|
|
44
44
|
| Build a battle royale / large multiplayer | [Pattern: Battle Royale Example](#real-world-production-example-battle-royale-game) |
|
|
45
|
+
| Use with Scriptable Object Architecture | [Pattern 14: SOA Compatibility](#14-compatibility-with-scriptable-object-architecture-soa) |
|
|
45
46
|
|
|
46
47
|
---
|
|
47
48
|
|
|
@@ -64,6 +65,7 @@
|
|
|
64
65
|
- [Global Accept-All Handlers](#10-global-accept-all-handlers)
|
|
65
66
|
- [Diagnostics and Tuning](#11-diagnostics-and-tuning)
|
|
66
67
|
- [Testing](#12-testing)
|
|
68
|
+
- [Compatibility with Scriptable Object Architecture (SOA)](#14-compatibility-with-scriptable-object-architecture-soa)
|
|
67
69
|
|
|
68
70
|
### Real-World Scale Patterns
|
|
69
71
|
|
|
@@ -768,6 +770,290 @@ public class MatchStats : MessageAwareComponent {
|
|
|
768
770
|
|
|
769
771
|
---
|
|
770
772
|
|
|
773
|
+
## 14) Compatibility with Scriptable Object Architecture (SOA)
|
|
774
|
+
|
|
775
|
+
**Disclaimer:** Scriptable Object Architecture (SOA) is a debated pattern in the Unity community. While it has proponents, there are documented criticisms regarding its scalability and maintainability. See [Anti-ScriptableObject Architecture](https://github.com/cathei/AntiScriptableObjectArchitecture) for a detailed critique. **SOA is not a recommended pattern** for most projects, unless you need designers wiring events. Consider alternatives like dependency injection (Zenject, VContainer), reactive systems (UniRx), or messaging systems (DxMessaging, MessagePipe), as they often provide better long-term maintainability.
|
|
776
|
+
|
|
777
|
+
That said, if your project uses or requires SOA, DxMessaging can work alongside it.
|
|
778
|
+
|
|
779
|
+
### What is Scriptable Object Architecture?
|
|
780
|
+
|
|
781
|
+
**SOA Background:** Popularized by Ryan Hipple's [Unite Austin 2017 talk](https://www.youtube.com/watch?v=raQ3iHhE_Kk), SOA uses ScriptableObject assets as:
|
|
782
|
+
|
|
783
|
+
1. **Shared Variables** - `FloatVariable`, `IntVariable`, etc. (ScriptableObject assets that hold runtime state)
|
|
784
|
+
1. **Event Channels** - `GameEvent` + `GameEventListener` pattern (designer-created events)
|
|
785
|
+
1. **Runtime Sets** - Collections of active game objects (e.g., all enemies)
|
|
786
|
+
|
|
787
|
+
**Core idea:** Systems communicate through serialized SO assets instead of direct references.
|
|
788
|
+
|
|
789
|
+
#### Key resources
|
|
790
|
+
|
|
791
|
+
- [Unite 2017 Talk by Ryan Hipple](https://www.youtube.com/watch?v=raQ3iHhE_Kk)
|
|
792
|
+
- [Official Unity Guide](https://unity.com/how-to/architect-game-code-scriptable-objects)
|
|
793
|
+
- [Reference Implementation](https://github.com/roboryantron/Unite2017)
|
|
794
|
+
- [Community Package](https://github.com/DanielEverland/ScriptableObject-Architecture)
|
|
795
|
+
|
|
796
|
+
### Why SOA is Controversial
|
|
797
|
+
|
|
798
|
+
From [Anti-ScriptableObject Architecture](https://github.com/cathei/AntiScriptableObjectArchitecture), key criticisms include:
|
|
799
|
+
|
|
800
|
+
1. **Wrong Purpose** - ScriptableObjects are designed for immutable design data, not runtime mutable state
|
|
801
|
+
1. **Redundant Complexity** - Standard C# objects achieve the same goals without SO restrictions
|
|
802
|
+
1. **Inspector Dependency** - Binds architecture to Unity's GUI, complicating debugging and maintenance
|
|
803
|
+
1. **Limited Scalability** - Runtime-created variables undermine the pattern; managing numerous assets becomes unwieldy
|
|
804
|
+
1. **Domain Reload Issues** - Disabled domain reloading causes ScriptableObjects to retain values unpredictably
|
|
805
|
+
1. **Testability Concerns** - SO assets persist between tests, requiring manual cleanup
|
|
806
|
+
|
|
807
|
+
#### Recommended alternatives
|
|
808
|
+
|
|
809
|
+
- **Dependency Injection** - Zenject, VContainer, Reflex (see [DxMessaging DI Integrations](Integrations/))
|
|
810
|
+
- **Reactive Systems** - UniRx, UniTask
|
|
811
|
+
- **Messaging** - DxMessaging (this framework), MessagePipe
|
|
812
|
+
- **Configuration Data** - Spreadsheet-based solutions (e.g., BakingSheet)
|
|
813
|
+
|
|
814
|
+
Use ScriptableObjects for their intended purpose: **immutable design-time data** (configs, balance tables, prefab references).
|
|
815
|
+
|
|
816
|
+
### Can DxMessaging Work with SOA?
|
|
817
|
+
|
|
818
|
+
**Yes, but with caveats.** DxMessaging and SOA solve similar problems (decoupling, communication) with different philosophies:
|
|
819
|
+
|
|
820
|
+
| Aspect | SOA | DxMessaging |
|
|
821
|
+
| -------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------- |
|
|
822
|
+
| **Paradigm** | Asset-based, persistent state | Runtime message passing, transient |
|
|
823
|
+
| **Designer-Centric** | ✅ High (create events in Inspector) | ❌ Low (code-driven) |
|
|
824
|
+
| **Type Safety** | ⚠️ Mixed (SO refs typed, but UnityEvent inspector wiring loses compile-time safety) | ✅ Strong (compile-time validation) |
|
|
825
|
+
| **Lifecycle** | ⚠️ Manual (SO assets persist) | ✅ Automatic (tokens clean up) |
|
|
826
|
+
| **Debugging** | ⚠️ Inspector-dependent | ✅ Built-in diagnostics |
|
|
827
|
+
| **Performance** | ⚠️ List iteration, UnityAction overhead | ✅ Zero-allocation structs |
|
|
828
|
+
| **Use Case** | Shared state, designer-driven configs | Event-driven communication, runtime logic |
|
|
829
|
+
| **Testability** | ⚠️ Requires SO asset cleanup | ✅ Isolated buses per test |
|
|
830
|
+
|
|
831
|
+
**Bottom line:** If you're starting fresh, prefer DxMessaging or DI. If you have legacy SOA code, the patterns below show coexistence strategies.
|
|
832
|
+
|
|
833
|
+
### Pattern Overview
|
|
834
|
+
|
|
835
|
+
| Pattern | What it shows | When to use | SOA involvement |
|
|
836
|
+
| ------- | ------------------------------------------------------ | ----------------------------------------------------- | ---------------------------- |
|
|
837
|
+
| **A** | SOA Events (GameEvent) forwarding to DxMessaging | Designer-created event assets, modern code downstream | ✅ Yes - SOA Event pattern |
|
|
838
|
+
| **B** | ScriptableObjects for configs + DxMessaging for events | New projects / best practice | ❌ No - proper SO usage only |
|
|
839
|
+
|
|
840
|
+
### Pattern A: SOA → DxMessaging (Event Forwarding)
|
|
841
|
+
|
|
842
|
+
**Use case:** Designer-created SOA events, but you want DxMessaging benefits downstream.
|
|
843
|
+
|
|
844
|
+
**Strategy:** SOA GameEventListener forwards to DxMessaging.
|
|
845
|
+
|
|
846
|
+
> **This uses the SOA GameEvent pattern:** If you're NOT using designer-created GameEvent assets
|
|
847
|
+
> with `Raise()`/listener management, you don't need this pattern. For immutable config data,
|
|
848
|
+
> see Pattern B instead.
|
|
849
|
+
|
|
850
|
+
#### Example: Scene Transitions
|
|
851
|
+
|
|
852
|
+
```csharp
|
|
853
|
+
using DxMessaging.Core.Messages;
|
|
854
|
+
using DxMessaging.Core.Attributes;
|
|
855
|
+
using DxMessaging.Core.Extensions;
|
|
856
|
+
using UnityEngine;
|
|
857
|
+
using UnityEngine.Events;
|
|
858
|
+
|
|
859
|
+
// Traditional SOA event
|
|
860
|
+
[CreateAssetMenu(menuName = "Events/Game Event")]
|
|
861
|
+
public class GameEvent : ScriptableObject
|
|
862
|
+
{
|
|
863
|
+
private readonly List<UnityAction> listeners = new();
|
|
864
|
+
|
|
865
|
+
public void Raise()
|
|
866
|
+
{
|
|
867
|
+
for (int i = listeners.Count - 1; i >= 0; i--)
|
|
868
|
+
listeners[i]?.Invoke();
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
public void RegisterListener(UnityAction listener) => listeners.Add(listener);
|
|
872
|
+
public void UnregisterListener(UnityAction listener) => listeners.Remove(listener);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// DxMessaging message (modern, type-safe)
|
|
876
|
+
[DxUntargetedMessage]
|
|
877
|
+
public readonly struct SceneTransitionRequested { }
|
|
878
|
+
|
|
879
|
+
// Bridge: SOA Event → DxMessaging
|
|
880
|
+
public class SOAEventBridge : MonoBehaviour
|
|
881
|
+
{
|
|
882
|
+
[SerializeField] private GameEvent onSceneTransitionSO; // Designer-created asset
|
|
883
|
+
|
|
884
|
+
void OnEnable()
|
|
885
|
+
{
|
|
886
|
+
onSceneTransitionSO.RegisterListener(OnSOAEvent);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
void OnDisable()
|
|
890
|
+
{
|
|
891
|
+
onSceneTransitionSO.UnregisterListener(OnSOAEvent);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
void OnSOAEvent()
|
|
895
|
+
{
|
|
896
|
+
// Forward to DxMessaging
|
|
897
|
+
var message = new SceneTransitionRequested();
|
|
898
|
+
message.Emit();
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// Modern DxMessaging listeners (no SO dependency)
|
|
903
|
+
public class AudioSystem : MessageAwareComponent
|
|
904
|
+
{
|
|
905
|
+
protected override void RegisterMessageHandlers()
|
|
906
|
+
{
|
|
907
|
+
base.RegisterMessageHandlers();
|
|
908
|
+
_ = Token.RegisterUntargeted<SceneTransitionRequested>(OnTransition);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
void OnTransition(ref SceneTransitionRequested msg)
|
|
912
|
+
{
|
|
913
|
+
FadeOutMusic(); // Type-safe, debuggable via DxMessaging Inspector
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
##### Benefits
|
|
919
|
+
|
|
920
|
+
- ✅ Designers create events in Inspector (SOA workflow preserved)
|
|
921
|
+
- ✅ Code uses DxMessaging (type-safe, lifecycle-safe)
|
|
922
|
+
|
|
923
|
+
###### Drawbacks
|
|
924
|
+
|
|
925
|
+
- ⚠️ Bridge boilerplate for each SOA event
|
|
926
|
+
- ⚠️ Double registration (SOA listener + DxMessaging handler)
|
|
927
|
+
|
|
928
|
+
### Pattern B: Proper ScriptableObject Usage (Recommended)
|
|
929
|
+
|
|
930
|
+
**Use case:** ScriptableObjects for immutable config data, DxMessaging for runtime events.
|
|
931
|
+
|
|
932
|
+
**Strategy:** Use each tool for its intended purpose; avoid bridging.
|
|
933
|
+
|
|
934
|
+
> **Important:** This pattern uses ScriptableObjects CORRECTLY (immutable design data),
|
|
935
|
+
> NOT as SOA (mutable runtime state). This is standard Unity best practice, not SOA.
|
|
936
|
+
> If you're only using SOs for config data like this, you don't need SOA patterns at all.
|
|
937
|
+
|
|
938
|
+
#### Example: Combat with Designer-Tunable Data
|
|
939
|
+
|
|
940
|
+
```csharp
|
|
941
|
+
using DxMessaging.Core.Messages;
|
|
942
|
+
using DxMessaging.Core.Attributes;
|
|
943
|
+
using DxMessaging.Unity;
|
|
944
|
+
using UnityEngine;
|
|
945
|
+
|
|
946
|
+
// ScriptableObject: Designer-tunable balance data (immutable at runtime)
|
|
947
|
+
// This is CORRECT SO usage, NOT SOA
|
|
948
|
+
[CreateAssetMenu(menuName = "Config/Weapon Stats")]
|
|
949
|
+
public class WeaponStats : ScriptableObject
|
|
950
|
+
{
|
|
951
|
+
public int baseDamage = 10; // Designer tweaks in Inspector
|
|
952
|
+
public float critMultiplier = 2f;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// DxMessaging: Runtime event (code-driven)
|
|
956
|
+
[DxBroadcastMessage]
|
|
957
|
+
[DxAutoConstructor]
|
|
958
|
+
public readonly partial struct DamageDealt
|
|
959
|
+
{
|
|
960
|
+
public readonly int amount;
|
|
961
|
+
public readonly bool wasCrit;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// Combat system: Reads immutable SO data, emits DxMessaging events
|
|
965
|
+
public class Weapon : MessageAwareComponent
|
|
966
|
+
{
|
|
967
|
+
[SerializeField] private WeaponStats stats; // Immutable config (correct SO usage)
|
|
968
|
+
|
|
969
|
+
public void Fire()
|
|
970
|
+
{
|
|
971
|
+
bool crit = Random.value < 0.1f;
|
|
972
|
+
int damage = Mathf.RoundToInt(stats.baseDamage * (crit ? stats.critMultiplier : 1f));
|
|
973
|
+
|
|
974
|
+
var msg = new DamageDealt(damage, crit);
|
|
975
|
+
msg.EmitComponentBroadcast(this); // Runtime event via DxMessaging
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// Analytics: Pure DxMessaging (no SOA dependency)
|
|
980
|
+
public class CombatAnalytics : MessageAwareComponent
|
|
981
|
+
{
|
|
982
|
+
protected override void RegisterMessageHandlers()
|
|
983
|
+
{
|
|
984
|
+
base.RegisterMessageHandlers();
|
|
985
|
+
_ = Token.RegisterBroadcastWithoutSource<DamageDealt>(OnDamage);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
void OnDamage(InstanceId source, DamageDealt msg)
|
|
989
|
+
{
|
|
990
|
+
Debug.Log($"{source} dealt {msg.amount} damage (crit: {msg.wasCrit})");
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
##### Benefits
|
|
996
|
+
|
|
997
|
+
- ✅ **Best of both worlds** - ScriptableObjects for static configs, DxMessaging for runtime events
|
|
998
|
+
- ✅ No bridging overhead
|
|
999
|
+
- ✅ Uses each system correctly: SOs for their intended purpose (immutable design data), messaging for runtime communication
|
|
1000
|
+
- ✅ This is NOT SOA - it's proper Unity architecture
|
|
1001
|
+
|
|
1002
|
+
###### This is the recommended pattern for all projects
|
|
1003
|
+
|
|
1004
|
+
### When to Use Each Pattern
|
|
1005
|
+
|
|
1006
|
+
| Pattern | Use When | Complexity | Performance |
|
|
1007
|
+
| --------------------------- | ------------------------------------------------------- | ---------- | ----------- |
|
|
1008
|
+
| **A: SOA → DxMessaging** | Designers create SOA events, modern code uses messaging | Medium | ⚠️ Medium |
|
|
1009
|
+
| **B: Proper SO Usage** | Immutable configs only, messaging for events | Low | ✅ Good |
|
|
1010
|
+
| **None (Pure DxMessaging)** | Greenfield project or full SOA migration | Lowest | ✅ Best |
|
|
1011
|
+
|
|
1012
|
+
### Migration Path: SOA → DxMessaging
|
|
1013
|
+
|
|
1014
|
+
If you're moving away from SOA:
|
|
1015
|
+
|
|
1016
|
+
1. **Phase 1:** Identify SOA event usage (GameEvent/GameEventListener patterns)
|
|
1017
|
+
1. **Phase 2:** Create equivalent DxMessaging messages (Untargeted/Broadcast)
|
|
1018
|
+
1. **Phase 3:** Add bridges (Pattern A or B) to maintain compatibility
|
|
1019
|
+
1. **Phase 4:** Migrate listeners to DxMessaging incrementally
|
|
1020
|
+
1. **Phase 5:** Remove bridges and SOA assets once all references gone
|
|
1021
|
+
|
|
1022
|
+
For SOA variables:
|
|
1023
|
+
|
|
1024
|
+
1. Convert read-only SO configs → Keep as-is (correct SO usage) or move to JSON/ScriptableObjects for data
|
|
1025
|
+
1. Convert mutable SO variables → DxMessaging messages or DI-injected services
|
|
1026
|
+
1. Convert RuntimeSets → DxMessaging global observers (`RegisterBroadcastWithoutSource`)
|
|
1027
|
+
|
|
1028
|
+
### Final Recommendations
|
|
1029
|
+
|
|
1030
|
+
#### If you're using SOA
|
|
1031
|
+
|
|
1032
|
+
- ✅ **Do:** Use Pattern B (Proper SO Usage) - SOs for immutable configs ONLY, DxMessaging for runtime events
|
|
1033
|
+
- ✅ **Do:** Use Pattern A to bridge existing SOA GameEvent assets to DxMessaging during migration
|
|
1034
|
+
- ✅ **Do:** Read [Anti-ScriptableObject Architecture](https://github.com/cathei/AntiScriptableObjectArchitecture) to understand risks
|
|
1035
|
+
- ✅ **Do:** Consider gradual migration to DxMessaging or DI frameworks
|
|
1036
|
+
- ❌ **Don't:** Use SOs for mutable runtime state (health, scores, etc.)
|
|
1037
|
+
- ❌ **Don't:** Create new SOA event assets—use DxMessaging messages instead
|
|
1038
|
+
|
|
1039
|
+
##### If you're starting fresh
|
|
1040
|
+
|
|
1041
|
+
- ✅ **Do:** Use DxMessaging for all messaging/events
|
|
1042
|
+
- ✅ **Do:** Use ScriptableObjects ONLY for immutable design data (weapon stats, level configs)
|
|
1043
|
+
- ✅ **Do:** Consider DI frameworks (Zenject/VContainer) for service dependencies
|
|
1044
|
+
- ❌ **Don't:** Adopt SOA's GameEvent/Variable patterns—they're superseded by better tools
|
|
1045
|
+
|
|
1046
|
+
###### Resources
|
|
1047
|
+
|
|
1048
|
+
- [Anti-ScriptableObject Architecture](https://github.com/cathei/AntiScriptableObjectArchitecture) - Detailed critique
|
|
1049
|
+
- [Ryan Hipple Unite 2017 Talk](https://www.youtube.com/watch?v=raQ3iHhE_Kk) - Original SOA presentation
|
|
1050
|
+
- [Unity Official Guide](https://unity.com/how-to/architect-game-code-scriptable-objects) - Unity's perspective
|
|
1051
|
+
- [DxMessaging DI Integrations](Integrations/) - Better alternatives for dependency management
|
|
1052
|
+
- [Zenject](https://github.com/modesttree/Zenject) - Recommended DI framework
|
|
1053
|
+
- [VContainer](https://github.com/hadashiA/VContainer) - Lightweight DI alternative
|
|
1054
|
+
|
|
1055
|
+
---
|
|
1056
|
+
|
|
771
1057
|
## Related Documentation
|
|
772
1058
|
|
|
773
1059
|
### Learn the Basics First?
|
package/Docs/Performance.md
CHANGED
|
@@ -14,15 +14,15 @@ See also: `Docs/DesignAndArchitecture.md#performance-optimizations` for design d
|
|
|
14
14
|
|
|
15
15
|
| Message Tech | Operations / Second | Allocations? |
|
|
16
16
|
| ---------------------------------- | ------------------- | ------------ |
|
|
17
|
-
| Unity | 2,
|
|
18
|
-
| DxMessaging (GameObject) - Normal | 8,
|
|
19
|
-
| DxMessaging (Component) - Normal | 8,
|
|
20
|
-
| DxMessaging (GameObject) - No-Copy | 9,
|
|
21
|
-
| DxMessaging (Component) - No-Copy | 9,
|
|
22
|
-
| DxMessaging (Untargeted) - No-Copy | 14,
|
|
23
|
-
| Reflexive (One Argument) | 2,832,
|
|
24
|
-
| Reflexive (Two Arguments) | 2,
|
|
25
|
-
| Reflexive (Three Arguments) | 2,
|
|
17
|
+
| Unity | 2,490,000 | Yes |
|
|
18
|
+
| DxMessaging (GameObject) - Normal | 8,520,000 | No |
|
|
19
|
+
| DxMessaging (Component) - Normal | 8,542,000 | No |
|
|
20
|
+
| DxMessaging (GameObject) - No-Copy | 9,426,000 | No |
|
|
21
|
+
| DxMessaging (Component) - No-Copy | 9,552,000 | No |
|
|
22
|
+
| DxMessaging (Untargeted) - No-Copy | 14,900,000 | No |
|
|
23
|
+
| Reflexive (One Argument) | 2,832,000 | No |
|
|
24
|
+
| Reflexive (Two Arguments) | 2,348,000 | No |
|
|
25
|
+
| Reflexive (Three Arguments) | 2,364,000 | No |
|
|
26
26
|
|
|
27
27
|
## macOS
|
|
28
28
|
|
package/Docs/QuickReference.md
CHANGED
|
@@ -9,6 +9,7 @@ Do’s
|
|
|
9
9
|
- Use GameObject/Component emit helpers (no manual `InstanceId`).
|
|
10
10
|
- Register once; enable/disable with component state.
|
|
11
11
|
- Prefer named handler methods over inline lambdas for reuse and clarity.
|
|
12
|
+
- When using DI, inject `IMessageRegistrationBuilder` instead of newing `MessageHandler`s manually.
|
|
12
13
|
|
|
13
14
|
Don’ts
|
|
14
15
|
|
|
@@ -77,6 +78,36 @@ _ = token.RegisterBroadcastWithoutSource<TookDamage>(OnAnyDamage);
|
|
|
77
78
|
void OnAnyDamage(ref InstanceId src, ref TookDamage m) { /* ... */ }
|
|
78
79
|
```
|
|
79
80
|
|
|
81
|
+
Register (DI / services)
|
|
82
|
+
|
|
83
|
+
```csharp
|
|
84
|
+
using DxMessaging.Core.MessageBus;
|
|
85
|
+
|
|
86
|
+
public sealed class DamageSystem : IStartable, IDisposable
|
|
87
|
+
{
|
|
88
|
+
private readonly MessageRegistrationLease lease;
|
|
89
|
+
|
|
90
|
+
public DamageSystem(IMessageRegistrationBuilder registrationBuilder)
|
|
91
|
+
{
|
|
92
|
+
lease = registrationBuilder.Build(new MessageRegistrationBuildOptions
|
|
93
|
+
{
|
|
94
|
+
Configure = token =>
|
|
95
|
+
{
|
|
96
|
+
_ = token.RegisterUntargeted<TookDamage>(OnDamage);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public void Start() => lease.Activate();
|
|
102
|
+
|
|
103
|
+
public void Dispose() => lease.Dispose();
|
|
104
|
+
|
|
105
|
+
private static void OnDamage(ref TookDamage message) { /* respond */ }
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Tip: Define `ZENJECT_PRESENT`, `VCONTAINER_PRESENT`, or `REFLEX_PRESENT` to enable the optional shims under `Runtime/Unity/Integrations/` that bind the builder automatically for those containers.
|
|
110
|
+
|
|
80
111
|
Interceptors and post‑processors
|
|
81
112
|
|
|
82
113
|
```csharp
|