Initial commit: AIGame Unity client with URP, HybridCLR, YooAsset and tooling.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
namespace IlInterpreter.Interpreter
|
||||
{
|
||||
|
||||
// Describes a script-defined class: maps field tokens to typed offsets.
|
||||
internal sealed class ScriptTypeDescriptor
|
||||
{
|
||||
// Non-nullable fields are always set by the descriptor-building pass in Parse;
|
||||
// `= null!` marks that invariant.
|
||||
public string Name = null!;
|
||||
public int FieldCount;
|
||||
// FieldDef metadata token → slot index in ScriptObject.Fields
|
||||
// (kept for write-back path in call_host_byref; slot index = field index)
|
||||
public Dictionary<int, int> FieldSlots = null!;
|
||||
// Per-field type tag (parallel to field declaration order 0..FieldCount-1)
|
||||
public SType[] FieldTypes = null!;
|
||||
// Per-field storage offset:
|
||||
// I4/R4 fields: byte offset into ScriptObject.PrimBytes
|
||||
// O fields: index into ScriptObject.RefSlots
|
||||
// Vt fields: byte offset into ScriptObject.PrimBytes (inline storage)
|
||||
public int[] FieldOffsets = null!;
|
||||
public int PrimByteSize; // total size of PrimBytes array
|
||||
public int RefSlotCount; // total length of RefSlots array
|
||||
// Per-field struct layout, non-null only for SType.Vt fields.
|
||||
// Length = FieldCount. Parallel to FieldTypes/FieldOffsets.
|
||||
public HostBinding.StructLayout?[]? VtFieldLayouts;
|
||||
// Per-field flag: true when field i is a SCRIPT-defined struct stored in an O slot (a value type
|
||||
// masquerading as a ScriptObject reference). Non-null only when at least one such field exists.
|
||||
// Parallel to FieldTypes/FieldOffsets. Used by Clone() to deep-copy nested value-type fields so a
|
||||
// struct copy does not alias the source's nested structs (genuine reference fields stay shared).
|
||||
public bool[]? FieldIsScriptStruct;
|
||||
// Per-field descriptor of a script-struct field's own type (parallel to FieldTypes). Non-null entry
|
||||
// only for a resolved script-struct field; used by ScriptObject.Create to recursively allocate the
|
||||
// nested struct so a value-type field is never null (matching C#'s zero-init of value fields).
|
||||
public ScriptTypeDescriptor?[]? FieldStructDescriptors;
|
||||
// True when this type is a script-defined STRUCT (value type, not an enum, not a class). Used to
|
||||
// zero-init the elements of `new T[n]` — a value-type array holds usable structs, not nulls.
|
||||
public bool IsScriptStructValue;
|
||||
|
||||
// Non-null when this script struct is BLITTABLE (no reference fields, transitively) and is
|
||||
// represented FLAT: locals/args/returns live as raw bytes in Vt frame slots (the flat image is
|
||||
// identical to the PrimBytes image), and only O-boundary crossings materialize a boxed
|
||||
// ScriptObject via the layout's marshallers. Synthesized by the parser's flat-resolution pass.
|
||||
public HostBinding.StructLayout? FlatLayout;
|
||||
}
|
||||
|
||||
// An instance of a script-defined class.
|
||||
// Primitives (I4, R4) live in PrimBytes at their FieldOffsets[i] byte offset.
|
||||
// References (O, boxed Vt) live in RefSlots at their FieldOffsets[i] ref index.
|
||||
internal sealed class ScriptObject
|
||||
{
|
||||
// Create and Clone (the only construction sites) always set all three fields;
|
||||
// `= null!` marks that invariant.
|
||||
public ScriptTypeDescriptor Type = null!;
|
||||
public byte[] PrimBytes = null!; // typed primitive storage (I4/R4/bool)
|
||||
public object?[] RefSlots = null!; // reference fields only (O slots)
|
||||
|
||||
// Allocate an instance of a script class/struct, recursively initializing nested SCRIPT-struct
|
||||
// fields to fresh zeroed instances. A value-type field is never null in C# (`new Outer()` gives a
|
||||
// usable `inner`), so `a.inner.v = x` must not dereference null. Recursion terminates because
|
||||
// value-type containment is acyclic (a struct cannot contain itself by value).
|
||||
public static ScriptObject Create(ScriptTypeDescriptor desc)
|
||||
{
|
||||
var o = new ScriptObject
|
||||
{
|
||||
Type = desc,
|
||||
PrimBytes = new byte[desc.PrimByteSize],
|
||||
RefSlots = new object?[desc.RefSlotCount],
|
||||
};
|
||||
var subs = desc.FieldStructDescriptors;
|
||||
if (subs != null)
|
||||
{
|
||||
var offs = desc.FieldOffsets;
|
||||
for (int i = 0; i < subs.Length; i++)
|
||||
if (subs[i] != null)
|
||||
o.RefSlots[offs[i]] = Create(subs[i]!);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
// Value-copy for script-struct copy semantics. Genuine reference fields keep their reference
|
||||
// shared (a struct copy copies the reference, not its target) — but a NESTED SCRIPT STRUCT is
|
||||
// itself a value type stored in an O slot, so it must be deep-copied recursively, or
|
||||
// `b = a; b.inner.v = x` would alias a.inner. Recursion terminates because struct nesting
|
||||
// is acyclic.
|
||||
public ScriptObject Clone()
|
||||
{
|
||||
var copy = new ScriptObject
|
||||
{
|
||||
Type = Type,
|
||||
PrimBytes = PrimBytes == null ? null! : (byte[])PrimBytes.Clone(),
|
||||
RefSlots = RefSlots == null ? null! : (object?[])RefSlots.Clone(),
|
||||
};
|
||||
var isSc = Type?.FieldIsScriptStruct;
|
||||
if (isSc != null && copy.RefSlots != null)
|
||||
{
|
||||
var offs = Type!.FieldOffsets;
|
||||
for (int i = 0; i < isSc.Length; i++)
|
||||
{
|
||||
if (!isSc[i]) continue;
|
||||
int ri = offs[i];
|
||||
if ((uint)ri < (uint)copy.RefSlots.Length && copy.RefSlots[ri] is ScriptObject so)
|
||||
copy.RefSlots[ri] = so.Clone();
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
// A script-created array of FLAT structs: one byte[] backing for all elements instead of one
|
||||
// ScriptObject (3+ allocations) per element. Elements are memcpy'd in/out of Vt frame slots by
|
||||
// ldelem_vt/stelem_vt. Host-ABI note: like the old object?[] representation, this cannot be
|
||||
// passed to a host T[] parameter — unchanged limitation.
|
||||
internal sealed class ScriptVtArray
|
||||
{
|
||||
public HostBinding.StructLayout Layout = null!;
|
||||
public byte[] Bytes = null!;
|
||||
public int Length;
|
||||
public int Stride; // element size rounded up to 4
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user