A stable modding interface between Techblox and mods https://mod.exmods.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

63 lines
2.6KB

  1. using System;
  2. using System.Linq.Expressions;
  3. using Svelto.DataStructures;
  4. using Svelto.ECS;
  5. using Svelto.ECS.Internal;
  6. using TechbloxModdingAPI.Blocks;
  7. namespace TechbloxModdingAPI
  8. {
  9. public abstract class EcsObjectBase
  10. {
  11. public abstract EGID Id { get; } //Abstract to support the 'place' Block constructor
  12. protected internal EcsInitData InitData;
  13. /// <summary>
  14. /// Holds information needed to construct a component initializer
  15. /// </summary>
  16. protected internal struct EcsInitData
  17. {
  18. private FasterDictionary<RefWrapperType, ITypeSafeDictionary> group;
  19. private EntityReference reference;
  20. public static implicit operator EcsInitData(EntityInitializer initializer) => new EcsInitData
  21. {group = GetInitGroup(initializer), reference = initializer.reference};
  22. public EntityInitializer Initializer(EGID id) => new EntityInitializer(id, group, reference);
  23. public bool Valid => group != null;
  24. }
  25. private delegate FasterDictionary<RefWrapperType, ITypeSafeDictionary> GetInitGroupFunc(
  26. EntityInitializer initializer);
  27. /// <summary>
  28. /// Accesses the group field of the initializer
  29. /// </summary>
  30. private static GetInitGroupFunc GetInitGroup = CreateAccessor<GetInitGroupFunc>("_group");
  31. //https://stackoverflow.com/questions/55878525/unit-testing-ref-structs-with-private-fields-via-reflection
  32. private static TDelegate CreateAccessor<TDelegate>(string memberName) where TDelegate : Delegate
  33. {
  34. var invokeMethod = typeof(TDelegate).GetMethod("Invoke");
  35. if (invokeMethod == null)
  36. throw new InvalidOperationException($"{typeof(TDelegate)} signature could not be determined.");
  37. var delegateParameters = invokeMethod.GetParameters();
  38. if (delegateParameters.Length != 1)
  39. throw new InvalidOperationException("Delegate must have a single parameter.");
  40. var paramType = delegateParameters[0].ParameterType;
  41. var objParam = Expression.Parameter(paramType, "obj");
  42. var memberExpr = Expression.PropertyOrField(objParam, memberName);
  43. Expression returnExpr = memberExpr;
  44. if (invokeMethod.ReturnType != memberExpr.Type)
  45. returnExpr = Expression.ConvertChecked(memberExpr, invokeMethod.ReturnType);
  46. var lambda =
  47. Expression.Lambda<TDelegate>(returnExpr, $"Access{paramType.Name}_{memberName}", new[] {objParam});
  48. return lambda.Compile();
  49. }
  50. }
  51. }