com.wallstop-studios.unity-helpers 2.0.0-rc44 → 2.0.0-rc46

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.
@@ -12,7 +12,6 @@
12
12
  {
13
13
  public int Capacity { get; private set; }
14
14
  public int Count { get; private set; }
15
- public bool IsReadOnly => false;
16
15
 
17
16
  private readonly List<T> _buffer;
18
17
  private int _position;
@@ -52,7 +51,7 @@
52
51
  {
53
52
  for (int i = 0; i < Count; ++i)
54
53
  {
55
- // No need for bounds check, we're safe
54
+ // No need for bound check, we're safe
56
55
  yield return _buffer[AdjustedIndexFor(i)];
57
56
  }
58
57
  }
@@ -87,7 +86,6 @@
87
86
 
88
87
  public void Clear()
89
88
  {
90
- /* Simply reset state */
91
89
  Count = 0;
92
90
  _position = 0;
93
91
  _buffer.Clear();
@@ -272,19 +272,21 @@
272
272
  }
273
273
  }
274
274
 
275
- nearestNeighbors.AddRange(nearestNeighborsSet);
275
+ foreach (T element in nearestNeighborsSet)
276
+ {
277
+ nearestNeighbors.Add(element);
278
+ }
276
279
  if (count < nearestNeighbors.Count)
277
280
  {
281
+ Vector2 localPosition = position;
278
282
  nearestNeighbors.Sort(NearestComparison);
279
283
  nearestNeighbors.RemoveRange(count, nearestNeighbors.Count - count);
280
- }
281
284
 
282
- return;
283
-
284
- int NearestComparison(T lhs, T rhs) =>
285
- (_elementTransformer(lhs) - position).sqrMagnitude.CompareTo(
286
- (_elementTransformer(rhs) - position).sqrMagnitude
287
- );
285
+ int NearestComparison(T lhs, T rhs) =>
286
+ (_elementTransformer(lhs) - localPosition).sqrMagnitude.CompareTo(
287
+ (_elementTransformer(rhs) - localPosition).sqrMagnitude
288
+ );
289
+ }
288
290
  }
289
291
  }
290
292
  }
@@ -231,11 +231,15 @@
231
231
  HashSet<T> nearestNeighborsSet = nearestNeighborBuffer ?? new HashSet<T>(count);
232
232
  nearestNeighborsSet.Clear();
233
233
 
234
+ Comparison<QuadTreeNode<T>> comparison = Comparison;
234
235
  while (!current.isTerminal)
235
236
  {
236
237
  childrenCopy.Clear();
237
- childrenCopy.AddRange(current.children);
238
- childrenCopy.Sort(Comparison);
238
+ foreach (QuadTreeNode<T> child in current.children)
239
+ {
240
+ childrenCopy.Add(child);
241
+ }
242
+ childrenCopy.Sort(comparison);
239
243
  for (int i = childrenCopy.Count - 1; 0 <= i; --i)
240
244
  {
241
245
  stack.Push(childrenCopy[i]);
@@ -256,11 +260,20 @@
256
260
  }
257
261
  }
258
262
 
259
- nearestNeighbors.AddRange(nearestNeighborsSet);
263
+ foreach (T element in nearestNeighborsSet)
264
+ {
265
+ nearestNeighbors.Add(element);
266
+ }
260
267
  if (count < nearestNeighbors.Count)
261
268
  {
269
+ Vector2 localPosition = position;
262
270
  nearestNeighbors.Sort(NearestComparison);
263
271
  nearestNeighbors.RemoveRange(count, nearestNeighbors.Count - count);
272
+
273
+ int NearestComparison(T lhs, T rhs) =>
274
+ (_elementTransformer(lhs) - localPosition).sqrMagnitude.CompareTo(
275
+ (_elementTransformer(rhs) - localPosition).sqrMagnitude
276
+ );
264
277
  }
265
278
 
266
279
  return;
@@ -269,11 +282,6 @@
269
282
  ((Vector2)lhs.boundary.center - position).sqrMagnitude.CompareTo(
270
283
  ((Vector2)rhs.boundary.center - position).sqrMagnitude
271
284
  );
272
-
273
- int NearestComparison(T lhs, T rhs) =>
274
- (_elementTransformer(lhs) - position).sqrMagnitude.CompareTo(
275
- (_elementTransformer(rhs) - position).sqrMagnitude
276
- );
277
285
  }
278
286
  }
279
287
  }
@@ -288,11 +288,15 @@
288
288
  HashSet<T> nearestNeighborsSet = nearestNeighborsBuffer ?? new HashSet<T>(count);
289
289
  nearestNeighborsSet.Clear();
290
290
 
291
+ Comparison<RTreeNode<T>> comparison = Comparison;
291
292
  while (!current.isTerminal)
292
293
  {
293
294
  childrenCopy.Clear();
294
- childrenCopy.AddRange(current.children);
295
- childrenCopy.Sort(Comparison);
295
+ foreach (RTreeNode<T> child in current.children)
296
+ {
297
+ childrenCopy.Add(child);
298
+ }
299
+ childrenCopy.Sort(comparison);
296
300
  for (int i = childrenCopy.Count - 1; 0 <= i; --i)
297
301
  {
298
302
  stack.Push(childrenCopy[i]);
@@ -313,11 +317,22 @@
313
317
  }
314
318
  }
315
319
 
316
- nearestNeighbors.AddRange(nearestNeighborsSet);
320
+ foreach (T element in nearestNeighborsSet)
321
+ {
322
+ nearestNeighbors.Add(element);
323
+ }
317
324
  if (count < nearestNeighbors.Count)
318
325
  {
326
+ Vector2 localPosition = position;
319
327
  nearestNeighbors.Sort(NearestComparison);
320
328
  nearestNeighbors.RemoveRange(count, nearestNeighbors.Count - count);
329
+
330
+ int NearestComparison(T lhs, T rhs) =>
331
+ (
332
+ (Vector2)_elementTransformer(lhs).center - localPosition
333
+ ).sqrMagnitude.CompareTo(
334
+ ((Vector2)_elementTransformer(rhs).center - localPosition).sqrMagnitude
335
+ );
321
336
  }
322
337
 
323
338
  return;
@@ -326,11 +341,6 @@
326
341
  ((Vector2)lhs.boundary.center - position).sqrMagnitude.CompareTo(
327
342
  ((Vector2)rhs.boundary.center - position).sqrMagnitude
328
343
  );
329
-
330
- int NearestComparison(T lhs, T rhs) =>
331
- ((Vector2)_elementTransformer(lhs).center - position).sqrMagnitude.CompareTo(
332
- ((Vector2)_elementTransformer(rhs).center - position).sqrMagnitude
333
- );
334
344
  }
335
345
  }
336
346
  }
@@ -19,7 +19,7 @@
19
19
  private StringWrapper(string value)
20
20
  {
21
21
  this.value = value;
22
- _hashCode = value?.GetHashCode() ?? 0;
22
+ _hashCode = value.GetHashCode();
23
23
  }
24
24
 
25
25
  public static StringWrapper Get(string value)
@@ -27,9 +27,9 @@
27
27
  return Cache.GetOrAdd(value, key => new StringWrapper(key));
28
28
  }
29
29
 
30
- public static void Remove(string value)
30
+ public static bool Remove(string value)
31
31
  {
32
- _ = Cache.TryRemove(value, out _);
32
+ return Cache.TryRemove(value, out _);
33
33
  }
34
34
 
35
35
  public bool Equals(StringWrapper other)
@@ -49,7 +49,7 @@
49
49
  return false;
50
50
  }
51
51
 
52
- return string.Equals(value, other.value);
52
+ return string.Equals(value, other.value, StringComparison.Ordinal);
53
53
  }
54
54
 
55
55
  public int CompareTo(StringWrapper other)
@@ -11,10 +11,23 @@
11
11
  {
12
12
  get
13
13
  {
14
- if (!_lastRead.HasValue || Helpers.HasEnoughTimePassed(_lastRead.Value, _cacheTtl))
14
+ if (!_lastRead.HasValue)
15
15
  {
16
16
  Reset();
17
17
  }
18
+ else if (
19
+ Helpers.HasEnoughTimePassed(
20
+ _lastRead.Value,
21
+ _cacheTtl + (_shouldUseJitter && !_usedJitter ? _jitterAmount : 0f)
22
+ )
23
+ )
24
+ {
25
+ if (_shouldUseJitter)
26
+ {
27
+ _usedJitter = true;
28
+ }
29
+ Reset();
30
+ }
18
31
 
19
32
  return _value;
20
33
  }
@@ -26,6 +39,10 @@
26
39
  private float? _lastRead;
27
40
  private T _value;
28
41
 
42
+ private bool _usedJitter;
43
+ private readonly bool _shouldUseJitter;
44
+ private readonly float _jitterAmount;
45
+
29
46
  public TimedCache(Func<T> valueProducer, float cacheTtl, bool useJitter = false)
30
47
  {
31
48
  _valueProducer =
@@ -36,10 +53,8 @@
36
53
  }
37
54
 
38
55
  _cacheTtl = cacheTtl;
39
- if (useJitter && 0 < _cacheTtl)
40
- {
41
- _cacheTtl += PRNG.Instance.NextFloat(_cacheTtl);
42
- }
56
+ _shouldUseJitter = useJitter;
57
+ _jitterAmount = useJitter ? PRNG.Instance.NextFloat(0f, cacheTtl) : 0f;
43
58
  }
44
59
 
45
60
  public void Reset()
@@ -85,5 +85,22 @@
85
85
  list[index] = last;
86
86
  list.RemoveAt(lastIndex);
87
87
  }
88
+
89
+ public static void InsertionSort<T, TComparer>(this IList<T> array, TComparer comparer)
90
+ where TComparer : struct, IComparer<T>
91
+ {
92
+ int arrayCount = array.Count;
93
+ for (int i = 1; i < arrayCount; ++i)
94
+ {
95
+ T key = array[i];
96
+ int j = i - 1;
97
+ while (j >= 0 && comparer.Compare(array[j], key) > 0)
98
+ {
99
+ array[j + 1] = array[j];
100
+ j--;
101
+ }
102
+ array[j + 1] = key;
103
+ }
104
+ }
88
105
  }
89
106
  }
@@ -4,19 +4,19 @@
4
4
 
5
5
  public static class FormattingHelpers
6
6
  {
7
+ private static readonly string[] ByteSizes = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
8
+
7
9
  public static string FormatBytes(long bytes)
8
10
  {
9
- string[] sizes = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
11
+ bytes = Math.Max(0L, bytes);
10
12
  double len = bytes;
11
13
  int order = 0;
12
14
 
13
- bytes = Math.Max(0, bytes);
14
-
15
15
  const int byteInChunk = 1024;
16
16
  while (byteInChunk <= len)
17
17
  {
18
18
  len /= byteInChunk;
19
- if (order < sizes.Length - 1)
19
+ if (order < ByteSizes.Length - 1)
20
20
  {
21
21
  ++order;
22
22
  }
@@ -26,7 +26,7 @@
26
26
  }
27
27
  }
28
28
 
29
- return $"{len:0.##} {sizes[order]}";
29
+ return $"{len:0.##} {ByteSizes[order]}";
30
30
  }
31
31
  }
32
32
  }
@@ -7,8 +7,8 @@
7
7
 
8
8
  public static class Objects
9
9
  {
10
- private const int HashBase = 839;
11
- private const int HashMultiplier = 4021;
10
+ private const int HashBase = 5556137;
11
+ private const int HashMultiplier = 95785853;
12
12
 
13
13
  public static T FromWeakReference<T>(WeakReference weakReference)
14
14
  where T : class
@@ -20,6 +20,7 @@
20
20
  public static Array CreateArray(Type type, int length)
21
21
  {
22
22
  return ArrayCreators
23
+ // ReSharper disable once ConvertClosureToMethodGroup
23
24
  .GetOrAdd(type, elementType => GetArrayCreator(elementType))
24
25
  .Invoke(length);
25
26
  }
@@ -28,6 +29,7 @@
28
29
  public static IList CreateList(Type elementType, int length)
29
30
  {
30
31
  return ListWithCapacityCreators
32
+ // ReSharper disable once ConvertClosureToMethodGroup
31
33
  .GetOrAdd(elementType, type => GetListWithCapacityCreator(type))
32
34
  .Invoke(length);
33
35
  }
@@ -35,6 +37,7 @@
35
37
  [MethodImpl(MethodImplOptions.AggressiveInlining)]
36
38
  public static IList CreateList(Type elementType)
37
39
  {
40
+ // ReSharper disable once ConvertClosureToMethodGroup
38
41
  return ListCreators.GetOrAdd(elementType, type => GetListCreator(type)).Invoke();
39
42
  }
40
43
 
@@ -44,7 +47,7 @@
44
47
  return field.GetValue;
45
48
  #else
46
49
  DynamicMethod dynamicMethod = new(
47
- $"Get{(field.DeclaringType?.Name ?? string.Empty)}{field.Name}",
50
+ $"Get{field.DeclaringType.Name}{field.Name}",
48
51
  typeof(object),
49
52
  new[] { typeof(object) },
50
53
  field.DeclaringType,
@@ -72,6 +75,41 @@
72
75
  #endif
73
76
  }
74
77
 
78
+ public static Func<object> GetStaticFieldGetter(FieldInfo field)
79
+ {
80
+ if (!field.IsStatic)
81
+ {
82
+ throw new ArgumentException(nameof(field));
83
+ }
84
+
85
+ #if WEB_GL
86
+ return () => field.GetValue(null);
87
+ #else
88
+ DynamicMethod dynamicMethod = new(
89
+ $"Get{field.DeclaringType.Name}{field.Name}",
90
+ typeof(object),
91
+ Type.EmptyTypes, // No parameters for static fields
92
+ field.DeclaringType,
93
+ true
94
+ );
95
+
96
+ ILGenerator il = dynamicMethod.GetILGenerator();
97
+
98
+ // Load the static field
99
+ il.Emit(OpCodes.Ldsfld, field);
100
+
101
+ // If the field's type is a value type, box it.
102
+ if (field.FieldType.IsValueType)
103
+ {
104
+ il.Emit(OpCodes.Box, field.FieldType);
105
+ }
106
+
107
+ il.Emit(OpCodes.Ret);
108
+
109
+ return (Func<object>)dynamicMethod.CreateDelegate(typeof(Func<object>));
110
+ #endif
111
+ }
112
+
75
113
  public static Func<TInstance, TValue> GetFieldGetter<TInstance, TValue>(FieldInfo field)
76
114
  {
77
115
  #if WEB_GL
@@ -142,6 +180,59 @@
142
180
  #endif
143
181
  }
144
182
 
183
+ public static Func<TValue> GetStaticFieldGetter<TValue>(FieldInfo field)
184
+ {
185
+ if (!field.IsStatic)
186
+ {
187
+ throw new ArgumentException(nameof(field));
188
+ }
189
+
190
+ #if WEB_GL
191
+ return Getter;
192
+ TValue Getter()
193
+ {
194
+ return (TValue)field.GetValue(null);
195
+ }
196
+ #else
197
+ DynamicMethod dynamicMethod = new(
198
+ $"GetGenericStatic{field.DeclaringType.Name}{field.Name}",
199
+ typeof(TValue),
200
+ Type.EmptyTypes, // no parameters needed for static fields
201
+ field.DeclaringType,
202
+ true
203
+ );
204
+
205
+ ILGenerator il = dynamicMethod.GetILGenerator();
206
+
207
+ // Load the static field.
208
+ il.Emit(OpCodes.Ldsfld, field);
209
+
210
+ // Handle conversion from the field type to TValue.
211
+ if (field.FieldType.IsValueType)
212
+ {
213
+ if (!typeof(TValue).IsValueType)
214
+ {
215
+ il.Emit(OpCodes.Box, field.FieldType);
216
+ }
217
+ }
218
+ else
219
+ {
220
+ if (typeof(TValue).IsValueType)
221
+ {
222
+ il.Emit(OpCodes.Unbox_Any, typeof(TValue));
223
+ }
224
+ else if (typeof(TValue) != field.FieldType)
225
+ {
226
+ il.Emit(OpCodes.Castclass, typeof(TValue));
227
+ }
228
+ }
229
+
230
+ il.Emit(OpCodes.Ret);
231
+
232
+ return (Func<TValue>)dynamicMethod.CreateDelegate(typeof(Func<TValue>));
233
+ #endif
234
+ }
235
+
145
236
  public static FieldSetter<TInstance, TValue> GetFieldSetter<TInstance, TValue>(
146
237
  FieldInfo field
147
238
  )
@@ -184,6 +275,36 @@
184
275
  #endif
185
276
  }
186
277
 
278
+ public static Action<TValue> GetStaticFieldSetter<TValue>(FieldInfo field)
279
+ {
280
+ if (!field.IsStatic)
281
+ {
282
+ throw new ArgumentException(nameof(field));
283
+ }
284
+ #if WEB_GL
285
+ return Setter;
286
+ void Setter(TValue newValue)
287
+ {
288
+ field.SetValue(null, newValue);
289
+ }
290
+ #else
291
+ DynamicMethod dynamicMethod = new(
292
+ $"SetFieldGenericStatic{field.DeclaringType.Name}{field.Name}",
293
+ typeof(void),
294
+ new[] { typeof(TValue) },
295
+ field.Module,
296
+ true
297
+ );
298
+
299
+ ILGenerator il = dynamicMethod.GetILGenerator();
300
+ il.Emit(OpCodes.Ldarg_0);
301
+ il.Emit(OpCodes.Stsfld, field);
302
+ il.Emit(OpCodes.Ret);
303
+
304
+ return (Action<TValue>)dynamicMethod.CreateDelegate(typeof(Action<TValue>));
305
+ #endif
306
+ }
307
+
187
308
  public static Action<object, object> GetFieldSetter(FieldInfo field)
188
309
  {
189
310
  #if WEB_GL
@@ -217,6 +338,40 @@
217
338
  #endif
218
339
  }
219
340
 
341
+ public static Action<object> GetStaticFieldSetter(FieldInfo field)
342
+ {
343
+ if (!field.IsStatic)
344
+ {
345
+ throw new ArgumentException(nameof(field));
346
+ }
347
+ #if WEB_GL
348
+ return value => field.SetValue(null, value);
349
+ #else
350
+ DynamicMethod dynamicMethod = new(
351
+ $"SetFieldStatic{field.DeclaringType.Name}{field.Name}",
352
+ null,
353
+ new[] { typeof(object) },
354
+ field.DeclaringType.Module,
355
+ true
356
+ );
357
+
358
+ ILGenerator il = dynamicMethod.GetILGenerator();
359
+
360
+ // Load the new value (argument 0)
361
+ il.Emit(OpCodes.Ldarg_0);
362
+ // Convert the object to the field's type (unbox or cast as needed)
363
+ il.Emit(
364
+ field.FieldType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass,
365
+ field.FieldType
366
+ );
367
+ // Set the static field
368
+ il.Emit(OpCodes.Stsfld, field);
369
+ il.Emit(OpCodes.Ret);
370
+
371
+ return (Action<object>)dynamicMethod.CreateDelegate(typeof(Action<object>));
372
+ #endif
373
+ }
374
+
220
375
  public static Func<int, Array> GetArrayCreator(Type elementType)
221
376
  {
222
377
  #if WEB_GL
@@ -3,13 +3,12 @@
3
3
  using Extension;
4
4
  using UnityEditor;
5
5
  using UnityEngine;
6
- using Utils;
7
6
 
8
7
  public static class SpriteHelpers
9
8
  {
10
9
  public static void MakeReadable(this Texture2D texture)
11
10
  {
12
- if (texture.isReadable)
11
+ if (texture == null || texture.isReadable)
13
12
  {
14
13
  return;
15
14
  }
@@ -29,58 +28,14 @@
29
28
  return;
30
29
  }
31
30
 
32
- tImporter.isReadable = true;
33
- EditorUtility.SetDirty(tImporter);
34
- tImporter.SaveAndReimport();
35
- EditorUtility.SetDirty(texture);
36
- #endif
37
- }
38
-
39
- public static void SetSpritePivot(string fullSpritePath, Vector2 pivot)
40
- {
41
- #if UNITY_EDITOR
42
- SetSpritePivot(AssetImporter.GetAtPath(fullSpritePath) as TextureImporter, pivot);
43
- #endif
44
- }
45
-
46
- public static void SetSpritePivot(Sprite sprite, Vector2 pivot)
47
- {
48
- #if UNITY_EDITOR
49
- SetSpritePivot(
50
- AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(sprite)) as TextureImporter,
51
- pivot
52
- );
53
- #endif
54
- }
55
-
56
- #if UNITY_EDITOR
57
- public static void SetSpritePivot(TextureImporter textureImporter, Vector2 pivot)
58
- {
59
- if (textureImporter == null)
31
+ if (!tImporter.isReadable)
60
32
  {
61
- return;
33
+ tImporter.isReadable = true;
34
+ EditorUtility.SetDirty(tImporter);
35
+ tImporter.SaveAndReimport();
36
+ EditorUtility.SetDirty(texture);
62
37
  }
63
-
64
- TextureImporterSettings textureImportSettings = new TextureImporterSettings();
65
- textureImporter.ReadTextureSettings(textureImportSettings);
66
- textureImportSettings.spriteAlignment = (int)SpriteAlignment.Custom;
67
- textureImportSettings.wrapMode = TextureWrapMode.Clamp;
68
- textureImportSettings.filterMode = FilterMode.Trilinear;
69
- textureImporter.SetTextureSettings(textureImportSettings);
70
-
71
- TextureImporterPlatformSettings importerSettings = new TextureImporterPlatformSettings
72
- {
73
- resizeAlgorithm = TextureResizeAlgorithm.Bilinear,
74
- maxTextureSize = SetTextureImportData.RegularTextureSize,
75
- textureCompression = TextureImporterCompression.Compressed,
76
- format = TextureImporterFormat.Automatic,
77
- };
78
-
79
- textureImporter.SetPlatformTextureSettings(importerSettings);
80
- textureImporter.isReadable = true;
81
- textureImporter.spritePivot = pivot;
82
- textureImporter.SaveAndReimport();
83
- }
84
38
  #endif
39
+ }
85
40
  }
86
41
  }
@@ -125,12 +125,12 @@
125
125
  if (0 < direction.x)
126
126
  {
127
127
  float t2 = (max.x - center.x) / direction.x;
128
- tMax = Math.Min(tMax, t2);
128
+ tMax = Mathf.Min(tMax, t2);
129
129
  }
130
130
  else
131
131
  {
132
132
  float t1 = (min.x - center.x) / direction.x;
133
- tMax = Math.Min(tMax, t1);
133
+ tMax = Mathf.Min(tMax, t1);
134
134
  }
135
135
  }
136
136
 
@@ -139,12 +139,12 @@
139
139
  if (direction.y > 0)
140
140
  {
141
141
  float t2 = (max.y - center.y) / direction.y;
142
- tMax = Math.Min(tMax, t2);
142
+ tMax = Mathf.Min(tMax, t2);
143
143
  }
144
144
  else
145
145
  {
146
146
  float t1 = (min.y - center.y) / direction.y;
147
- tMax = Math.Min(tMax, t1);
147
+ tMax = Mathf.Min(tMax, t1);
148
148
  }
149
149
  }
150
150
 
@@ -160,7 +160,7 @@
160
160
 
161
161
  public static bool Approximately(this float lhs, float rhs, float tolerance = 0.045f)
162
162
  {
163
- return Math.Abs(lhs - rhs) <= tolerance;
163
+ return Mathf.Abs(lhs - rhs) <= tolerance;
164
164
  }
165
165
  }
166
166
  }
@@ -45,12 +45,20 @@
45
45
 
46
46
  protected virtual void Start()
47
47
  {
48
- if (_instance != null && _instance != this)
48
+ if (_instance == null || _instance == this)
49
49
  {
50
- this.LogError(
51
- $"Double singleton detected, {_instance.name} conflicts with {name}."
52
- );
53
- gameObject.Destroy();
50
+ return;
51
+ }
52
+
53
+ this.LogError($"Double singleton detected, {_instance.name} conflicts with {name}.");
54
+ gameObject.Destroy();
55
+ }
56
+
57
+ protected virtual void OnDestroy()
58
+ {
59
+ if (_instance == this)
60
+ {
61
+ _instance = null;
54
62
  }
55
63
  }
56
64
  }