Arrays
REFramework exposes managed arrays through the _System.Array typed proxy interface. This page covers reading, creating, and manipulating managed arrays from C# plugins.
_System.Array
Any managed array (T[]) can be cast to _System.Array using .As<T>():
var arr = managedObj.As<_System.Array>();
int len = arr.Length; // element count
var elem = arr.GetValue(i); // read element at index i
arr.SetValue(newElem, i); // write element at index i
GetValue returns a ManagedObject for reference-type elements. For value-type elements, it returns the boxed value.
The
_Systemnamespace prefix exists to avoid collision with the realSystemnamespace in .NET. All generated proxies forSystem.*types live under_System.
Creating Managed Arrays
Use TypeDefinition.CreateManagedArray(uint size) to allocate a new managed array. The element type is determined by the TypeDefinition you call it on:
// Create an array of 90 app.GuiSaveDataInfo elements
var newArr = app.GuiSaveDataInfo.REFType.CreateManagedArray(90);
newArr.Globalize(); // prevent GC collection if storing long-term
var arr = newArr.As<_System.Array>();
// arr.Length == 90, all elements initially null/default
The returned ManagedObject is the array itself. Cast it to _System.Array to use indexed access.
Copying Elements
There is no built-in bulk copy operation. Copy elements with a loop:
var oldArr = oldMo.As<_System.Array>();
var newArr = newMo.As<_System.Array>();
for (int i = 0; i < oldArr.Length; i++) {
var elem = oldArr.GetValue(i);
if (elem != null)
newArr.SetValue(elem, i);
}
If the new array is larger than the old one, uncopied slots remain at their default value (null for reference types).
Arrays in Hooks
When a hooked method returns an array, retval holds the array's raw address. Convert it to a ManagedObject to inspect or replace it:
[MethodHook(typeof(SomeType), nameof(SomeType.getItems), MethodHookType.Post)]
static void OnGetItemsPost(ref ulong retval) {
var arrMo = ManagedObject.ToManagedObject(retval);
var arr = arrMo?.As<_System.Array>();
if (arr == null) return;
// Example: replace the returned array with a larger one
var newArrMo = SomeElementType.REFType.CreateManagedArray((uint)(arr.Length + 10));
newArrMo.Globalize();
var newArr = newArrMo.As<_System.Array>();
for (int i = 0; i < arr.Length; i++) {
var elem = arr.GetValue(i);
if (elem != null)
newArr.SetValue(elem, i);
}
retval = newArrMo.GetAddress(); // caller now sees the new array
}
Important Notes
-
Real arrays only.
_System.Arrayworks on actualSystem.Arraytypes (T[]). It does not work on collection wrappers likeList<T>,RingBuffer<T>, or other generic collections. For those, navigate to the inner backing array field first (e.g._itemsforList<T>,_BufferforRingBuffer<T>), then cast that to_System.Array. -
Globalize arrays you keep. If you create an array with
CreateManagedArrayand store it beyond the current frame (e.g. in a static field, or by writing it into a game object's field), callGlobalize()on it immediately. Without this, the GC may collect it between frames. -
Value-type elements are boxed.
GetValuereturnsManagedObjectfor reference-type elements. For value-type elements (integers, structs, enums), it returns the boxed representation. Cast or unbox as needed.