Mirror of Svelto.ECS because we're a fan of it
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.

146 lines
4.8KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using Svelto.DataStructures;
  5. using Svelto.ECS.Hybrid;
  6. using Svelto.ECS.Internal;
  7. using Svelto.Utilities;
  8. namespace Svelto.ECS
  9. {
  10. public class EntityBuilder<T> : IEntityBuilder where T : struct, IEntityStruct
  11. {
  12. static class EntityView
  13. {
  14. internal static readonly FasterList<KeyValuePair<Type, ActionCast<T>>> cachedFields;
  15. internal static readonly Dictionary<Type, Type[]> cachedTypes;
  16. #if DEBUG && !PROFILER
  17. internal static readonly Dictionary<Type, ECSTuple<object, int>> implementorsByType;
  18. #else
  19. internal static readonly Dictionary<Type, object> implementorsByType;
  20. #endif
  21. static EntityView()
  22. {
  23. cachedFields = new FasterList<KeyValuePair<Type, ActionCast<T>>>();
  24. var type = typeof(T);
  25. var fields = type.GetFields(BindingFlags.Public |
  26. BindingFlags.Instance);
  27. for (var i = fields.Length - 1; i >= 0; --i)
  28. {
  29. var field = fields[i];
  30. var setter = FastInvoke<T>.MakeSetter(field);
  31. cachedFields.Add(new KeyValuePair<Type, ActionCast<T>>(field.FieldType, setter));
  32. }
  33. cachedTypes = new Dictionary<Type, Type[]>();
  34. #if DEBUG && !PROFILER
  35. implementorsByType = new Dictionary<Type, ECSTuple<object, int>>();
  36. #else
  37. implementorsByType = new Dictionary<Type, object>();
  38. #endif
  39. }
  40. internal static void InitCache()
  41. {}
  42. internal static void BuildEntityView(out T entityView)
  43. {
  44. entityView = new T();
  45. }
  46. }
  47. public EntityBuilder()
  48. {
  49. _initializer = DEFAULT_IT;
  50. EntityBuilderUtilities.CheckFields(ENTITY_VIEW_TYPE, NEEDS_REFLECTION);
  51. if (NEEDS_REFLECTION)
  52. EntityView.InitCache();
  53. }
  54. public EntityBuilder(in T initializer) : this()
  55. {
  56. _initializer = initializer;
  57. }
  58. public void BuildEntityAndAddToList(ref ITypeSafeDictionary dictionary, EGID egid,
  59. IEnumerable<object> implementors)
  60. {
  61. if (dictionary == null)
  62. dictionary = new TypeSafeDictionary<T>();
  63. var castedDic = dictionary as TypeSafeDictionary<T>;
  64. if (NEEDS_REFLECTION)
  65. {
  66. DBC.ECS.Check.Require(implementors != null,
  67. $"Implementors not found while building an EntityView `{typeof(T)}`");
  68. DBC.ECS.Check.Require(castedDic.ContainsKey(egid.entityID) == false,
  69. $"building an entity with already used entity id! id: '{(ulong) egid}', {ENTITY_VIEW_NAME}");
  70. EntityView.BuildEntityView(out var entityView);
  71. this.FillEntityView(ref entityView, entityViewBlazingFastReflection, implementors,
  72. EntityView.implementorsByType, EntityView.cachedTypes);
  73. castedDic.Add(egid.entityID, entityView);
  74. }
  75. else
  76. {
  77. DBC.ECS.Check.Require(!castedDic.ContainsKey(egid.entityID),
  78. $"building an entity with already used entity id! id: '{egid.entityID}'");
  79. castedDic.Add(egid.entityID, _initializer);
  80. }
  81. }
  82. ITypeSafeDictionary IEntityBuilder.Preallocate(ref ITypeSafeDictionary dictionary, uint size)
  83. {
  84. return Preallocate(ref dictionary, size);
  85. }
  86. static ITypeSafeDictionary Preallocate(ref ITypeSafeDictionary dictionary, uint size)
  87. {
  88. if (dictionary == null)
  89. dictionary = new TypeSafeDictionary<T>(size);
  90. else
  91. dictionary.SetCapacity(size);
  92. return dictionary;
  93. }
  94. public Type GetEntityType()
  95. {
  96. return ENTITY_VIEW_TYPE;
  97. }
  98. static EntityBuilder()
  99. {
  100. ENTITY_VIEW_TYPE = typeof(T);
  101. DEFAULT_IT = default;
  102. NEEDS_REFLECTION = typeof(IEntityViewStruct).IsAssignableFrom(ENTITY_VIEW_TYPE);
  103. HAS_EGID = typeof(INeedEGID).IsAssignableFrom(ENTITY_VIEW_TYPE);
  104. ENTITY_VIEW_NAME = ENTITY_VIEW_TYPE.ToString();
  105. SetEGIDWithoutBoxing<T>.Warmup();
  106. }
  107. readonly T _initializer;
  108. static FasterList<KeyValuePair<Type, ActionCast<T>>> entityViewBlazingFastReflection =>
  109. EntityView.cachedFields;
  110. internal static readonly Type ENTITY_VIEW_TYPE;
  111. public static readonly bool HAS_EGID;
  112. static readonly T DEFAULT_IT;
  113. static readonly bool NEEDS_REFLECTION;
  114. static readonly string ENTITY_VIEW_NAME;
  115. }
  116. }