using System; using System.Linq.Expressions; using Svelto.DataStructures; using Svelto.ECS; using Svelto.ECS.Internal; namespace GamecraftModdingAPI.Blocks { public partial class BlockEngine { /// /// Holds information needed to construct a component initializer /// internal struct BlockInitData { public FasterDictionary Group; } internal delegate FasterDictionary GetInitGroup( EntityComponentInitializer initializer); /// /// Accesses the group field of the initializer /// internal GetInitGroup InitGroup = CreateAccessor("_group"); //https://stackoverflow.com/questions/55878525/unit-testing-ref-structs-with-private-fields-via-reflection internal static TDelegate CreateAccessor(string memberName) where TDelegate : Delegate { var invokeMethod = typeof(TDelegate).GetMethod("Invoke"); if (invokeMethod == null) throw new InvalidOperationException($"{typeof(TDelegate)} signature could not be determined."); var delegateParameters = invokeMethod.GetParameters(); if (delegateParameters.Length != 1) throw new InvalidOperationException("Delegate must have a single parameter."); var paramType = delegateParameters[0].ParameterType; var objParam = Expression.Parameter(paramType, "obj"); var memberExpr = Expression.PropertyOrField(objParam, memberName); Expression returnExpr = memberExpr; if (invokeMethod.ReturnType != memberExpr.Type) returnExpr = Expression.ConvertChecked(memberExpr, invokeMethod.ReturnType); var lambda = Expression.Lambda(returnExpr, $"Access{paramType.Name}_{memberName}", new[] {objParam}); return lambda.Compile(); } } }