com.wallstop-studios.dxmessaging 2.0.0-rc16 → 2.0.0-rc18

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 (33) hide show
  1. package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll +0 -0
  2. package/Editor/Analyzers/System.Runtime.CompilerServices.Unsafe.dll.meta +33 -0
  3. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.dll +0 -0
  4. package/Editor/Analyzers/WallstopStudios.DxMessaging.SourceGenerators.pdb.meta +7 -0
  5. package/Editor/SetupCscRsp.cs +37 -12
  6. package/README.md +8 -21
  7. package/Runtime/Core/Attributes/DxBroadcastMessageAttribute.cs +5 -1
  8. package/Runtime/Core/Attributes/DxTargetedMessageAttribute.cs +5 -1
  9. package/Runtime/Core/Attributes/DxUntargetedMessageAttribute.cs +5 -1
  10. package/Runtime/Core/IMessage.cs +13 -0
  11. package/Runtime/Core/InstanceId.cs +6 -16
  12. package/Runtime/Core/MessageBus/MessageBus.cs +1751 -828
  13. package/Runtime/Core/MessageHandler.cs +408 -292
  14. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs +445 -0
  15. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxMessageIdGenerator.cs.meta +3 -0
  16. package/Tests/Runtime/Benchmarks/PerformanceTests.cs +41 -26
  17. package/Tests/Runtime/Core/EnablementTests.cs +69 -0
  18. package/Tests/Runtime/Core/EnablementTests.cs.meta +3 -0
  19. package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs +19 -0
  20. package/Tests/Runtime/Scripts/Components/GenericMessageAwareComponent.cs.meta +3 -0
  21. package/Tests/Runtime/Scripts/Messages/GenericUntargetedMessage.cs +7 -0
  22. package/Tests/Runtime/Scripts/Messages/GenericUntargetedMessage.cs.meta +3 -0
  23. package/package.json +2 -4
  24. package/Runtime/Core/Attributes/DxAutoMessageTypeAttribute.cs +0 -7
  25. package/Runtime/Core/Attributes/DxAutoMessageTypeAttribute.cs.meta +0 -3
  26. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoMessageTypeGenerator.cs +0 -92
  27. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxAutoMessageTypeGenerator.cs.meta +0 -11
  28. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxBroadcastMessageGenerator.cs +0 -94
  29. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxBroadcastMessageGenerator.cs.meta +0 -3
  30. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxTargetedMessageGenerator.cs +0 -94
  31. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxTargetedMessageGenerator.cs.meta +0 -3
  32. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxUntargetedMessageGenerator.cs +0 -94
  33. package/SourceGenerators/WallstopStudios.DxMessaging.SourceGenerators/DxUntargetedMessageGenerator.cs.meta +0 -3
@@ -0,0 +1,33 @@
1
+ fileFormatVersion: 2
2
+ guid: 8c1cadaf86b083c49aac429e53fa3008
3
+ PluginImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ iconMap: {}
7
+ executionOrder: {}
8
+ defineConstraints: []
9
+ isPreloaded: 0
10
+ isOverridable: 1
11
+ isExplicitlyReferenced: 0
12
+ validateReferences: 1
13
+ platformData:
14
+ - first:
15
+ Any:
16
+ second:
17
+ enabled: 0
18
+ settings: {}
19
+ - first:
20
+ Editor: Editor
21
+ second:
22
+ enabled: 1
23
+ settings:
24
+ DefaultValueInitialized: true
25
+ - first:
26
+ Windows Store Apps: WindowsStoreApps
27
+ second:
28
+ enabled: 0
29
+ settings:
30
+ CPU: AnyCPU
31
+ userData:
32
+ assetBundleName:
33
+ assetBundleVariant:
@@ -0,0 +1,7 @@
1
+ fileFormatVersion: 2
2
+ guid: 9e450a3f92f4be74da41959260563827
3
+ DefaultImporter:
4
+ externalObjects: {}
5
+ userData:
6
+ assetBundleName:
7
+ assetBundleVariant:
@@ -35,10 +35,13 @@ namespace DxMessaging.Editor
35
35
  "Microsoft.CodeAnalysis.dll",
36
36
  "Microsoft.CodeAnalysis.CSharp.dll",
37
37
  "System.Reflection.Metadata.dll",
38
+ "System.Runtime.CompilerServices.Unsafe.dll",
38
39
  };
39
40
 
40
41
  private static readonly string LibraryArgument = $"-a:\"{LibraryPathRelative}\"";
41
42
 
43
+ private static readonly HashSet<string> DllNames = new(StringComparer.OrdinalIgnoreCase);
44
+
42
45
  static SetupCscRsp()
43
46
  {
44
47
  EditorApplication.delayCall += EnsureDLLsExistInAssets;
@@ -47,19 +50,27 @@ namespace DxMessaging.Editor
47
50
 
48
51
  private static void EnsureDLLsExistInAssets()
49
52
  {
50
- HashSet<string> dllNames = new();
53
+ DllNames.Clear();
51
54
  foreach (
52
55
  string dllGuid in AssetDatabase.FindAssets("t:DefaultAsset", new[] { "Assets" })
53
56
  )
54
57
  {
55
58
  string dllPath = AssetDatabase.GUIDToAssetPath(dllGuid);
56
- if (!dllPath.EndsWith(".dll"))
59
+ if (!dllPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
57
60
  {
58
61
  continue;
59
62
  }
60
63
 
61
- string dllName = Path.GetFileName(dllPath);
62
- dllNames.Add(dllName);
64
+ if (
65
+ !dllPath.Contains(
66
+ "Assets/Plugins/WallstopStudios.DxMessaging",
67
+ StringComparison.OrdinalIgnoreCase
68
+ )
69
+ )
70
+ {
71
+ string dllName = Path.GetFileName(dllPath);
72
+ DllNames.Add(dllName);
73
+ }
63
74
  }
64
75
 
65
76
  string[] dllRelativeDirectories = { LibraryPathRelative, AnalyzerPathRelative };
@@ -67,7 +78,7 @@ namespace DxMessaging.Editor
67
78
  bool anyFound = false;
68
79
  foreach (
69
80
  string requiredDllName in RequiredDllNames.Where(dllName =>
70
- !dllNames.Contains(dllName)
81
+ !DllNames.Contains(dllName)
71
82
  )
72
83
  )
73
84
  {
@@ -85,13 +96,31 @@ namespace DxMessaging.Editor
85
96
  const string pluginsDirectory =
86
97
  "Assets/Plugins/WallstopStudios.DxMessaging/";
87
98
  string outputAsset = $"{pluginsDirectory}{requiredDllName}";
99
+ string sourceAsset = $"{relativeDirectory}{requiredDllName}";
88
100
  Directory.CreateDirectory(pluginsDirectory);
89
101
  if (!File.Exists(outputAsset))
90
102
  {
91
- File.Copy($"{relativeDirectory}{requiredDllName}", outputAsset);
103
+ File.Copy(sourceAsset, outputAsset);
92
104
  AssetDatabase.ImportAsset(outputAsset);
93
105
  found = true;
94
106
  }
107
+ else
108
+ {
109
+ FileInfo sourceInfo = new(sourceAsset);
110
+ FileInfo destInfo = new(outputAsset);
111
+
112
+ if (destInfo.LastWriteTime < sourceInfo.LastWriteTime)
113
+ {
114
+ // Source file is newer, so copy the file (overwrite destination)
115
+ File.Copy(sourceAsset, outputAsset, true);
116
+ AssetDatabase.ImportAsset(outputAsset);
117
+ found = true;
118
+ }
119
+ else
120
+ {
121
+ continue;
122
+ }
123
+ }
95
124
 
96
125
  if (requiredDllName == SourceGeneratorDllName)
97
126
  {
@@ -120,10 +149,6 @@ namespace DxMessaging.Editor
120
149
  }
121
150
 
122
151
  anyFound |= found;
123
- Debug.Log(
124
- $"Missing required dll '{requiredDllName}', "
125
- + $"{(found ? "creation successful." : "WARNING! Manual creation required.")}"
126
- );
127
152
  }
128
153
 
129
154
  if (anyFound)
@@ -143,12 +168,12 @@ namespace DxMessaging.Editor
143
168
  }
144
169
 
145
170
  string rspContent = File.ReadAllText(RspFilePath);
146
- if (rspContent.Contains(LibraryArgument))
171
+ if (rspContent.Contains(LibraryArgument, StringComparison.OrdinalIgnoreCase))
147
172
  {
148
173
  return;
149
174
  }
150
175
 
151
- File.AppendAllText(RspFilePath, $"{LibraryArgument}\n");
176
+ File.AppendAllText(RspFilePath, $"{LibraryArgument}{Environment.NewLine}");
152
177
  AssetDatabase.ImportAsset("csc.rsp");
153
178
  Debug.Log("Updated csc.rsp.");
154
179
  }
package/README.md CHANGED
@@ -26,26 +26,23 @@ Check out the latest [Releases](https://github.com/wallstop/DxMessaging/releases
26
26
  4. Add an entry for a new "Scoped Registry"
27
27
  - Name: `NPM`
28
28
  - URL: `https://registry.npmjs.org`
29
- - Scope(s): `com.wallstop-studios.dxmessaging` *and* `com.wallstop-studios.unity-helpers`
29
+ - Scope(s): `com.wallstop-studios.dxmessaging`
30
30
  5. Resolve the latest `DxMessaging`
31
31
 
32
32
  ## From Source
33
33
  Grab a copy of this repo (either `git clone` both [this repo](https://github.com/wallstop/DxMessaging) *and* [Unity Helpers](https://github.com/wallstop/unity-helpers) or [download a zip of the source](https://github.com/wallstop/DxMessaging/archive/refs/heads/master.zip) and [Unity Helper's source](https://github.com/wallstop/unity-helpers/archive/refs/heads/main.zip)) and copy the contents to your project's `Assets` folder.
34
34
 
35
- # Dependencies
36
- This project has a dependency on my [`Unity Helpers`](https://github.com/wallstop/unity-helpers) project, which contains the `System.Runtime.CompilerServices.Unsafe.dll`, which is used for some speed hacks in DxMessaging directly. Unity Helpers bundles a few (small) dependencies, including protobuf. If you don't want these dependencies, or if they conflict in some way, you can either include a copy of the `System.Runtime.CompilerServices.Unsafe.dll` yourself without relying on UnityHelpers, or manually download and include the Unity Helpers project and delete anything that conflicts with your project. Or, manually download this project without UnityHelpers. The choice is yours.
37
-
38
35
  # Benchmarks
39
- DxMessaging is currently a bit slower (2-3x) than Unity's built in messaging solution (when running in Unity). [Source](./Tests/Runtime/Benchmarks/PerformanceTests.cs).
36
+ DxMessaging is currently roughly on-par with than Unity's built in messaging solution (when running in Unity). [Source](./Tests/Runtime/Benchmarks/PerformanceTests.cs). However, it is allocation-free and can be used in hot paths.
40
37
 
41
38
  | Message Tech | Operations / Second | Allocations? |
42
39
  | ------------ | ------------------- | ------------ |
43
- | Unity | 2,287,562 | Yes |
44
- | DxMessaging (GameObject) - Normal | 1,198,797 | No |
45
- | DxMessaging (Component) - Normal | 1,198,796 | No |
46
- | DxMessaging (GameObject) - No-Copy | 1,137,634 | No |
47
- | DxMessaging (Component) - No-Copy | 1,225,105 | No |
48
- | DxMessaging (Untargeted) - No-Copy | 1,681,407 | No |
40
+ | Unity | 2,621,200 | Yes |
41
+ | DxMessaging (GameObject) - Normal | 2,048,600 | No |
42
+ | DxMessaging (Component) - Normal | 2,054,600 | No |
43
+ | DxMessaging (GameObject) - No-Copy | 2,137,800 | No |
44
+ | DxMessaging (Component) - No-Copy | 2,136,400 | No |
45
+ | DxMessaging (Untargeted) - No-Copy | 3,028,400 | No |
49
46
 
50
47
  # Functionality
51
48
  While not as fast, DxMessaging offers *additional functionality* as compared to Unity's messaging solution.
@@ -121,16 +118,6 @@ public partial struct SimpleUntargetedMessage // No longer needed : IUntargetedM
121
118
  }
122
119
  ```
123
120
 
124
- Or, if you already have messages, you can leave the interface implementations as-is and get a no-boxing implementation with the `DxAutoMessageType` attribute. `partial` is still required.
125
-
126
- To use:
127
- ```csharp
128
- [DxAutoMessageType]
129
- public partial struct SimpleTargetedMessage : ITargetedMessage<SimpleTargetedMessage>
130
- {
131
- }
132
- ```
133
-
134
121
  ## Integration
135
122
  See the [tests](./Tests/Runtime/Scripts/) directory for examples about how to integrate with the MessageAwareComponent. But, for some starters:
136
123
  ```csharp
@@ -2,6 +2,10 @@
2
2
  {
3
3
  using System;
4
4
 
5
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
5
+ [AttributeUsage(
6
+ AttributeTargets.Class | AttributeTargets.Struct,
7
+ Inherited = false,
8
+ AllowMultiple = false
9
+ )]
6
10
  public sealed class DxBroadcastMessageAttribute : Attribute { }
7
11
  }
@@ -2,6 +2,10 @@
2
2
  {
3
3
  using System;
4
4
 
5
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
5
+ [AttributeUsage(
6
+ AttributeTargets.Class | AttributeTargets.Struct,
7
+ Inherited = false,
8
+ AllowMultiple = false
9
+ )]
6
10
  public sealed class DxTargetedMessageAttribute : Attribute { }
7
11
  }
@@ -2,6 +2,10 @@
2
2
  {
3
3
  using System;
4
4
 
5
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
5
+ [AttributeUsage(
6
+ AttributeTargets.Class | AttributeTargets.Struct,
7
+ Inherited = false,
8
+ AllowMultiple = false
9
+ )]
6
10
  public sealed class DxUntargetedMessageAttribute : Attribute { }
7
11
  }
@@ -8,5 +8,18 @@
8
8
  public interface IMessage
9
9
  {
10
10
  Type MessageType => GetType();
11
+
12
+ /// <summary>
13
+ /// Gets the optimized, unique integer ID for this message type, if available.
14
+ /// Returns null if this type uses the fallback mechanism (e.g., due to a compile-time
15
+ /// hash collision or manual implementation without an assigned ID).
16
+ /// </summary>
17
+ /// <remarks>
18
+ /// The ID is generated at compile-time for attributed types and is stable
19
+ /// across builds assuming the type's fully qualified name does not change.
20
+ /// It facilitates faster dictionary lookups compared to using System.Type directly.
21
+ /// Check for HasValue before using the Value.
22
+ /// </remarks>
23
+ int? OptimizedMessageId => null;
11
24
  }
12
25
  }
@@ -46,22 +46,12 @@
46
46
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
47
47
  public static implicit operator InstanceId(UnityEngine.GameObject gameObject)
48
48
  {
49
- if (gameObject == null)
50
- {
51
- throw new ArgumentNullException(nameof(gameObject));
52
- }
53
-
54
49
  return new InstanceId(gameObject);
55
50
  }
56
51
 
57
52
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
58
53
  public static implicit operator InstanceId(UnityEngine.Component component)
59
54
  {
60
- if (component == null)
61
- {
62
- throw new ArgumentNullException(nameof(component));
63
- }
64
-
65
55
  return new InstanceId(component);
66
56
  }
67
57
  #endif
@@ -98,37 +88,37 @@
98
88
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
99
89
  public static bool operator ==(InstanceId lhs, InstanceId rhs)
100
90
  {
101
- return lhs.Equals(rhs);
91
+ return lhs._id == rhs._id;
102
92
  }
103
93
 
104
94
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
105
95
  public static bool operator !=(InstanceId lhs, InstanceId rhs)
106
96
  {
107
- return !lhs.Equals(rhs);
97
+ return lhs._id != rhs._id;
108
98
  }
109
99
 
110
100
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
111
101
  public static bool operator <(InstanceId lhs, InstanceId rhs)
112
102
  {
113
- return lhs.CompareTo(rhs) < 0;
103
+ return lhs._id.CompareTo(rhs._id) < 0;
114
104
  }
115
105
 
116
106
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
117
107
  public static bool operator <=(InstanceId lhs, InstanceId rhs)
118
108
  {
119
- return lhs.CompareTo(rhs) <= 0;
109
+ return lhs._id.CompareTo(rhs._id) <= 0;
120
110
  }
121
111
 
122
112
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
123
113
  public static bool operator >(InstanceId lhs, InstanceId rhs)
124
114
  {
125
- return lhs.CompareTo(rhs) > 0;
115
+ return lhs._id.CompareTo(rhs._id) > 0;
126
116
  }
127
117
 
128
118
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
129
119
  public static bool operator >=(InstanceId lhs, InstanceId rhs)
130
120
  {
131
- return lhs.CompareTo(rhs) >= 0;
121
+ return lhs._id.CompareTo(rhs._id) >= 0;
132
122
  }
133
123
 
134
124
  [MethodImpl(MethodImplOptions.AggressiveInlining)]