Open BeanCheeseBurrito opened 2 months ago
I messed around with trying to implement this and it seems like there's no way to get the size of the component without breaking NativeAOT.
You can construct an instance of T using Activator as long as you annotate the type properly. However, there's no way to size it directly since you can't access Marshal.SizeOf
in AoT.
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
You might be able to hack some sort size estimator by walking the fields and using known sizes for base types but that would get very messy.
Might be out of scope but you could consider splitting into a Flecs.Core package with AoT support and a Flecs package without that adds support for dynamic registration and types. Alternatively you could use defines for gating off non-aot compatible code.
Worth noting, it seems Type
Adding \
dotnet publish --property:Example=Reflection_BasicsEnum -r osx-arm64
./bin/Release/net8.0/osx-arm64/publish/Flecs.NET.Examples
Unhandled Exception: System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property.
---> System.NotSupportedException: '<BasicsEnum>FD8BE5548CB1ACE8A8CBC7E39E2FB23FDF52B13BA421B001B7B83140A7A1DF813__Color[]' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
at System.Reflection.Runtime.General.TypeUnifier.WithVerifiedTypeHandle(RuntimeArrayTypeInfo, RuntimeTypeInfo) + 0x70
at System.Array.InternalCreate(RuntimeType, Int32, Int32*, Int32*) + 0x78
at System.Array.CreateInstance(Type, Int32) + 0x48
at System.RuntimeType.GetEnumValues() + 0x64
at Flecs.NET.Core.Type`1.InitEnumCacheIndexes() + 0x64
at Flecs.NET.Core.Type`1..cctor() + 0x128
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0xbc
--- End of inner exception stack trace ---
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x15c
at System.Runtime.CompilerServices.ClassConstructorRunner.CheckStaticClassConstructionReturnNonGCStaticBase(StaticClassConstructionContext*, IntPtr) + 0x14
at Flecs.NET.Core.Component`1..ctor(flecs.ecs_world_t*) + 0xa4
at Reflection_BasicsEnum.Main() + 0x44
at Flecs.NET!<BaseAddress>+0x171fb4
Worth noting, it seems Type currently isn't AoT compatible. Its usage of GetEnumValues throws an AoT warning.
I wonder if switching to Enum.GetValuesAsUnderlyingType fixes AOT compatibility. I dropped support for versions below .NET 8 in the type-safe-queries branch so we have access to this function now.
Yup that fixes it! AoT still gives off a warning about the
if (RuntimeFeature.IsDynamicCodeSupported)
{
FieldInfo[] fields =
type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
size = fields.Length == 0 ? 0 : size;
alignment = size == 0 ? 0 : alignment;
}
but seems fine since its gated. You could annotate it but it looks like you'd have to bubble up that annotation to 50+ other generic methods that call Type\
In the meantime, would you have any qualms with storing the reflection Type on the component entity? I have a usecase for going from the component entity Id to knowing its type for runtime reflection.
I figure easiest solution would be to just do
world.Entity(component).Set(typeof(T));
in Type
It would be useful in reflection scenarios to allow the user to lookup component ids and execute ECS operations using
System.Type
. This functionality is required for automatic member registration/serialization/deserialization support. Needs to also support NativeAOT with trimming which might not be possible with the way component registration currently works.