com.wallstop-studios.unity-helpers 2.0.0-rc25 → 2.0.0-rc26

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/README.md CHANGED
@@ -10,3 +10,91 @@ Various Unity Helpers. Includes many deterministic, seedable random number gener
10
10
  - URL: `https://registry.npmjs.org`
11
11
  - Scope(s): `com.wallstop-studios.unity-helpers`
12
12
  5. Resolve the latest `com.wallstop-studios.unity-helpers`
13
+
14
+ # Package Contents
15
+ - Random Number Generators
16
+ - Spatial Trees
17
+ - Protobuf, Binary, and JSON formatting
18
+ - A resizable CyclicBuffer
19
+ - Simple single-threaded thread pool
20
+ - A LayeredImage for use with Unity's UI Toolkit
21
+ - Geometry Helpers
22
+ - Child/Parent/Sibling Attributes to automatically get components
23
+ - ReadOnly attribute to disable editing of serialized properties in the inspector
24
+ - An extensive collection of helpers
25
+ - Simple math functions including a generic Range
26
+ - Common buffers to reduce allocations
27
+ - A RuntimeSingleton implementation for automatic creation/accessing of singletons
28
+ - String helpers, like converting to PascalCase, like Unity does for variable names in the inspector
29
+ - A randomizable PerlinNoise implementation
30
+ - And more!
31
+
32
+ # Random Number Generators
33
+ This package implements several high quality, seedable, and serializable random number generators. The best one (currently) is the PCG Random. This has been hidden behind the `PRNG.Instance` class, which is thread-safe. As the package evolves, the exact implementation of this may change.
34
+
35
+ All of these implement a custom [IRandom](./Runtime/Core/Random/IRandom.cs) interface with a significantly richer suite of methods than the standard .Net and Unity randoms offer.
36
+
37
+ To use:
38
+
39
+ ```csharp
40
+ IRandom random = PRNG.Instance;
41
+
42
+ random.NextFloat(); // Something between 0.0f and 1.0f
43
+ random.NextDouble(); // Something between 0.0d and 1.0d
44
+ random.Next(); // Something between 0 and int.MaxValue
45
+ random.NextUint(); // Something between 0 and uint.MaxValue
46
+
47
+ int [] values = {1, 2, 3};
48
+ random.NextOf(values); // 1, 2, or 3
49
+ random.NextOf(Enumerable.Range(0, 3)); // 1, 2, or 3
50
+ HashSet<int> setValues = new() {1, 2, 3};
51
+ random.NextOf(setValues); // 1, 2, or 3
52
+
53
+ random.NextGuid(); // A valid UUIDv4
54
+ random.NextGaussian(); // A value sampled from a gaussian curve around mean=0, stdDev=1 (configurable via parameters)
55
+ random.NextEnum<T>(); // A randomly selected enum of type T
56
+
57
+ int width = 100;
58
+ int height = 100;
59
+ random.NextNoiseMap(width, height); // A configurable noise map generated using random octave offsets
60
+ ```
61
+
62
+ ## Implemented Random Number Generators
63
+ - PCG
64
+ - DotNet (uses the currently implemented .Net Random)
65
+ - RomoDuo
66
+ - SplitMix64
67
+ - Squirrel
68
+ - System (uses a port of the Windows .Net Random)
69
+ - Unity (uses Unity's random under the hood)
70
+ - Wy
71
+ - XorShift
72
+ - XorShiro
73
+
74
+ # Spatial Trees
75
+ There are three implemented 2D immutable spatial trees that can store generic objects, as long as there is some resolution function that can convert them into Vector2 spatial positions.
76
+
77
+ - QuadTree (easiest to use)
78
+ - KDTree
79
+ - RTree
80
+
81
+ Spatial trees, after construction, allow for O(log(n)) spatial query time instead of O(n). They are extremely useful if you need repeated spatial queries, or if you have relatively static spatial data.
82
+
83
+ ## Usage
84
+
85
+ ```csharp
86
+ GameObject [] spatialStorage = { myCoolGameObject };
87
+ QuadTree<GameObject> quadTree = new(spatialStorage, go => go.transform.position);
88
+
89
+ // Might return your object, might not
90
+ GameObject [] inBounds = quadTree.GetElementsInBounds(new Bounds(0, 0, 100, 100));
91
+
92
+ // Uses a "good-enough" nearest-neighbor approximately for cheap neighbors
93
+ List<GameObject> nearestNeighbors = new();
94
+ quadTree.GetApproximateNearestNeighbors(myCoolGameObject.transform.position, 1, nearestNeighbors);
95
+ Assert.AreEqual(1, nearestNeighbors.Count);
96
+ Assert.AreEqual(myCoolGameObject, nearestNeighbors[0]);
97
+ ```
98
+
99
+ ## Note
100
+ All spatial trees expect the positional data to be *immutable*. It is very important that the positions do not change. If they do, you will need to reconstruct the tree.
@@ -95,19 +95,26 @@
95
95
 
96
96
  public void Resize(int newCapacity)
97
97
  {
98
+ if (newCapacity == Capacity)
99
+ {
100
+ return;
101
+ }
102
+
98
103
  if (newCapacity < 0)
99
104
  {
100
105
  throw new ArgumentException(nameof(newCapacity));
101
106
  }
102
107
 
108
+ int oldCapacity = Capacity;
103
109
  Capacity = newCapacity;
104
110
  _buffer.Shift(-_position);
105
111
  if (newCapacity < _buffer.Count)
106
112
  {
107
113
  _buffer.RemoveRange(newCapacity, _buffer.Count - newCapacity);
108
- _position = 0;
109
114
  }
110
115
 
116
+ _position =
117
+ newCapacity < oldCapacity && newCapacity <= _buffer.Count ? 0 : _buffer.Count;
111
118
  Count = Math.Min(newCapacity, Count);
112
119
  }
113
120
 
@@ -1,5 +1,6 @@
1
1
  namespace UnityHelpers.Core.Extension
2
2
  {
3
+ using System;
3
4
  using System.Collections.Generic;
4
5
  using Helper;
5
6
  using Random;
@@ -48,6 +49,15 @@
48
49
 
49
50
  public static void Reverse<T>(this IList<T> list, int start, int end)
50
51
  {
52
+ if (start < 0 || list.Count <= start)
53
+ {
54
+ throw new ArgumentException(nameof(start));
55
+ }
56
+ if (end < 0 || list.Count <= end)
57
+ {
58
+ throw new ArgumentException(nameof(end));
59
+ }
60
+
51
61
  while (start < end)
52
62
  {
53
63
  (list[start], list[end]) = (list[end], list[start]);
@@ -244,6 +244,11 @@
244
244
  Assert.AreEqual(newCapacity, newValues.Length);
245
245
  Assert.That(values.Take(newCapacity), Is.EqualTo(newValues));
246
246
 
247
+ buffer.Add(1);
248
+ buffer.Add(2);
249
+ int[] afterAddition = buffer.ToArray();
250
+ Assert.That(afterAddition, Is.EqualTo(newValues.Skip(2).Concat(new[] { 1, 2 })));
251
+
247
252
  newCapacity = 0;
248
253
  buffer.Resize(newCapacity);
249
254
  newValues = buffer.ToArray();
@@ -277,6 +282,37 @@
277
282
  Assert.AreEqual(Math.Min(filled, newCapacity), newValues.Length);
278
283
  Assert.That(values.Take(newCapacity), Is.EqualTo(newValues));
279
284
 
285
+ buffer.Add(1);
286
+ buffer.Add(2);
287
+ int[] afterAddition = buffer.ToArray();
288
+ if (newCapacity <= filled)
289
+ {
290
+ Assert.That(
291
+ afterAddition,
292
+ Is.EqualTo(newValues.Skip(2).Concat(new[] { 1, 2 })),
293
+ $"Resize failed for iteration {i}, fillPercent {fillPercent:0.00}, capacityPercent: {capacityPercent:0.00}. "
294
+ + $"Capacity: {capacity}, newCapacity: {newCapacity}, filled: {filled}."
295
+ );
296
+ }
297
+ else if (newCapacity == filled + 1)
298
+ {
299
+ Assert.That(
300
+ afterAddition,
301
+ Is.EqualTo(newValues.Skip(1).Concat(new[] { 1, 2 })),
302
+ $"Resize failed for iteration {i}, fillPercent {fillPercent:0.00}, capacityPercent: {capacityPercent:0.00}. "
303
+ + $"Capacity: {capacity}, newCapacity: {newCapacity}, filled: {filled}."
304
+ );
305
+ }
306
+ else
307
+ {
308
+ Assert.That(
309
+ afterAddition,
310
+ Is.EqualTo(newValues.Concat(new[] { 1, 2 })),
311
+ $"Resize failed for iteration {i}, fillPercent {fillPercent:0.00}, capacityPercent: {capacityPercent:0.00}. "
312
+ + $"Capacity: {capacity}, newCapacity: {newCapacity}, filled: {filled}."
313
+ );
314
+ }
315
+
280
316
  newCapacity = 0;
281
317
  buffer.Resize(newCapacity);
282
318
  newValues = buffer.ToArray();
@@ -0,0 +1,76 @@
1
+ namespace UnityHelpers.Tests.Extensions
2
+ {
3
+ using System;
4
+ using System.Linq;
5
+ using Core.Extension;
6
+ using NUnit.Framework;
7
+
8
+ public sealed class IListExtensionTests
9
+ {
10
+ [Test]
11
+ public void ShiftLeft()
12
+ {
13
+ int[] input = Enumerable.Range(0, 10).ToArray();
14
+ for (int i = 0; i < input.Length * 2; ++i)
15
+ {
16
+ int[] shifted = input.ToArray();
17
+ shifted.Shift(-1 * i);
18
+ Assert.That(
19
+ input.Skip(i % input.Length).Concat(input.Take(i % input.Length)),
20
+ Is.EqualTo(shifted)
21
+ );
22
+ }
23
+ }
24
+
25
+ [Test]
26
+ public void ShiftRight()
27
+ {
28
+ int[] input = Enumerable.Range(0, 10).ToArray();
29
+ for (int i = 0; i < input.Length * 2; ++i)
30
+ {
31
+ int[] shifted = input.ToArray();
32
+ shifted.Shift(i);
33
+ Assert.That(
34
+ input
35
+ .Skip((input.Length * 3 - i) % input.Length)
36
+ .Concat(input.Take((input.Length * 3 - i) % input.Length)),
37
+ Is.EqualTo(shifted),
38
+ $"Shift failed for amount {i}."
39
+ );
40
+ }
41
+ }
42
+
43
+ [Test]
44
+ public void Reverse()
45
+ {
46
+ int[] input = Enumerable.Range(0, 10).ToArray();
47
+ for (int i = 0; i < input.Length; ++i)
48
+ {
49
+ int[] shifted = input.ToArray();
50
+ shifted.Reverse(0, i);
51
+ Assert.That(
52
+ input.Take(i + 1).Reverse().Concat(input.Skip(i + 1)),
53
+ Is.EqualTo(shifted),
54
+ $"Reverse failed for reversal from [0, {i}]."
55
+ );
56
+ }
57
+
58
+ // TODO
59
+ }
60
+
61
+ [Test]
62
+ public void ReverseInvalidArguments()
63
+ {
64
+ int[] input = Enumerable.Range(0, 10).ToArray();
65
+ Assert.Throws<ArgumentException>(() => input.Reverse(-1, 1));
66
+ Assert.Throws<ArgumentException>(() => input.Reverse(input.Length, 1));
67
+ Assert.Throws<ArgumentException>(() => input.Reverse(int.MaxValue, 1));
68
+ Assert.Throws<ArgumentException>(() => input.Reverse(int.MinValue, 1));
69
+
70
+ Assert.Throws<ArgumentException>(() => input.Reverse(1, -1));
71
+ Assert.Throws<ArgumentException>(() => input.Reverse(1, input.Length));
72
+ Assert.Throws<ArgumentException>(() => input.Reverse(1, int.MaxValue));
73
+ Assert.Throws<ArgumentException>(() => input.Reverse(1, int.MinValue));
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 53f10c10d1a14859a9a8616477fd318a
3
+ timeCreated: 1741982863
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.wallstop-studios.unity-helpers",
3
- "version": "2.0.0-rc25",
3
+ "version": "2.0.0-rc26",
4
4
  "displayName": "Unity Helpers",
5
5
  "description": "Various Unity Helper Library",
6
6
  "dependencies": {},