com.wallstop-studios.dxmessaging 2.1.1 → 2.1.3

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.
Files changed (158) hide show
  1. package/.github/workflows/dotnet-tests.yml +72 -0
  2. package/.lychee.toml +4 -2
  3. package/AGENTS.md +13 -12
  4. package/Docs/Comparisons.md +5 -5
  5. package/Docs/Install.md +2 -1
  6. package/Docs/InterceptorsAndOrdering.md +1 -1
  7. package/Docs/Performance.md +15 -13
  8. package/Docs/QuickReference.md +1 -1
  9. package/Docs/Reference.md +5 -5
  10. package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll +0 -0
  11. package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +13 -2
  12. package/Editor/Analyzers/Microsoft.CodeAnalysis.dll +0 -0
  13. package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +11 -0
  14. package/Editor/Analyzers/System.Collections.Immutable.dll +0 -0
  15. package/Editor/Analyzers/System.Collections.Immutable.dll.meta +11 -0
  16. package/Editor/Analyzers/System.Reflection.Metadata.dll +0 -0
  17. package/Editor/Analyzers/System.Reflection.Metadata.dll.meta +13 -2
  18. package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll +0 -0
  19. package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll.meta +11 -0
  20. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
  21. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll.meta +3 -2
  22. package/Editor/AssemblyInfo.cs +3 -0
  23. package/Editor/AssemblyInfo.cs.meta +3 -0
  24. package/Editor/CustomEditors/MessagingComponentEditor.cs +24 -0
  25. package/Editor/DxMessagingEditorInitializer.cs +58 -1
  26. package/Editor/DxMessagingMenu.cs +38 -0
  27. package/Editor/DxMessagingMenu.cs.meta +11 -0
  28. package/Editor/DxMessagingSceneBuildProcessor.cs +81 -0
  29. package/Editor/DxMessagingSceneBuildProcessor.cs.meta +11 -0
  30. package/Editor/Settings/DxMessagingSettings.cs +37 -6
  31. package/Editor/Settings/DxMessagingSettingsProvider.cs +45 -7
  32. package/Editor/SetupCscRsp.cs +133 -53
  33. package/Editor/Testing/MessagingComponentEditorHarness.cs +218 -0
  34. package/Editor/Testing/MessagingComponentEditorHarness.cs.meta +3 -0
  35. package/Editor/Testing.meta +3 -0
  36. package/README.md +10 -4
  37. package/Runtime/AssemblyInfo.cs +1 -0
  38. package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs +52 -0
  39. package/Runtime/Core/DataStructure/CyclicBuffer.cs +16 -0
  40. package/Runtime/Core/Diagnostics/MessageEmissionData.cs +27 -12
  41. package/Runtime/Core/Diagnostics/MessageRegistrationType.cs +62 -0
  42. package/Runtime/Core/DxMessagingStaticState.cs +108 -0
  43. package/Runtime/Core/DxMessagingStaticState.cs.meta +11 -0
  44. package/Runtime/Core/Extensions/IListExtensions.cs +24 -0
  45. package/Runtime/Core/Extensions/MessageBusExtensions.cs +144 -2
  46. package/Runtime/Core/Extensions/MessageExtensions.cs +2 -2
  47. package/Runtime/Core/Helper/MessageCache.cs +16 -0
  48. package/Runtime/Core/Helper/MessageHelperIndexer.cs +77 -0
  49. package/Runtime/Core/InstanceId.cs +91 -3
  50. package/Runtime/Core/MessageBus/DiagnosticsTarget.cs +31 -0
  51. package/Runtime/Core/MessageBus/DiagnosticsTarget.cs.meta +11 -0
  52. package/Runtime/Core/MessageBus/IMessageBus.cs +44 -16
  53. package/Runtime/Core/MessageBus/MessageBus.cs +96 -25
  54. package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs +46 -2
  55. package/Runtime/Core/MessageBus/MessagingRegistration.cs +63 -5
  56. package/Runtime/Core/MessageBus/RegistrationLog.cs +10 -0
  57. package/Runtime/Core/MessageHandler.cs +141 -8
  58. package/Runtime/Core/MessageRegistrationHandle.cs +59 -0
  59. package/Runtime/Core/MessageRegistrationToken.cs +20 -4
  60. package/Runtime/Core/Messages/ReflexiveMessage.cs +38 -0
  61. package/Runtime/Core/MessagingDebug.cs +16 -1
  62. package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs +6 -0
  63. package/Runtime/Unity/DxMessagingRuntimeInitializer.cs +19 -0
  64. package/Runtime/Unity/DxMessagingRuntimeInitializer.cs.meta +11 -0
  65. package/Runtime/Unity/InitialGlobalMessageBusProvider.cs +6 -0
  66. package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs +19 -0
  67. package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs +10 -0
  68. package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs +14 -0
  69. package/Runtime/Unity/MessageAwareComponent.cs +2 -0
  70. package/Runtime/Unity/MessageBusProviderHandle.cs +4 -0
  71. package/Runtime/Unity/MessagingComponent.cs +109 -0
  72. package/Runtime/Unity/MessagingComponentInstaller.cs +2 -0
  73. package/Runtime/Unity/ScriptableMessageBusProvider.cs +2 -0
  74. package/Samples~/DI/README.md +13 -13
  75. package/Samples~/Mini Combat/README.md +15 -15
  76. package/Samples~/Mini Combat/Walkthrough.md +12 -12
  77. package/Samples~/UI Buttons + Inspector/README.md +4 -4
  78. package/SourceGenerators/Directory.Build.props +9 -0
  79. package/{Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.csproj.meta → SourceGenerators/Directory.Build.props.meta} +1 -1
  80. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs +23 -24
  81. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs +91 -27
  82. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj +24 -4
  83. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DocsSnippetCompilationTests.cs +193 -0
  84. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DocsSnippetCompilationTests.cs.meta +11 -0
  85. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DxAutoConstructorGeneratorDiagnosticsTests.cs +69 -0
  86. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DxAutoConstructorGeneratorDiagnosticsTests.cs.meta +11 -0
  87. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DxMessageIdGeneratorDiagnosticsTests.cs +66 -0
  88. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/DxMessageIdGeneratorDiagnosticsTests.cs.meta +11 -0
  89. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/GeneratorTestUtilities.cs +155 -0
  90. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/GeneratorTestUtilities.cs.meta +11 -0
  91. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/WallstopStudios.DxMessaging.SourceGenerators.Tests.csproj +20 -0
  92. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests/WallstopStudios.DxMessaging.SourceGenerators.Tests.csproj.meta +7 -0
  93. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.Tests.meta +8 -0
  94. package/Tests/Editor/MessagingComponentEditorHarnessTests.cs +243 -0
  95. package/Tests/Editor/MessagingComponentEditorHarnessTests.cs.meta +3 -0
  96. package/Tests/Editor/MessagingComponentSerializationTests.cs +129 -0
  97. package/Tests/Editor/MessagingComponentSerializationTests.cs.meta +3 -0
  98. package/Tests/Editor/WallstopStudios.DxMessaging.Tests.Editor.asmdef +19 -0
  99. package/Tests/Editor/WallstopStudios.DxMessaging.Tests.Editor.asmdef.meta +3 -0
  100. package/Tests/Editor.meta +3 -0
  101. package/Tests/Runtime/Benchmarks/BenchmarkSession.cs +3 -0
  102. package/Tests/Runtime/Benchmarks/BenchmarkTestBase.cs +3 -0
  103. package/Tests/Runtime/Benchmarks/ComparisonPerformanceTests.cs +3 -0
  104. package/Tests/Runtime/Benchmarks/PerformanceTests.cs +137 -0
  105. package/Tests/Runtime/Core/AlternateBusTests.cs +3 -0
  106. package/Tests/Runtime/Core/BroadcastTests.cs +3 -0
  107. package/Tests/Runtime/Core/CyclicBufferTests.cs +3 -0
  108. package/Tests/Runtime/Core/DefaultBusFallbackTests.cs +5 -2
  109. package/Tests/Runtime/Core/DiagnosticsTests.cs +6 -3
  110. package/Tests/Runtime/Core/DxMessagingStaticStateTests.cs +69 -0
  111. package/Tests/Runtime/Core/DxMessagingStaticStateTests.cs.meta +11 -0
  112. package/Tests/Runtime/Core/EdgeCaseTests.cs +3 -0
  113. package/Tests/Runtime/Core/EnablementTests.cs +3 -0
  114. package/Tests/Runtime/Core/Extensions/MessageExtensionsProviderTests.cs +2 -2
  115. package/Tests/Runtime/Core/GenericMessageTests.cs +3 -0
  116. package/Tests/Runtime/Core/GlobalAcceptAllTests.cs +3 -0
  117. package/Tests/Runtime/Core/InterceptorCancellationTests.cs +3 -0
  118. package/Tests/Runtime/Core/LifecycleTests.cs +3 -0
  119. package/Tests/Runtime/Core/MessageEmissionDataTests.cs +70 -0
  120. package/Tests/Runtime/Core/MessageEmissionDataTests.cs.meta +11 -0
  121. package/Tests/Runtime/Core/MessagingComponentLifecycleTests.cs +3 -0
  122. package/Tests/Runtime/Core/MessagingTestBase.cs +3 -0
  123. package/Tests/Runtime/Core/MutationDedupeTests.cs +3 -0
  124. package/Tests/Runtime/Core/MutationDestructionTests.cs +3 -0
  125. package/Tests/Runtime/Core/MutationDuringEmissionTests.cs +3 -0
  126. package/Tests/Runtime/Core/MutationGlobalAddTests.cs +3 -0
  127. package/Tests/Runtime/Core/MutationInterceptorTests.cs +3 -0
  128. package/Tests/Runtime/Core/MutationPostProcessorAcrossHandlersTests.cs +3 -0
  129. package/Tests/Runtime/Core/MutationPostProcessorMoreTests.cs +3 -0
  130. package/Tests/Runtime/Core/MutationPriorityTests.cs +3 -0
  131. package/Tests/Runtime/Core/NominalTests.cs +3 -0
  132. package/Tests/Runtime/Core/OrderingTests.cs +3 -0
  133. package/Tests/Runtime/Core/OverDeregistrationTests.cs +3 -0
  134. package/Tests/Runtime/Core/PostProcessorTests.cs +3 -0
  135. package/Tests/Runtime/Core/ReflexiveErrorTests.cs +3 -0
  136. package/Tests/Runtime/Core/ReflexiveMessageWarningTests.cs +4 -1
  137. package/Tests/Runtime/Core/ReflexiveTests.cs +3 -0
  138. package/Tests/Runtime/Core/RegistrationTests.cs +3 -0
  139. package/Tests/Runtime/Core/StringShorthandTests.cs +3 -0
  140. package/Tests/Runtime/Core/TargetedTests.cs +3 -0
  141. package/Tests/Runtime/Core/TypedShorthandTests.cs +3 -0
  142. package/Tests/Runtime/Core/UntargetedEquivalenceTests.cs +3 -0
  143. package/Tests/Runtime/Core/UntargetedPrefreezeTests.cs +14 -78
  144. package/Tests/Runtime/Core/UntargetedTests.cs +3 -0
  145. package/Tests/Runtime/Integrations/Reflex/ReflexIntegrationTests.cs +4 -1
  146. package/Tests/Runtime/Integrations/VContainer/VContainerIntegrationTests.cs +3 -0
  147. package/Tests/Runtime/Integrations/Zenject/ZenjectIntegrationTests.cs +3 -0
  148. package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs +3 -0
  149. package/Tests/Runtime/Scripts/Components/ManualListenerComponent.cs +3 -0
  150. package/Tests/Runtime/Scripts/Components/ReflexiveReceiverComponent.cs +3 -0
  151. package/Tests/Runtime/TestUtilities/UnityFixtureBase.cs +3 -0
  152. package/Tests/Runtime/Unity/MessageBusProviderAssetTests.cs +3 -0
  153. package/Tests/Runtime/Unity/MessageBusProviderHandleTests.cs +87 -3
  154. package/Tests/Runtime/Unity/MessagingComponentInstallerSceneTests.cs +109 -0
  155. package/Tests/Runtime/Unity/MessagingComponentInstallerSceneTests.cs.meta +11 -0
  156. package/Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs +159 -17
  157. package/package.json +1 -1
  158. package/Tests/Runtime/WallstopStudios.DxMessaging.Tests.Runtime.csproj +0 -7
@@ -0,0 +1,81 @@
1
+ namespace DxMessaging.Editor
2
+ {
3
+ #if UNITY_EDITOR && UNITY_2021_3_OR_NEWER
4
+ using System.Collections.Generic;
5
+ using DxMessaging.Unity;
6
+ using UnityEditor.Build;
7
+ using UnityEditor.Build.Reporting;
8
+ using UnityEngine;
9
+ using UnityEngine.SceneManagement;
10
+
11
+ /// <summary>
12
+ /// Ensures MessagingComponent instances do not carry runtime registrations into player builds.
13
+ /// </summary>
14
+ internal sealed class DxMessagingSceneBuildProcessor : IProcessSceneWithReport
15
+ {
16
+ public int callbackOrder => int.MaxValue;
17
+
18
+ /// <summary>
19
+ /// Strips runtime-only messaging state from the scene before it is serialized into the build.
20
+ /// </summary>
21
+ /// <param name="scene">Scene currently being processed.</param>
22
+ /// <param name="report">Build report associated with the scene export.</param>
23
+ public void OnProcessScene(Scene scene, BuildReport report)
24
+ {
25
+ if (!scene.IsValid() || !scene.isLoaded)
26
+ {
27
+ return;
28
+ }
29
+
30
+ MessagingComponent[] components = FindMessagingComponents(scene);
31
+ if (components == null || components.Length == 0)
32
+ {
33
+ return;
34
+ }
35
+
36
+ int cleared = 0;
37
+ for (int i = 0; i < components.Length; ++i)
38
+ {
39
+ MessagingComponent component = components[i];
40
+ if (component != null && component.EditorResetRuntimeState())
41
+ {
42
+ cleared++;
43
+ }
44
+ }
45
+
46
+ if (cleared > 0 && report != null)
47
+ {
48
+ Debug.Log(
49
+ $"[DxMessaging] Cleared {cleared} MessagingComponent instance(s) in scene '{scene.path}' prior to build."
50
+ );
51
+ }
52
+ }
53
+
54
+ private static MessagingComponent[] FindMessagingComponents(Scene scene)
55
+ {
56
+ List<MessagingComponent> buffer = new List<MessagingComponent>();
57
+ GameObject[] roots = scene.GetRootGameObjects();
58
+ for (int i = 0; i < roots.Length; ++i)
59
+ {
60
+ GameObject root = roots[i];
61
+ if (root == null)
62
+ {
63
+ continue;
64
+ }
65
+
66
+ MessagingComponent[] components = root.GetComponentsInChildren<MessagingComponent>(
67
+ includeInactive: true
68
+ );
69
+ if (components == null || components.Length == 0)
70
+ {
71
+ continue;
72
+ }
73
+
74
+ buffer.AddRange(components);
75
+ }
76
+
77
+ return buffer.ToArray();
78
+ }
79
+ }
80
+ #endif
81
+ }
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: ec8789213f7f4c30a9353e90fb4345c8
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -2,8 +2,10 @@ namespace DxMessaging.Editor.Settings
2
2
  {
3
3
  #if UNITY_EDITOR
4
4
  using System.Linq;
5
+ using Core.MessageBus;
5
6
  using UnityEditor;
6
7
  using UnityEngine;
8
+ using UnityEngine.Serialization;
7
9
 
8
10
  /// <summary>
9
11
  /// Project-wide DxMessaging settings asset (Editor-only).
@@ -18,18 +20,26 @@ namespace DxMessaging.Editor.Settings
18
20
  private const string SettingsPath = "Assets/Editor/DxMessagingSettings.asset";
19
21
 
20
22
  [SerializeField]
21
- internal bool _enableDiagnosticsInEditor;
23
+ internal DiagnosticsTarget _diagnosticsTargets = DiagnosticsTarget.Off;
24
+
25
+ [SerializeField]
26
+ [HideInInspector]
27
+ [FormerlySerializedAs("_enableDiagnosticsInEditor")]
28
+ private bool _legacyEnableDiagnosticsInEditor;
22
29
 
23
30
  [SerializeField]
24
31
  internal int _messageBufferSize = DefaultBufferSize;
25
32
 
33
+ [SerializeField]
34
+ internal bool _suppressDomainReloadWarning = true;
35
+
26
36
  /// <summary>
27
- /// Enables <see cref="Core.MessageBus.IMessageBus.GlobalDiagnosticsMode"/> in the Editor.
37
+ /// Controls <see cref="DiagnosticsTarget"/> values applied to <see cref="IMessageBus.GlobalDiagnosticsTargets"/>.
28
38
  /// </summary>
29
- public bool EnableDiagnosticsInEditor
39
+ public DiagnosticsTarget DiagnosticsTargets
30
40
  {
31
- get => _enableDiagnosticsInEditor;
32
- set => _enableDiagnosticsInEditor = value;
41
+ get => _diagnosticsTargets;
42
+ set => _diagnosticsTargets = value;
33
43
  }
34
44
 
35
45
  /// <summary>
@@ -41,6 +51,15 @@ namespace DxMessaging.Editor.Settings
41
51
  set => _messageBufferSize = value;
42
52
  }
43
53
 
54
+ /// <summary>
55
+ /// When true, suppresses the Enter Play Mode Options domain reload warning in the Editor.
56
+ /// </summary>
57
+ public bool SuppressDomainReloadWarning
58
+ {
59
+ get => _suppressDomainReloadWarning;
60
+ set => _suppressDomainReloadWarning = value;
61
+ }
62
+
44
63
  /// <summary>
45
64
  /// Loads the settings asset if present, otherwise creates it with sensible defaults.
46
65
  /// </summary>
@@ -62,8 +81,9 @@ namespace DxMessaging.Editor.Settings
62
81
  if (settings == null)
63
82
  {
64
83
  settings = CreateInstance<DxMessagingSettings>();
65
- settings._enableDiagnosticsInEditor = false;
84
+ settings._diagnosticsTargets = DiagnosticsTarget.Off;
66
85
  settings._messageBufferSize = DefaultBufferSize;
86
+ settings._suppressDomainReloadWarning = true;
67
87
  if (!AssetDatabase.IsValidFolder("Assets/Editor"))
68
88
  {
69
89
  AssetDatabase.CreateFolder("Assets", "Editor");
@@ -72,6 +92,17 @@ namespace DxMessaging.Editor.Settings
72
92
  AssetDatabase.SaveAssets();
73
93
  }
74
94
 
95
+ if (
96
+ settings._diagnosticsTargets == DiagnosticsTarget.Off
97
+ && settings._legacyEnableDiagnosticsInEditor
98
+ )
99
+ {
100
+ settings._diagnosticsTargets = DiagnosticsTarget.Editor;
101
+ settings._legacyEnableDiagnosticsInEditor = false;
102
+ EditorUtility.SetDirty(settings);
103
+ AssetDatabase.SaveAssets();
104
+ }
105
+
75
106
  return settings;
76
107
  }
77
108
 
@@ -2,6 +2,7 @@ namespace DxMessaging.Editor.Settings
2
2
  {
3
3
  #if UNITY_EDITOR
4
4
  using System.Collections.Generic;
5
+ using Core.MessageBus;
5
6
  using UnityEditor;
6
7
  using UnityEngine;
7
8
 
@@ -21,6 +22,11 @@ namespace DxMessaging.Editor.Settings
21
22
  )
22
23
  : base(path, scope) { }
23
24
 
25
+ /// <summary>
26
+ /// Initializes the serialized settings backing store when the settings page is opened.
27
+ /// </summary>
28
+ /// <param name="searchContext">Search text provided by the Project Settings window.</param>
29
+ /// <param name="rootElement">Root visual element for UI Toolkit-based providers.</param>
24
30
  public override void OnActivate(
25
31
  string searchContext,
26
32
  UnityEngine.UIElements.VisualElement rootElement
@@ -29,28 +35,60 @@ namespace DxMessaging.Editor.Settings
29
35
  _messagingSettings = DxMessagingSettings.GetSerializedSettings();
30
36
  }
31
37
 
38
+ /// <summary>
39
+ /// Renders the DxMessaging settings UI and persists any modifications.
40
+ /// </summary>
41
+ /// <param name="searchContext">Search text provided by the Project Settings window.</param>
32
42
  public override void OnGUI(string searchContext)
33
43
  {
34
- EditorGUILayout.PropertyField(
35
- _messagingSettings.FindProperty(
36
- nameof(DxMessagingSettings._enableDiagnosticsInEditor)
37
- ),
38
- new GUIContent("Global Diagnostics Mode")
44
+ SerializedProperty targetsProp = _messagingSettings.FindProperty(
45
+ nameof(DxMessagingSettings._diagnosticsTargets)
39
46
  );
47
+ DiagnosticsTarget currentTargets = (DiagnosticsTarget)targetsProp.enumValueFlag;
48
+ DiagnosticsTarget updatedTargets = (DiagnosticsTarget)
49
+ EditorGUILayout.EnumFlagsField(
50
+ new GUIContent(
51
+ "Diagnostics Targets",
52
+ "Select where global diagnostics should be enabled by default. Combine flags for multiple targets."
53
+ ),
54
+ currentTargets
55
+ );
56
+ if (updatedTargets != currentTargets)
57
+ {
58
+ targetsProp.enumValueFlag = (int)updatedTargets;
59
+ }
40
60
  EditorGUILayout.PropertyField(
41
61
  _messagingSettings.FindProperty(nameof(DxMessagingSettings._messageBufferSize)),
42
- new GUIContent("Message Buffer Size")
62
+ new GUIContent(
63
+ "Message Buffer Size",
64
+ "Number of emissions kept per bus/token when diagnostics mode is active."
65
+ )
66
+ );
67
+ EditorGUILayout.PropertyField(
68
+ _messagingSettings.FindProperty(
69
+ nameof(DxMessagingSettings._suppressDomainReloadWarning)
70
+ ),
71
+ new GUIContent(
72
+ "Suppress Domain Reload Warning",
73
+ "Disable the warning shown when Enter Play Mode Options skips domain reload; DxMessaging still resets its statics."
74
+ )
43
75
  );
44
76
 
45
77
  _messagingSettings.ApplyModifiedProperties();
46
78
  }
47
79
 
48
80
  [SettingsProvider]
81
+ /// <summary>
82
+ /// Factory used by Unity to register the DxMessaging project settings page.
83
+ /// </summary>
84
+ /// <returns>Configured settings provider instance.</returns>
49
85
  public static SettingsProvider CreateDxMessagingSettingsProvider()
50
86
  {
51
87
  DxMessagingSettingsProvider provider = new("Project/DxMessaging")
52
88
  {
53
- keywords = new HashSet<string>(new[] { "DxMessaging", "Diagnostics" }),
89
+ keywords = new HashSet<string>(
90
+ new[] { "DxMessaging", "Diagnostics", "MessageBus", "Targets" }
91
+ ),
54
92
  };
55
93
 
56
94
  return provider;
@@ -6,6 +6,7 @@ namespace DxMessaging.Editor
6
6
  using System.Collections.Generic;
7
7
  using System.IO;
8
8
  using System.Linq;
9
+ using System.Security.Cryptography;
9
10
  using UnityEditor;
10
11
  using UnityEngine;
11
12
  using Object = UnityEngine.Object;
@@ -20,11 +21,11 @@ namespace DxMessaging.Editor
20
21
  )
21
22
  .Replace("\\", "/");
22
23
 
23
- private static readonly string AnalyzerPathRelative =
24
- "Packages/com.wallstop-studios.dxmessaging/Editor/Analyzers/";
25
-
26
- private static readonly string LibraryPathRelative =
27
- "Library/PackageCache/com.wallstop-studios.dxmessaging/Editor/Analyzers/";
24
+ private static readonly string[] AnalyzerDirectories =
25
+ {
26
+ "Packages/com.wallstop-studios.dxmessaging/Editor/Analyzers/",
27
+ "Library/PackageCache/com.wallstop-studios.dxmessaging/Editor/Analyzers/",
28
+ };
28
29
 
29
30
  private static readonly string SourceGeneratorDllName =
30
31
  "WallstopStudios.DxMessaging.SourceGenerators.dll";
@@ -34,13 +35,18 @@ namespace DxMessaging.Editor
34
35
  SourceGeneratorDllName,
35
36
  "Microsoft.CodeAnalysis.dll",
36
37
  "Microsoft.CodeAnalysis.CSharp.dll",
38
+ "System.Text.Encodings.Web.dll",
37
39
  "System.Reflection.Metadata.dll",
38
40
  "System.Runtime.CompilerServices.Unsafe.dll",
39
41
  "System.Collections.Immutable.dll",
42
+ "System.Memory.dll",
43
+ "System.Buffers.dll",
44
+ "System.Threading.Tasks.Extensions.dll",
45
+ "System.Numerics.Vectors.dll",
46
+ "System.Text.Encoding.CodePages.dll",
47
+ "Microsoft.Bcl.AsyncInterfaces.dll",
40
48
  };
41
49
 
42
- private static readonly string LibraryArgument = $"-a:\"{LibraryPathRelative}\"";
43
-
44
50
  private static readonly HashSet<string> DllNames = new(StringComparer.OrdinalIgnoreCase);
45
51
 
46
52
  static SetupCscRsp()
@@ -69,17 +75,14 @@ namespace DxMessaging.Editor
69
75
  }
70
76
  }
71
77
 
72
- string[] dllRelativeDirectories = { LibraryPathRelative, AnalyzerPathRelative };
73
-
74
- bool anyFound = false;
75
- foreach (
76
- string requiredDllName in RequiredDllNames.Where(dllName =>
77
- !DllNames.Contains(dllName)
78
- )
79
- )
78
+ foreach (string requiredDllName in RequiredDllNames)
80
79
  {
81
- bool found = false;
82
- foreach (string relativeDirectory in dllRelativeDirectories)
80
+ if (DllNames.Contains(requiredDllName))
81
+ {
82
+ continue;
83
+ }
84
+
85
+ foreach (string relativeDirectory in AnalyzerDirectories)
83
86
  {
84
87
  try
85
88
  {
@@ -92,52 +95,62 @@ namespace DxMessaging.Editor
92
95
  const string pluginsDirectory =
93
96
  "Assets/Plugins/Editor/WallstopStudios.DxMessaging/";
94
97
  string outputAsset = $"{pluginsDirectory}{requiredDllName}";
95
- string sourceAsset = $"{relativeDirectory}{requiredDllName}";
96
98
  if (!Directory.Exists(pluginsDirectory))
97
99
  {
98
100
  Directory.CreateDirectory(pluginsDirectory);
99
101
  AssetDatabase.Refresh();
100
102
  }
101
- if (!File.Exists(outputAsset))
103
+ bool needsCopy = FilesDiffer(sourceFile, outputAsset);
104
+ if (needsCopy)
102
105
  {
103
- File.Copy(sourceAsset, outputAsset);
106
+ File.Copy(sourceFile, outputAsset, true);
104
107
  AssetDatabase.ImportAsset(outputAsset);
105
- found = true;
106
108
  }
107
- else
109
+
110
+ if (requiredDllName == SourceGeneratorDllName)
111
+ {
112
+ Object loadedDll = AssetDatabase.LoadMainAssetAtPath(outputAsset);
113
+ if (loadedDll != null)
114
+ {
115
+ string[] existingLabels = AssetDatabase.GetLabels(loadedDll);
116
+ if (!existingLabels.Contains("RoslynAnalyzer"))
117
+ {
118
+ List<string> newLabels = existingLabels.ToList();
119
+ newLabels.Add("RoslynAnalyzer");
120
+ AssetDatabase.SetLabels(loadedDll, newLabels.ToArray());
121
+ }
122
+ }
123
+ }
124
+
125
+ if (AssetImporter.GetAtPath(outputAsset) is PluginImporter importer)
108
126
  {
109
- FileInfo sourceInfo = new(sourceAsset);
110
- FileInfo destInfo = new(outputAsset);
127
+ bool importerDirty = false;
111
128
 
112
- if (destInfo.LastWriteTime < sourceInfo.LastWriteTime)
129
+ if (importer.GetCompatibleWithAnyPlatform())
113
130
  {
114
- // Source file is newer, so copy the file (overwrite destination)
115
- File.Copy(sourceAsset, outputAsset, true);
116
- AssetDatabase.ImportAsset(outputAsset);
117
- found = true;
131
+ importer.SetCompatibleWithAnyPlatform(false);
132
+ importerDirty = true;
118
133
  }
119
- else
134
+
135
+ if (importer.GetExcludeFromAnyPlatform("Editor"))
120
136
  {
121
- continue;
137
+ importer.SetExcludeFromAnyPlatform("Editor", false);
138
+ importerDirty = true;
122
139
  }
123
- }
124
140
 
125
- if (requiredDllName == SourceGeneratorDllName)
126
- {
127
- Object loadedDll = AssetDatabase.LoadMainAssetAtPath(outputAsset);
128
- AssetDatabase.SetLabels(loadedDll, new[] { "RoslynAnalyzer" });
129
- }
141
+ if (!importer.GetExcludeFromAnyPlatform("Standalone"))
142
+ {
143
+ importer.SetExcludeFromAnyPlatform("Standalone", true);
144
+ importerDirty = true;
145
+ }
130
146
 
131
- PluginImporter importer =
132
- AssetImporter.GetAtPath(outputAsset) as PluginImporter;
133
- if (importer != null)
134
- {
135
- importer.SetCompatibleWithAnyPlatform(false);
136
- importer.SetExcludeFromAnyPlatform("Editor", false);
137
- importer.SetExcludeFromAnyPlatform("Standalone", false);
138
- importer.SaveAndReimport();
147
+ if (importerDirty || needsCopy)
148
+ {
149
+ importer.SaveAndReimport();
150
+ }
139
151
  }
140
152
 
153
+ DllNames.Add(requiredDllName);
141
154
  break;
142
155
  }
143
156
  catch (Exception e)
@@ -147,16 +160,36 @@ namespace DxMessaging.Editor
147
160
  );
148
161
  }
149
162
  }
150
-
151
- anyFound |= found;
152
163
  }
153
164
 
154
- if (anyFound)
165
+ if (DllNames.Count > 0)
155
166
  {
156
167
  AssetDatabase.Refresh();
157
168
  }
158
169
  }
159
170
 
171
+ private static bool FilesDiffer(string sourcePath, string destinationPath)
172
+ {
173
+ if (!File.Exists(destinationPath))
174
+ {
175
+ return true;
176
+ }
177
+
178
+ FileInfo sourceInfo = new(sourcePath);
179
+ FileInfo destinationInfo = new(destinationPath);
180
+ if (sourceInfo.Length != destinationInfo.Length)
181
+ {
182
+ return true;
183
+ }
184
+
185
+ using FileStream sourceStream = File.OpenRead(sourcePath);
186
+ using FileStream destinationStream = File.OpenRead(destinationPath);
187
+ using SHA256 sha256 = SHA256.Create();
188
+ byte[] sourceHash = sha256.ComputeHash(sourceStream);
189
+ byte[] destinationHash = sha256.ComputeHash(destinationStream);
190
+ return !sourceHash.AsSpan().SequenceEqual(destinationHash);
191
+ }
192
+
160
193
  private static void EnsureCscRsp()
161
194
  {
162
195
  try
@@ -168,20 +201,67 @@ namespace DxMessaging.Editor
168
201
  }
169
202
 
170
203
  string rspContent = File.ReadAllText(RspFilePath);
171
- if (rspContent.Contains(LibraryArgument, StringComparison.OrdinalIgnoreCase))
204
+ bool modified = false;
205
+ foreach (string analyzerArgument in GetAnalyzerArguments())
172
206
  {
173
- return;
207
+ if (rspContent.Contains(analyzerArgument, StringComparison.OrdinalIgnoreCase))
208
+ {
209
+ continue;
210
+ }
211
+
212
+ File.AppendAllText(RspFilePath, analyzerArgument + Environment.NewLine);
213
+ modified = true;
174
214
  }
175
215
 
176
- File.AppendAllText(RspFilePath, $"{LibraryArgument}{Environment.NewLine}");
177
- AssetDatabase.ImportAsset("csc.rsp");
178
- Debug.Log("Updated csc.rsp.");
216
+ if (modified)
217
+ {
218
+ AssetDatabase.ImportAsset("csc.rsp");
219
+ Debug.Log("Updated csc.rsp.");
220
+ }
179
221
  }
180
222
  catch (IOException ex)
181
223
  {
182
224
  Debug.LogError($"Failed to modify csc.rsp: {ex}");
183
225
  }
184
226
  }
227
+
228
+ private static IEnumerable<string> GetAnalyzerArguments()
229
+ {
230
+ HashSet<string> yielded = new(StringComparer.OrdinalIgnoreCase);
231
+ string projectRoot = Path.GetFullPath(Path.Combine(Application.dataPath, ".."));
232
+
233
+ foreach (string directory in AnalyzerDirectories)
234
+ {
235
+ foreach (string dllName in RequiredDllNames)
236
+ {
237
+ string absoluteDirectory = Path.IsPathRooted(directory)
238
+ ? directory
239
+ : Path.GetFullPath(Path.Combine(projectRoot, directory));
240
+
241
+ string absoluteAnalyzerPath = Path.Combine(absoluteDirectory, dllName);
242
+ if (!File.Exists(absoluteAnalyzerPath))
243
+ {
244
+ continue;
245
+ }
246
+
247
+ string projectRelativePath = FileUtil.GetProjectRelativePath(
248
+ absoluteAnalyzerPath
249
+ );
250
+ if (string.IsNullOrEmpty(projectRelativePath))
251
+ {
252
+ continue;
253
+ }
254
+
255
+ string normalizedRelativePath = projectRelativePath.Replace("\\", "/");
256
+ if (!yielded.Add(normalizedRelativePath))
257
+ {
258
+ continue;
259
+ }
260
+
261
+ yield return $"-a:\"{normalizedRelativePath}\"";
262
+ }
263
+ }
264
+ }
185
265
  }
186
266
  }
187
267
  #endif