diff --git a/GameKit/Dependencies/GameKit.Dependencies.asmdef b/GameKit/Dependencies/GameKit.Dependencies.asmdef
index 438b416..751eaca 100644
--- a/GameKit/Dependencies/GameKit.Dependencies.asmdef
+++ b/GameKit/Dependencies/GameKit.Dependencies.asmdef
@@ -2,7 +2,10 @@
"name": "GameKit.Dependencies",
"rootNamespace": "",
"references": [
- "GUID:6055be8ebefd69e48b49212b09b47b2f"
+ "GUID:6055be8ebefd69e48b49212b09b47b2f",
+ "GUID:d8b63aba1907145bea998dd612889d6b",
+ "GUID:2665a8d13d1b3f18800f46e256720795",
+ "GUID:e0cd26848372d4e5c891c569017e11f1"
],
"includePlatforms": [],
"excludePlatforms": [],
diff --git a/GameKit/Dependencies/Utilities/Dictionaries.cs b/GameKit/Dependencies/Utilities/Dictionaries.cs
index 2b1041c..d7d6507 100644
--- a/GameKit/Dependencies/Utilities/Dictionaries.cs
+++ b/GameKit/Dependencies/Utilities/Dictionaries.cs
@@ -4,12 +4,11 @@ namespace GameKit.Dependencies.Utilities
{
public static class DictionaryFN
{
-
///
/// Uses a hacky way to TryGetValue on a dictionary when using IL2CPP and on mobile.
/// This is to support older devices that don't properly handle IL2CPP builds.
///
- public static bool TryGetValueIL2CPP(this IDictionary dict, TKey key, out TValue value)
+ public static bool TryGetValueIL2CPP(this IReadOnlyDictionary dict, TKey key, out TValue value)
{
#if ENABLE_IL2CPP && UNITY_IOS || UNITY_ANDROID
if (dict.ContainsKey(key))
@@ -28,36 +27,53 @@ public static bool TryGetValueIL2CPP(this IDictionary
- /// Returns values as an allocated list.
+ /// Returns values as a list.
///
///
- public static List ValuesToList(this IDictionary dict)
+ public static List ValuesToList(this IReadOnlyDictionary dict, bool useCache)
{
- List result = new(dict.Count);
- dict.ValuesToList(ref result);
+ List result = useCache ? CollectionCaches.RetrieveList() : new(dict.Count);
+
+ //No need to clear the list since it's already clear.
+ dict.ValuesToList(ref result, clearLst: false);
+
return result;
}
///
- /// Clears a collection and populates it with this dictionaries values.
+ /// Adds values to a list.
///
- public static void ValuesToList(this IDictionary dict, ref List result)
+ public static void ValuesToList(this IReadOnlyDictionary dict, ref List result, bool clearLst)
{
- result.Clear();
+ if (clearLst)
+ result.Clear();
+
foreach (TValue item in dict.Values)
result.Add(item);
}
-
+
///
- /// Clears a collection and populates it with this dictionaries keys.
+ /// Returns keys as a list.
///
- public static void KeysToList(this IDictionary dict, ref List result)
+ public static List KeysToList(this IReadOnlyDictionary dict, bool useCache)
+ {
+ List result = useCache ? CollectionCaches.RetrieveList() : new(dict.Count);
+
+ //No need to clear the list since it's already clear.
+ dict.KeysToList(ref result, clearLst: false);
+
+ return result;
+ }
+
+ ///
+ /// Adds keys to a list.
+ ///
+ public static void KeysToList(this IReadOnlyDictionary dict, ref List result, bool clearLst)
{
result.Clear();
+
foreach (TKey item in dict.Keys)
result.Add(item);
}
-
}
-
}
\ No newline at end of file
diff --git a/GameKit/Dependencies/Utilities/Floats.cs b/GameKit/Dependencies/Utilities/Floats.cs
index 418b313..5b7a908 100644
--- a/GameKit/Dependencies/Utilities/Floats.cs
+++ b/GameKit/Dependencies/Utilities/Floats.cs
@@ -1,9 +1,9 @@
using System;
+using System.Runtime.CompilerServices;
using UnityEngine;
namespace GameKit.Dependencies.Utilities
{
-
public static class Floats
{
///
@@ -14,9 +14,10 @@ public static class Floats
///
/// Sets a source float to value if equal to or greater than tolerance.
///
- /// Float to check against tolerance.
- /// Tolerance float must be equal to or greater than to change to value.
- /// Value source is set to when breaking tolerance.
+ /// Float to check against tolerance.
+ /// Tolerance float must be equal to or greater than to change to value.
+ /// Value source is set to when breaking tolerance.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float SetIfOverTolerance(this float source, float tolerance, float value)
{
if (source >= tolerance)
@@ -28,9 +29,10 @@ public static float SetIfOverTolerance(this float source, float tolerance, float
///
/// Sets a source float to value if equal to or less than tolerance.
///
- /// Float to check against tolerance.
- /// Tolerance float must be equal to or less than to change to value.
- /// Value source is set to when breaking tolerance.
+ /// Float to check against tolerance.
+ /// Tolerance float must be equal to or less than to change to value.
+ /// Value source is set to when breaking tolerance.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float SetIfUnderTolerance(this float source, float tolerance, float value)
{
if (source <= tolerance)
@@ -43,38 +45,39 @@ public static float SetIfUnderTolerance(this float source, float tolerance, floa
/// Returns how much time is left on an endTime. Returns -1 if no time is left.
///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float TimeRemainingValue(this float endTime)
{
float remaining = endTime - Time.time;
- //None remaining.
+ // None remaining.
if (remaining < 0f)
return -1f;
- return (endTime - Time.time);
+ return endTime - Time.time;
}
///
/// Returns how much time is left on an endTime. Returns -1 if no time is left.
///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int TimeRemainingValue(this float endTime, bool useFloor = true)
{
float remaining = endTime - Time.time;
- //None remaining.
+ // None remaining.
if (remaining < 0f)
return -1;
- float result = (endTime - Time.time);
- return (useFloor) ? Mathf.FloorToInt(result) : Mathf.CeilToInt(result);
+ float result = endTime - Time.time;
+ return useFloor ? Mathf.FloorToInt(result) : Mathf.CeilToInt(result);
}
-
///
/// Returns time remaining as a string using hh:mm:ss.
///
- ///
- /// Number of places to return. 1 is seconds, 2 is minutes, 3 is hours. If a placement does not exist it is replaced with 00.
- /// True to return an empty string when value is 0 or less.
+ ///
+ /// Number of places to return. 1 is seconds, 2 is minutes, 3 is hours. If a placement does not exist it is replaced with 00.
+ /// True to return an empty string when value is 0 or less.
///
public static string TimeRemainingText(this float value, byte segments, bool emptyOnZero = false)
{
@@ -91,13 +94,13 @@ public static string TimeRemainingText(this float value, byte segments, bool emp
string timeText;
if (segments == 1)
{
- seconds += (minutes * 60);
- seconds += (hours * 3600);
+ seconds += minutes * 60;
+ seconds += hours * 3600;
timeText = string.Format("{0:D2}", seconds);
}
else if (segments == 2)
{
- minutes += (hours * 60);
+ minutes += hours * 60;
timeText = string.Format("{0:D2}:{1:D2}", minutes, seconds);
}
else
@@ -109,17 +112,17 @@ public static string TimeRemainingText(this float value, byte segments, bool emp
}
///
- /// Provides a random inclusive int within a given range. Preferred over Unity's Random to eliminate confusion as Unity uses inclusive for floats max, and exclusive for int max.
+ /// Provides a random inclusive int within a given range. Preferred over Unity's Random to eliminate confusion as Unity uses inclusive for floats max, and exclusive for int max.
///
- /// Inclusive minimum value.
- /// Inclusive maximum value.
+ /// Inclusive minimum value.
+ /// Inclusive maximum value.
///
public static float RandomInclusiveRange(float minimum, float maximum)
{
double min = Convert.ToDouble(minimum);
double max = Convert.ToDouble(maximum);
- double result = (_random.NextDouble() * (max - min)) + min;
+ double result = _random.NextDouble() * (max - min) + min;
return Convert.ToSingle(result);
}
@@ -135,29 +138,31 @@ public static float Random01()
///
/// Returns if a target float is within variance of the source float.
///
- ///
- ///
- ///
+ ///
+ ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Near(this float a, float b, float tolerance = 0.01f)
{
- return (Mathf.Abs(a - b) <= tolerance);
+ return Mathf.Abs(a - b) <= tolerance;
}
///
/// Clamps a float and returns if the float required clamping.
///
- ///
- ///
- ///
- ///
+ ///
+ ///
+ ///
+ ///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Clamp(float value, float min, float max, ref bool clamped)
{
- clamped = (value < min);
+ clamped = value < min;
if (clamped)
return min;
- clamped = (value > min);
+ clamped = value > min;
if (clamped)
return max;
@@ -168,65 +173,65 @@ public static float Clamp(float value, float min, float max, ref bool clamped)
///
/// Returns a float after being adjusted by the specified variance.
///
- ///
- ///
+ ///
+ ///
///
public static float Variance(this float source, float variance)
{
float pickedVariance = RandomInclusiveRange(1f - variance, 1f + variance);
- return (source * pickedVariance);
+ return source * pickedVariance;
}
+
///
/// Sets a float value to result after being adjusted by the specified variance.
///
- ///
- ///
+ ///
+ ///
///
public static void Variance(this float source, float variance, ref float result)
{
float pickedVariance = RandomInclusiveRange(1f - variance, 1f + variance);
- result = (source * pickedVariance);
+ result = source * pickedVariance;
}
///
/// Returns negative-one, zero, or postive-one of a value instead of just negative-one or positive-one.
///
- /// Value to sign.
+ /// Value to sign.
/// Precise sign.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float PreciseSign(float value)
{
if (value == 0f)
return 0f;
else
- return (Mathf.Sign(value));
+ return Mathf.Sign(value);
}
///
/// Returns if a float is within a range.
///
- /// Value of float.
- /// Minimum of range.
- /// Maximum of range.
+ /// Value of float.
+ /// Minimum of range.
+ /// Maximum of range.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool InRange(this float source, float rangeMin, float rangeMax)
{
- return (source >= rangeMin && source <= rangeMax);
+ return source >= rangeMin && source <= rangeMax;
}
///
/// Randomly flips a float value.
///
- ///
+ ///
///
public static float RandomlyFlip(this float value)
{
if (Ints.RandomInclusiveRange(0, 1) == 0)
return value;
else
- return (value *= -1f);
+ return value *= -1f;
}
-
}
-
-
}
\ No newline at end of file
diff --git a/GameKit/Dependencies/Utilities/Quaternions.cs b/GameKit/Dependencies/Utilities/Quaternions.cs
index b67b47c..bfac65d 100644
--- a/GameKit/Dependencies/Utilities/Quaternions.cs
+++ b/GameKit/Dependencies/Utilities/Quaternions.cs
@@ -1,19 +1,31 @@
-using UnityEngine;
+using Unity.Mathematics;
+using UnityEngine;
namespace GameKit.Dependencies.Utilities
{
-
public static class Quaternions
{
-
///
/// Returns how fast an object must rotate over duration to reach goal.
///
- /// Quaternion to measure distance against.
- /// How long it should take to move to goal.
- /// A multiplier applied towards interval. Typically this is used for ticks passed.
+ /// Quaternion to measure distance against.
+ /// How long it should take to move to goal.
+ /// A multiplier applied towards interval. Typically this is used for ticks passed.
+ ///
+ public static float GetRate(this Quaternion a, Quaternion goal, float duration, out float angle, uint interval = 1, float tolerance = 0f)
+ {
+ angle = a.Angle(goal, true);
+ return angle / (duration * interval);
+ }
+
+ ///
+ /// Returns how fast an object must rotate over duration to reach goal.
+ ///
+ /// Quaternion to measure distance against.
+ /// How long it should take to move to goal.
+ /// A multiplier applied towards interval. Typically this is used for ticks passed.
///
- public static float GetRate(this Quaternion a, Quaternion goal, float duration, out float angle, uint interval = 1, float tolerance = 0f)
+ public static float GetRate(this quaternion a, quaternion goal, float duration, out float angle, uint interval = 1, float tolerance = 0f)
{
angle = a.Angle(goal, true);
return angle / (duration * interval);
@@ -22,43 +34,74 @@ public static float GetRate(this Quaternion a, Quaternion goal, float duration,
///
/// Subtracts b quaternion from a.
///
- public static Quaternion Subtract(this Quaternion a, Quaternion b) => (Quaternion.Inverse(b) * a);
+ public static Quaternion Subtract(this Quaternion a, Quaternion b) => Quaternion.Inverse(b) * a;
+
+ ///
+ /// Subtracts b quaternion from a.
+ ///
+ public static quaternion Subtract(this quaternion a, quaternion b) => math.mul(math.inverse(b), a);
+
///
/// Adds quaternion b onto quaternion a.
///
- public static Quaternion Add(this Quaternion a, Quaternion b) => (a * b);
+ public static Quaternion Add(this Quaternion a, Quaternion b) => a * b;
+
+ ///
+ /// Adds quaternion b onto quaternion a.
+ ///
+ public static quaternion Add(this quaternion a, quaternion b) => math.mul(a, b);
///
/// Returns if two quaternions match.
///
- /// True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return a match even when not true due to error tolerance.
+ /// True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return a match even when not true due to error tolerance.
///
public static bool Matches(this Quaternion a, Quaternion b, bool precise = false)
{
if (precise)
- return (a.w == b.w && a.x == b.x && a.y == b.y && a.z == b.z);
+ return a.w == b.w && a.x == b.x && a.y == b.y && a.z == b.z;
else
- return (a == b);
+ return a == b;
}
///
/// Returns the angle between two quaterions.
///
- /// True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return 0f due to error tolerance, even while there is a difference.
+ /// True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return 0f due to error tolerance, even while there is a difference.
///
public static float Angle(this Quaternion a, Quaternion b, bool precise = false)
{
if (precise)
{
- //This is run Unitys implementation without the error tolerance.
- float dot = (a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w);
- return (Mathf.Acos(Mathf.Min(Mathf.Abs(dot), 1f)) * 2f * 57.29578f);
+ // This is run Unitys implementation without the error tolerance.
+ float dot = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
+ return Mathf.Acos(Mathf.Min(Mathf.Abs(dot), 1f)) * 2f * 57.29578f;
}
else
{
return Quaternion.Angle(a, b);
}
}
- }
+
+ ///
+ /// Returns the angle between two quaterions.
+ ///
+ /// True to use a custom implementation with no error tolerance. False to use Unity's implementation which may return 0f due to error tolerance, even while there is a difference.
+ ///
+ public static float Angle(this quaternion a, quaternion b, bool precise = false)
+ {
+ if (!precise)
+ {
+ float d = math.dot(a.value, b.value);
+ float c = math.saturate(math.abs(d));
+ return math.degrees(2f * math.acos(c));
+ }
+ quaternion an = math.normalize(a);
+ quaternion bn = math.normalize(b);
+ float dn = math.dot(an.value, bn.value);
+ float cn = math.saturate(math.abs(dn));
+ return math.degrees(2f * math.acos(cn));
+ }
+ }
}
\ No newline at end of file
diff --git a/GameKit/Dependencies/Utilities/Types/StripedRingQueue.cs b/GameKit/Dependencies/Utilities/Types/StripedRingQueue.cs
new file mode 100644
index 0000000..eccd238
--- /dev/null
+++ b/GameKit/Dependencies/Utilities/Types/StripedRingQueue.cs
@@ -0,0 +1,370 @@
+using System;
+using System.Runtime.CompilerServices;
+using Unity.Collections;
+using Unity.Jobs;
+using Unity.Mathematics;
+using UnityEngine;
+
+namespace GameKit.Dependencies.Utilities.Types
+{
+ ///
+ /// A striped ring-buffer that stores N independent queues addressed by i = 0..N-1.
+ /// Backing storage uses NativeList-based stripes with a fixed per-queue capacity.
+ /// Designed for job-friendly, per-index parallel work without cross contention.
+ ///
+ public struct StripedRingQueue : IDisposable
+ where T : unmanaged
+ {
+ ///
+ /// Backing storage for all stripes; length equals _queueCount * _capacity.
+ ///
+ [NativeDisableParallelForRestriction] private NativeList _data;
+ ///
+ /// Per-queue head (read index)
+ /// Advances on dequeue operations modulo _capacity.
+ ///
+ [NativeDisableParallelForRestriction] private NativeList _head;
+ ///
+ /// Per-queue item count.
+ /// Always clamped to the range [0.._capacity].
+ ///
+ [NativeDisableParallelForRestriction] private NativeList _count;
+ ///
+ /// Compact metadata buffer stored in native memory:
+ /// [0] = fixed per-queue capacity, [1] = current queue count.
+ ///
+ [NativeDisableParallelForRestriction] private NativeArray _meta;
+
+ ///
+ /// True when internal lists are allocated and usable.
+ ///
+ public bool IsCreated
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data.IsCreated && _head.IsCreated && _count.IsCreated && _meta.IsCreated;
+ }
+ ///
+ /// Fixed capacity per queue (ring size).
+ ///
+ public int Capacity
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _meta[0];
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private set => _meta[0] = value;
+ }
+ ///
+ /// Number of independent queues (stripes).
+ ///
+ public int QueueCount
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _meta[1];
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private set => _meta[1] = value;
+ }
+ ///
+ /// Total addressable storage, equal to QueueCount * Capacity.
+ ///
+ public int TotalCapacity
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => QueueCount * Capacity;
+ }
+
+ ///
+ /// Indexer for direct access by queue index and raw ring index (0..Capacity-1).
+ /// Does not account for head/count; use GetCount/Clear/Enqueue/Dequeue for logical queue semantics.
+ ///
+ public T this[int queueIndex, int simulatedIndex]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ int offset = GetRealOffset(queueIndex, simulatedIndex);
+ return _data[offset];
+ }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set
+ {
+ int offset = GetRealOffset(queueIndex, simulatedIndex);
+ _data[offset] = value;
+ }
+ }
+
+ ///
+ /// Constructs the striped ring with an initial queue count and per-queue capacity.
+ /// Allocates NativeList storage and zeroes head/count for all stripes.
+ ///
+ public StripedRingQueue(int initialQueueCount, int capacity, Allocator allocator)
+ {
+ if (initialQueueCount < 0) throw new ArgumentOutOfRangeException(nameof(initialQueueCount));
+ if (capacity <= 0) throw new ArgumentOutOfRangeException(nameof(capacity));
+
+ _meta = new NativeArray(2, allocator, NativeArrayOptions.UninitializedMemory);
+ _meta[0] = capacity;
+ _meta[1] = initialQueueCount;
+
+ _data = new NativeList(math.max(1, initialQueueCount * capacity), allocator);
+ _head = new NativeList(math.max(1, initialQueueCount), allocator);
+ _count = new NativeList(math.max(1, initialQueueCount), allocator);
+
+ _data.ResizeUninitialized(initialQueueCount * capacity);
+ _head.ResizeUninitialized(initialQueueCount);
+ _count.ResizeUninitialized(initialQueueCount);
+
+ for (int i = 0; i < initialQueueCount; i++)
+ {
+ _head[i] = 0;
+ _count[i] = 0;
+ }
+ }
+
+ ///
+ /// Disposes all internal lists synchronously.
+ /// Ensure that no jobs are accessing this storage when disposing.
+ ///
+ public void Dispose()
+ {
+ if (_data.IsCreated) _data.Dispose();
+ if (_head.IsCreated) _head.Dispose();
+ if (_count.IsCreated) _count.Dispose();
+ if (_meta.IsCreated) _meta.Dispose();
+ }
+
+ ///
+ /// Schedules disposal of internal lists and returns a combined JobHandle.
+ /// Use this to free storage once dependent jobs have completed.
+ ///
+ public JobHandle Dispose(JobHandle inputDeps)
+ {
+ JobHandle h = inputDeps;
+ if (_data.IsCreated) h = _data.Dispose(h);
+ if (_head.IsCreated) h = _head.Dispose(h);
+ if (_count.IsCreated) h = _count.Dispose(h);
+ if (_meta.IsCreated) h = _meta.Dispose(h);
+ return h;
+ }
+
+ ///
+ /// Adds a new empty queue (stripe) and returns its index.
+ /// Grows the data buffer by Capacity and zeroes the stripe's head/count.
+ ///
+ public int AddQueue()
+ {
+ int capacity = Capacity;
+ int queueCount = QueueCount;
+
+ int newIndex = queueCount;
+
+ int newDataLen = (newIndex + 1) * capacity;
+ if (_data.Capacity < newDataLen) _data.Capacity = newDataLen;
+ _data.ResizeUninitialized(newDataLen);
+
+ _head.Add(0);
+ _count.Add(0);
+
+ QueueCount = newIndex + 1;
+ return newIndex;
+ }
+
+ ///
+ /// Removes the queue at the given index by swapping with the last stripe,
+ /// then shrinking storage by one stripe. Data swap is O(Capacity).
+ ///
+ public void RemoveQueueAtSwapBack(int index)
+ {
+ int queueCount = QueueCount;
+ int capacity = Capacity;
+
+ int last = queueCount - 1;
+ if ((uint)index >= (uint)queueCount)
+ throw new ArgumentOutOfRangeException(nameof(index));
+ if (last < 0)
+ return;
+
+ if (index != last)
+ {
+ int a = index * capacity;
+ int b = last * capacity;
+
+ for (int k = 0; k < capacity; k++)
+ {
+ (_data[a + k], _data[b + k]) = (_data[b + k], _data[a + k]);
+ }
+ }
+
+ _data.ResizeUninitialized(_data.Length - capacity);
+ _head.RemoveAtSwapBack(index);
+ _count.RemoveAtSwapBack(index);
+
+ QueueCount = last;
+ }
+
+ ///
+ /// Returns the current number of items in queue i.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public int GetCount(int i) => _count[i];
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private int BaseOffset(int i) => i * Capacity;
+
+ ///
+ /// Returns the real index of the collection using a simulated index.
+ ///
+ ///
+ ///
+ /// True to allow an index be returned from an unused portion of the buffer so long as it is within bounds.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private int GetRealOffset(int queueIndex, int simulatedIndex, bool allowUnusedBuffer = false)
+ {
+ int capacity = Capacity;
+ int queueCount = QueueCount;
+
+ if ((uint)queueIndex >= (uint)queueCount)
+ throw new ArgumentOutOfRangeException(nameof(queueIndex));
+ if ((uint)simulatedIndex >= (uint)capacity)
+ throw new ArgumentOutOfRangeException(nameof(simulatedIndex));
+
+ int count = _count[queueIndex];
+ if (simulatedIndex >= count && !allowUnusedBuffer)
+ throw new ArgumentOutOfRangeException(
+ nameof(simulatedIndex),
+ $"Index {simulatedIndex} >= item count {count} in queue {queueIndex}");
+
+ int head = _head[queueIndex];
+ int offset = (head + simulatedIndex) % capacity;
+ return BaseOffset(queueIndex) + offset;
+ }
+
+ ///
+ /// Clears queue i by resetting head and count to zero.
+ /// Stored values remain but are considered invalid.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Clear(int i)
+ {
+ _head[i] = 0;
+ _count[i] = 0;
+ }
+
+ ///
+ /// Enqueues 'value' into queue i; overwrites the oldest item when full.
+ /// Main-thread only unless no concurrent access to the same i is guaranteed.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Enqueue(int i, in T value)
+ {
+ int capacity = Capacity;
+
+ int h = _head[i];
+ int c = _count[i];
+ int baseOff = BaseOffset(i);
+ int tail = (h + c) % capacity;
+
+ _data[baseOff + tail] = value;
+
+ if (c < capacity)
+ {
+ _count[i] = c + 1;
+ }
+ else
+ {
+ _head[i] = (h + 1) % capacity; // overwrite oldest
+ }
+ }
+
+ ///
+ /// Tries to dequeue one item from queue i into 'value'.
+ /// Returns false when the queue is empty.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool TryDequeue(int i, out T value)
+ {
+ int c = _count[i];
+ if (c == 0)
+ {
+ value = default;
+ return false;
+ }
+
+ int capacity = Capacity;
+
+ int h = _head[i];
+ int baseOff = BaseOffset(i);
+ value = _data[baseOff + h];
+
+ _head[i] = (h + 1) % capacity;
+ _count[i] = c - 1;
+ return true;
+ }
+
+ ///
+ /// Dequeues up to 'n' items from queue i and returns how many were removed.
+ /// The last removed item (if any) is written to 'last'.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public int DequeueUpTo(int i, int n, out T last)
+ {
+ int c = _count[i];
+ int drop = math.clamp(n, 0, c);
+ if (drop == 0)
+ {
+ last = default;
+ return 0;
+ }
+
+ int capacity = Capacity;
+
+ int h = _head[i];
+ int baseOff = BaseOffset(i);
+ int lastIdx = (h + drop - 1) % capacity;
+
+ last = _data[baseOff + lastIdx];
+
+ _head[i] = (h + drop) % capacity;
+ _count[i] = c - drop;
+ return drop;
+ }
+
+ ///
+ /// Peeks the next entry from i queue.
+ ///
+ ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T Peek(int i)
+ {
+ int c = _count[i];
+ if (c == 0)
+ throw new InvalidOperationException($"{nameof(StripedRingQueue)} of type {typeof(T).Name} is empty.");
+
+ int h = _head[i];
+ int baseOff = BaseOffset(i);
+ return _data[baseOff + h];
+ }
+
+ ///
+ /// Tries to peek the next entry from queue i.
+ ///
+ ///
+ /// Peeked entry.
+ /// True if an entry existed to peek.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool TryPeek(int i, out T result)
+ {
+ int c = _count[i];
+ if (c == 0)
+ {
+ result = default;
+ return false;
+ }
+
+ int h = _head[i];
+ int baseOff = BaseOffset(i);
+ result = _data[baseOff + h];
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/GameKit/Dependencies/Utilities/Vectors.cs b/GameKit/Dependencies/Utilities/Vectors.cs
index b20b87a..6102fc0 100644
--- a/GameKit/Dependencies/Utilities/Vectors.cs
+++ b/GameKit/Dependencies/Utilities/Vectors.cs
@@ -1,10 +1,10 @@
using System;
using System.Runtime.CompilerServices;
+using Unity.Mathematics;
using UnityEngine;
namespace GameKit.Dependencies.Utilities
{
-
public static class Vectors
{
///
@@ -20,36 +20,57 @@ public static class Vectors
///
/// Returns how fast an object must move over duration to reach goal.
///
- /// Vector3 to measure distance against.
- /// How long it should take to move to goal.
- /// A multiplier applied towards interval. Typically this is used for ticks passed.
+ /// Vector3 to measure distance against.
+ /// How long it should take to move to goal.
+ /// A multiplier applied towards interval. Typically this is used for ticks passed.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float GetRate(this Vector3 a, Vector3 b, float duration, out float distance, uint interval = 1)
{
distance = Vector3.Distance(a, b);
return distance / (duration * interval);
}
+
+ ///
+ /// Returns how fast an object must move over duration to reach goal.
+ ///
+ /// Vector3 to measure distance against.
+ /// How long it should take to move to goal.
+ /// A multiplier applied towards interval. Typically this is used for ticks passed.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float GetRate(this float3 a, float3 b, float duration, out float distance, uint interval = 1)
+ {
+ distance = math.distance(a, b);
+ return distance / (duration * interval);
+ }
+
///
/// Adds a Vector2 X/Y onto a Vector3.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Add(this Vector3 v3, Vector2 v2)
{
- return (v3 + new Vector3(v2.x, v2.y, 0f));
+ return v3 + new Vector3(v2.x, v2.y, 0f);
}
+
///
/// Subtracts a Vector2 X/Y from a Vector3.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Subtract(this Vector3 v3, Vector2 v2)
{
- return (v3 - new Vector3(v2.x, v2.y, 0f));
+ return v3 - new Vector3(v2.x, v2.y, 0f);
}
+
///
/// Calculates the linear parameter t that produces the interpolant value within the range [a, b].
///
- ///
- ///
- ///
+ ///
+ ///
+ ///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float InverseLerp(Vector3 a, Vector3 b, Vector3 value)
{
Vector3 ab = b - a;
@@ -60,29 +81,32 @@ public static float InverseLerp(Vector3 a, Vector3 b, Vector3 value)
///
/// Returns if the target Vector3 is within variance of the source Vector3.
///
- /// Source vector.
- /// Target vector.
- /// How close the target vector must be to be considered close.
+ /// Source vector.
+ /// Target vector.
+ /// How close the target vector must be to be considered close.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Near(this Vector3 a, Vector3 b, float tolerance = 0.01f)
{
- return (Vector3.Distance(a, b) <= tolerance);
+ return Vector3.Distance(a, b) <= tolerance;
}
///
/// Returns if any values within a Vector3 are NaN.
///
- ///
+ ///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNan(this Vector3 source)
{
- return (float.IsNaN(source.x) || float.IsNaN(source.y) || float.IsNaN(source.z));
+ return float.IsNaN(source.x) || float.IsNaN(source.y) || float.IsNaN(source.z);
}
///
/// Lerp between three Vector3 values.
///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Lerp3(Vector3 a, Vector3 b, Vector3 c, float percent)
{
Vector3 r0 = Vector3.Lerp(a, b, percent);
@@ -93,9 +117,10 @@ public static Vector3 Lerp3(Vector3 a, Vector3 b, Vector3 c, float percent)
///
/// Lerp between three Vector3 values.
///
- ///
- ///
+ ///
+ ///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Lerp3(Vector3[] vectors, float percent)
{
if (vectors.Length < 3)
@@ -110,9 +135,10 @@ public static Vector3 Lerp3(Vector3[] vectors, float percent)
///
/// Multiplies a Vector3 by another.
///
- ///
- ///
+ ///
+ ///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 Multiply(this Vector3 src, Vector3 multiplier)
{
return new(src.x * multiplier.x, src.y * multiplier.y, src.z * multiplier.z);
@@ -120,31 +146,31 @@ public static Vector3 Multiply(this Vector3 src, Vector3 multiplier)
#region Fast.
/* Fast checks are property of:
- * Copyright (c) 2020 Maxim Munnig Schmidt
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
+ * Copyright (c) 2020 Maxim Munnig Schmidt
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
///
/// Fast Distance.
///
- ///
- ///
+ ///
+ ///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float FastDistance(Vector3 a, Vector3 b)
@@ -154,35 +180,39 @@ public static float FastDistance(Vector3 a, Vector3 b)
var distz = a.z - b.z;
return (float)Math.Sqrt(distx * distx + disty * disty + distz * distz);
}
+
///
/// Fast SqrMagnitude.
///
- ///
+ ///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float FastSqrMagnitude(Vector3 vector)
{
return vector.x * vector.x + vector.y * vector.y + vector.z * vector.z;
}
+
///
/// Fast Normalize.
///
- ///
+ ///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 FastNormalize(Vector3 value)
{
- float mag = (float)Math.Sqrt(value.x * value.x + value.y * value.y + value.z * value.z); //Magnitude(value);
+ float mag = (float)Math.Sqrt(value.x * value.x + value.y * value.y + value.z * value.z); // Magnitude(value);
if (mag > FLOAT_EPSILON)
{
Vector3 result;
result.x = value.x / mag;
result.y = value.y / mag;
result.z = value.z / mag;
- return result;// value / mag;
+ return result; // value / mag;
}
else
+ {
return VECTOR3_ZERO;
+ }
}
#endregion
#endregion
@@ -191,10 +221,11 @@ public static Vector3 FastNormalize(Vector3 value)
///
/// Returns how fast an object must move over duration to reach goal.
///
- /// Vector3 to measure distance against.
- /// How long it should take to move to goal.
- /// A multiplier applied towards interval. Typically this is used for ticks passed.
+ /// Vector3 to measure distance against.
+ /// How long it should take to move to goal.
+ /// A multiplier applied towards interval. Typically this is used for ticks passed.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float GetRate(this Vector2 a, Vector2 goal, float duration, out float distance, uint interval = 1)
{
distance = Vector2.Distance(a, goal);
@@ -204,11 +235,12 @@ public static float GetRate(this Vector2 a, Vector2 goal, float duration, out fl
///
/// Lerp between three Vector2 values.
///
- ///
- ///
- ///
- ///
+ ///
+ ///
+ ///
+ ///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Lerp3(Vector2 a, Vector2 b, Vector2 c, float percent)
{
Vector2 r0 = Vector2.Lerp(a, b, percent);
@@ -219,9 +251,10 @@ public static Vector2 Lerp3(Vector2 a, Vector2 b, Vector2 c, float percent)
///
/// Lerp between three Vector2 values.
///
- ///
- ///
+ ///
+ ///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Lerp2(Vector2[] vectors, float percent)
{
if (vectors.Length < 3)
@@ -233,19 +266,17 @@ public static Vector2 Lerp2(Vector2[] vectors, float percent)
return Lerp3(vectors[0], vectors[1], vectors[2], percent);
}
-
///
/// Multiplies a Vector2 by another.
///
- ///
- ///
+ ///
+ ///
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector2 Multiply(this Vector2 src, Vector2 multiplier)
{
return new(src.x * multiplier.x, src.y * multiplier.y);
}
#endregion
-
}
-
}
\ No newline at end of file