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.
- package/Editor/CustomDrawers/WShowIfPropertyDrawer.cs +1 -0
- package/Editor/CustomEditors/PersistentDirectoryGUI.cs +4 -1
- package/Editor/CustomEditors/PolygonCollider2DOptimizerEditor.cs +40 -0
- package/Editor/CustomEditors/PolygonCollider2DOptimizerEditor.cs.meta +3 -0
- package/Editor/CustomEditors/SourceFolderEntryDrawer.cs +43 -31
- package/{Runtime/Core/Extension → Editor/Extensions}/SerializedPropertyExtensions.cs +1 -1
- package/Editor/Sprites/ScriptableSpriteAtlasEditor.cs +9 -1
- package/Editor/Sprites/SpriteSheetAnimationCreator.cs +1218 -0
- package/Editor/Sprites/SpriteSheetAnimationCreator.cs.meta +3 -0
- package/Runtime/Core/DataStructure/CyclicBuffer.cs +29 -19
- package/Runtime/Core/Extension/DictionaryExtensions.cs +30 -10
- package/Runtime/Core/Extension/IEnumerableExtensions.cs +12 -10
- package/Runtime/Core/Extension/IListExtensions.cs +6 -0
- package/Runtime/Core/Extension/UnityExtensions.cs +68 -0
- package/Runtime/Core/Helper/Helpers.cs +12 -0
- package/Runtime/Core/Helper/LineHelper.cs +194 -0
- package/Runtime/Core/Helper/LineHelper.cs.meta +3 -0
- package/Runtime/Tags/CollisionSenses.cs +91 -0
- package/Runtime/Tags/CollisionSenses.cs.meta +3 -0
- package/Runtime/Utils/ChildSpawner.cs +100 -0
- package/Runtime/Utils/ChildSpawner.cs.meta +3 -0
- package/Runtime/Utils/CollisionProxy.cs +48 -0
- package/Runtime/Utils/CollisionProxy.cs.meta +3 -0
- package/Runtime/Utils/PolygonCollider2DOptimizer.cs +83 -0
- package/Runtime/Utils/PolygonCollider2DOptimizer.cs.meta +3 -0
- package/Runtime/Utils/SerializedStringComparer.cs +107 -0
- package/Runtime/Utils/SerializedStringComparer.cs.meta +3 -0
- package/Runtime/Utils/UnityObjectNameComparer.cs +46 -1
- package/Tests/Runtime/DataStructures/CyclicBufferTests.cs +2 -2
- package/package.json +3 -1
- /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,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,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,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
|
+
}
|
|
@@ -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 =
|
|
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
|
-
|
|
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.
|
|
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
|
|
|
File without changes
|