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.

EntityViewUtility.cs 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. internal static void SetEntityViewComponentImplementors<T>(this IComponentBuilder componentBuilder,
  30. ref T entityComponent, IEnumerable<object> implementors,
  31. ComponentBuilder<T>.EntityViewComponentCache localCache) where T : struct, IBaseEntityComponent
  32. {
  33. DBC.ECS.Check.Require(implementors != null,
  34. NULL_IMPLEMENTOR_ERROR.FastConcat(" entityComponent ",
  35. componentBuilder.GetEntityComponentType().ToString()));
  36. var cachedTypeInterfaces = localCache.cachedTypes;
  37. var implementorsByType = localCache.implementorsByType;
  38. var entityComponentBlazingFastReflection = localCache.cachedFields;
  39. foreach (var implementor in implementors)
  40. {
  41. DBC.ECS.Check.Require(implementor != null, "invalid null implementor used to build an entity");
  42. {
  43. var type = implementor.GetType();
  44. //fetch all the interfaces that the implementor implements
  45. if (cachedTypeInterfaces.TryGetValue(type, out var interfaces) == false)
  46. interfaces = cachedTypeInterfaces[type] = type.GetInterfacesEx();
  47. for (var iindex = 0; iindex < interfaces.Length; iindex++)
  48. {
  49. var componentType = interfaces[iindex];
  50. //an implementor can implement multiple interfaces, so for each interface we reference
  51. //the implementation object. Multiple entity view component fields can then be implemented
  52. //by the same implementor
  53. #if DEBUG && !PROFILE_SVELTO
  54. if (implementorsByType.TryGetValue(componentType, out var implementorData))
  55. {
  56. implementorData.numberOfImplementations++;
  57. implementorsByType[componentType] = implementorData;
  58. }
  59. else
  60. implementorsByType[componentType] = new ECSTuple<object, int>(implementor, 1);
  61. #else
  62. implementorsByType[componentType] = implementor;
  63. #endif
  64. }
  65. }
  66. }
  67. //efficient way to collect the fields of every EntityComponentType
  68. var setters = FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>>.NoVirt.ToArrayFast(
  69. entityComponentBlazingFastReflection, out var count);
  70. for (var i = 0; i < count; i++)
  71. {
  72. var fieldSetter = setters[i];
  73. var fieldType = fieldSetter.Key;
  74. #if DEBUG && !PROFILE_SVELTO
  75. ECSTuple<object, int> implementor;
  76. #else
  77. object implementor;
  78. #endif
  79. if (implementorsByType.TryGetValue(fieldType, out implementor) == false)
  80. {
  81. var e = new ECSException(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name +
  82. " - EntityComponent: " + componentBuilder.GetEntityComponentType().Name);
  83. throw e;
  84. }
  85. #if DEBUG && !PROFILE_SVELTO
  86. if (implementor.numberOfImplementations > 1)
  87. throw new ECSException(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat(
  88. "Component Type: ", fieldType.Name, " implementor: ", implementor.instance.ToString()) +
  89. " - EntityComponent: " + componentBuilder.GetEntityComponentType().Name);
  90. #endif
  91. #if DEBUG && !PROFILE_SVELTO
  92. fieldSetter.Value(ref entityComponent, implementor.instance);
  93. #else
  94. fieldSetter.Value(ref entityComponent, implementor);
  95. #endif
  96. }
  97. implementorsByType.Clear();
  98. }
  99. }
  100. }