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.

185 lines
6.5KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Threading;
  5. using DBC.ECS;
  6. using Svelto.Common;
  7. using Svelto.DataStructures;
  8. using Svelto.ECS.Hybrid;
  9. using Svelto.ECS.Internal;
  10. using Svelto.Utilities;
  11. namespace Svelto.ECS
  12. {
  13. struct ComponentBuilderComparer : IEqualityComparer<IComponentBuilder>
  14. {
  15. public bool Equals(IComponentBuilder x, IComponentBuilder y)
  16. {
  17. return x.GetEntityComponentType() == y.GetEntityComponentType();
  18. }
  19. public int GetHashCode(IComponentBuilder obj)
  20. {
  21. return obj.GetEntityComponentType().GetHashCode();
  22. }
  23. }
  24. public class ComponentBuilder<T> : IComponentBuilder where T : struct, _IInternalEntityComponent
  25. {
  26. internal static readonly Type ENTITY_COMPONENT_TYPE;
  27. internal static readonly bool IS_ENTITY_VIEW_COMPONENT;
  28. static readonly string ENTITY_COMPONENT_NAME;
  29. static readonly bool IS_UNMANAGED;
  30. #if SLOW_SVELTO_SUBMISSION
  31. public static readonly bool HAS_EGID;
  32. public static readonly bool HAS_REFERENCE;
  33. #endif
  34. static ComponentBuilder()
  35. {
  36. ENTITY_COMPONENT_TYPE = typeof(T);
  37. IS_ENTITY_VIEW_COMPONENT = typeof(IEntityViewComponent).IsAssignableFrom(ENTITY_COMPONENT_TYPE);
  38. #if SLOW_SVELTO_SUBMISSION
  39. HAS_EGID = typeof(INeedEGID).IsAssignableFrom(ENTITY_COMPONENT_TYPE);
  40. HAS_REFERENCE = typeof(INeedEntityReference).IsAssignableFrom(ENTITY_COMPONENT_TYPE);
  41. SetEGIDWithoutBoxing<T>.Warmup();
  42. #endif
  43. ENTITY_COMPONENT_NAME = ENTITY_COMPONENT_TYPE.ToString();
  44. IS_UNMANAGED = TypeCache<T>.isUnmanaged; //attention this is important as it serves as warm up for Type<T>
  45. #if UNITY_NATIVE
  46. if (IS_UNMANAGED)
  47. EntityComponentIDMap.Register<T>(new Filler<T>());
  48. #endif
  49. ComponentTypeID<T>.Init();
  50. ComponentBuilderUtilities.CheckFields(ENTITY_COMPONENT_TYPE, IS_ENTITY_VIEW_COMPONENT);
  51. if (IS_ENTITY_VIEW_COMPONENT)
  52. {
  53. EntityViewComponentCache.InitCache();
  54. }
  55. else
  56. {
  57. if (ENTITY_COMPONENT_TYPE != ComponentBuilderUtilities.ENTITY_INFO_COMPONENT &&
  58. TypeCache<T>.isUnmanaged == false)
  59. throw new Exception(
  60. $"Entity Component check failed, unexpected struct type (must be unmanaged) {ENTITY_COMPONENT_TYPE}");
  61. }
  62. }
  63. public ComponentBuilder()
  64. {
  65. _initializer = default;
  66. }
  67. public ComponentBuilder(in T initializer) : this()
  68. {
  69. _initializer = initializer;
  70. }
  71. public bool isUnmanaged => IS_UNMANAGED;
  72. public ComponentID getComponentID => ComponentTypeID<T>.id;
  73. static readonly ThreadLocal<EntityViewComponentCache> _localCache = new ThreadLocal<EntityViewComponentCache>(() => new EntityViewComponentCache());
  74. public void BuildEntityAndAddToList(ITypeSafeDictionary dictionary, EGID egid, IEnumerable<object> implementors)
  75. {
  76. var castedDic = dictionary as ITypeSafeDictionary<T>;
  77. if (IS_ENTITY_VIEW_COMPONENT)
  78. {
  79. T entityComponent = default;
  80. Check.Require(castedDic.ContainsKey(egid.entityID) == false,
  81. $"building an entity with already used entity id! id: '{(ulong)egid}', {ENTITY_COMPONENT_NAME}");
  82. this.SetEntityViewComponentImplementors(ref entityComponent, implementors, _localCache.Value);
  83. castedDic.Add(egid.entityID, entityComponent);
  84. }
  85. else
  86. {
  87. Check.Require(!castedDic.ContainsKey(egid.entityID),
  88. $"building an entity with already used entity id! id: '{egid.entityID}'");
  89. castedDic.Add(egid.entityID, _initializer);
  90. }
  91. }
  92. void IComponentBuilder.Preallocate(ITypeSafeDictionary dictionary, uint size)
  93. {
  94. Preallocate(dictionary, size);
  95. }
  96. public ITypeSafeDictionary CreateDictionary(uint size)
  97. {
  98. return TypeSafeDictionaryFactory<T>.Create(size);
  99. }
  100. public Type GetEntityComponentType()
  101. {
  102. return ENTITY_COMPONENT_TYPE;
  103. }
  104. public override int GetHashCode()
  105. {
  106. return _initializer.GetHashCode();
  107. }
  108. static void Preallocate(ITypeSafeDictionary dictionary, uint size)
  109. {
  110. dictionary.EnsureCapacity(size);
  111. }
  112. readonly T _initializer;
  113. internal class EntityViewComponentCache
  114. {
  115. internal readonly FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>> cachedFields;
  116. internal readonly Dictionary<Type, Type[]> cachedTypes;
  117. //this is just a local static cache that is cleared after every use
  118. #if DEBUG && !PROFILE_SVELTO
  119. internal readonly Dictionary<Type, ECSTuple<object, int>> implementorsByType;
  120. #else
  121. internal readonly Dictionary<Type, object> implementorsByType;
  122. #endif
  123. internal EntityViewComponentCache()
  124. {
  125. cachedFields = new FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>>();
  126. var type = typeof(T);
  127. var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
  128. for (var i = fields.Length - 1; i >= 0; --i)
  129. {
  130. var field = fields[i];
  131. if (field.FieldType.IsInterface == true)
  132. {
  133. var setter = FastInvoke<T>.MakeSetter(field);
  134. //for each interface, cache the setter for this type
  135. cachedFields.Add(new KeyValuePair<Type, FastInvokeActionCast<T>>(field.FieldType, setter));
  136. }
  137. }
  138. #if DEBUG && !PROFILE_SVELTO
  139. if (fields.Length == 0)
  140. Console.LogWarning($"No fields found in component {type}. Are you declaring only properties?");
  141. #endif
  142. cachedTypes = new Dictionary<Type, Type[]>();
  143. #if DEBUG && !PROFILE_SVELTO
  144. implementorsByType = new Dictionary<Type, ECSTuple<object, int>>();
  145. #else
  146. implementorsByType = new Dictionary<Type, object>();
  147. #endif
  148. }
  149. internal static void InitCache()
  150. {
  151. }
  152. }
  153. }
  154. }