com.wallstop-studios.unity-helpers 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 (65) hide show
  1. package/AGENTS.md +1 -0
  2. package/Docs/ILIST_SORTING_PERFORMANCE.md +16 -16
  3. package/Docs/INDEX.md +1 -0
  4. package/Docs/RANDOM_PERFORMANCE.md +15 -15
  5. package/Docs/REFLECTION_HELPERS.md +84 -1
  6. package/Docs/REFLECTION_PERFORMANCE.md +169 -0
  7. package/{package-lock.json.meta → Docs/REFLECTION_PERFORMANCE.md.meta} +1 -1
  8. package/Docs/RELATIONAL_COMPONENTS.md +6 -0
  9. package/Docs/RELATIONAL_COMPONENT_PERFORMANCE.md +63 -0
  10. package/Docs/RELATIONAL_COMPONENT_PERFORMANCE.md.meta +7 -0
  11. package/Docs/SPATIAL_TREE_2D_PERFORMANCE.md +64 -64
  12. package/Docs/SPATIAL_TREE_3D_PERFORMANCE.md +64 -64
  13. package/Editor/Sprites/AnimationCopier.cs +1 -1
  14. package/Editor/Sprites/AnimationViewerWindow.cs +4 -4
  15. package/Editor/Sprites/SpriteSettingsApplierAPI.cs +2 -1
  16. package/Editor/Sprites/TextureResizerWizard.cs +4 -3
  17. package/Editor/Utils/ScriptableObjectSingletonCreator.cs +3 -3
  18. package/README.md +8 -3
  19. package/Runtime/Core/Attributes/BaseRelationalComponentAttribute.cs +147 -20
  20. package/Runtime/Core/Attributes/ChildComponentAttribute.cs +630 -117
  21. package/Runtime/Core/Attributes/NotNullAttribute.cs +5 -2
  22. package/Runtime/Core/Attributes/ParentComponentAttribute.cs +477 -103
  23. package/Runtime/Core/Attributes/RelationalComponentAssigner.cs +26 -3
  24. package/Runtime/Core/Attributes/RelationalComponentExtensions.cs +19 -3
  25. package/Runtime/Core/Attributes/SiblingComponentAttribute.cs +265 -92
  26. package/Runtime/Core/CodeGen.meta +8 -0
  27. package/Runtime/Core/DataStructure/ImmutableBitSet.cs +5 -20
  28. package/Runtime/Core/Helper/Helpers.cs +8 -0
  29. package/Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs +11 -7
  30. package/Runtime/Core/Helper/Objects.cs +1 -1
  31. package/Runtime/Core/Helper/ReflectionHelpers.Factory.cs +5142 -0
  32. package/Runtime/Core/Helper/ReflectionHelpers.Factory.cs.meta +11 -0
  33. package/Runtime/Core/Helper/ReflectionHelpers.cs +1812 -1518
  34. package/Runtime/Core/Math/Line2D.cs +2 -4
  35. package/Runtime/Core/Math/Line3D.cs +2 -4
  36. package/Runtime/Core/Random/FlurryBurstRandom.cs +0 -6
  37. package/Runtime/Tags/AttributeMetadataCache.cs +4 -6
  38. package/Runtime/Tags/CosmeticEffectData.cs +1 -1
  39. package/Runtime/Visuals/UIToolkit/MultiFileSelectorElement.cs +3 -3
  40. package/Tests/Editor/Helper/HelpersTests.cs +2 -2
  41. package/Tests/Editor/Helper/ReflectionHelpersTypedEditorTests.cs +87 -0
  42. package/Tests/Editor/Helper/ReflectionHelpersTypedEditorTests.cs.meta +11 -0
  43. package/Tests/Editor/Helper/SpriteHelpersTests.cs +1 -1
  44. package/Tests/Editor/PrefabCheckerReportTests.cs +3 -3
  45. package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs +18 -12
  46. package/Tests/Editor/Sprites/AnimationCopierWindowTests.cs +8 -7
  47. package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs +2 -1
  48. package/Tests/Editor/Sprites/ScriptableSpriteAtlasEditorTests.cs +6 -5
  49. package/Tests/Editor/Sprites/SpriteCropperAdditionalTests.cs +2 -1
  50. package/Tests/Editor/Sprites/SpriteCropperTests.cs +7 -6
  51. package/Tests/Editor/Sprites/SpritePivotAdjusterAdditionalTests.cs +2 -1
  52. package/Tests/Editor/Sprites/SpritePivotAdjusterTests.cs +4 -3
  53. package/Tests/Editor/Sprites/TextureResizerWizardTests.cs +10 -9
  54. package/Tests/Editor/Sprites/TextureSettingsApplierAPITests.cs +2 -1
  55. package/Tests/Runtime/Helper/ObjectsTests.cs +1 -1
  56. package/Tests/Runtime/Helper/ReflectionHelperCapabilityMatrixTests.cs +2923 -0
  57. package/Tests/Runtime/Helper/ReflectionHelperCapabilityMatrixTests.cs.meta +11 -0
  58. package/Tests/Runtime/Helper/ReflectionHelperTests.cs +660 -0
  59. package/Tests/Runtime/Performance/ReflectionPerformanceTests.cs +1238 -0
  60. package/Tests/Runtime/Performance/ReflectionPerformanceTests.cs.meta +11 -0
  61. package/Tests/Runtime/Performance/RelationalComponentBenchmarkTests.cs +832 -0
  62. package/Tests/Runtime/Performance/RelationalComponentBenchmarkTests.cs.meta +11 -0
  63. package/package.json +1 -1
  64. package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs +0 -60
  65. package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs.meta +0 -3
@@ -7,6 +7,7 @@ namespace WallstopStudios.UnityHelpers.Core.Math
7
7
  using Extension;
8
8
  using ProtoBuf;
9
9
  using UnityEngine;
10
+ using WallstopStudios.UnityHelpers.Core.Helper;
10
11
 
11
12
  /// <summary>
12
13
  /// Represents a line segment defined by two endpoints in 2D space.
@@ -230,10 +231,7 @@ namespace WallstopStudios.UnityHelpers.Core.Math
230
231
  /// </summary>
231
232
  public override int GetHashCode()
232
233
  {
233
- unchecked
234
- {
235
- return (from.GetHashCode() * 397) ^ to.GetHashCode();
236
- }
234
+ return Objects.HashCode(from, to);
237
235
  }
238
236
 
239
237
  /// <summary>
@@ -6,6 +6,7 @@ namespace WallstopStudios.UnityHelpers.Core.Math
6
6
  using DataStructure;
7
7
  using ProtoBuf;
8
8
  using UnityEngine;
9
+ using WallstopStudios.UnityHelpers.Core.Helper;
9
10
 
10
11
  /// <summary>
11
12
  /// Represents a line segment defined by two endpoints in 3D space.
@@ -419,10 +420,7 @@ namespace WallstopStudios.UnityHelpers.Core.Math
419
420
  /// </summary>
420
421
  public override int GetHashCode()
421
422
  {
422
- unchecked
423
- {
424
- return (from.GetHashCode() * 397) ^ to.GetHashCode();
425
- }
423
+ return Objects.HashCode(from, to);
426
424
  }
427
425
 
428
426
  /// <summary>
@@ -240,12 +240,6 @@ namespace WallstopStudios.UnityHelpers.Core.Random
240
240
  return _f.CompareTo(other._f);
241
241
  }
242
242
 
243
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
244
- private static uint RotateLeft(uint value, int count)
245
- {
246
- return (value << count) | (value >> (32 - count));
247
- }
248
-
249
243
  private void InitializeFromGuid(Guid guid)
250
244
  {
251
245
  (ulong seed0, ulong seed1) = RandomUtilities.GuidToUInt64Pair(guid);
@@ -5,6 +5,7 @@ namespace WallstopStudios.UnityHelpers.Tags
5
5
  using Core.Attributes;
6
6
  using UnityEngine;
7
7
  using Utils;
8
+ using WallstopStudios.UnityHelpers.Core.Helper;
8
9
 
9
10
  /// <summary>
10
11
  /// Serialized cache of attribute metadata to avoid runtime reflection.
@@ -150,7 +151,8 @@ namespace WallstopStudios.UnityHelpers.Tags
150
151
 
151
152
  public bool Equals(ElementTypeKey other)
152
153
  {
153
- return componentType == other.componentType && fieldName == other.fieldName;
154
+ return componentType == other.componentType
155
+ && string.Equals(fieldName, other.fieldName, StringComparison.Ordinal);
154
156
  }
155
157
 
156
158
  public override bool Equals(object obj)
@@ -160,11 +162,7 @@ namespace WallstopStudios.UnityHelpers.Tags
160
162
 
161
163
  public override int GetHashCode()
162
164
  {
163
- unchecked
164
- {
165
- return ((componentType?.GetHashCode() ?? 0) * 397)
166
- ^ (fieldName?.GetHashCode() ?? 0);
167
- }
165
+ return Objects.HashCode(componentType, fieldName);
168
166
  }
169
167
  }
170
168
 
@@ -103,7 +103,7 @@ namespace WallstopStudios.UnityHelpers.Tags
103
103
 
104
104
  public override int GetHashCode()
105
105
  {
106
- return _cosmeticTypes.Value.Count.GetHashCode();
106
+ return Objects.HashCode(_cosmeticTypes.Value.Count);
107
107
  }
108
108
  }
109
109
  }
@@ -663,7 +663,7 @@ namespace WallstopStudios.UnityHelpers.Visuals.UIToolkit
663
663
  if (!string.IsNullOrEmpty(rel))
664
664
  {
665
665
  // If rel starts with Assets, strip it for subsequent segments
666
- display = rel.Replace('\\', '/');
666
+ display = rel.SanitizePath();
667
667
  if (display.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase))
668
668
  {
669
669
  display = display.Substring("Assets/".Length);
@@ -712,8 +712,8 @@ namespace WallstopStudios.UnityHelpers.Visuals.UIToolkit
712
712
  {
713
713
  return;
714
714
  }
715
- Toggle toggle = (evt.currentTarget as VisualElement)?.userData as Toggle;
716
- if (toggle != null)
715
+
716
+ if ((evt.currentTarget as VisualElement)?.userData is Toggle toggle)
717
717
  {
718
718
  toggle.value = !toggle.value;
719
719
  }
@@ -28,7 +28,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Helper
28
28
  AssetDatabase.CreateFolder("Assets", "TempHelpersPrefabs");
29
29
  }
30
30
 
31
- string assetPath = Path.Combine(folder, "TestPrefab.prefab").Replace('\\', '/');
31
+ string assetPath = Path.Combine(folder, "TestPrefab.prefab").SanitizePath();
32
32
  GameObject prefabSource = Track(new GameObject("Helpers_PrefabSource"));
33
33
  try
34
34
  {
@@ -63,7 +63,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Helper
63
63
  AssetDatabase.CreateFolder("Assets", "TempHelpersScriptables");
64
64
  }
65
65
 
66
- string assetPath = Path.Combine(folder, "Dummy.asset").Replace('\\', '/');
66
+ string assetPath = Path.Combine(folder, "Dummy.asset").SanitizePath();
67
67
  DummyScriptableObject asset = Track(
68
68
  ScriptableObject.CreateInstance<DummyScriptableObject>()
69
69
  );
@@ -0,0 +1,87 @@
1
+ #if UNITY_EDITOR
2
+ namespace WallstopStudios.UnityHelpers.Tests.Editor.Helper
3
+ {
4
+ using System;
5
+ using System.Reflection;
6
+ using NUnit.Framework;
7
+ using WallstopStudios.UnityHelpers.Core.Helper;
8
+
9
+ public sealed class TypedHelperEditorTarget
10
+ {
11
+ public int Field;
12
+ public int Property { get; set; }
13
+ }
14
+
15
+ [TestFixture]
16
+ public sealed class ReflectionHelpersTypedEditorTests
17
+ {
18
+ [Test]
19
+ public void EditorTypedFieldSetterFallbacksWhenCapabilitiesDisabled()
20
+ {
21
+ FieldInfo field = typeof(TypedHelperEditorTarget).GetField(
22
+ nameof(TypedHelperEditorTarget.Field)
23
+ );
24
+ using (
25
+ ReflectionHelpers.OverrideReflectionCapabilities(
26
+ expressions: false,
27
+ dynamicIl: false
28
+ )
29
+ )
30
+ {
31
+ FieldSetter<TypedHelperEditorTarget, int> setter = ReflectionHelpers.GetFieldSetter<
32
+ TypedHelperEditorTarget,
33
+ int
34
+ >(field);
35
+ TypedHelperEditorTarget instance = new();
36
+ setter(ref instance, 12);
37
+ Assert.AreEqual(12, instance.Field);
38
+ }
39
+ }
40
+
41
+ [Test]
42
+ public void EditorTypedPropertySetterFallbacksWhenCapabilitiesDisabled()
43
+ {
44
+ PropertyInfo property = typeof(TypedHelperEditorTarget).GetProperty(
45
+ nameof(TypedHelperEditorTarget.Property)
46
+ );
47
+ using (
48
+ ReflectionHelpers.OverrideReflectionCapabilities(
49
+ expressions: false,
50
+ dynamicIl: false
51
+ )
52
+ )
53
+ {
54
+ Action<TypedHelperEditorTarget, int> setter = ReflectionHelpers.GetPropertySetter<
55
+ TypedHelperEditorTarget,
56
+ int
57
+ >(property);
58
+ TypedHelperEditorTarget instance = new();
59
+ setter(instance, 34);
60
+ Assert.AreEqual(34, instance.Property);
61
+ }
62
+ }
63
+
64
+ [Test]
65
+ public void EditorTypedPropertyGetterFallbacksWhenCapabilitiesDisabled()
66
+ {
67
+ PropertyInfo property = typeof(TypedHelperEditorTarget).GetProperty(
68
+ nameof(TypedHelperEditorTarget.Property)
69
+ );
70
+ TypedHelperEditorTarget instance = new() { Property = 56 };
71
+ using (
72
+ ReflectionHelpers.OverrideReflectionCapabilities(
73
+ expressions: false,
74
+ dynamicIl: false
75
+ )
76
+ )
77
+ {
78
+ Func<TypedHelperEditorTarget, int> getter = ReflectionHelpers.GetPropertyGetter<
79
+ TypedHelperEditorTarget,
80
+ int
81
+ >(property);
82
+ Assert.AreEqual(56, getter(instance));
83
+ }
84
+ }
85
+ }
86
+ }
87
+ #endif
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: 93f41b1f874e3e349b8eecd9d3d2038e
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -296,7 +296,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Helper
296
296
  private void CreateTestTexture(bool readable, int width = 4, int height = 4)
297
297
  {
298
298
  _testTexturePath = Path.Combine(TestFolder, $"TestTexture_{System.Guid.NewGuid()}.png")
299
- .Replace('\\', '/');
299
+ .SanitizePath();
300
300
 
301
301
  Texture2D tempTexture = Track(
302
302
  new Texture2D(width, height, TextureFormat.RGBA32, false)
@@ -11,7 +11,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor
11
11
  [Test]
12
12
  public void ScanReportConstructorCopiesFolders()
13
13
  {
14
- var report = new PrefabChecker.ScanReport(new[] { "A", "B" });
14
+ PrefabChecker.ScanReport report = new PrefabChecker.ScanReport(new[] { "A", "B" });
15
15
  string[] folders = report.folders;
16
16
  CollectionAssert.AreEqual(new[] { "A", "B" }, folders);
17
17
  }
@@ -19,10 +19,10 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor
19
19
  [Test]
20
20
  public void ScanReportAddCopiesMessages()
21
21
  {
22
- var report = new PrefabChecker.ScanReport(Array.Empty<string>());
22
+ PrefabChecker.ScanReport report = new PrefabChecker.ScanReport(Array.Empty<string>());
23
23
  report.Add("path.prefab", new List<string> { "m1", "m2" });
24
24
  Assert.AreEqual(1, report.items.Count);
25
- var first = report.items[0];
25
+ PrefabChecker.ScanReport.Item first = report.items[0];
26
26
  Assert.AreEqual("path.prefab", first.path);
27
27
  string[] messages = first.messages;
28
28
  CollectionAssert.AreEqual(new[] { "m1", "m2" }, messages);
@@ -18,20 +18,23 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
18
18
  public void SortsAscendingAndDescending()
19
19
  {
20
20
  AnimationCopierWindow wnd = ScriptableObject.CreateInstance<AnimationCopierWindow>();
21
- var a = NewFileInfo("zeta.anim");
22
- var b = NewFileInfo("alpha.anim");
23
- var c = NewFileInfo("beta.anim");
24
- var items = new List<AnimationCopierWindow.AnimationFileInfo> { a, b, c };
21
+ AnimationCopierWindow.AnimationFileInfo a = NewFileInfo("zeta.anim");
22
+ AnimationCopierWindow.AnimationFileInfo b = NewFileInfo("alpha.anim");
23
+ AnimationCopierWindow.AnimationFileInfo c = NewFileInfo("beta.anim");
24
+ List<AnimationCopierWindow.AnimationFileInfo> items =
25
+ new List<AnimationCopierWindow.AnimationFileInfo> { a, b, c };
25
26
 
26
27
  wnd._filterText = string.Empty;
27
28
  wnd._filterUseRegex = false;
28
29
  wnd._sortAscending = true;
29
- var asc = wnd.ApplyFilterAndSort(items).ToList();
30
+ List<AnimationCopierWindow.AnimationFileInfo> asc = wnd.ApplyFilterAndSort(items)
31
+ .ToList();
30
32
  string[] ascNames = asc.Select(o => o.FileName).ToArray();
31
33
  CollectionAssert.AreEqual(new[] { "alpha.anim", "beta.anim", "zeta.anim" }, ascNames);
32
34
 
33
35
  wnd._sortAscending = false;
34
- var desc = wnd.ApplyFilterAndSort(items).ToList();
36
+ List<AnimationCopierWindow.AnimationFileInfo> desc = wnd.ApplyFilterAndSort(items)
37
+ .ToList();
35
38
  string[] descNames = desc.Select(o => o.FileName).ToArray();
36
39
  CollectionAssert.AreEqual(new[] { "zeta.anim", "beta.anim", "alpha.anim" }, descNames);
37
40
  }
@@ -40,21 +43,24 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
40
43
  public void FiltersBySubstringAndRegex()
41
44
  {
42
45
  AnimationCopierWindow wnd = ScriptableObject.CreateInstance<AnimationCopierWindow>();
43
- var a = NewFileInfo("walk.anim");
44
- var b = NewFileInfo("attack.anim");
45
- var c = NewFileInfo("idle.anim");
46
- var items = new List<AnimationCopierWindow.AnimationFileInfo> { a, b, c };
46
+ AnimationCopierWindow.AnimationFileInfo a = NewFileInfo("walk.anim");
47
+ AnimationCopierWindow.AnimationFileInfo b = NewFileInfo("attack.anim");
48
+ AnimationCopierWindow.AnimationFileInfo c = NewFileInfo("idle.anim");
49
+ List<AnimationCopierWindow.AnimationFileInfo> items =
50
+ new List<AnimationCopierWindow.AnimationFileInfo> { a, b, c };
47
51
 
48
52
  wnd._filterText = "ta";
49
53
  wnd._filterUseRegex = false;
50
54
  wnd._sortAscending = true;
51
- var sub = wnd.ApplyFilterAndSort(items).ToList();
55
+ List<AnimationCopierWindow.AnimationFileInfo> sub = wnd.ApplyFilterAndSort(items)
56
+ .ToList();
52
57
  string[] subNames = sub.Select(o => o.FileName).ToArray();
53
58
  CollectionAssert.AreEquivalent(new[] { "attack.anim" }, subNames);
54
59
 
55
60
  wnd._filterText = "^i";
56
61
  wnd._filterUseRegex = true;
57
- var rx = wnd.ApplyFilterAndSort(items).ToList();
62
+ List<AnimationCopierWindow.AnimationFileInfo> rx = wnd.ApplyFilterAndSort(items)
63
+ .ToList();
58
64
  string[] rxNames = rx.Select(o => o.FileName).ToArray();
59
65
  CollectionAssert.AreEquivalent(new[] { "idle.anim" }, rxNames);
60
66
  }
@@ -5,6 +5,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
5
5
  using NUnit.Framework;
6
6
  using UnityEditor;
7
7
  using UnityEngine;
8
+ using WallstopStudios.UnityHelpers.Core.Helper;
8
9
  using WallstopStudios.UnityHelpers.Editor.Sprites;
9
10
  using WallstopStudios.UnityHelpers.Tests.Editor.Utils;
10
11
 
@@ -35,7 +36,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
35
36
  [Test]
36
37
  public void AnalyzeDetectsNewChangedUnchangedAndOrphans()
37
38
  {
38
- string srcA = Path.Combine(SrcRoot, "A.anim").Replace('\\', '/');
39
+ string srcA = Path.Combine(SrcRoot, "A.anim").SanitizePath();
39
40
  CreateEmptyClip(srcA);
40
41
  AssetDatabase.SaveAssets();
41
42
  AssetDatabase.Refresh();
@@ -55,7 +56,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
55
56
  Assert.AreEqual(0, orphansCount);
56
57
 
57
58
  // Create destination copy to become unchanged
58
- string dstA = Path.Combine(DstRoot, "A.anim").Replace('\\', '/');
59
+ string dstA = Path.Combine(DstRoot, "A.anim").SanitizePath();
59
60
  Assert.IsTrue(AssetDatabase.CopyAsset(srcA, dstA));
60
61
  AssetDatabase.SaveAssets();
61
62
  AssetDatabase.Refresh();
@@ -66,7 +67,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
66
67
  AssetDatabase.Refresh();
67
68
 
68
69
  // Add orphan in destination
69
- string dstB = Path.Combine(DstRoot, "B.anim").Replace('\\', '/');
70
+ string dstB = Path.Combine(DstRoot, "B.anim").SanitizePath();
70
71
  CreateEmptyClip(dstB);
71
72
  AssetDatabase.SaveAssets();
72
73
  AssetDatabase.Refresh();
@@ -87,8 +88,8 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
87
88
  [Test]
88
89
  public void CopyChangedPreservesGuidAndOverwrites()
89
90
  {
90
- string srcA = Path.Combine(SrcRoot, "A.anim").Replace('\\', '/');
91
- string dstA = Path.Combine(DstRoot, "A.anim").Replace('\\', '/');
91
+ string srcA = Path.Combine(SrcRoot, "A.anim").SanitizePath();
92
+ string dstA = Path.Combine(DstRoot, "A.anim").SanitizePath();
92
93
  CreateEmptyClip(srcA);
93
94
  AssetDatabase.SaveAssets();
94
95
  AssetDatabase.Refresh();
@@ -121,8 +122,8 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
121
122
  [Test]
122
123
  public void MirrorDeleteRemovesOrphansWhenNotDryRun()
123
124
  {
124
- string srcA = Path.Combine(SrcRoot, "A.anim").Replace('\\', '/');
125
- string dstB = Path.Combine(DstRoot, "B.anim").Replace('\\', '/');
125
+ string srcA = Path.Combine(SrcRoot, "A.anim").SanitizePath();
126
+ string dstB = Path.Combine(DstRoot, "B.anim").SanitizePath();
126
127
  CreateEmptyClip(srcA);
127
128
  CreateEmptyClip(dstB);
128
129
  AssetDatabase.SaveAssets();
@@ -29,7 +29,8 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
29
29
  keys[2] = new ObjectReferenceKeyframe { time = 0.2f, value = s3 };
30
30
  AnimationUtility.SetObjectReferenceCurve(clip, binding, keys);
31
31
 
32
- var instance = new AnimationViewerWindow.EditorLayerData(clip);
32
+ AnimationViewerWindow.EditorLayerData instance =
33
+ new AnimationViewerWindow.EditorLayerData(clip);
33
34
  Assert.NotNull(instance);
34
35
  Assert.AreEqual(3, instance.Sprites.Count);
35
36
  }
@@ -6,6 +6,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
6
6
  using UnityEditor;
7
7
  using UnityEngine;
8
8
  using UnityEngine.U2D;
9
+ using WallstopStudios.UnityHelpers.Core.Helper;
9
10
  using WallstopStudios.UnityHelpers.Editor.Sprites;
10
11
  using WallstopStudios.UnityHelpers.Tests.Editor.Utils;
11
12
 
@@ -31,7 +32,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
31
32
  public void GeneratesSpriteAtlasAssetFromConfig()
32
33
  {
33
34
  // Create a source sprite
34
- string spritePath = Path.Combine(Root, "icon.png").Replace('\\', '/');
35
+ string spritePath = Path.Combine(Root, "icon.png").SanitizePath();
35
36
  CreatePng(spritePath, 8, 8, Color.red);
36
37
  AssetDatabase.Refresh();
37
38
 
@@ -41,7 +42,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
41
42
  config.spritesToPack.Add(AssetDatabase.LoadAssetAtPath<Sprite>(spritePath));
42
43
  config.outputSpriteAtlasDirectory = Root;
43
44
  config.outputSpriteAtlasName = "TestAtlas";
44
- string configPath = Path.Combine(Root, "TestAtlasConfig.asset").Replace('\\', '/');
45
+ string configPath = Path.Combine(Root, "TestAtlasConfig.asset").SanitizePath();
45
46
  AssetDatabase.CreateAsset(config, configPath);
46
47
  AssetDatabase.SaveAssets();
47
48
  AssetDatabase.Refresh();
@@ -55,7 +56,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
55
56
 
56
57
  AssetDatabase.Refresh();
57
58
 
58
- string atlasPath = Path.Combine(Root, "TestAtlas.spriteatlas").Replace('\\', '/');
59
+ string atlasPath = Path.Combine(Root, "TestAtlas.spriteatlas").SanitizePath();
59
60
  SpriteAtlas atlas = AssetDatabase.LoadAssetAtPath<SpriteAtlas>(atlasPath);
60
61
  Assert.IsTrue(atlas != null, ".spriteatlas should be generated");
61
62
  }
@@ -77,7 +78,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
77
78
 
78
79
  private static void CreatePng(string relPath, int w, int h, Color c)
79
80
  {
80
- string dir = Path.GetDirectoryName(relPath).Replace('\\', '/');
81
+ string dir = Path.GetDirectoryName(relPath)?.SanitizePath();
81
82
  EnsureFolder(dir);
82
83
  Texture2D t = new(w, h, TextureFormat.RGBA32, false);
83
84
  Color[] pix = new Color[w * h];
@@ -101,7 +102,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
101
102
  ),
102
103
  rel
103
104
  )
104
- .Replace('\\', '/');
105
+ .SanitizePath();
105
106
  }
106
107
  }
107
108
  #endif
@@ -5,6 +5,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
5
5
  using NUnit.Framework;
6
6
  using UnityEditor;
7
7
  using UnityEngine;
8
+ using WallstopStudios.UnityHelpers.Core.Helper;
8
9
  using WallstopStudios.UnityHelpers.Editor.Sprites;
9
10
  using WallstopStudios.UnityHelpers.Tests.Editor.Utils;
10
11
  using Object = UnityEngine.Object;
@@ -30,7 +31,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
30
31
  [Test]
31
32
  public void AppliesPaddingAndAdjustsPivotCorrectly()
32
33
  {
33
- string src = (Root + "/pad_src.png").Replace('\\', '/');
34
+ string src = (Root + "/pad_src.png").SanitizePath();
34
35
  // 20x20, opaque 10x10 at (5,5)
35
36
  CreatePngWithOpaqueRect(src, 20, 20, 5, 5, 10, 10, Color.white);
36
37
  AssetDatabase.Refresh();
@@ -5,6 +5,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
5
5
  using NUnit.Framework;
6
6
  using UnityEditor;
7
7
  using UnityEngine;
8
+ using WallstopStudios.UnityHelpers.Core.Helper;
8
9
  using WallstopStudios.UnityHelpers.Editor.Sprites;
9
10
  using WallstopStudios.UnityHelpers.Tests.Editor.Utils;
10
11
 
@@ -29,7 +30,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
29
30
  [Test]
30
31
  public void CropsTransparentMarginsAndPreservesPivot()
31
32
  {
32
- string src = Path.Combine(Root, "src.png").Replace('\\', '/');
33
+ string src = Path.Combine(Root, "src.png").SanitizePath();
33
34
  // 16x16 with an opaque 10x10 square starting at (3,3)
34
35
  CreatePngWithOpaqueRect(src, 16, 16, 3, 3, 10, 10, Color.white);
35
36
  AssetDatabase.Refresh();
@@ -72,8 +73,8 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
72
73
  [Test]
73
74
  public void WritesToOutputDirectoryWhenNotOverwriting()
74
75
  {
75
- string src = Path.Combine(Root, "src2.png").Replace('\\', '/');
76
- string outDir = Path.Combine(Root, "Out").Replace('\\', '/');
76
+ string src = Path.Combine(Root, "src2.png").SanitizePath();
77
+ string outDir = Path.Combine(Root, "Out").SanitizePath();
77
78
  EnsureFolder(outDir);
78
79
  CreatePngWithOpaqueRect(src, 8, 8, 2, 2, 4, 4, Color.green);
79
80
  AssetDatabase.Refresh();
@@ -96,7 +97,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
96
97
 
97
98
  AssetDatabase.Refresh();
98
99
 
99
- string dst = Path.Combine(outDir, "Cropped_src2.png").Replace('\\', '/');
100
+ string dst = Path.Combine(outDir, "Cropped_src2.png").SanitizePath();
100
101
  Assert.That(File.Exists(RelToFull(dst)), Is.True, "Cropped output should exist");
101
102
 
102
103
  Texture2D tex = AssetDatabase.LoadAssetAtPath<Texture2D>(dst);
@@ -116,7 +117,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
116
117
  Color color
117
118
  )
118
119
  {
119
- string dir = Path.GetDirectoryName(relPath).Replace('\\', '/');
120
+ string dir = Path.GetDirectoryName(relPath)?.SanitizePath();
120
121
  EnsureFolder(dir);
121
122
  Texture2D t = new(w, h, TextureFormat.RGBA32, false) { alphaIsTransparency = true };
122
123
  Color[] pix = new Color[w * h];
@@ -155,7 +156,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
155
156
  ),
156
157
  rel
157
158
  )
158
- .Replace('\\', '/');
159
+ .SanitizePath();
159
160
  }
160
161
  }
161
162
  #endif
@@ -5,6 +5,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
5
5
  using NUnit.Framework;
6
6
  using UnityEditor;
7
7
  using UnityEngine;
8
+ using WallstopStudios.UnityHelpers.Core.Helper;
8
9
  using WallstopStudios.UnityHelpers.Editor.Sprites;
9
10
  using WallstopStudios.UnityHelpers.Tests.Editor.Utils;
10
11
  using Object = UnityEngine.Object;
@@ -32,7 +33,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
32
33
  [Test]
33
34
  public void RespectsAlphaCutoffWhenComputingPivot()
34
35
  {
35
- string src = (Root + "/alpha_bias.png").Replace('\\', '/');
36
+ string src = (Root + "/alpha_bias.png").SanitizePath();
36
37
  // 20x20 with a faint (alpha=0.2) 4x4 block at bottom-left and a solid 4x4 at top-right
37
38
  CreateDualAlphaPattern(src, 20, 20);
38
39
  AssetDatabase.Refresh();
@@ -5,6 +5,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
5
5
  using NUnit.Framework;
6
6
  using UnityEditor;
7
7
  using UnityEngine;
8
+ using WallstopStudios.UnityHelpers.Core.Helper;
8
9
  using WallstopStudios.UnityHelpers.Editor.Sprites;
9
10
  using WallstopStudios.UnityHelpers.Tests.Editor.Utils;
10
11
 
@@ -29,7 +30,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
29
30
  [Test]
30
31
  public void AdjustsPivotToAlphaWeightedCenter()
31
32
  {
32
- string path = Path.Combine(Root, "pivot.png").Replace('\\', '/');
33
+ string path = Path.Combine(Root, "pivot.png").SanitizePath();
33
34
  // 10x10 image, opaque L-shape to bias center toward bottom-left
34
35
  CreateAsymmetricAlpha(path, 10, 10);
35
36
  AssetDatabase.Refresh();
@@ -66,7 +67,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
66
67
 
67
68
  private static void CreateAsymmetricAlpha(string relPath, int w, int h)
68
69
  {
69
- string dir = Path.GetDirectoryName(relPath).Replace('\\', '/');
70
+ string dir = Path.GetDirectoryName(relPath).SanitizePath();
70
71
  EnsureFolder(dir);
71
72
  Texture2D t = new(w, h, TextureFormat.RGBA32, false) { alphaIsTransparency = true };
72
73
  Color[] pix = new Color[w * h];
@@ -106,7 +107,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
106
107
  ),
107
108
  rel
108
109
  )
109
- .Replace('\\', '/');
110
+ .SanitizePath();
110
111
  }
111
112
  }
112
113
  #endif