Skip to content

Instantly share code, notes, and snippets.

@LukasFratzl
Created December 3, 2021 09:23
Show Gist options
  • Select an option

  • Save LukasFratzl/a0faa1d6c044c50b8de36df76b21acb1 to your computer and use it in GitHub Desktop.

Select an option

Save LukasFratzl/a0faa1d6c044c50b8de36df76b21acb1 to your computer and use it in GitHub Desktop.
A example of Allocating and resizing NativeArrays generic with Reflection in Unity c# Jobs | DOTS
public class AllocatingNativeArrayWithReflection : MonoBehaviour
{
protected virtual void AllocateCharacters(ref CharacterMotorJobs job, int length)
{
HandleArraysAll(ref job._motorJob, ArrayAction.ADD, length, new int[0]);
}
protected virtual void DisposeCharacters(ref CharacterMotorJobs job, int[] indexesToRemove)
{
HandleArraysAll(ref job._motorJob, ArrayAction.REMOVE, 0, indexesToRemove);
}
protected virtual void DisposeAllCharacters(ref CharacterMotorJobs job)
{
HandleArraysAll(ref job._motorJob, ArrayAction.DISPOSE, 0, new int[0]);
}
public enum ArrayAction
{
ADD,
REMOVE,
DISPOSE
}
protected void HandleArraysAll(ref SR_Motor.MotorJob job, ArrayAction _action, int countToAdd, int[] indexToRemove)
{
int currentCount = CharactersInScene.Count;
indexToRemove = indexToRemove.ToList().OrderBy(x => x).ToArray(); // NEEDS TO REMOVE ORDERED BECAUSE SOMETIMES INDEXES ARE LOWER WHICH RESULT A REMOVE OF THE LOWER INDEX AND IF THE NEXT WOULD BE THE LAST IT'S OUT OF RANGE, SO WE START WITH THE HIGHEST INDEX IN THE "HandleArray" REMOVE METHOD
HandleJob(ref job, currentCount, _action, indexToRemove, countToAdd);
}
protected void HandleJob<T>(ref T job, int _currentCount, ArrayAction _action, int[] _indexesToRemove = default, int _valuesCountToAdd = 0) where T : struct
{
Type type = job.GetType();
System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Default | System.Reflection.BindingFlags.DeclaredOnly;
System.Reflection.FieldInfo[] finfos = type.GetFields(flags);
object boxed = job;
for (int f = 0; f < finfos.Length; f++)
{
object v = finfos[f].GetValue(boxed);
bool changed = false;
if (v != null)
{
changed = HandleField<int>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<bool>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<float>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<float3>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<quaternion>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<float2>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<Quaternion>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<sbyte>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<byte>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<int2>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<int3>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<Vector2>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<Vector3>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<Vector2Int>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
changed = HandleField<Vector3Int>(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd);
if (changed) { finfos[f].SetValue(boxed, v); continue; }
}
}
job = (T)boxed;
}
protected bool HandleField<U>(ref object value, int _currentCount, ArrayAction _action, int[] _indexesToRemove = default, int _valuesCountToAdd = 0) where U : struct
{
bool hasChanged = false;
if (value is NativeArray<U>)
{
var v = (NativeArray<U>)value;
if (v != null) { hasChanged = true; HandleArray(ref v, _currentCount, _action, _indexesToRemove, _valuesCountToAdd); }
if (hasChanged) value = v;
}
return hasChanged;
}
protected void HandleArray<T>(ref NativeArray<T> array, int _currentCount, ArrayAction _action, int[] _indexesToRemove = default, int _valuesCountToAdd = 0) where T : struct
{
if (_action == ArrayAction.ADD && _valuesCountToAdd > 0) AddItemsToNativeArray(ref array, _valuesCountToAdd);
else if (_action == ArrayAction.REMOVE) DisposeArrayItems(ref array, _currentCount, _indexesToRemove);
else if (_action == ArrayAction.DISPOSE) DisposeArray(ref array);
}
protected void DisposeArrayItems<T>(ref NativeArray<T> array, int _currentCount, int[] _indexesToRemove) where T : struct
{
if (_currentCount == 0 && array.IsCreated) DisposeArray(ref array);
else if (_currentCount != 0 && array.IsCreated) RemoveItemsToNativeArrayAtIndexes(ref array, _indexesToRemove);
}
protected void DisposeArray<T>(ref NativeArray<T> array) where T : struct
{
if (array.IsCreated) array.Dispose();
}
protected void AddItemsToNativeArray<T>(ref NativeArray<T> array, T[] items) where T : struct
{
T[] oldItems = array.IsCreated == false ? new T[0] : array.ToArray();
if (array.IsCreated) { DisposeArray(ref array); }
var listItems = oldItems.ToList();
listItems.AddRange(items);
array = new NativeArray<T>(listItems.ToArray(), Allocator.Persistent);
}
protected void AddItemsToNativeArray<T>(ref NativeArray<T> array, int items) where T : struct
{
T[] oldItems = array.IsCreated == false ? new T[0] : array.ToArray();
if (array.IsCreated) { DisposeArray(ref array); }
var listItems = oldItems.ToList();
listItems.AddRange(new T[items]);
array = new NativeArray<T>(listItems.ToArray(), Allocator.Persistent);
}
protected void RemoveItemsToNativeArrayAtIndexes<T>(ref NativeArray<T> array, int[] indexesOrdered) where T : struct
{
if (array.IsCreated == false) return;
T[] oldItems = array.ToArray();
array.Dispose();
var listItems = oldItems.ToList();
for (int i = indexesOrdered.Length - 1; i >= 0; i--) // REVERSE LOOP TO START WITH THE HIGHEST INDEX
{
if (i < listItems.Count) listItems.RemoveAt(indexesOrdered[i]);
}
array = new NativeArray<T>(listItems.ToArray(), Allocator.Persistent);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment