com.wallstop-studios.dxmessaging 2.1.9 → 3.0.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.
Files changed (249) hide show
  1. package/CHANGELOG.md +106 -65
  2. package/CHANGELOG.md.meta +7 -7
  3. package/Editor/Analyzers/BaseCallIlInspector.cs +277 -0
  4. package/Editor/Analyzers/BaseCallIlInspector.cs.meta +11 -0
  5. package/Editor/Analyzers/BaseCallLogMessageParser.cs +295 -0
  6. package/Editor/Analyzers/BaseCallLogMessageParser.cs.meta +11 -0
  7. package/Editor/Analyzers/BaseCallReportAggregator.cs +308 -0
  8. package/Editor/Analyzers/BaseCallReportAggregator.cs.meta +11 -0
  9. package/Editor/Analyzers/BaseCallTypeScanner.cs +110 -0
  10. package/Editor/Analyzers/BaseCallTypeScanner.cs.meta +11 -0
  11. package/Editor/Analyzers/BaseCallTypeScannerCore.cs +562 -0
  12. package/Editor/Analyzers/BaseCallTypeScannerCore.cs.meta +11 -0
  13. package/Editor/Analyzers/DxMessagingConsoleHarvester.cs +1122 -0
  14. package/Editor/Analyzers/DxMessagingConsoleHarvester.cs.meta +11 -0
  15. package/Editor/Analyzers/Microsoft.CodeAnalysis.CSharp.dll.meta +44 -44
  16. package/Editor/Analyzers/Microsoft.CodeAnalysis.dll.meta +44 -44
  17. package/Editor/Analyzers/System.Collections.Immutable.dll.meta +44 -44
  18. package/Editor/Analyzers/System.Reflection.Metadata.dll.meta +44 -44
  19. package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll.meta +44 -44
  20. package/Editor/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll +0 -0
  21. package/Editor/Analyzers/WallstopStudios.DxMessaging.Analyzer.dll.meta +33 -0
  22. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
  23. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll.meta +72 -72
  24. package/Editor/Analyzers.meta +8 -8
  25. package/Editor/AssemblyInfo.cs.meta +3 -3
  26. package/Editor/CustomEditors/MessageAwareComponentFallbackEditor.cs +81 -0
  27. package/Editor/CustomEditors/MessageAwareComponentFallbackEditor.cs.meta +11 -0
  28. package/Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs +420 -0
  29. package/Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs.meta +11 -0
  30. package/Editor/CustomEditors/MessagingComponentEditor.cs +1 -1
  31. package/Editor/CustomEditors/MessagingComponentEditor.cs.meta +2 -2
  32. package/Editor/CustomEditors.meta +2 -2
  33. package/Editor/DxMessagingEditorInitializer.cs +1 -1
  34. package/Editor/DxMessagingEditorInitializer.cs.meta +2 -2
  35. package/Editor/DxMessagingMenu.cs.meta +11 -11
  36. package/Editor/DxMessagingSceneBuildProcessor.cs.meta +11 -11
  37. package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs +190 -0
  38. package/Editor/Settings/DxMessagingBaseCallIgnoreSync.cs.meta +11 -0
  39. package/Editor/Settings/DxMessagingSettings.cs +189 -0
  40. package/Editor/Settings/DxMessagingSettings.cs.meta +2 -2
  41. package/Editor/Settings/DxMessagingSettingsProvider.cs +50 -33
  42. package/Editor/Settings/DxMessagingSettingsProvider.cs.meta +2 -2
  43. package/Editor/Settings.meta +2 -2
  44. package/Editor/SetupCscRsp.cs +209 -8
  45. package/Editor/SetupCscRsp.cs.meta +2 -2
  46. package/Editor/Testing/MessagingComponentEditorHarness.cs +1 -1
  47. package/Editor/Testing/MessagingComponentEditorHarness.cs.meta +3 -3
  48. package/Editor/Testing.meta +3 -3
  49. package/Editor/WallstopStudios.DxMessaging.Editor.asmdef +14 -14
  50. package/Editor/WallstopStudios.DxMessaging.Editor.asmdef.meta +7 -7
  51. package/Editor.meta +8 -8
  52. package/LICENSE.md +9 -9
  53. package/LICENSE.md.meta +7 -7
  54. package/README.md +941 -900
  55. package/README.md.meta +7 -7
  56. package/Runtime/AssemblyInfo.cs +4 -0
  57. package/Runtime/AssemblyInfo.cs.meta +2 -2
  58. package/Runtime/Core/Attributes/DxAutoConstructorAttribute.cs.meta +2 -2
  59. package/Runtime/Core/Attributes/DxBroadcastMessageAttribute.cs.meta +2 -2
  60. package/Runtime/Core/Attributes/DxIgnoreMissingBaseCallAttribute.cs +26 -0
  61. package/Runtime/Core/Attributes/DxIgnoreMissingBaseCallAttribute.cs.meta +11 -0
  62. package/Runtime/Core/Attributes/DxOptionalParameterAttribute.cs.meta +2 -2
  63. package/Runtime/Core/Attributes/DxTargetedMessageAttribute.cs.meta +2 -2
  64. package/Runtime/Core/Attributes/DxUntargetedMessageAttribute.cs.meta +2 -2
  65. package/Runtime/Core/Attributes.meta +2 -2
  66. package/Runtime/Core/Configuration/DxMessagingRuntimeSettings.cs +195 -0
  67. package/Runtime/Core/Configuration/DxMessagingRuntimeSettings.cs.meta +11 -0
  68. package/Runtime/Core/Configuration/DxMessagingRuntimeSettingsProvider.cs +179 -0
  69. package/Runtime/Core/Configuration/DxMessagingRuntimeSettingsProvider.cs.meta +11 -0
  70. package/Runtime/Core/Configuration.meta +9 -0
  71. package/Runtime/Core/DataStructure/CyclicBuffer.cs +2 -2
  72. package/Runtime/Core/DataStructure/CyclicBuffer.cs.meta +2 -2
  73. package/Runtime/Core/DataStructure.meta +2 -2
  74. package/Runtime/Core/Diagnostics/MessageEmissionData.cs.meta +2 -2
  75. package/Runtime/Core/Diagnostics/MessageRegistrationData.cs.meta +2 -2
  76. package/Runtime/Core/Diagnostics/MessageRegistrationType.cs.meta +2 -2
  77. package/Runtime/Core/Diagnostics.meta +2 -2
  78. package/Runtime/Core/DxMessagingStaticState.cs +19 -0
  79. package/Runtime/Core/DxMessagingStaticState.cs.meta +11 -11
  80. package/Runtime/Core/Extensions/EnumExtensions.cs.meta +2 -2
  81. package/Runtime/Core/Extensions/IListExtensions.cs.meta +2 -2
  82. package/Runtime/Core/Extensions/MessageBusExtensions.cs.meta +12 -12
  83. package/Runtime/Core/Extensions/MessageExtensions.cs.meta +11 -11
  84. package/Runtime/Core/Extensions.meta +8 -8
  85. package/Runtime/Core/Helper/MessageCache.cs +32 -0
  86. package/Runtime/Core/Helper/MessageCache.cs.meta +2 -2
  87. package/Runtime/Core/Helper/MessageHelperIndexer.cs.meta +2 -2
  88. package/Runtime/Core/Helper.meta +2 -2
  89. package/Runtime/Core/IMessage.cs +3 -3
  90. package/Runtime/Core/IMessage.cs.meta +11 -11
  91. package/Runtime/Core/InstanceId.cs.meta +11 -11
  92. package/Runtime/Core/Internal/TypedDispatchLinkIndex.cs +51 -0
  93. package/Runtime/Core/Internal/TypedDispatchLinkIndex.cs.meta +11 -0
  94. package/Runtime/Core/Internal/TypedGlobalSlotIndex.cs +38 -0
  95. package/Runtime/Core/Internal/TypedGlobalSlotIndex.cs.meta +11 -0
  96. package/Runtime/Core/Internal/TypedSlotIndex.cs +81 -0
  97. package/Runtime/Core/Internal/TypedSlotIndex.cs.meta +11 -0
  98. package/Runtime/Core/Internal/TypedSlots.cs +613 -0
  99. package/Runtime/Core/Internal/TypedSlots.cs.meta +11 -0
  100. package/Runtime/Core/Internal.meta +9 -0
  101. package/Runtime/Core/MessageBus/DiagnosticsTarget.cs.meta +11 -11
  102. package/Runtime/Core/MessageBus/GlobalMessageBusProvider.cs.meta +11 -11
  103. package/Runtime/Core/MessageBus/IMessageBus.cs +177 -3
  104. package/Runtime/Core/MessageBus/IMessageBus.cs.meta +11 -11
  105. package/Runtime/Core/MessageBus/IMessageBusProvider.cs.meta +11 -11
  106. package/Runtime/Core/MessageBus/IMessageRegistrationBuilder.cs.meta +11 -11
  107. package/Runtime/Core/MessageBus/Internal/BusContextIndex.cs +16 -0
  108. package/Runtime/Core/MessageBus/Internal/BusContextIndex.cs.meta +11 -0
  109. package/Runtime/Core/MessageBus/Internal/BusSinkIndex.cs +40 -0
  110. package/Runtime/Core/MessageBus/Internal/BusSinkIndex.cs.meta +11 -0
  111. package/Runtime/Core/MessageBus/Internal/BusSlots.cs +718 -0
  112. package/Runtime/Core/MessageBus/Internal/BusSlots.cs.meta +11 -0
  113. package/Runtime/Core/MessageBus/Internal/DispatchKind.cs +38 -0
  114. package/Runtime/Core/MessageBus/Internal/DispatchKind.cs.meta +11 -0
  115. package/Runtime/Core/MessageBus/Internal/DispatchPhase.cs +20 -0
  116. package/Runtime/Core/MessageBus/Internal/DispatchPhase.cs.meta +11 -0
  117. package/Runtime/Core/MessageBus/Internal/DispatchVariant.cs +28 -0
  118. package/Runtime/Core/MessageBus/Internal/DispatchVariant.cs.meta +11 -0
  119. package/Runtime/Core/MessageBus/Internal/IEvictableSlot.cs +48 -0
  120. package/Runtime/Core/MessageBus/Internal/IEvictableSlot.cs.meta +11 -0
  121. package/Runtime/Core/MessageBus/Internal/ISweepable.cs +15 -0
  122. package/Runtime/Core/MessageBus/Internal/ISweepable.cs.meta +11 -0
  123. package/Runtime/Core/MessageBus/Internal/RegistrationMethodAxes.cs +222 -0
  124. package/Runtime/Core/MessageBus/Internal/RegistrationMethodAxes.cs.meta +11 -0
  125. package/Runtime/Core/MessageBus/Internal/SlotKey.cs +192 -0
  126. package/Runtime/Core/MessageBus/Internal/SlotKey.cs.meta +11 -0
  127. package/Runtime/Core/MessageBus/Internal.meta +9 -0
  128. package/Runtime/Core/MessageBus/MessageBus.cs +2651 -500
  129. package/Runtime/Core/MessageBus/MessageBus.cs.meta +11 -11
  130. package/Runtime/Core/MessageBus/MessageBusRebindMode.cs.meta +11 -11
  131. package/Runtime/Core/MessageBus/MessageRegistrationBuilder.cs.meta +11 -11
  132. package/Runtime/Core/MessageBus/MessagingRegistration.cs.meta +11 -11
  133. package/Runtime/Core/MessageBus/RegistrationLog.cs.meta +11 -11
  134. package/Runtime/Core/MessageBus.meta +8 -8
  135. package/Runtime/Core/MessageHandler.cs +2019 -542
  136. package/Runtime/Core/MessageHandler.cs.meta +11 -11
  137. package/Runtime/Core/MessageRegistrationHandle.cs.meta +11 -11
  138. package/Runtime/Core/MessageRegistrationToken.cs +7 -0
  139. package/Runtime/Core/MessageRegistrationToken.cs.meta +11 -11
  140. package/Runtime/Core/Messages/GlobalStringMessage.cs.meta +2 -2
  141. package/Runtime/Core/Messages/IBroadcastMessage.cs.meta +11 -11
  142. package/Runtime/Core/Messages/ITargetedMessage.cs.meta +11 -11
  143. package/Runtime/Core/Messages/IUntargetedMessage.cs.meta +11 -11
  144. package/Runtime/Core/Messages/ReflexiveMessage.cs.meta +2 -2
  145. package/Runtime/Core/Messages/SourcedStringMessage.cs.meta +11 -11
  146. package/Runtime/Core/Messages/StringMessage.cs.meta +2 -2
  147. package/Runtime/Core/Messages.meta +8 -8
  148. package/Runtime/Core/MessagingDebug.cs.meta +11 -11
  149. package/Runtime/Core/Pooling/CollectionPool.cs +266 -0
  150. package/Runtime/Core/Pooling/CollectionPool.cs.meta +11 -0
  151. package/Runtime/Core/Pooling/CollectionPoolDiagnostics.cs +30 -0
  152. package/Runtime/Core/Pooling/CollectionPoolDiagnostics.cs.meta +11 -0
  153. package/Runtime/Core/Pooling/DxPools.cs +157 -0
  154. package/Runtime/Core/Pooling/DxPools.cs.meta +11 -0
  155. package/Runtime/Core/Pooling/EvictionPlayerLoopHook.cs +106 -0
  156. package/Runtime/Core/Pooling/EvictionPlayerLoopHook.cs.meta +11 -0
  157. package/Runtime/Core/Pooling/IDxMessagingClock.cs +18 -0
  158. package/Runtime/Core/Pooling/IDxMessagingClock.cs.meta +11 -0
  159. package/Runtime/Core/Pooling/PoolDiagnosticsSnapshot.cs +55 -0
  160. package/Runtime/Core/Pooling/PoolDiagnosticsSnapshot.cs.meta +11 -0
  161. package/Runtime/Core/Pooling/StopwatchClock.cs +27 -0
  162. package/Runtime/Core/Pooling/StopwatchClock.cs.meta +11 -0
  163. package/Runtime/Core/Pooling/UnityRealtimeClock.cs +31 -0
  164. package/Runtime/Core/Pooling/UnityRealtimeClock.cs.meta +11 -0
  165. package/Runtime/Core/Pooling.meta +9 -0
  166. package/Runtime/Core.meta +8 -8
  167. package/Runtime/Unity/CurrentGlobalMessageBusProvider.cs.meta +12 -12
  168. package/Runtime/Unity/DxMessagingRuntimeInitializer.cs.meta +11 -11
  169. package/Runtime/Unity/InitialGlobalMessageBusProvider.cs.meta +12 -12
  170. package/Runtime/Unity/Integrations/Reflex/AssemblyInfo.cs.meta +2 -2
  171. package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs +73 -0
  172. package/Runtime/Unity/Integrations/Reflex/ReflexRegistrationInstaller.cs.meta +11 -11
  173. package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef +20 -20
  174. package/Runtime/Unity/Integrations/Reflex/WallstopStudios.DxMessaging.Reflex.asmdef.meta +7 -7
  175. package/Runtime/Unity/Integrations/Reflex.meta +8 -8
  176. package/Runtime/Unity/Integrations/VContainer/AssemblyInfo.cs.meta +2 -2
  177. package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs +109 -1
  178. package/Runtime/Unity/Integrations/VContainer/VContainerRegistrationExtensions.cs.meta +11 -11
  179. package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef +30 -30
  180. package/Runtime/Unity/Integrations/VContainer/WallstopStudios.DxMessaging.VContainer.asmdef.meta +7 -7
  181. package/Runtime/Unity/Integrations/VContainer.meta +8 -8
  182. package/Runtime/Unity/Integrations/Zenject/AssemblyInfo.cs.meta +2 -2
  183. package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef +30 -30
  184. package/Runtime/Unity/Integrations/Zenject/WallstopStudios.DxMessaging.Zenject.asmdef.meta +7 -7
  185. package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs +79 -1
  186. package/Runtime/Unity/Integrations/Zenject/ZenjectRegistrationInstaller.cs.meta +11 -11
  187. package/Runtime/Unity/Integrations/Zenject.meta +8 -8
  188. package/Runtime/Unity/Integrations.meta +8 -8
  189. package/Runtime/Unity/MessageAwareComponent.cs +29 -0
  190. package/Runtime/Unity/MessageAwareComponent.cs.meta +11 -11
  191. package/Runtime/Unity/MessageBusProviderHandle.cs.meta +12 -12
  192. package/Runtime/Unity/MessagingComponent.cs.meta +11 -11
  193. package/Runtime/Unity/MessagingComponentInstaller.cs.meta +12 -12
  194. package/Runtime/Unity/ScriptableMessageBusProvider.cs.meta +12 -12
  195. package/Runtime/Unity.meta +8 -8
  196. package/Runtime/WallstopStudios.DxMessaging.asmdef +14 -14
  197. package/Runtime/WallstopStudios.DxMessaging.asmdef.meta +7 -7
  198. package/Runtime.meta +8 -8
  199. package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab +98 -98
  200. package/Samples~/DI/Prefabs/MessagingInstallerSample.prefab.meta +7 -7
  201. package/Samples~/DI/Prefabs.meta +8 -8
  202. package/Samples~/DI/Providers/GlobalMessageBusProvider.asset +14 -14
  203. package/Samples~/DI/Providers/GlobalMessageBusProvider.asset.meta +8 -8
  204. package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset +14 -14
  205. package/Samples~/DI/Providers/InitialGlobalMessageBusProvider.asset.meta +8 -8
  206. package/Samples~/DI/Providers.meta +8 -8
  207. package/Samples~/DI/README.md +51 -51
  208. package/Samples~/DI/README.md.meta +7 -7
  209. package/Samples~/DI/Reflex/SampleInstaller.cs +7 -0
  210. package/Samples~/DI/Reflex/SampleInstaller.cs.meta +11 -11
  211. package/Samples~/DI/Reflex.meta +8 -8
  212. package/Samples~/DI/VContainer/SampleLifetimeScope.cs +6 -1
  213. package/Samples~/DI/VContainer/SampleLifetimeScope.cs.meta +11 -11
  214. package/Samples~/DI/VContainer.meta +8 -8
  215. package/Samples~/DI/Zenject/SampleInstaller.cs +8 -0
  216. package/Samples~/DI/Zenject/SampleInstaller.cs.meta +11 -11
  217. package/Samples~/DI/Zenject.meta +8 -8
  218. package/Samples~/DI.meta +8 -8
  219. package/Samples~/Mini Combat/Boot.cs.meta +11 -11
  220. package/Samples~/Mini Combat/Enemy.cs.meta +11 -11
  221. package/Samples~/Mini Combat/Messages.cs.meta +11 -11
  222. package/Samples~/Mini Combat/Player.cs.meta +11 -11
  223. package/Samples~/Mini Combat/README.md +324 -323
  224. package/Samples~/Mini Combat/README.md.meta +7 -7
  225. package/Samples~/Mini Combat/UIOverlay.cs.meta +11 -11
  226. package/Samples~/Mini Combat/Walkthrough.md +430 -430
  227. package/Samples~/Mini Combat/Walkthrough.md.meta +7 -7
  228. package/Samples~/Mini Combat/WallstopStudios.DxMessaging.MiniCombat.Sample.asmdef +13 -13
  229. package/Samples~/Mini Combat/WallstopStudios.DxMessaging.MiniCombat.Sample.asmdef.meta +7 -7
  230. package/Samples~/Mini Combat.meta +8 -8
  231. package/Samples~/UI Buttons + Inspector/DiagnosticsEnabler.cs.meta +11 -11
  232. package/Samples~/UI Buttons + Inspector/Messages.cs.meta +11 -11
  233. package/Samples~/UI Buttons + Inspector/MessagingObserver.cs.meta +11 -11
  234. package/Samples~/UI Buttons + Inspector/README.md +210 -209
  235. package/Samples~/UI Buttons + Inspector/README.md.meta +7 -7
  236. package/Samples~/UI Buttons + Inspector/UIButtonEmitter.cs.meta +11 -11
  237. package/Samples~/UI Buttons + Inspector/WallstopStudios.DxMessaging.UIButtons.Sample.asmdef +13 -13
  238. package/Samples~/UI Buttons + Inspector/WallstopStudios.DxMessaging.UIButtons.Sample.asmdef.meta +7 -7
  239. package/Samples~/UI Buttons + Inspector.meta +8 -8
  240. package/SourceGenerators/Directory.Build.props.meta +7 -7
  241. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoConstructorGenerator.cs.meta +11 -11
  242. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs.meta +2 -2
  243. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.csproj.meta +7 -7
  244. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators.meta +8 -8
  245. package/SourceGenerators.meta +8 -8
  246. package/Third Party Notices.md +3 -3
  247. package/Third Party Notices.md.meta +7 -7
  248. package/package.json +115 -92
  249. package/package.json.meta +7 -7
@@ -0,0 +1,81 @@
1
+ namespace DxMessaging.Editor.CustomEditors
2
+ {
3
+ #if UNITY_EDITOR
4
+ using DxMessaging.Unity;
5
+ using UnityEditor;
6
+
7
+ /// <summary>
8
+ /// Primary CustomEditor for every <see cref="MessageAwareComponent"/> subclass. Renders the
9
+ /// DxMessaging warning HelpBox above an inspector body that is byte-for-byte identical to
10
+ /// Unity's default <c>GenericInspector</c> (achieved via
11
+ /// <see cref="Editor.DrawDefaultInspector"/>).
12
+ /// </summary>
13
+ /// <remarks>
14
+ /// We register as a non-fallback (primary) editor with
15
+ /// <c>editorForChildClasses: true</c>. Several alternatives were tried and rejected:
16
+ ///
17
+ /// <list type="number">
18
+ /// <item>
19
+ /// <b><c>isFallback = true</c>:</b> Unity selects this editor only when no other matches.
20
+ /// In practice that meant Unity's <c>GenericInspector</c> handled every
21
+ /// <see cref="MessageAwareComponent"/> subclass and the warning HelpBox vanished entirely
22
+ /// (Unity 2021's <see cref="Editor.finishedDefaultHeaderGUI"/> hook did not reliably fire
23
+ /// for those types). This regressed the analyzer warning surface.
24
+ /// </item>
25
+ /// <item>
26
+ /// <b>Manual <see cref="SerializedObject"/> iteration that skips <c>m_Script</c>:</b> the
27
+ /// rationale was to avoid a "duplicate Script row," but Unity does NOT draw <c>m_Script</c>
28
+ /// in the component header -- <see cref="Editor.DrawDefaultInspector"/> draws the same
29
+ /// disabled "Script" row that <c>GenericInspector</c> draws. Skipping it produced a visible
30
+ /// vertical gap below the header for empty subclasses, because the row Unity reserves for
31
+ /// the script reference was left blank.
32
+ /// </item>
33
+ /// </list>
34
+ ///
35
+ /// <para>
36
+ /// The current design is the simple one: be the primary editor, prepend the overlay's
37
+ /// HelpBox via <see cref="MessageAwareComponentInspectorOverlay.RenderInsideOnInspectorGUI"/>,
38
+ /// then call <see cref="Editor.DrawDefaultInspector"/>. The body therefore matches
39
+ /// <c>GenericInspector</c> exactly: no missing Script row, no extra vertical gap. To avoid
40
+ /// double-rendering when the header hook ALSO fires for our editor instance (Unity 2022+),
41
+ /// <see cref="MessageAwareComponentInspectorOverlay"/> unconditionally skips the header path
42
+ /// for <see cref="MessageAwareComponentFallbackEditor"/> instances.
43
+ /// </para>
44
+ ///
45
+ /// <para>
46
+ /// We do NOT short-circuit <see cref="OnInspectorGUI"/> on event type. Unity invokes
47
+ /// editors twice per frame (Layout + Repaint), and both passes MUST emit identical control
48
+ /// counts, otherwise the inspector window's layout cache is corrupted and adjacent
49
+ /// components fail to render. See
50
+ /// <see cref="MessageAwareComponentInspectorOverlay.RenderInsideOnInspectorGUI"/> for the
51
+ /// matching invariant on the overlay side.
52
+ /// </para>
53
+ ///
54
+ /// <para>
55
+ /// User-defined custom editors for specific <see cref="MessageAwareComponent"/> subclasses
56
+ /// still win precedence: a <c>[CustomEditor(typeof(MySpecificSubclass))]</c> is more
57
+ /// specific than our <c>editorForChildClasses</c> registration, so Unity selects the user's
58
+ /// editor for that subclass. The header-hook overlay still surfaces the warning above the
59
+ /// user's editor in that case.
60
+ /// </para>
61
+ /// </remarks>
62
+ [CustomEditor(typeof(MessageAwareComponent), true)]
63
+ [CanEditMultipleObjects]
64
+ public sealed class MessageAwareComponentFallbackEditor : Editor
65
+ {
66
+ public override void OnInspectorGUI()
67
+ {
68
+ // Render the overlay BEFORE the default body so the warning appears prominently at
69
+ // the top of the inspector. The overlay's render body has identical Layout/Repaint
70
+ // control counts, so we can call it unconditionally here.
71
+ MessageAwareComponentInspectorOverlay.RenderInsideOnInspectorGUI(target);
72
+
73
+ // Match Unity's GenericInspector exactly; including the disabled "Script" row that
74
+ // every MonoBehaviour inspector shows. This is intentional: skipping the script row
75
+ // creates a visible empty gap below the header for subclasses with no
76
+ // [SerializeField] fields.
77
+ DrawDefaultInspector();
78
+ }
79
+ }
80
+ #endif
81
+ }
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: 0d8deac538fe4f5da0a0cffe1a7ee670
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -0,0 +1,420 @@
1
+ namespace DxMessaging.Editor.CustomEditors
2
+ {
3
+ #if UNITY_EDITOR
4
+ using System.Collections.Generic;
5
+ using System.Linq;
6
+ using DxMessaging.Editor.Analyzers;
7
+ using DxMessaging.Editor.Settings;
8
+ using DxMessaging.Unity;
9
+ using UnityEditor;
10
+ using UnityEditorInternal;
11
+ using UnityEngine;
12
+
13
+ /// <summary>
14
+ /// Header-injection overlay for every Inspector showing a <see cref="MessageAwareComponent"/> subclass.
15
+ /// </summary>
16
+ /// <remarks>
17
+ /// We hook <see cref="Editor.finishedDefaultHeaderGUI"/> rather than registering a
18
+ /// <c>[CustomEditor(typeof(MessageAwareComponent), editorForChildClasses: true)]</c> so we never
19
+ /// clobber a user's own custom editor. The overlay reads its data from
20
+ /// <see cref="DxMessagingConsoleHarvester"/> (which reflects directly into Unity's
21
+ /// <c>UnityEditor.LogEntries</c> console store) and from <see cref="DxMessagingSettings"/>
22
+ /// (project-wide ignore list and master toggle).
23
+ ///
24
+ /// <para>
25
+ /// <b>Layout/Repaint control-count invariant.</b> When the overlay renders from inside an
26
+ /// <see cref="Editor.OnInspectorGUI"/> body (the fallback CustomEditor path), Unity invokes
27
+ /// us TWICE per frame: once with <c>Event.current.type == EventType.Layout</c> (where every
28
+ /// <c>EditorGUILayout.*</c> call REGISTERS a control) and once with <c>EventType.Repaint</c>
29
+ /// (where the registered controls are drawn). The two passes MUST emit identical control
30
+ /// counts, otherwise Unity's layout cache for the entire inspector window is corrupted and
31
+ /// adjacent components fail to render. That is why we expose two entry points:
32
+ /// </para>
33
+ /// <list type="bullet">
34
+ /// <item>
35
+ /// <see cref="DrawHeader"/> (registered to <see cref="Editor.finishedDefaultHeaderGUI"/>) is
36
+ /// post-body and Unity has already settled layout for the inspector by the time it fires --
37
+ /// gating on <c>EventType.Repaint</c> there is safe.
38
+ /// </item>
39
+ /// <item>
40
+ /// <see cref="RenderInsideOnInspectorGUI"/> is called from inside an editor body and CANNOT
41
+ /// gate on event type. It must call the same <c>EditorGUILayout</c> sequence on both passes.
42
+ /// </item>
43
+ /// </list>
44
+ /// </remarks>
45
+ [InitializeOnLoad]
46
+ public static class MessageAwareComponentInspectorOverlay
47
+ {
48
+ // Per-Repaint latch keyed on instanceID for the header-hook entry point. We render once
49
+ // per Repaint event per target. EventType.Layout marks the start of a fresh GUI cycle, so
50
+ // we clear the set then; rendering happens on EventType.Repaint, which Unity guarantees
51
+ // fires once per visible inspector per frame.
52
+ //
53
+ // NOTE: cross-path dedupe between the header hook and the OnInspectorGUI hook is
54
+ // accomplished by an UNCONDITIONAL skip at the top of <see cref="DrawHeader"/> when the
55
+ // target editor is our fallback CustomEditor; see that method's comment. We do NOT use
56
+ // a per-frame "header drew" set, because such a set would necessarily be populated only
57
+ // on the Repaint pass of the header hook, while OnInspectorGUI runs on BOTH the Layout
58
+ // and Repaint passes; that asymmetry would corrupt the inspector's layout cache.
59
+ private static readonly HashSet<int> _renderedThisRepaint = new();
60
+
61
+ static MessageAwareComponentInspectorOverlay()
62
+ {
63
+ Editor.finishedDefaultHeaderGUI += DrawHeader;
64
+ DxMessagingConsoleHarvester.ReportUpdated += RepaintAllInspectors;
65
+ }
66
+
67
+ private static void RepaintAllInspectors()
68
+ {
69
+ try
70
+ {
71
+ // InternalEditorUtility.RepaintAllViews is the cheap path: it walks the
72
+ // existing GUIView list once. Resources.FindObjectsOfTypeAll<Editor>() allocates
73
+ // a fresh array of every Editor instance Unity has loaded, which is wasteful
74
+ // when we just want a redraw signal.
75
+ InternalEditorUtility.RepaintAllViews();
76
+ }
77
+ catch (System.Exception ex)
78
+ {
79
+ Debug.LogWarning(
80
+ $"[DxMessaging] Failed to repaint inspectors after analyzer report update: {ex.Message}"
81
+ );
82
+ }
83
+ }
84
+
85
+ private static void DrawHeader(Editor editor)
86
+ {
87
+ if (editor == null)
88
+ {
89
+ return;
90
+ }
91
+ // If our own fallback CustomEditor is the editor instance, skip the header path
92
+ // entirely; the editor's OnInspectorGUI will call RenderInsideOnInspectorGUI and we
93
+ // would otherwise render twice. Unconditional skip (not gated on EventType) keeps
94
+ // control counts balanced on both Layout and Repaint passes.
95
+ if (editor is MessageAwareComponentFallbackEditor)
96
+ {
97
+ return;
98
+ }
99
+ RenderForHeaderHook(editor.target);
100
+ }
101
+
102
+ /// <summary>
103
+ /// Header-hook entry point. Fires after Unity's default header has been drawn, so the
104
+ /// inspector's layout pass for this editor has already completed. Safe to gate on
105
+ /// <see cref="EventType.Repaint"/> here -- we are not inside an OnInspectorGUI body.
106
+ /// </summary>
107
+ private static void RenderForHeaderHook(Object target)
108
+ {
109
+ if (target == null)
110
+ {
111
+ return;
112
+ }
113
+ if (target is not MessageAwareComponent messageAwareComponent)
114
+ {
115
+ return;
116
+ }
117
+
118
+ Event currentEvent = Event.current;
119
+ if (currentEvent == null)
120
+ {
121
+ return;
122
+ }
123
+ if (currentEvent.type == EventType.Layout)
124
+ {
125
+ // Start of a fresh GUI cycle; wipe the per-Repaint latch.
126
+ _renderedThisRepaint.Clear();
127
+ return;
128
+ }
129
+ if (currentEvent.type != EventType.Repaint)
130
+ {
131
+ return;
132
+ }
133
+ int instanceId = messageAwareComponent.GetInstanceID();
134
+ if (!_renderedThisRepaint.Add(instanceId))
135
+ {
136
+ return;
137
+ }
138
+
139
+ BuildAndRenderOverlay(messageAwareComponent);
140
+ }
141
+
142
+ /// <summary>
143
+ /// OnInspectorGUI entry point. Called from inside the fallback CustomEditor's
144
+ /// <see cref="Editor.OnInspectorGUI"/>, where Unity invokes the editor on BOTH the Layout
145
+ /// pass and the Repaint pass. This method MUST emit the same <c>EditorGUILayout</c> calls
146
+ /// on both passes, so it does NOT gate on <see cref="EventType"/> and does NOT latch.
147
+ /// Cross-path dedupe with the header-hook path is handled inside
148
+ /// <see cref="DrawHeader"/>, which unconditionally skips when the editor is our fallback.
149
+ /// </summary>
150
+ internal static void RenderInsideOnInspectorGUI(Object target)
151
+ {
152
+ if (target is not MessageAwareComponent messageAwareComponent)
153
+ {
154
+ return;
155
+ }
156
+ BuildAndRenderOverlay(messageAwareComponent);
157
+ }
158
+
159
+ /// <summary>
160
+ /// Rendering body shared by both entry points. Performs ALL gating decisions up-front
161
+ /// before any <c>EditorGUILayout.*</c> call, then runs straight-line layout calls. This
162
+ /// guarantees the function emits an identical sequence of layout calls on the Layout and
163
+ /// Repaint passes when invoked from within <see cref="Editor.OnInspectorGUI"/>.
164
+ /// </summary>
165
+ /// <returns>True if the HelpBox + buttons were drawn; false if we drew nothing.</returns>
166
+ private static bool BuildAndRenderOverlay(MessageAwareComponent messageAwareComponent)
167
+ {
168
+ // ---- Gating phase: every "should we draw?" decision happens here, before any
169
+ // EditorGUILayout call. The result is a single bool: shouldRender. ----
170
+
171
+ // Mid-compile / mid-import is the worst time to dereference the settings asset:
172
+ // AssetDatabase may be in a transitional state. Bail and let the next OnGUI redraw
173
+ // pick up where we left off.
174
+ if (EditorApplication.isCompiling || EditorApplication.isUpdating)
175
+ {
176
+ return false;
177
+ }
178
+
179
+ DxMessagingSettings settings;
180
+ try
181
+ {
182
+ settings = DxMessagingSettings.GetOrCreateSettings();
183
+ }
184
+ catch (System.Exception ex)
185
+ {
186
+ Debug.LogWarning(
187
+ $"[DxMessaging] Inspector overlay could not load settings: {ex.Message}"
188
+ );
189
+ return false;
190
+ }
191
+
192
+ if (settings == null || !settings._baseCallCheckEnabled)
193
+ {
194
+ return false;
195
+ }
196
+
197
+ // S6: System.Type.FullName renders nested types as `Outer+Nested`, but the analyzer's
198
+ // `containingType.ToDisplayString()` (which produces the FQN we key the snapshot by)
199
+ // renders them as `Outer.Nested`. Without this normalization the lookup misses for
200
+ // every nested MessageAwareComponent subclass and the HelpBox never shows.
201
+ System.Type targetType = messageAwareComponent.GetType();
202
+ string fullName = (targetType.FullName ?? string.Empty).Replace('+', '.');
203
+ if (string.IsNullOrEmpty(fullName))
204
+ {
205
+ return false;
206
+ }
207
+
208
+ // Decide which of the three render shapes (if any) to draw.
209
+ // 0 = render nothing; 1 = harvester-unavailable info; 2 = ignored-type info; 3 = warning.
210
+ int shape = 0;
211
+ BaseCallReportEntry entry = null;
212
+ bool isIgnored = false;
213
+
214
+ if (!DxMessagingConsoleHarvester.IsAvailable)
215
+ {
216
+ shape = 1;
217
+ }
218
+ else
219
+ {
220
+ isIgnored =
221
+ settings._baseCallIgnoredTypes != null
222
+ && settings._baseCallIgnoredTypes.Any(e =>
223
+ string.Equals(e, fullName, System.StringComparison.Ordinal)
224
+ );
225
+ if (isIgnored)
226
+ {
227
+ shape = 2;
228
+ }
229
+ else if (
230
+ DxMessagingConsoleHarvester.TryGetEntry(fullName, out entry)
231
+ && entry != null
232
+ && entry.missingBaseFor != null
233
+ && entry.missingBaseFor.Count > 0
234
+ )
235
+ {
236
+ shape = 3;
237
+ }
238
+ }
239
+
240
+ if (shape == 0)
241
+ {
242
+ // "Render nothing" branch: emit ZERO EditorGUILayout calls. This must hold on
243
+ // both Layout and Repaint passes when called from OnInspectorGUI, so Unity's
244
+ // layout cache stays consistent.
245
+ return false;
246
+ }
247
+
248
+ // ---- Render phase: straight-line EditorGUILayout calls, identical sequence on
249
+ // every pass. Wrapped in a vertical group so any internal mismatch we missed cannot
250
+ // propagate to sibling inspectors. ----
251
+ EditorGUILayout.BeginVertical();
252
+ try
253
+ {
254
+ switch (shape)
255
+ {
256
+ case 1:
257
+ EditorGUILayout.HelpBox(
258
+ "DxMessaging inspector overlay is disabled on this Unity version. "
259
+ + "Check the console for DXMSG006/007/009 warnings instead.",
260
+ MessageType.Info
261
+ );
262
+ break;
263
+ case 2:
264
+ DrawIgnoredBox(messageAwareComponent, settings, fullName);
265
+ break;
266
+ case 3:
267
+ DrawWarningBox(messageAwareComponent, settings, fullName, entry);
268
+ break;
269
+ }
270
+ }
271
+ finally
272
+ {
273
+ EditorGUILayout.EndVertical();
274
+ }
275
+
276
+ return true;
277
+ }
278
+
279
+ private static void DrawWarningBox(
280
+ MessageAwareComponent component,
281
+ DxMessagingSettings settings,
282
+ string fullName,
283
+ BaseCallReportEntry entry
284
+ )
285
+ {
286
+ string missingMethods = string.Join(", ", entry.missingBaseFor);
287
+ // Per-method consequence lines mirror the analyzer's DXMSG006 message text. Reading
288
+ // the dictionary on BaseCallTypeScannerCore keeps the overlay copy in lockstep with
289
+ // the analyzer; both are updated together when a new guarded method is added.
290
+ System.Text.StringBuilder consequenceBuilder = new();
291
+ foreach (string missingMethod in entry.missingBaseFor)
292
+ {
293
+ consequenceBuilder.Append("\n- ");
294
+ consequenceBuilder.Append(
295
+ BaseCallTypeScannerCore.GetMissingBaseConsequenceLine(missingMethod, fullName)
296
+ );
297
+ }
298
+ string consequenceLines = consequenceBuilder.ToString();
299
+
300
+ // Cached-vs-fresh suffix is appended to the SAME HelpBox string rather than emitted
301
+ // as a sibling control, which keeps the Layout and Repaint passes emitting an
302
+ // identical sequence of EditorGUILayout.* calls regardless of harvester freshness.
303
+ // The suffix only appears when the harvester is showing entries loaded eagerly from
304
+ // `Library/DxMessaging/baseCallReport.json` and the first post-reload scan has not
305
+ // yet completed; once the scan flips IsFreshThisSession to true and RepaintAllInspectors
306
+ // fires, the overlay redraws without the suffix.
307
+ string freshnessSuffix = DxMessagingConsoleHarvester.IsFreshThisSession
308
+ ? string.Empty
309
+ : "\n(cached from previous session; refreshing...)";
310
+ string message =
311
+ $"{fullName} has lifecycle methods that don't chain to MessageAwareComponent ({missingMethods}); DxMessaging will not function on this component."
312
+ + consequenceLines
313
+ + "\nSee docs/reference/analyzers.md."
314
+ + freshnessSuffix;
315
+
316
+ EditorGUILayout.HelpBox(message, MessageType.Warning);
317
+ using (new EditorGUILayout.HorizontalScope())
318
+ {
319
+ if (GUILayout.Button("Open Script"))
320
+ {
321
+ OpenScriptForComponent(component, entry);
322
+ }
323
+ if (GUILayout.Button("Ignore this type"))
324
+ {
325
+ TryAddIgnoredType(settings, fullName);
326
+ }
327
+ }
328
+ }
329
+
330
+ private static void DrawIgnoredBox(
331
+ MessageAwareComponent component,
332
+ DxMessagingSettings settings,
333
+ string fullName
334
+ )
335
+ {
336
+ EditorGUILayout.HelpBox(
337
+ $"{fullName} is excluded from the DxMessaging base-call check.",
338
+ MessageType.Info
339
+ );
340
+ using (new EditorGUILayout.HorizontalScope())
341
+ {
342
+ if (GUILayout.Button("Stop ignoring"))
343
+ {
344
+ TryRemoveIgnoredType(settings, fullName);
345
+ }
346
+ }
347
+ }
348
+
349
+ private static void OpenScriptForComponent(
350
+ MessageAwareComponent component,
351
+ BaseCallReportEntry entry
352
+ )
353
+ {
354
+ try
355
+ {
356
+ MonoScript monoScript = MonoScript.FromMonoBehaviour(component);
357
+ if (monoScript == null)
358
+ {
359
+ return;
360
+ }
361
+ if (entry != null && entry.line > 0)
362
+ {
363
+ AssetDatabase.OpenAsset(monoScript, entry.line);
364
+ }
365
+ else
366
+ {
367
+ AssetDatabase.OpenAsset(monoScript);
368
+ }
369
+ }
370
+ catch (System.Exception ex)
371
+ {
372
+ Debug.LogWarning($"[DxMessaging] Failed to open script: {ex.Message}");
373
+ }
374
+ }
375
+
376
+ private static void TryAddIgnoredType(DxMessagingSettings settings, string fullName)
377
+ {
378
+ // Defer the mutation to AFTER the current frame's Layout/Repaint pair completes.
379
+ // Mutating settings._baseCallIgnoredTypes synchronously inside a button handler
380
+ // would flip the overlay's shape between Layout and Repaint passes of the SAME
381
+ // frame, corrupting Unity's per-window layout cache. delayCall fires AFTER the
382
+ // current GUI cycle, so the next frame's Layout pass sees the new state and
383
+ // both passes emit consistent control counts.
384
+ EditorApplication.delayCall += () =>
385
+ {
386
+ try
387
+ {
388
+ settings.AddIgnoredType(fullName);
389
+ }
390
+ catch (System.Exception ex)
391
+ {
392
+ Debug.LogWarning(
393
+ $"[DxMessaging] Failed to add ignored type '{fullName}': {ex.Message}"
394
+ );
395
+ }
396
+ };
397
+ }
398
+
399
+ private static void TryRemoveIgnoredType(DxMessagingSettings settings, string fullName)
400
+ {
401
+ // Same reasoning as TryAddIgnoredType: defer mutation past the current GUI cycle so
402
+ // the overlay's shape gating remains identical on Layout and Repaint passes of THIS
403
+ // frame. The next frame's Layout pass observes the new state; both passes agree.
404
+ EditorApplication.delayCall += () =>
405
+ {
406
+ try
407
+ {
408
+ settings.RemoveIgnoredType(fullName);
409
+ }
410
+ catch (System.Exception ex)
411
+ {
412
+ Debug.LogWarning(
413
+ $"[DxMessaging] Failed to remove ignored type '{fullName}': {ex.Message}"
414
+ );
415
+ }
416
+ };
417
+ }
418
+ }
419
+ #endif
420
+ }
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: b2e06a6b39994b51bc06b0131c49428e
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -8,7 +8,7 @@ namespace DxMessaging.Editor.CustomEditors
8
8
  using Core.MessageBus;
9
9
  using Core.Messages;
10
10
  using DxMessaging.Editor.Testing;
11
- using Unity;
11
+ using DxMessaging.Unity;
12
12
  using UnityEditor;
13
13
  using UnityEngine;
14
14
  using Object = UnityEngine.Object;
@@ -1,3 +1,3 @@
1
- fileFormatVersion: 2
2
- guid: e078b310572343318b79a3c00d0f274d
1
+ fileFormatVersion: 2
2
+ guid: e078b310572343318b79a3c00d0f274d
3
3
  timeCreated: 1749666380
@@ -1,3 +1,3 @@
1
- fileFormatVersion: 2
2
- guid: 652cab55c8444567a5101966444e9071
1
+ fileFormatVersion: 2
2
+ guid: 652cab55c8444567a5101966444e9071
3
3
  timeCreated: 1749666371
@@ -26,7 +26,7 @@ namespace DxMessaging.Editor
26
26
  {
27
27
  if (
28
28
  stateChange == PlayModeStateChange.EnteredEditMode
29
- || stateChange == PlayModeStateChange.EnteredPlayMode
29
+ || stateChange == PlayModeStateChange.ExitingEditMode
30
30
  )
31
31
  {
32
32
  ApplyEditorSettings();
@@ -1,3 +1,3 @@
1
- fileFormatVersion: 2
2
- guid: b5eeb11bcc9d4d70861d5dc7084daae5
1
+ fileFormatVersion: 2
2
+ guid: b5eeb11bcc9d4d70861d5dc7084daae5
3
3
  timeCreated: 1749668189
@@ -1,11 +1,11 @@
1
- fileFormatVersion: 2
2
- guid: 517da34a8f694371b843ba34f89077d3
3
- MonoImporter:
4
- externalObjects: {}
5
- serializedVersion: 2
6
- defaultReferences: []
7
- executionOrder: 0
8
- icon: {instanceID: 0}
9
- userData:
10
- assetBundleName:
11
- assetBundleVariant:
1
+ fileFormatVersion: 2
2
+ guid: 517da34a8f694371b843ba34f89077d3
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -1,11 +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:
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: