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.

119 lines
4.8KB

  1. using System;
  2. using System.Collections.Generic;
  3. using Svelto.DataStructures;
  4. using Svelto.Utilities;
  5. namespace Svelto.ECS
  6. {
  7. #if DEBUG && !PROFILE_SVELTO
  8. struct ECSTuple<T1, T2>
  9. {
  10. public readonly T1 instance;
  11. public T2 numberOfImplementations;
  12. public ECSTuple(T1 implementor, T2 v)
  13. {
  14. instance = implementor;
  15. numberOfImplementations = v;
  16. }
  17. }
  18. #endif
  19. static class EntityComponentUtility
  20. {
  21. const string DUPLICATE_IMPLEMENTOR_ERROR =
  22. "<color=teal>Svelto.ECS</color> the same component is implemented with more than one implementor. This is "
  23. + "considered an error and MUST be fixed. ";
  24. const string NULL_IMPLEMENTOR_ERROR =
  25. "<color=teal>Svelto.ECS</color> Null implementor, please be careful about the implementors passed to avoid "
  26. + "performance loss ";
  27. const string NOT_FOUND_EXCEPTION =
  28. "<color=teal>Svelto.ECS</color> Implementor not found for an EntityComponent. ";
  29. public static void SetEntityViewComponentImplementors<T>
  30. (this IComponentBuilder componentBuilder, ref T entityComponent
  31. , FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>> entityComponentBlazingFastReflection
  32. , IEnumerable<object> implementors
  33. #if DEBUG && !PROFILE_SVELTO
  34. ,Dictionary<Type, ECSTuple<object, int>> implementorsByType
  35. #else
  36. , Dictionary<Type, object> implementorsByType
  37. #endif
  38. , Dictionary<Type, Type[]> cachedTypeInterfaces)
  39. {
  40. DBC.ECS.Check.Require(implementors != null, NULL_IMPLEMENTOR_ERROR.FastConcat(" entityComponent "
  41. , componentBuilder
  42. .GetEntityComponentType().ToString()));
  43. foreach (var implementor in implementors)
  44. {
  45. DBC.ECS.Check.Require(implementor != null, "invalid null implementor used to build an entity");
  46. {
  47. var type = implementor.GetType();
  48. //fetch all the interfaces that the implementor implements
  49. if (cachedTypeInterfaces.TryGetValue(type, out var interfaces) == false)
  50. interfaces = cachedTypeInterfaces[type] = type.GetInterfacesEx();
  51. for (var iindex = 0; iindex < interfaces.Length; iindex++)
  52. {
  53. var componentType = interfaces[iindex];
  54. //an implementor can implement multiple interfaces, so for each interface we reference
  55. //the implementation object. Multiple entity view component fields can then be implemented
  56. //by the same implementor
  57. #if DEBUG && !PROFILE_SVELTO
  58. if (implementorsByType.TryGetValue(componentType, out var implementorData))
  59. {
  60. implementorData.numberOfImplementations++;
  61. implementorsByType[componentType] = implementorData;
  62. }
  63. else
  64. implementorsByType[componentType] = new ECSTuple<object, int>(implementor, 1);
  65. #else
  66. implementorsByType[componentType] = implementor;
  67. #endif
  68. }
  69. }
  70. }
  71. //efficient way to collect the fields of every EntityComponentType
  72. var setters = FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>>.NoVirt.ToArrayFast(
  73. entityComponentBlazingFastReflection, out var count);
  74. for (var i = 0; i < count; i++)
  75. {
  76. var fieldSetter = setters[i];
  77. var fieldType = fieldSetter.Key;
  78. #if DEBUG && !PROFILE_SVELTO
  79. ECSTuple<object, int> implementor;
  80. #else
  81. object implementor;
  82. #endif
  83. if (implementorsByType.TryGetValue(fieldType, out implementor) == false)
  84. {
  85. var e = new ECSException(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name
  86. + " - EntityComponent: " + componentBuilder.GetEntityComponentType().Name);
  87. throw e;
  88. }
  89. #if DEBUG && !PROFILE_SVELTO
  90. if (implementor.numberOfImplementations > 1)
  91. throw new ECSException(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat(
  92. "Component Type: ", fieldType.Name, " implementor: ", implementor.instance.ToString()) +
  93. " - EntityComponent: " + componentBuilder.GetEntityComponentType().Name);
  94. #endif
  95. #if DEBUG && !PROFILE_SVELTO
  96. fieldSetter.Value(ref entityComponent, implementor.instance);
  97. #else
  98. fieldSetter.Value(ref entityComponent, implementor);
  99. #endif
  100. }
  101. implementorsByType.Clear();
  102. }
  103. }
  104. }