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.

118 lines
4.9KB

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