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.
@@ -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 IEnumerator<T> GetEnumerator()
89
+ public CyclicBufferEnumerator GetEnumerator()
51
90
  {
52
- for (int i = 0; i < Count; ++i)
53
- {
54
- // No need for bound check, we're safe
55
- yield return _buffer[AdjustedIndexFor(i)];
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
- int count = list.Count;
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 : struct, IComparer<T>
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 >= 0 && comparer.Compare(array[j], key) > 0)
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 = new();
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,3 @@
1
+ fileFormatVersion: 2
2
+ guid: aefe35fe27e449f2b56e61a24c16cf62
3
+ timeCreated: 1744994158
@@ -365,7 +365,7 @@
365
365
 
366
366
  if (content == null)
367
367
  {
368
- Debug.LogError($"Unable to load {prefab} as a prefab");
368
+ Debug.LogError($"Unable to load {prefab} as a prefab", prefab);
369
369
  return;
370
370
  }
371
371
 
@@ -103,11 +103,7 @@
103
103
  }
104
104
  }
105
105
 
106
- public
107
- #if UNITY_EDITOR
108
- readonly
109
- #endif
110
- struct SceneLoadScope
106
+ public sealed class SceneLoadScope
111
107
  {
112
108
  private
113
109
  #if UNITY_EDITOR
@@ -0,0 +1,15 @@
1
+ namespace UnityHelpers.Utils
2
+ {
3
+ using UnityEngine;
4
+
5
+ [DisallowMultipleComponent]
6
+ public sealed class StartTracker : MonoBehaviour
7
+ {
8
+ public bool Started { get; private set; }
9
+
10
+ private void Start()
11
+ {
12
+ Started = true;
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: a3a542214e594fd199901492cbaaceac
3
+ timeCreated: 1744835337
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 24d2fd0003b641b7be52bc54e743be35
3
+ timeCreated: 1744989641
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.wallstop-studios.unity-helpers",
3
- "version": "2.0.0-rc57",
3
+ "version": "2.0.0-rc59",
4
4
  "displayName": "Unity Helpers",
5
5
  "description": "Various Unity Helper Library",
6
6
  "dependencies": {},