From 87dbf593bc441c6a7a671f8c34acdf6c15f2b519 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 18 Oct 2025 23:04:49 +0000
Subject: [PATCH 1/4] Initial plan
From 4eaa6b08cf15c175a239e503ab2831e0f9bc3558 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 18 Oct 2025 23:13:11 +0000
Subject: [PATCH 2/4] Optimize RandomUtility: remove LINQ allocations and
improve algorithms
Co-authored-by: D3TONAT0R <20219966+D3TONAT0R@users.noreply.github.com>
---
Runtime/RandomUtility.cs | 106 ++++++++++++++++++++++++++++++++-------
1 file changed, 87 insertions(+), 19 deletions(-)
diff --git a/Runtime/RandomUtility.cs b/Runtime/RandomUtility.cs
index 18216d2..6b2e439 100644
--- a/Runtime/RandomUtility.cs
+++ b/Runtime/RandomUtility.cs
@@ -72,15 +72,37 @@ public static Vector4 RandomPoint4D(float min, float max)
public static int RangeExcluding(int min, int max, params int[] exclude)
{
if(max - min <= 0) return -1;
- var array = Enumerable.Range(min, max - min).Except(exclude).ToArray();
- if(array.Length > 0)
+
+ // Build valid range without LINQ to avoid allocations
+ int rangeSize = max - min;
+ int validCount = rangeSize;
+
+ // Count how many values are excluded
+ for(int i = 0; i < exclude.Length; i++)
{
- return Random.Range(0, array.Length);
+ if(exclude[i] >= min && exclude[i] < max)
+ {
+ validCount--;
+ }
}
- else
+
+ if(validCount <= 0) return -1;
+
+ // Pick a random index in the valid range
+ int pick = Random.Range(0, validCount);
+ int current = min;
+
+ // Skip excluded values
+ for(int offset = 0; offset <= pick; offset++)
{
- return -1;
+ while(System.Array.IndexOf(exclude, current) >= 0)
+ {
+ current++;
+ }
+ if(offset < pick) current++;
}
+
+ return current;
}
///
@@ -89,6 +111,10 @@ public static int RangeExcluding(int min, int max, params int[] exclude)
/// A random item from the array.
public static T PickRandom(params T[] array)
{
+ if(array == null || array.Length == 0)
+ {
+ throw new System.ArgumentException("Array cannot be null or empty");
+ }
return array[Random.Range(0, array.Length)];
}
@@ -98,6 +124,10 @@ public static T PickRandom(params T[] array)
/// A random item from the list.
public static T PickRandom(List list)
{
+ if(list == null || list.Count == 0)
+ {
+ throw new System.ArgumentException("List cannot be null or empty");
+ }
return list[Random.Range(0, list.Count)];
}
@@ -129,15 +159,34 @@ public static T PickRandomExcluding(List list, params int[] excludeIndices
/// A random item from the array.
public static int PickRandomIndexExcluding(int length, params int[] excludeIndices)
{
- var indices = Enumerable.Range(0, length).Except(excludeIndices).ToArray();
- if(indices.Length > 0)
+ // Calculate valid count without LINQ to avoid allocations
+ int validCount = length;
+
+ for(int i = 0; i < excludeIndices.Length; i++)
{
- return indices[Random.Range(0, indices.Length)];
+ if(excludeIndices[i] >= 0 && excludeIndices[i] < length)
+ {
+ validCount--;
+ }
}
- else
+
+ if(validCount <= 0) return -1;
+
+ // Pick a random index in the valid range
+ int pick = Random.Range(0, validCount);
+ int current = 0;
+
+ // Skip excluded indices
+ for(int offset = 0; offset <= pick; offset++)
{
- return -1;
+ while(System.Array.IndexOf(excludeIndices, current) >= 0)
+ {
+ current++;
+ }
+ if(offset < pick) current++;
}
+
+ return current;
}
///
@@ -145,6 +194,10 @@ public static int PickRandomIndexExcluding(int length, params int[] excludeIndic
///
public static T TakeRandomItem(List list)
{
+ if(list == null || list.Count == 0)
+ {
+ throw new System.ArgumentException("List cannot be null or empty");
+ }
int i = Random.Range(0, list.Count);
var item = list[i];
list.RemoveAt(i);
@@ -158,8 +211,16 @@ public static T TakeRandomItem(List list)
/// The picked item's index.
public static int PickRandomWeighted(float[] weights)
{
+ if(weights == null || weights.Length == 0)
+ {
+ throw new System.ArgumentException("Weights array cannot be null or empty");
+ }
float total = 0;
foreach(var w in weights) total += w;
+ if(total <= 0)
+ {
+ throw new System.ArgumentException("Total weight must be greater than zero");
+ }
float pick = Random.value * total;
for(int i = 0; i < weights.Length; i++)
{
@@ -173,29 +234,36 @@ public static int PickRandomWeighted(float[] weights)
}
///
- /// Returns a shuffled version of the given array.
+ /// Returns a shuffled version of the given array using the Fisher-Yates algorithm.
///
public static T[] Shuffle(T[] array)
{
T[] shuffled = new T[array.Length];
- var list = array.ToList();
- for(int i = 0; i < array.Length; i++)
+ System.Array.Copy(array, shuffled, array.Length);
+
+ // Fisher-Yates shuffle algorithm
+ for(int i = shuffled.Length - 1; i > 0; i--)
{
- shuffled[i] = TakeRandomItem(list);
+ int j = Random.Range(0, i + 1);
+ T temp = shuffled[i];
+ shuffled[i] = shuffled[j];
+ shuffled[j] = temp;
}
return shuffled;
}
///
- /// Randomly shuffles the given list.
+ /// Randomly shuffles the given list using the Fisher-Yates algorithm.
///
public static void Shuffle(List list)
{
- var elements = new List(list);
- list.Clear();
- for(int i = 0; i < elements.Count; i++)
+ // Fisher-Yates shuffle algorithm - in-place
+ for(int i = list.Count - 1; i > 0; i--)
{
- list.Add(TakeRandomItem(elements));
+ int j = Random.Range(0, i + 1);
+ T temp = list[i];
+ list[i] = list[j];
+ list[j] = temp;
}
}
}
From 14e07e2eb9bd3a99ea3751199d1723ebf4a74ddf Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 18 Oct 2025 23:15:53 +0000
Subject: [PATCH 3/4] Add readonly modifiers for better performance and
immutability
Co-authored-by: D3TONAT0R <20219966+D3TONAT0R@users.noreply.github.com>
---
Runtime/ExtraGizmos.cs | 2 +-
Runtime/InstancePool.cs | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/Runtime/ExtraGizmos.cs b/Runtime/ExtraGizmos.cs
index 8baae9e..c78d1b4 100644
--- a/Runtime/ExtraGizmos.cs
+++ b/Runtime/ExtraGizmos.cs
@@ -34,7 +34,7 @@ public class ExtraGizmos
internal static GUIStyle labelStyle;
internal static GUIStyle boxStyle;
- private static List circlePointCache = new List();
+ private static readonly List circlePointCache = new List(128);
static ExtraGizmos()
{
diff --git a/Runtime/InstancePool.cs b/Runtime/InstancePool.cs
index 2d66d33..31b9b8b 100644
--- a/Runtime/InstancePool.cs
+++ b/Runtime/InstancePool.cs
@@ -57,10 +57,10 @@ public class InstancePool where T : Component
///
public int TotalInstanceCount => InactiveInstanceCount + ActiveInstanceCount;
- private List inactivePool;
- private List activePool;
- private Dictionary lastActivationTimes;
- private T[] iterationCache;
+ private readonly List inactivePool;
+ private readonly List activePool;
+ private readonly Dictionary lastActivationTimes;
+ private readonly T[] iterationCache;
private float lastUpdateTime;
///
From defa7afe0101aab30141f22846ec4348184cdd46 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 18 Oct 2025 23:18:22 +0000
Subject: [PATCH 4/4] Add readonly modifiers to UpdateLoop InvocationTarget
fields
Co-authored-by: D3TONAT0R <20219966+D3TONAT0R@users.noreply.github.com>
---
Runtime/UpdateLoop/UpdateLoop.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Runtime/UpdateLoop/UpdateLoop.cs b/Runtime/UpdateLoop/UpdateLoop.cs
index c03066f..1d76bff 100644
--- a/Runtime/UpdateLoop/UpdateLoop.cs
+++ b/Runtime/UpdateLoop/UpdateLoop.cs
@@ -33,8 +33,8 @@ internal class InvocationList
{
public class InvocationTarget
{
- public Action action;
- public Behaviour targetComponent;
+ public readonly Action action;
+ public readonly Behaviour targetComponent;
public readonly bool isComponentTarget;
@@ -55,7 +55,7 @@ public bool IsActiveAndEnabled()
}
public readonly string name;
- public List subscribers = new List(256);
+ public readonly List subscribers = new List(256);
public InvocationList(string name)
{