com.wallstop-studios.unity-helpers 2.0.0-rc57 → 2.0.0-rc59
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/Runtime/Core/DataStructure/CyclicBuffer.cs +46 -6
- package/Runtime/Core/Extension/IListExtensions.cs +44 -4
- package/Runtime/Core/Extension/StringExtensions.cs +30 -1
- package/Runtime/Core/Helper/DirectoryHelper.cs +132 -0
- package/Runtime/Core/Helper/DirectoryHelper.cs.meta +3 -0
- package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +1 -1
- package/Runtime/Core/Helper/SceneHelper.cs +1 -5
- package/Runtime/Utils/StartTracker.cs +15 -0
- package/Runtime/Utils/StartTracker.cs.meta +3 -0
- package/Runtime/Utils/UnityObjectNameComparer.cs +33 -0
- package/Runtime/Utils/UnityObjectNameComparer.cs.meta +3 -0
- package/package.json +1 -1
|
@@ -10,6 +10,45 @@
|
|
|
10
10
|
[Serializable]
|
|
11
11
|
public sealed class CyclicBuffer<T> : IReadOnlyList<T>
|
|
12
12
|
{
|
|
13
|
+
public struct CyclicBufferEnumerator : IEnumerator<T>
|
|
14
|
+
{
|
|
15
|
+
private readonly CyclicBuffer<T> _buffer;
|
|
16
|
+
|
|
17
|
+
private int _index;
|
|
18
|
+
private T _current;
|
|
19
|
+
|
|
20
|
+
internal CyclicBufferEnumerator(CyclicBuffer<T> buffer)
|
|
21
|
+
{
|
|
22
|
+
_buffer = buffer;
|
|
23
|
+
_index = -1;
|
|
24
|
+
_current = default;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public bool MoveNext()
|
|
28
|
+
{
|
|
29
|
+
if (++_index < _buffer.Count)
|
|
30
|
+
{
|
|
31
|
+
_current = _buffer._buffer[_buffer.AdjustedIndexFor(_index)];
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
_current = default;
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public T Current => _current;
|
|
40
|
+
|
|
41
|
+
object IEnumerator.Current => Current;
|
|
42
|
+
|
|
43
|
+
public void Reset()
|
|
44
|
+
{
|
|
45
|
+
_index = -1;
|
|
46
|
+
_current = default;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public void Dispose() { }
|
|
50
|
+
}
|
|
51
|
+
|
|
13
52
|
public int Capacity { get; private set; }
|
|
14
53
|
public int Count { get; private set; }
|
|
15
54
|
|
|
@@ -47,13 +86,14 @@
|
|
|
47
86
|
}
|
|
48
87
|
}
|
|
49
88
|
|
|
50
|
-
public
|
|
89
|
+
public CyclicBufferEnumerator GetEnumerator()
|
|
51
90
|
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
91
|
+
return new CyclicBufferEnumerator(this);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
95
|
+
{
|
|
96
|
+
return GetEnumerator();
|
|
57
97
|
}
|
|
58
98
|
|
|
59
99
|
IEnumerator IEnumerable.GetEnumerator()
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
using System.Collections.Generic;
|
|
5
5
|
using Helper;
|
|
6
6
|
using Random;
|
|
7
|
+
using Utils;
|
|
7
8
|
|
|
8
9
|
public static class IListExtensions
|
|
9
10
|
{
|
|
@@ -30,12 +31,12 @@
|
|
|
30
31
|
|
|
31
32
|
public static void Shift<T>(this IList<T> list, int amount)
|
|
32
33
|
{
|
|
33
|
-
|
|
34
|
-
if (count <= 1)
|
|
34
|
+
if (list is not { Count: > 1 })
|
|
35
35
|
{
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
int count = list.Count;
|
|
39
40
|
amount = amount.PositiveMod(count);
|
|
40
41
|
if (amount == 0)
|
|
41
42
|
{
|
|
@@ -87,14 +88,14 @@
|
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
public static void InsertionSort<T, TComparer>(this IList<T> array, TComparer comparer)
|
|
90
|
-
where TComparer :
|
|
91
|
+
where TComparer : IComparer<T>
|
|
91
92
|
{
|
|
92
93
|
int arrayCount = array.Count;
|
|
93
94
|
for (int i = 1; i < arrayCount; ++i)
|
|
94
95
|
{
|
|
95
96
|
T key = array[i];
|
|
96
97
|
int j = i - 1;
|
|
97
|
-
while (j
|
|
98
|
+
while (0 <= j && 0 < comparer.Compare(array[j], key))
|
|
98
99
|
{
|
|
99
100
|
array[j + 1] = array[j];
|
|
100
101
|
j--;
|
|
@@ -102,5 +103,44 @@
|
|
|
102
103
|
array[j + 1] = key;
|
|
103
104
|
}
|
|
104
105
|
}
|
|
106
|
+
|
|
107
|
+
public static void SortByName<T>(this IList<T> inputList)
|
|
108
|
+
where T : UnityEngine.Object
|
|
109
|
+
{
|
|
110
|
+
switch (inputList)
|
|
111
|
+
{
|
|
112
|
+
case T[] array:
|
|
113
|
+
Array.Sort(array, UnityObjectNameComparer<T>.Instance);
|
|
114
|
+
return;
|
|
115
|
+
case List<T> list:
|
|
116
|
+
list.Sort(UnityObjectNameComparer<T>.Instance);
|
|
117
|
+
return;
|
|
118
|
+
default:
|
|
119
|
+
inputList.InsertionSort(UnityObjectNameComparer<T>.Instance);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public static bool IsSorted<T>(this IList<T> list, IComparer<T> comparer = null)
|
|
125
|
+
{
|
|
126
|
+
if (list.Count <= 1)
|
|
127
|
+
{
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
comparer ??= Comparer<T>.Default;
|
|
132
|
+
|
|
133
|
+
T previous = list[0];
|
|
134
|
+
for (int i = 1; i < list.Count; ++i)
|
|
135
|
+
{
|
|
136
|
+
T current = list[i];
|
|
137
|
+
if (comparer.Compare(previous, current) > 0)
|
|
138
|
+
{
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
105
145
|
}
|
|
106
146
|
}
|
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
{
|
|
3
3
|
using System.Collections.Generic;
|
|
4
4
|
using System.Text;
|
|
5
|
+
using System.Threading;
|
|
5
6
|
using Serialization;
|
|
6
7
|
|
|
7
8
|
public static class StringExtensions
|
|
8
9
|
{
|
|
10
|
+
private static ThreadLocal<StringBuilder> StringBuilderCache = new(
|
|
11
|
+
() => new StringBuilder()
|
|
12
|
+
);
|
|
13
|
+
|
|
9
14
|
private static readonly HashSet<char> PascalCaseSeparators = new()
|
|
10
15
|
{
|
|
11
16
|
'_',
|
|
@@ -46,7 +51,8 @@
|
|
|
46
51
|
public static string ToPascalCase(this string value, string separator = "")
|
|
47
52
|
{
|
|
48
53
|
int startIndex = 0;
|
|
49
|
-
StringBuilder stringBuilder =
|
|
54
|
+
StringBuilder stringBuilder = StringBuilderCache.Value;
|
|
55
|
+
stringBuilder.Clear();
|
|
50
56
|
bool appendedAnySeparator = false;
|
|
51
57
|
for (int i = 0; i < value.Length; ++i)
|
|
52
58
|
{
|
|
@@ -147,5 +153,28 @@
|
|
|
147
153
|
|
|
148
154
|
return stringBuilder.ToString();
|
|
149
155
|
}
|
|
156
|
+
|
|
157
|
+
public static bool NeedsLowerInvariantConversion(this string input)
|
|
158
|
+
{
|
|
159
|
+
foreach (char inputCharacter in input)
|
|
160
|
+
{
|
|
161
|
+
if (char.ToLowerInvariant(inputCharacter) != inputCharacter)
|
|
162
|
+
{
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
public static bool NeedsTrim(this string input)
|
|
171
|
+
{
|
|
172
|
+
if (string.IsNullOrEmpty(input))
|
|
173
|
+
{
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return char.IsWhiteSpace(input[0]) || char.IsWhiteSpace(input[^1]);
|
|
178
|
+
}
|
|
150
179
|
}
|
|
151
180
|
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
namespace UnityHelpers.Core.Helper
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.IO;
|
|
5
|
+
using System.Runtime.CompilerServices;
|
|
6
|
+
using UnityEngine;
|
|
7
|
+
|
|
8
|
+
public static class DirectoryHelper
|
|
9
|
+
{
|
|
10
|
+
public static string GetCallerScriptDirectory([CallerFilePath] string sourceFilePath = "")
|
|
11
|
+
{
|
|
12
|
+
return string.IsNullOrWhiteSpace(sourceFilePath)
|
|
13
|
+
? string.Empty
|
|
14
|
+
: Path.GetDirectoryName(sourceFilePath);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public static string FindPackageRootPath(string startDirectory)
|
|
18
|
+
{
|
|
19
|
+
return FindRootPath(
|
|
20
|
+
startDirectory,
|
|
21
|
+
path => File.Exists(Path.Combine(path, "package.json"))
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public static string FindRootPath(
|
|
26
|
+
string startDirectory,
|
|
27
|
+
Func<string, bool> terminalCondition
|
|
28
|
+
)
|
|
29
|
+
{
|
|
30
|
+
string currentPath = startDirectory;
|
|
31
|
+
while (!string.IsNullOrWhiteSpace(currentPath))
|
|
32
|
+
{
|
|
33
|
+
try
|
|
34
|
+
{
|
|
35
|
+
if (terminalCondition(currentPath))
|
|
36
|
+
{
|
|
37
|
+
DirectoryInfo directoryInfo = new(currentPath);
|
|
38
|
+
if (!directoryInfo.Exists)
|
|
39
|
+
{
|
|
40
|
+
return currentPath;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return directoryInfo.FullName;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch
|
|
47
|
+
{
|
|
48
|
+
return currentPath;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try
|
|
52
|
+
{
|
|
53
|
+
string parentPath = Path.GetDirectoryName(currentPath);
|
|
54
|
+
if (string.Equals(parentPath, currentPath, StringComparison.OrdinalIgnoreCase))
|
|
55
|
+
{
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
currentPath = parentPath;
|
|
60
|
+
}
|
|
61
|
+
catch
|
|
62
|
+
{
|
|
63
|
+
return currentPath;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return string.Empty;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public static string FindAbsolutePathToDirectory(string directory)
|
|
71
|
+
{
|
|
72
|
+
string scriptDirectory = GetCallerScriptDirectory();
|
|
73
|
+
if (string.IsNullOrEmpty(scriptDirectory))
|
|
74
|
+
{
|
|
75
|
+
return string.Empty;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
string packageRootAbsolute = FindPackageRootPath(scriptDirectory);
|
|
79
|
+
if (string.IsNullOrEmpty(packageRootAbsolute))
|
|
80
|
+
{
|
|
81
|
+
return string.Empty;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
string targetPathAbsolute = Path.Combine(
|
|
85
|
+
packageRootAbsolute,
|
|
86
|
+
directory.Replace('/', Path.DirectorySeparatorChar)
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
return AbsoluteToUnityRelativePath(targetPathAbsolute);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public static string AbsoluteToUnityRelativePath(string absolutePath)
|
|
93
|
+
{
|
|
94
|
+
if (string.IsNullOrWhiteSpace(absolutePath))
|
|
95
|
+
{
|
|
96
|
+
return string.Empty;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
absolutePath = absolutePath.Replace('\\', '/');
|
|
100
|
+
string projectRoot = Application.dataPath.Replace('\\', '/');
|
|
101
|
+
|
|
102
|
+
projectRoot = Path.GetDirectoryName(projectRoot)?.Replace('\\', '/');
|
|
103
|
+
if (string.IsNullOrWhiteSpace(projectRoot))
|
|
104
|
+
{
|
|
105
|
+
return string.Empty;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (absolutePath.StartsWith(projectRoot, StringComparison.OrdinalIgnoreCase))
|
|
109
|
+
{
|
|
110
|
+
// +1 to remove the leading slash only if projectRoot doesn't end with one
|
|
111
|
+
int startIndex = projectRoot.EndsWith("/", StringComparison.OrdinalIgnoreCase)
|
|
112
|
+
? projectRoot.Length
|
|
113
|
+
: projectRoot.Length + 1;
|
|
114
|
+
return absolutePath.Length > startIndex ? absolutePath[startIndex..] : string.Empty;
|
|
115
|
+
}
|
|
116
|
+
if (absolutePath.StartsWith(projectRoot, StringComparison.OrdinalIgnoreCase))
|
|
117
|
+
{
|
|
118
|
+
int startIndex = projectRoot.EndsWith("/", StringComparison.OrdinalIgnoreCase)
|
|
119
|
+
? projectRoot.Length
|
|
120
|
+
: projectRoot.Length + 1;
|
|
121
|
+
if (startIndex < absolutePath.Length)
|
|
122
|
+
{
|
|
123
|
+
return "Assets/" + absolutePath[startIndex..];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return "Assets";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return string.Empty;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
namespace UnityHelpers.Utils
|
|
2
|
+
{
|
|
3
|
+
using System;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
|
|
6
|
+
public sealed class UnityObjectNameComparer<T> : IComparer<T>
|
|
7
|
+
where T : UnityEngine.Object
|
|
8
|
+
{
|
|
9
|
+
public static readonly UnityObjectNameComparer<T> Instance = new();
|
|
10
|
+
|
|
11
|
+
private UnityObjectNameComparer() { }
|
|
12
|
+
|
|
13
|
+
public int Compare(T x, T y)
|
|
14
|
+
{
|
|
15
|
+
if (x == y)
|
|
16
|
+
{
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (y == null)
|
|
21
|
+
{
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (x == null)
|
|
26
|
+
{
|
|
27
|
+
return -1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return string.Compare(x.name, y.name, StringComparison.OrdinalIgnoreCase);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|