com.wallstop-studios.unity-helpers 2.0.0-rc76.4 → 2.0.0-rc76.6

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 (31) hide show
  1. package/Editor/CustomDrawers/WShowIfPropertyDrawer.cs +1 -0
  2. package/Editor/CustomEditors/PersistentDirectoryGUI.cs +4 -1
  3. package/Editor/CustomEditors/PolygonCollider2DOptimizerEditor.cs +40 -0
  4. package/Editor/CustomEditors/PolygonCollider2DOptimizerEditor.cs.meta +3 -0
  5. package/Editor/CustomEditors/SourceFolderEntryDrawer.cs +43 -31
  6. package/{Runtime/Core/Extension → Editor/Extensions}/SerializedPropertyExtensions.cs +1 -1
  7. package/Editor/Sprites/ScriptableSpriteAtlasEditor.cs +9 -1
  8. package/Editor/Sprites/SpriteSheetAnimationCreator.cs +1218 -0
  9. package/Editor/Sprites/SpriteSheetAnimationCreator.cs.meta +3 -0
  10. package/Runtime/Core/DataStructure/CyclicBuffer.cs +29 -19
  11. package/Runtime/Core/Extension/DictionaryExtensions.cs +30 -10
  12. package/Runtime/Core/Extension/IEnumerableExtensions.cs +12 -10
  13. package/Runtime/Core/Extension/IListExtensions.cs +6 -0
  14. package/Runtime/Core/Extension/UnityExtensions.cs +68 -0
  15. package/Runtime/Core/Helper/Helpers.cs +12 -0
  16. package/Runtime/Core/Helper/LineHelper.cs +194 -0
  17. package/Runtime/Core/Helper/LineHelper.cs.meta +3 -0
  18. package/Runtime/Tags/CollisionSenses.cs +91 -0
  19. package/Runtime/Tags/CollisionSenses.cs.meta +3 -0
  20. package/Runtime/Utils/ChildSpawner.cs +100 -0
  21. package/Runtime/Utils/ChildSpawner.cs.meta +3 -0
  22. package/Runtime/Utils/CollisionProxy.cs +48 -0
  23. package/Runtime/Utils/CollisionProxy.cs.meta +3 -0
  24. package/Runtime/Utils/PolygonCollider2DOptimizer.cs +83 -0
  25. package/Runtime/Utils/PolygonCollider2DOptimizer.cs.meta +3 -0
  26. package/Runtime/Utils/SerializedStringComparer.cs +107 -0
  27. package/Runtime/Utils/SerializedStringComparer.cs.meta +3 -0
  28. package/Runtime/Utils/UnityObjectNameComparer.cs +46 -1
  29. package/Tests/Runtime/DataStructures/CyclicBufferTests.cs +2 -2
  30. package/package.json +3 -1
  31. /package/{Runtime/Core/Extension → Editor/Extensions}/SerializedPropertyExtensions.cs.meta +0 -0
@@ -0,0 +1,100 @@
1
+ namespace WallstopStudios.UnityHelpers.Utils
2
+ {
3
+ using System.Collections.Generic;
4
+ using System.Linq;
5
+ using Core.Extension;
6
+ using UnityEngine;
7
+
8
+ [DisallowMultipleComponent]
9
+ public sealed class ChildSpawner : MonoBehaviour
10
+ {
11
+ private static readonly HashSet<GameObject> SpawnedPrefabs = new();
12
+
13
+ [SerializeField]
14
+ private GameObject[] _prefabs;
15
+
16
+ [SerializeField]
17
+ private GameObject[] _editorOnlyPrefabs;
18
+
19
+ [SerializeField]
20
+ private GameObject[] _developmentOnlyPrefabs;
21
+
22
+ private void Start()
23
+ {
24
+ if (
25
+ _prefabs
26
+ .Concat(_editorOnlyPrefabs)
27
+ .Concat(_developmentOnlyPrefabs)
28
+ .Distinct()
29
+ .Count()
30
+ != (_prefabs.Length + _editorOnlyPrefabs.Length + _developmentOnlyPrefabs.Length)
31
+ )
32
+ {
33
+ IEnumerable<string> duplicateChildNames = _prefabs
34
+ .Concat(_editorOnlyPrefabs)
35
+ .Concat(_developmentOnlyPrefabs)
36
+ .GroupBy(x => x)
37
+ .Where(group => group.Count() > 1)
38
+ .Select(group => group.Key != null ? group.Key.name : "null");
39
+ this.LogError(
40
+ $"Duplicate child prefab detected: {string.Join(",", duplicateChildNames)}"
41
+ );
42
+ }
43
+
44
+ int count = 0;
45
+ foreach (GameObject prefab in _prefabs)
46
+ {
47
+ GameObject child = Spawn(prefab);
48
+ if (child != null)
49
+ {
50
+ child.name = $"{child.name} ({count++:00})";
51
+ }
52
+ }
53
+
54
+ if (Application.isEditor)
55
+ {
56
+ foreach (GameObject prefab in _editorOnlyPrefabs)
57
+ {
58
+ GameObject child = Spawn(prefab);
59
+ if (child != null)
60
+ {
61
+ child.name = $"{child.name} (EDITOR-ONLY {count++:00})";
62
+ }
63
+ }
64
+ }
65
+
66
+ if (Application.isEditor || Debug.isDebugBuild)
67
+ {
68
+ foreach (GameObject prefab in _developmentOnlyPrefabs)
69
+ {
70
+ GameObject child = Spawn(prefab);
71
+ if (child != null)
72
+ {
73
+ child.name = $"{child.name} (DEVELOPMENT-ONLY {count++:00})";
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ private static void CleanName(GameObject child)
80
+ {
81
+ child.name = child.name.Replace("(Clone)", string.Empty);
82
+ }
83
+
84
+ private GameObject Spawn(GameObject prefab)
85
+ {
86
+ if (SpawnedPrefabs.Contains(prefab))
87
+ {
88
+ return null;
89
+ }
90
+
91
+ GameObject child = Instantiate(prefab, transform);
92
+ CleanName(child);
93
+ if (child.IsDontDestroyOnLoad() || gameObject.IsDontDestroyOnLoad())
94
+ {
95
+ SpawnedPrefabs.Add(prefab);
96
+ }
97
+ return child;
98
+ }
99
+ }
100
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 2b3c4b1f5ea74914be632464d47b345b
3
+ timeCreated: 1748569304
@@ -0,0 +1,48 @@
1
+ namespace WallstopStudios.UnityHelpers.Utils
2
+ {
3
+ using System;
4
+ using UnityEngine;
5
+
6
+ [DisallowMultipleComponent]
7
+ [RequireComponent(typeof(Collider2D))]
8
+ public sealed class CollisionProxy : MonoBehaviour
9
+ {
10
+ public event Action<Collision2D> OnCollisionEnter = _ => { };
11
+ public event Action<Collision2D> OnCollisionStay = _ => { };
12
+ public event Action<Collision2D> OnCollisionExit = _ => { };
13
+
14
+ public event Action<Collider2D> OnTriggerEnter = _ => { };
15
+ public event Action<Collider2D> OnTriggerStay = _ => { };
16
+ public event Action<Collider2D> OnTriggerExit = _ => { };
17
+
18
+ private void OnTriggerEnter2D(Collider2D other)
19
+ {
20
+ OnTriggerEnter?.Invoke(other);
21
+ }
22
+
23
+ private void OnTriggerStay2D(Collider2D other)
24
+ {
25
+ OnTriggerStay?.Invoke(other);
26
+ }
27
+
28
+ private void OnTriggerExit2D(Collider2D other)
29
+ {
30
+ OnTriggerExit?.Invoke(other);
31
+ }
32
+
33
+ private void OnCollisionEnter2D(Collision2D other)
34
+ {
35
+ OnCollisionEnter?.Invoke(other);
36
+ }
37
+
38
+ private void OnCollisionStay2D(Collision2D other)
39
+ {
40
+ OnCollisionStay?.Invoke(other);
41
+ }
42
+
43
+ private void OnCollisionExit2D(Collision2D other)
44
+ {
45
+ OnCollisionExit?.Invoke(other);
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 9d8886d28ef545d8967a436999bea13e
3
+ timeCreated: 1748569245
@@ -0,0 +1,83 @@
1
+ namespace WallstopStudios.UnityHelpers.Utils
2
+ {
3
+ using System;
4
+ using System.Collections.Generic;
5
+ using Core.Attributes;
6
+ using Core.Helper;
7
+ using UnityEngine;
8
+
9
+ /// <summary>
10
+ /// Polygon collider optimizer. Removes points from the collider polygon with
11
+ /// the given reduction Tolerance
12
+ /// </summary>
13
+ [AddComponentMenu("2D Collider Optimization/ Polygon Collider Optimizer")]
14
+ [RequireComponent(typeof(PolygonCollider2D))]
15
+ public sealed class PolygonCollider2DOptimizer : MonoBehaviour
16
+ {
17
+ [Serializable]
18
+ private sealed class Path
19
+ {
20
+ public List<Vector2> points = new();
21
+
22
+ public Path() { }
23
+
24
+ public Path(IEnumerable<Vector2> points)
25
+ {
26
+ this.points.AddRange(points);
27
+ }
28
+ }
29
+
30
+ public double tolerance;
31
+
32
+ [SiblingComponent]
33
+ private PolygonCollider2D _collider;
34
+
35
+ [SerializeField]
36
+ private List<Path> _originalPaths = new();
37
+
38
+ public void Refresh()
39
+ {
40
+ OnValidate();
41
+ }
42
+
43
+ private void OnValidate()
44
+ {
45
+ if (_collider == null)
46
+ {
47
+ this.AssignRelationalComponents();
48
+ }
49
+
50
+ /*
51
+ When first getting a reference to the collider save the paths
52
+ so that the optimization is re-doable (by performing it on the original path
53
+ every time)
54
+ */
55
+ if (_originalPaths.Count == 0)
56
+ {
57
+ for (int i = 0; i < _collider.pathCount; ++i)
58
+ {
59
+ List<Vector2> points = new(_collider.GetPath(i));
60
+ Path path = new(points);
61
+ _originalPaths.Add(path);
62
+ }
63
+ }
64
+
65
+ //Reset the original paths
66
+ if (tolerance <= 0)
67
+ {
68
+ for (int i = 0; i < _originalPaths.Count; ++i)
69
+ {
70
+ _collider.SetPath(i, _originalPaths[i].points.ToArray());
71
+ }
72
+ return;
73
+ }
74
+
75
+ for (int i = 0; i < _originalPaths.Count; ++i)
76
+ {
77
+ List<Vector2> path = _originalPaths[i].points;
78
+ List<Vector2> updatedPath = LineHelper.SimplifyPrecise(path, tolerance);
79
+ _collider.SetPath(i, updatedPath.ToArray());
80
+ }
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 9363f4728d254b8bae1afb829777d9d3
3
+ timeCreated: 1748566207
@@ -0,0 +1,107 @@
1
+ namespace WallstopStudios.UnityHelpers.Utils
2
+ {
3
+ using System;
4
+ using System.Collections.Generic;
5
+ using System.ComponentModel;
6
+
7
+ [Serializable]
8
+ public sealed class SerializedStringComparer : IEqualityComparer<string>
9
+ {
10
+ public enum StringCompareMode
11
+ {
12
+ Ordinal = 0,
13
+ OrdinalIgnoreCase = 1,
14
+ CurrentCulture = 2,
15
+ CurrentCultureIgnoreCase = 3,
16
+ InvariantCulture = 4,
17
+ InvariantCultureIgnoreCase = 5,
18
+ }
19
+
20
+ public StringCompareMode compareMode = StringCompareMode.Ordinal;
21
+
22
+ public SerializedStringComparer() { }
23
+
24
+ public SerializedStringComparer(StringCompareMode compareMode)
25
+ {
26
+ this.compareMode = compareMode;
27
+ }
28
+
29
+ public bool Equals(string x, string y)
30
+ {
31
+ switch (compareMode)
32
+ {
33
+ case StringCompareMode.Ordinal:
34
+ {
35
+ return StringComparer.Ordinal.Equals(x, y);
36
+ }
37
+ case StringCompareMode.OrdinalIgnoreCase:
38
+ {
39
+ return StringComparer.OrdinalIgnoreCase.Equals(x, y);
40
+ }
41
+ case StringCompareMode.CurrentCulture:
42
+ {
43
+ return StringComparer.CurrentCulture.Equals(x, y);
44
+ }
45
+ case StringCompareMode.CurrentCultureIgnoreCase:
46
+ {
47
+ return StringComparer.CurrentCultureIgnoreCase.Equals(x, y);
48
+ }
49
+ case StringCompareMode.InvariantCulture:
50
+ {
51
+ return StringComparer.InvariantCulture.Equals(x, y);
52
+ }
53
+ case StringCompareMode.InvariantCultureIgnoreCase:
54
+ {
55
+ return StringComparer.InvariantCultureIgnoreCase.Equals(x, y);
56
+ }
57
+ default:
58
+ {
59
+ throw new InvalidEnumArgumentException(
60
+ nameof(compareMode),
61
+ (int)compareMode,
62
+ typeof(StringCompareMode)
63
+ );
64
+ }
65
+ }
66
+ }
67
+
68
+ public int GetHashCode(string obj)
69
+ {
70
+ switch (compareMode)
71
+ {
72
+ case StringCompareMode.Ordinal:
73
+ {
74
+ return StringComparer.Ordinal.GetHashCode(obj);
75
+ }
76
+ case StringCompareMode.OrdinalIgnoreCase:
77
+ {
78
+ return StringComparer.OrdinalIgnoreCase.GetHashCode(obj);
79
+ }
80
+ case StringCompareMode.CurrentCulture:
81
+ {
82
+ return StringComparer.CurrentCulture.GetHashCode(obj);
83
+ }
84
+ case StringCompareMode.CurrentCultureIgnoreCase:
85
+ {
86
+ return StringComparer.CurrentCultureIgnoreCase.GetHashCode(obj);
87
+ }
88
+ case StringCompareMode.InvariantCulture:
89
+ {
90
+ return StringComparer.InvariantCulture.GetHashCode(obj);
91
+ }
92
+ case StringCompareMode.InvariantCultureIgnoreCase:
93
+ {
94
+ return StringComparer.InvariantCultureIgnoreCase.GetHashCode(obj);
95
+ }
96
+ default:
97
+ {
98
+ throw new InvalidEnumArgumentException(
99
+ nameof(compareMode),
100
+ (int)compareMode,
101
+ typeof(StringCompareMode)
102
+ );
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 2f66e3a62c374ef9a285d5e9e10f9fb2
3
+ timeCreated: 1748568941
@@ -2,6 +2,7 @@
2
2
  {
3
3
  using System;
4
4
  using System.Collections.Generic;
5
+ using System.Text.RegularExpressions;
5
6
  #if UNITY_EDITOR
6
7
  using UnityEditor;
7
8
  #endif
@@ -9,6 +10,10 @@
9
10
  public sealed class UnityObjectNameComparer<T> : IComparer<T>
10
11
  where T : UnityEngine.Object
11
12
  {
13
+ private static readonly Regex TrailingNumberRegex = new(
14
+ @"^(.*?)(\d+)$",
15
+ RegexOptions.Compiled
16
+ );
12
17
  public static readonly UnityObjectNameComparer<T> Instance = new();
13
18
 
14
19
  private UnityObjectNameComparer() { }
@@ -30,7 +35,7 @@
30
35
  return -1;
31
36
  }
32
37
 
33
- int comparison = string.Compare(x.name, y.name, StringComparison.OrdinalIgnoreCase);
38
+ int comparison = CompareNatural(x.name, y.name);
34
39
  if (comparison != 0)
35
40
  {
36
41
  return comparison;
@@ -50,5 +55,45 @@
50
55
 
51
56
  return comparison;
52
57
  }
58
+
59
+ private static int CompareNatural(string nameA, string nameB)
60
+ {
61
+ Match mA = TrailingNumberRegex.Match(nameA);
62
+ Match mB = TrailingNumberRegex.Match(nameB);
63
+
64
+ bool hasNumberA = mA.Success;
65
+ bool hasNumberB = mB.Success;
66
+
67
+ // If both have trailing numbers, compare prefix then numeric
68
+ if (hasNumberA && hasNumberB)
69
+ {
70
+ string prefixA = mA.Groups[1].Value;
71
+ string prefixB = mB.Groups[1].Value;
72
+
73
+ int prefixCompare = StringComparer.OrdinalIgnoreCase.Compare(prefixA, prefixB);
74
+ if (prefixCompare != 0)
75
+ {
76
+ return prefixCompare;
77
+ }
78
+
79
+ // same prefix → compare parsed integers
80
+ int numA = int.Parse(mA.Groups[2].Value);
81
+ int numB = int.Parse(mB.Groups[2].Value);
82
+ return numA.CompareTo(numB);
83
+ }
84
+ // If only one has a trailing number, treat the one without number as coming first
85
+
86
+ if (hasNumberA)
87
+ {
88
+ return 1; // B (no number) comes before A
89
+ }
90
+
91
+ if (hasNumberB)
92
+ {
93
+ return -1; // A (no number) comes before B
94
+ }
95
+ // Neither has a trailing number → pure string compare
96
+ return StringComparer.OrdinalIgnoreCase.Compare(nameA, nameB);
97
+ }
53
98
  }
54
99
  }
@@ -19,8 +19,8 @@
19
19
  Assert.Throws<ArgumentException>(() => new CyclicBuffer<int>(int.MinValue));
20
20
  for (int i = 0; i < NumTries; i++)
21
21
  {
22
- Assert.Throws<ArgumentException>(
23
- () => new CyclicBuffer<int>(PRNG.Instance.Next(int.MinValue, -1))
22
+ Assert.Throws<ArgumentException>(() =>
23
+ new CyclicBuffer<int>(PRNG.Instance.Next(int.MinValue, -1))
24
24
  );
25
25
  }
26
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.wallstop-studios.unity-helpers",
3
- "version": "2.0.0-rc76.4",
3
+ "version": "2.0.0-rc76.6",
4
4
  "displayName": "Unity Helpers",
5
5
  "description": "Various Unity Helper Library",
6
6
  "dependencies": {},
@@ -77,6 +77,8 @@
77
77
 
78
78
 
79
79
 
80
+
81
+
80
82
 
81
83
 
82
84