com.wallstop-studios.unity-helpers 2.0.0-rc07 → 2.0.0-rc08

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.
@@ -9,7 +9,10 @@
9
9
 
10
10
  public static class DirectionExtensions
11
11
  {
12
- private static readonly List<Direction> Directions = Enum.GetValues(typeof(Direction)).OfType<Direction>().Except(Enumerables.Of(Direction.None)).ToList();
12
+ private static readonly Direction[] Directions = Enum.GetValues(typeof(Direction))
13
+ .OfType<Direction>()
14
+ .Except(Enumerables.Of(Direction.None))
15
+ .ToArray();
13
16
 
14
17
  public static Direction Opposite(this Direction direction)
15
18
  {
@@ -106,7 +109,7 @@
106
109
 
107
110
  public static Direction AsDirection(this Vector2 vector, bool preferAngles = false)
108
111
  {
109
- if (vector.x == 0 && vector.y == 0)
112
+ if (vector == Vector2.zero)
110
113
  {
111
114
  return Direction.None;
112
115
  }
@@ -1,15 +1,20 @@
1
1
  namespace UnityHelpers.Core.Extension
2
2
  {
3
- using Random;
4
3
  using System;
5
4
  using System.Collections.Concurrent;
6
5
  using System.Collections.Generic;
7
6
  using System.Linq;
7
+ using Random;
8
8
 
9
9
  public static class IEnumerableExtensions
10
10
  {
11
11
  private static readonly ConcurrentDictionary<object, object> ComparerCache = new();
12
12
 
13
+ public static LinkedList<T> ToLinkedList<T>(this IEnumerable<T> source)
14
+ {
15
+ return new LinkedList<T>(source);
16
+ }
17
+
13
18
  public static IList<T> AsList<T>(this IEnumerable<T> enumeration)
14
19
  {
15
20
  if (enumeration is IList<T> list)
@@ -20,18 +25,27 @@
20
25
  return enumeration.ToList();
21
26
  }
22
27
 
23
- public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> enumeration, Func<T, T, int> comparer)
28
+ public static IEnumerable<T> OrderBy<T>(
29
+ this IEnumerable<T> enumeration,
30
+ Func<T, T, int> comparer
31
+ )
24
32
  {
25
- FuncBasedComparer<T> comparerObject = (FuncBasedComparer<T>) ComparerCache.GetOrAdd(comparer, () => new FuncBasedComparer<T>(comparer));
33
+ FuncBasedComparer<T> comparerObject =
34
+ (FuncBasedComparer<T>)
35
+ ComparerCache.GetOrAdd(comparer, () => new FuncBasedComparer<T>(comparer));
26
36
  return enumeration.OrderBy(_ => _, comparerObject);
27
37
  }
28
38
 
29
- public static IEnumerable<T> Ordered<T>(this IEnumerable<T> enumerable) where T : IComparable
39
+ public static IEnumerable<T> Ordered<T>(this IEnumerable<T> enumerable)
40
+ where T : IComparable
30
41
  {
31
42
  return enumerable.OrderBy(_ => _);
32
43
  }
33
44
 
34
- public static IEnumerable<T> Shuffled<T>(this IEnumerable<T> enumerable, IRandom random = null)
45
+ public static IEnumerable<T> Shuffled<T>(
46
+ this IEnumerable<T> enumerable,
47
+ IRandom random = null
48
+ )
35
49
  {
36
50
  random = random ?? ThreadLocalRandom<PcgRandom>.Instance;
37
51
  return enumerable.OrderBy(_ => random.Next());
@@ -90,7 +104,6 @@
90
104
  return list;
91
105
  }
92
106
 
93
-
94
107
  private class FuncBasedComparer<T> : IComparer<T>
95
108
  {
96
109
  private readonly Func<T, T, int> _comparer;
@@ -1,8 +1,5 @@
1
1
  namespace UnityHelpers.Core.Extension
2
2
  {
3
- using System;
4
- using System.Collections.Generic;
5
- using System.Linq;
6
3
  using Helper;
7
4
  using Random;
8
5
  using UnityEngine;
@@ -14,15 +11,6 @@
14
11
  return random.NextVector2(-amplitude, amplitude);
15
12
  }
16
13
 
17
- public static Vector2 NextVector2InRange(
18
- this IRandom random,
19
- float range,
20
- Vector2? origin = null
21
- )
22
- {
23
- return Helpers.GetRandomPointInCircle(origin ?? Vector2.zero, range, random);
24
- }
25
-
26
14
  public static Vector2 NextVector2(
27
15
  this IRandom random,
28
16
  float minAmplitude,
@@ -34,6 +22,15 @@
34
22
  return new Vector2(x, y);
35
23
  }
36
24
 
25
+ public static Vector2 NextVector2InRange(
26
+ this IRandom random,
27
+ float range,
28
+ Vector2? origin = null
29
+ )
30
+ {
31
+ return Helpers.GetRandomPointInCircle(origin ?? Vector2.zero, range, random);
32
+ }
33
+
37
34
  public static Vector3 NextVector3(this IRandom random, float amplitude)
38
35
  {
39
36
  return random.NextVector3(-amplitude, amplitude);
@@ -50,80 +47,5 @@
50
47
  result.z = z;
51
48
  return result;
52
49
  }
53
-
54
- public static T NextEnum<T>(this IRandom random)
55
- where T : struct
56
- {
57
- T[] enumValues = (T[])Enum.GetValues(typeof(T));
58
- if (enumValues.Length == 0)
59
- {
60
- return default(T);
61
- }
62
-
63
- if (enumValues.Length == 1)
64
- {
65
- return enumValues[0];
66
- }
67
-
68
- if (enumValues.Length == 2)
69
- {
70
- return random.NextBool() ? enumValues[0] : enumValues[1];
71
- }
72
-
73
- int nextIndex = random.Next(0, enumValues.Length);
74
- return enumValues[nextIndex];
75
- }
76
-
77
- public static T Next<T>(this IRandom random, IList<T> elements)
78
- {
79
- if (ReferenceEquals(elements, null) || elements.Count == 0)
80
- {
81
- return default(T);
82
- }
83
-
84
- switch (elements.Count)
85
- {
86
- case 1:
87
- return elements[0];
88
- case 2:
89
- return random.NextBool() ? elements[0] : elements[1];
90
- default:
91
- int index = random.Next(0, elements.Count);
92
- return elements[index];
93
- }
94
- }
95
-
96
- public static T Next<T>(this IRandom random, IEnumerable<T> elements)
97
- {
98
- if (ReferenceEquals(elements, null))
99
- {
100
- return default(T);
101
- }
102
-
103
- IList<T> elementsList = elements as IList<T>;
104
- if (!ReferenceEquals(elementsList, null))
105
- {
106
- return Next(random, elementsList);
107
- }
108
-
109
- ICollection<T> maybeCollection = elements as ICollection<T>;
110
- if (!ReferenceEquals(maybeCollection, null))
111
- {
112
- int count = maybeCollection.Count;
113
- int randomIndex = random.Next(0, count);
114
-
115
- int i = 0;
116
- foreach (T element in maybeCollection)
117
- {
118
- if (i++ == randomIndex)
119
- {
120
- return element;
121
- }
122
- }
123
- }
124
-
125
- elementsList = elements.ToArray();
126
- return Next(random, elementsList);
127
- }
128
50
  }
129
51
  }
@@ -266,7 +266,7 @@
266
266
  return convexHull;
267
267
  }
268
268
 
269
- Vector3Int nextPoint = random.Next(points);
269
+ Vector3Int nextPoint = random.NextOf(points);
270
270
  Vector2 currentPointWorldPosition = CellToWorld(currentPoint);
271
271
  Vector2 nextPointWorldPosition = CellToWorld(nextPoint);
272
272
  foreach (Vector3Int point in points)
@@ -389,7 +389,7 @@
389
389
  return convexHull;
390
390
  }
391
391
 
392
- FastVector3Int nextPoint = random.Next(points);
392
+ FastVector3Int nextPoint = random.NextOf(points);
393
393
  Vector2 currentPointWorldPosition = CellToWorld(currentPoint);
394
394
  Vector2 nextPointWorldPosition = CellToWorld(nextPoint);
395
395
  foreach (FastVector3Int point in points)
@@ -55,102 +55,6 @@
55
55
  return unchecked((int)(min + NextUint(range)));
56
56
  }
57
57
 
58
- public T Next<T>(IEnumerable<T> enumerable)
59
- {
60
- if (enumerable is ICollection<T> collection)
61
- {
62
- return Next(collection);
63
- }
64
-
65
- return Next((IReadOnlyList<T>)enumerable.ToList());
66
- }
67
-
68
- public T Next<T>(ICollection<T> collection)
69
- {
70
- int count = collection.Count;
71
- if (count <= 0)
72
- {
73
- throw new ArgumentException("Collection size cannot be less-than or equal-to 0");
74
- }
75
-
76
- switch (collection)
77
- {
78
- case IList<T> list:
79
- return Next(list);
80
- case IReadOnlyList<T> readOnlyList:
81
- return Next(readOnlyList);
82
- }
83
-
84
- int index = Next(count);
85
- int i = 0;
86
- foreach (T element in collection)
87
- {
88
- if (i++ == index)
89
- {
90
- return element;
91
- }
92
- }
93
-
94
- // Should never happen
95
- return default;
96
- }
97
-
98
- public T Next<T>(IList<T> list)
99
- {
100
- if (ReferenceEquals(list, null))
101
- {
102
- throw new ArgumentNullException(nameof(list));
103
- }
104
-
105
- /*
106
- For small lists, it's much more efficient to simply return one of their elements
107
- instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
108
- */
109
- switch (list.Count)
110
- {
111
- case 1:
112
- return list[0];
113
- case 2:
114
- return NextBool() ? list[0] : list[1];
115
- default:
116
- return list[Next(list.Count)];
117
- }
118
- }
119
-
120
- private T Next<T>(IReadOnlyList<T> list)
121
- {
122
- /*
123
- For small lists, it's much more efficient to simply return one of their elements
124
- instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
125
- */
126
- switch (list.Count)
127
- {
128
- case 1:
129
- return list[0];
130
- case 2:
131
- return NextBool() ? list[0] : list[1];
132
- default:
133
- return list[Next(list.Count)];
134
- }
135
- }
136
-
137
- public T Next<T>()
138
- where T : struct, Enum
139
- {
140
- Type enumType = typeof(T);
141
- T[] enumValues;
142
- if (EnumTypeCache.TryGetValue(enumType, out Array enumArray))
143
- {
144
- enumValues = (T[])enumArray;
145
- }
146
- else
147
- {
148
- enumValues = (T[])Enum.GetValues(enumType);
149
- }
150
-
151
- return RandomOf(enumValues);
152
- }
153
-
154
58
  // Internal sampler
155
59
  public abstract uint NextUint();
156
60
 
@@ -212,7 +116,7 @@
212
116
  uint lower = NextUint();
213
117
  unchecked
214
118
  {
215
- return (long)((((ulong)upper << 32) | lower) & (0x1UL << 63));
119
+ return (long)((((ulong)upper << 32) | lower) & 0x7FFFFFFFFFFFFFFF);
216
120
  }
217
121
  }
218
122
 
@@ -275,34 +179,36 @@
275
179
 
276
180
  public void NextBytes(byte[] buffer)
277
181
  {
278
- if (ReferenceEquals(buffer, null))
182
+ if (buffer == null)
279
183
  {
280
184
  throw new ArgumentException(nameof(buffer));
281
185
  }
282
186
 
283
- const byte sizeOfInt = sizeof(int); // May differ on some platforms
187
+ const int sizeOfInt = 4; // May differ on some platforms
284
188
 
285
189
  // See how many ints we can slap into it.
286
190
  int chunks = buffer.Length / sizeOfInt;
287
- byte spare = unchecked((byte)(buffer.Length - (chunks * sizeOfInt)));
191
+ int spare = buffer.Length - chunks * sizeOfInt;
288
192
  for (int i = 0; i < chunks; ++i)
289
193
  {
290
- int offset = i * chunks;
291
- int random = Next();
292
- buffer[offset] = unchecked((byte)(random & 0xFF000000));
293
- buffer[offset + 1] = unchecked((byte)(random & 0x00FF0000));
294
- buffer[offset + 2] = unchecked((byte)(random & 0x0000FF00));
295
- buffer[offset + 3] = unchecked((byte)(random & 0x000000FF));
194
+ int offset = i * sizeOfInt;
195
+ uint random = NextUint();
196
+ for (int j = 0; j < sizeOfInt; ++j)
197
+ {
198
+ buffer[offset + j] = unchecked(
199
+ (byte)((random >> (j * sizeOfInt)) & 0x000000FF)
200
+ );
201
+ }
296
202
  }
297
203
 
204
+ if (0 < spare)
298
205
  {
299
- /*
300
- This could be implemented more optimally by generating a single int and
301
- bit shifting along the position, but that is too much for me right now.
302
- */
303
- for (byte i = 0; i < spare; ++i)
206
+ uint spareRandom = NextUint();
207
+ for (int i = 0; i < spare; ++i)
304
208
  {
305
- buffer[buffer.Length - 1 - i] = unchecked((byte)Next());
209
+ buffer[buffer.Length - 1 - i] = unchecked(
210
+ (byte)((spareRandom >> (i * sizeOfInt)) & 0x000000FF)
211
+ );
306
212
  }
307
213
  }
308
214
  }
@@ -343,7 +249,7 @@
343
249
  return NextDoubleWithInfiniteRange(min, max);
344
250
  }
345
251
 
346
- return min + (NextDouble() * range);
252
+ return min + NextDouble() * range;
347
253
  }
348
254
 
349
255
  protected double NextDoubleWithInfiniteRange(double min, double max)
@@ -408,7 +314,7 @@
408
314
  x = 2 * NextDouble() - 1;
409
315
  y = 2 * NextDouble() - 1;
410
316
  square = x * x + y * y;
411
- } while (square == 0 || 1 < square);
317
+ } while (square is 0 or > 1);
412
318
 
413
319
  double fac = Math.Sqrt(-2 * Math.Log(square) / square);
414
320
  _cachedGaussian = x * fac;
@@ -454,7 +360,53 @@
454
360
  return min + NextFloat(range);
455
361
  }
456
362
 
457
- public T NextCachedEnum<T>()
363
+ public T NextOf<T>(IEnumerable<T> enumerable)
364
+ {
365
+ return enumerable switch
366
+ {
367
+ IReadOnlyList<T> list => NextOf(list),
368
+ IReadOnlyCollection<T> collection => NextOf(collection),
369
+ null => throw new ArgumentNullException(nameof(enumerable)),
370
+ _ => NextOf(enumerable.ToArray()),
371
+ };
372
+ }
373
+
374
+ public T NextOf<T>(IReadOnlyCollection<T> collection)
375
+ {
376
+ if (collection is not { Count: > 0 })
377
+ {
378
+ throw new ArgumentException("Collection cannot be empty");
379
+ }
380
+
381
+ if (collection is IReadOnlyList<T> list)
382
+ {
383
+ return NextOf(list);
384
+ }
385
+
386
+ int index = Next(collection.Count);
387
+ return collection.ElementAt(index);
388
+ }
389
+
390
+ public T NextOf<T>(IReadOnlyList<T> list)
391
+ {
392
+ if (list is not { Count: > 0 })
393
+ {
394
+ throw new ArgumentNullException(nameof(list));
395
+ }
396
+
397
+ /*
398
+ For small lists, it's much more efficient to simply return one of their elements
399
+ instead of trying to generate a random number within bounds (which is implemented as a while(true) loop)
400
+ */
401
+ return list.Count switch
402
+ {
403
+ 1 => list[0],
404
+ 2 => NextBool() ? list[0] : list[1],
405
+ _ => list[Next(list.Count)],
406
+ };
407
+ }
408
+
409
+ public T NextEnum<T>()
458
410
  where T : struct, Enum
459
411
  {
460
412
  Type enumType = typeof(T);
@@ -479,7 +431,13 @@
479
431
 
480
432
  // Advances the RNG
481
433
  // https://code2d.wordpress.com/2020/07/21/perlin-noise/
482
- public float[,] NextNoiseMap(int width, int height, float scale = 2.5f, int octaves = 8)
434
+ public float[,] NextNoiseMap(
435
+ int width,
436
+ int height,
437
+ PerlinNoise noise = null,
438
+ float scale = 2.5f,
439
+ int octaves = 8
440
+ )
483
441
  {
484
442
  if (width <= 0)
485
443
  {
@@ -501,6 +459,7 @@
501
459
  throw new ArgumentException(nameof(octaves));
502
460
  }
503
461
 
462
+ noise ??= PerlinNoise.Instance;
504
463
  float[,] noiseMap = new float[width, height];
505
464
 
506
465
  Vector2[] octaveOffsets = new Vector2[octaves];
@@ -529,8 +488,7 @@
529
488
  float sampleX = (x - halfWidth) / scale * frequency + octaveOffsets[i].x;
530
489
  float sampleY = (y - halfHeight) / scale * frequency + octaveOffsets[i].y;
531
490
 
532
- // Use unity's implementation of perlin noise
533
- float perlinValue = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1;
491
+ float perlinValue = noise.Noise(sampleX, sampleY) * 2 - 1;
534
492
  noiseHeight += perlinValue * amplitude;
535
493
  }
536
494
 
@@ -565,17 +523,13 @@
565
523
 
566
524
  protected T RandomOf<T>(T[] values)
567
525
  {
568
- switch (values.Length)
526
+ return values.Length switch
569
527
  {
570
- case 0:
571
- return default;
572
- case 1:
573
- return values[0];
574
- case 2:
575
- return NextBool() ? values[0] : values[1];
576
- default:
577
- return values[Next(values.Length)];
578
- }
528
+ 0 => default,
529
+ 1 => values[0],
530
+ 2 => NextBool() ? values[0] : values[1],
531
+ _ => values[Next(values.Length)],
532
+ };
579
533
  }
580
534
 
581
535
  public abstract IRandom Copy();
@@ -27,10 +27,12 @@
27
27
  /// </summary>
28
28
  /// <returns>A number within the range [0, uint.MaxValue].</returns>
29
29
  uint NextUint();
30
+
30
31
  /// <summary>
31
32
  /// </summary>
32
33
  /// <returns>A number within the range [0, max).</returns>
33
34
  uint NextUint(uint max);
35
+
34
36
  /// <summary>
35
37
  /// </summary>
36
38
  /// <returns>A number within the range [min, max).</returns>
@@ -45,6 +47,7 @@
45
47
  /// </summary>
46
48
  /// <returns>A number within the range [0, max).</returns>
47
49
  short NextShort(short max);
50
+
48
51
  /// <summary>
49
52
  /// </summary>
50
53
  /// <returns>A number within the range [min, max).</returns>
@@ -54,10 +57,12 @@
54
57
  /// </summary>
55
58
  /// <returns>A number within the range [0, byte.MaxValue).</returns>
56
59
  byte NextByte();
60
+
57
61
  /// <summary>
58
62
  /// </summary>
59
63
  /// <returns>A number within the range [0, max).</returns>
60
64
  byte NextByte(byte max);
65
+
61
66
  /// <summary>
62
67
  /// </summary>
63
68
  /// <returns>A number within the range [min, max).</returns>
@@ -67,10 +72,12 @@
67
72
  /// </summary>
68
73
  /// <returns>A number within the range [0, long.MaxValue).</returns>
69
74
  long NextLong();
75
+
70
76
  /// <summary>
71
77
  /// </summary>
72
78
  /// <returns>A number within the range [0, max).</returns>
73
79
  long NextLong(long max);
80
+
74
81
  /// <summary>
75
82
  /// </summary>
76
83
  /// <returns>A number within the range [min, max).</returns>
@@ -80,10 +87,12 @@
80
87
  /// </summary>
81
88
  /// <returns>A number within the range [0, ulong.MaxValue).</returns>
82
89
  ulong NextUlong();
90
+
83
91
  /// <summary>
84
92
  /// </summary>
85
93
  /// <returns>A number within the range [0, max).</returns>
86
94
  ulong NextUlong(ulong max);
95
+
87
96
  /// <summary>
88
97
  /// </summary>
89
98
  /// <returns>A number within the range [min, max).</returns>
@@ -100,10 +109,12 @@
100
109
  /// </summary>
101
110
  /// <returns>A number within the range [0, 1).</returns>
102
111
  float NextFloat();
112
+
103
113
  /// <summary>
104
114
  /// </summary>
105
115
  /// <returns>A number within the range [0, max).</returns>
106
116
  float NextFloat(float max);
117
+
107
118
  /// <summary>
108
119
  /// </summary>
109
120
  /// <returns>A number within the range min, max).</returns>
@@ -113,10 +124,12 @@
113
124
  /// </summary>
114
125
  /// <returns>A number within the range [0, 1).</returns>
115
126
  double NextDouble();
127
+
116
128
  /// <summary>
117
129
  /// </summary>
118
130
  /// <returns>A number within the range [0, max).</returns>
119
131
  double NextDouble(double max);
132
+
120
133
  /// <summary>
121
134
  /// </summary>
122
135
  /// <returns>A number within the range min, max).</returns>
@@ -127,15 +140,21 @@
127
140
  Guid NextGuid();
128
141
  KGuid NextKGuid();
129
142
 
130
- T Next<T>(IEnumerable<T> enumerable);
131
- T Next<T>(ICollection<T> collection);
132
- T Next<T>(IList<T> list);
143
+ T NextOf<T>(IEnumerable<T> enumerable);
144
+ T NextOf<T>(IReadOnlyCollection<T> collection);
145
+ T NextOf<T>(IReadOnlyList<T> list);
133
146
 
134
- T Next<T>() where T : struct, Enum;
135
- T NextCachedEnum<T>() where T : struct, Enum;
147
+ T NextEnum<T>()
148
+ where T : struct, Enum;
136
149
 
137
- float[,] NextNoiseMap(int width, int height, float scale = 2.5f, int octaves = 8);
150
+ float[,] NextNoiseMap(
151
+ int width,
152
+ int height,
153
+ PerlinNoise noise = null,
154
+ float scale = 2.5f,
155
+ int octaves = 8
156
+ );
138
157
 
139
158
  IRandom Copy();
140
159
  }
141
- }
160
+ }