Mirror of Svelto.ECS because we're a fan of it
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

ComponentBuilder.cs 6.5KB

Svelto.ECS 2.9 changes (random order of importance): New Serialization framework more thorough disposing of the EnginesRoot an EnginesRoot reference should never be held, unless it’s a weak reference. The code changed to stick to this rule IReactOnAddAndRemove callbacks are now guaranteed to be called after all the entity structs generated by the same entity have been added and before any is removed. both functions pass the EGID of the analysing entity by parameter now, so that the entity struct won’t need to implement INeedEGID for this sole purpose. The IReactOnSwap MovedFrom method has been removed, it is now redundant. Entities built or removed during the IReactOnAddAndRemove callbacks are now added and removed immediately and not on the next submission like used to happen. This avoid some awkward checks that were previously needed inside engines. EntityStreams can get (optionally) the EGID of the entity published, so that the EntityStruct won’t need an INeedEGID for this sole purpose. Groups are not trimmed anymore when they are emptied to avoid allocations. Removed a bunch of run-time allocations that weren’t supposed to happen in Release and/or when the Profile define is used in editor (for debugging reasons Svelto.ECS may need to use strings at run-time, but Svelto.ECS is allocation zero in Release and when the Profile keyword is used) A improved the DynamicEntityDescriptor and ExtendibleEntityDescriptor code and more notably, introduced the new method ExtendedWith<> to facilitate the writing of modular and reusable entity descriptors. Several minor code design improvements/optimisations
4 anos atrás
5 anos atrás
Svelto.ECS 2.9 changes (random order of importance): New Serialization framework more thorough disposing of the EnginesRoot an EnginesRoot reference should never be held, unless it’s a weak reference. The code changed to stick to this rule IReactOnAddAndRemove callbacks are now guaranteed to be called after all the entity structs generated by the same entity have been added and before any is removed. both functions pass the EGID of the analysing entity by parameter now, so that the entity struct won’t need to implement INeedEGID for this sole purpose. The IReactOnSwap MovedFrom method has been removed, it is now redundant. Entities built or removed during the IReactOnAddAndRemove callbacks are now added and removed immediately and not on the next submission like used to happen. This avoid some awkward checks that were previously needed inside engines. EntityStreams can get (optionally) the EGID of the entity published, so that the EntityStruct won’t need an INeedEGID for this sole purpose. Groups are not trimmed anymore when they are emptied to avoid allocations. Removed a bunch of run-time allocations that weren’t supposed to happen in Release and/or when the Profile define is used in editor (for debugging reasons Svelto.ECS may need to use strings at run-time, but Svelto.ECS is allocation zero in Release and when the Profile keyword is used) A improved the DynamicEntityDescriptor and ExtendibleEntityDescriptor code and more notably, introduced the new method ExtendedWith<> to facilitate the writing of modular and reusable entity descriptors. Several minor code design improvements/optimisations
4 anos atrás
Svelto.ECS 2.9 changes (random order of importance): New Serialization framework more thorough disposing of the EnginesRoot an EnginesRoot reference should never be held, unless it’s a weak reference. The code changed to stick to this rule IReactOnAddAndRemove callbacks are now guaranteed to be called after all the entity structs generated by the same entity have been added and before any is removed. both functions pass the EGID of the analysing entity by parameter now, so that the entity struct won’t need to implement INeedEGID for this sole purpose. The IReactOnSwap MovedFrom method has been removed, it is now redundant. Entities built or removed during the IReactOnAddAndRemove callbacks are now added and removed immediately and not on the next submission like used to happen. This avoid some awkward checks that were previously needed inside engines. EntityStreams can get (optionally) the EGID of the entity published, so that the EntityStruct won’t need an INeedEGID for this sole purpose. Groups are not trimmed anymore when they are emptied to avoid allocations. Removed a bunch of run-time allocations that weren’t supposed to happen in Release and/or when the Profile define is used in editor (for debugging reasons Svelto.ECS may need to use strings at run-time, but Svelto.ECS is allocation zero in Release and when the Profile keyword is used) A improved the DynamicEntityDescriptor and ExtendibleEntityDescriptor code and more notably, introduced the new method ExtendedWith<> to facilitate the writing of modular and reusable entity descriptors. Several minor code design improvements/optimisations
4 anos atrás
Svelto.ECS 2.9 changes (random order of importance): New Serialization framework more thorough disposing of the EnginesRoot an EnginesRoot reference should never be held, unless it’s a weak reference. The code changed to stick to this rule IReactOnAddAndRemove callbacks are now guaranteed to be called after all the entity structs generated by the same entity have been added and before any is removed. both functions pass the EGID of the analysing entity by parameter now, so that the entity struct won’t need to implement INeedEGID for this sole purpose. The IReactOnSwap MovedFrom method has been removed, it is now redundant. Entities built or removed during the IReactOnAddAndRemove callbacks are now added and removed immediately and not on the next submission like used to happen. This avoid some awkward checks that were previously needed inside engines. EntityStreams can get (optionally) the EGID of the entity published, so that the EntityStruct won’t need an INeedEGID for this sole purpose. Groups are not trimmed anymore when they are emptied to avoid allocations. Removed a bunch of run-time allocations that weren’t supposed to happen in Release and/or when the Profile define is used in editor (for debugging reasons Svelto.ECS may need to use strings at run-time, but Svelto.ECS is allocation zero in Release and when the Profile keyword is used) A improved the DynamicEntityDescriptor and ExtendibleEntityDescriptor code and more notably, introduced the new method ExtendedWith<> to facilitate the writing of modular and reusable entity descriptors. Several minor code design improvements/optimisations
4 anos atrás
Svelto.ECS 2.9 changes (random order of importance): New Serialization framework more thorough disposing of the EnginesRoot an EnginesRoot reference should never be held, unless it’s a weak reference. The code changed to stick to this rule IReactOnAddAndRemove callbacks are now guaranteed to be called after all the entity structs generated by the same entity have been added and before any is removed. both functions pass the EGID of the analysing entity by parameter now, so that the entity struct won’t need to implement INeedEGID for this sole purpose. The IReactOnSwap MovedFrom method has been removed, it is now redundant. Entities built or removed during the IReactOnAddAndRemove callbacks are now added and removed immediately and not on the next submission like used to happen. This avoid some awkward checks that were previously needed inside engines. EntityStreams can get (optionally) the EGID of the entity published, so that the EntityStruct won’t need an INeedEGID for this sole purpose. Groups are not trimmed anymore when they are emptied to avoid allocations. Removed a bunch of run-time allocations that weren’t supposed to happen in Release and/or when the Profile define is used in editor (for debugging reasons Svelto.ECS may need to use strings at run-time, but Svelto.ECS is allocation zero in Release and when the Profile keyword is used) A improved the DynamicEntityDescriptor and ExtendibleEntityDescriptor code and more notably, introduced the new method ExtendedWith<> to facilitate the writing of modular and reusable entity descriptors. Several minor code design improvements/optimisations
4 anos atrás
Svelto.ECS 2.9 changes (random order of importance): New Serialization framework more thorough disposing of the EnginesRoot an EnginesRoot reference should never be held, unless it’s a weak reference. The code changed to stick to this rule IReactOnAddAndRemove callbacks are now guaranteed to be called after all the entity structs generated by the same entity have been added and before any is removed. both functions pass the EGID of the analysing entity by parameter now, so that the entity struct won’t need to implement INeedEGID for this sole purpose. The IReactOnSwap MovedFrom method has been removed, it is now redundant. Entities built or removed during the IReactOnAddAndRemove callbacks are now added and removed immediately and not on the next submission like used to happen. This avoid some awkward checks that were previously needed inside engines. EntityStreams can get (optionally) the EGID of the entity published, so that the EntityStruct won’t need an INeedEGID for this sole purpose. Groups are not trimmed anymore when they are emptied to avoid allocations. Removed a bunch of run-time allocations that weren’t supposed to happen in Release and/or when the Profile define is used in editor (for debugging reasons Svelto.ECS may need to use strings at run-time, but Svelto.ECS is allocation zero in Release and when the Profile keyword is used) A improved the DynamicEntityDescriptor and ExtendibleEntityDescriptor code and more notably, introduced the new method ExtendedWith<> to facilitate the writing of modular and reusable entity descriptors. Several minor code design improvements/optimisations
4 anos atrás
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using DBC.ECS;
  5. using Svelto.Common;
  6. using Svelto.DataStructures;
  7. using Svelto.ECS.Hybrid;
  8. using Svelto.ECS.Internal;
  9. using Svelto.Utilities;
  10. namespace Svelto.ECS
  11. {
  12. struct ComponentBuilderComparer : IEqualityComparer<IComponentBuilder>
  13. {
  14. public bool Equals(IComponentBuilder x, IComponentBuilder y)
  15. {
  16. return x.GetEntityComponentType() == y.GetEntityComponentType();
  17. }
  18. public int GetHashCode(IComponentBuilder obj)
  19. {
  20. return obj.GetEntityComponentType().GetHashCode();
  21. }
  22. }
  23. public class ComponentBuilder<T> : IComponentBuilder
  24. where T : struct, IEntityComponent
  25. {
  26. internal static readonly Type ENTITY_COMPONENT_TYPE;
  27. public static readonly bool HAS_EGID;
  28. internal static readonly bool IS_ENTITY_VIEW_COMPONENT;
  29. static readonly T DEFAULT_IT;
  30. static readonly string ENTITY_COMPONENT_NAME;
  31. static readonly bool IS_UNMANAGED;
  32. public static bool HAS_REFERENCE;
  33. static ComponentBuilder()
  34. {
  35. ENTITY_COMPONENT_TYPE = typeof(T);
  36. DEFAULT_IT = default;
  37. IS_ENTITY_VIEW_COMPONENT = typeof(IEntityViewComponent).IsAssignableFrom(ENTITY_COMPONENT_TYPE);
  38. HAS_EGID = typeof(INeedEGID).IsAssignableFrom(ENTITY_COMPONENT_TYPE);
  39. HAS_REFERENCE = typeof(INeedEntityReference).IsAssignableFrom(ENTITY_COMPONENT_TYPE);
  40. ENTITY_COMPONENT_NAME = ENTITY_COMPONENT_TYPE.ToString();
  41. IS_UNMANAGED = ENTITY_COMPONENT_TYPE.IsUnmanagedEx();
  42. if (IS_UNMANAGED)
  43. EntityComponentIDMap.Register<T>(new Filler<T>());
  44. SetEGIDWithoutBoxing<T>.Warmup();
  45. ComponentBuilderUtilities.CheckFields(ENTITY_COMPONENT_TYPE, IS_ENTITY_VIEW_COMPONENT);
  46. if (IS_ENTITY_VIEW_COMPONENT)
  47. {
  48. EntityViewComponentCache.InitCache();
  49. }
  50. else
  51. {
  52. if (ENTITY_COMPONENT_TYPE != ComponentBuilderUtilities.ENTITY_INFO_COMPONENT
  53. && ENTITY_COMPONENT_TYPE.IsUnmanagedEx() == false)
  54. throw new Exception(
  55. $"Entity Component check failed, unexpected struct type (must be unmanaged) {ENTITY_COMPONENT_TYPE}");
  56. }
  57. }
  58. public ComponentBuilder() { _initializer = DEFAULT_IT; }
  59. public ComponentBuilder(in T initializer) : this() { _initializer = initializer; }
  60. public bool isUnmanaged => IS_UNMANAGED;
  61. public void BuildEntityAndAddToList(ITypeSafeDictionary dictionary, EGID egid, IEnumerable<object> implementors)
  62. {
  63. var castedDic = dictionary as ITypeSafeDictionary<T>;
  64. T entityComponent = default;
  65. if (IS_ENTITY_VIEW_COMPONENT)
  66. {
  67. Check.Require(castedDic.ContainsKey(egid.entityID) == false
  68. , $"building an entity with already used entity id! id: '{(ulong) egid}', {ENTITY_COMPONENT_NAME}");
  69. this.SetEntityViewComponentImplementors(ref entityComponent, EntityViewComponentCache.cachedFields
  70. , implementors, EntityViewComponentCache.implementorsByType
  71. , EntityViewComponentCache.cachedTypes);
  72. castedDic.Add(egid.entityID, entityComponent);
  73. }
  74. else
  75. {
  76. Check.Require(!castedDic.ContainsKey(egid.entityID)
  77. , $"building an entity with already used entity id! id: '{egid.entityID}'");
  78. castedDic.Add(egid.entityID, _initializer);
  79. }
  80. }
  81. void IComponentBuilder.Preallocate(ITypeSafeDictionary dictionary, uint size) { Preallocate(dictionary, size); }
  82. public ITypeSafeDictionary CreateDictionary(uint size) { return TypeSafeDictionaryFactory<T>.Create(size); }
  83. public Type GetEntityComponentType() { return ENTITY_COMPONENT_TYPE; }
  84. public override int GetHashCode() { return _initializer.GetHashCode(); }
  85. static void Preallocate(ITypeSafeDictionary dictionary, uint size) { dictionary.ResizeTo(size); }
  86. readonly T _initializer;
  87. /// <summary>
  88. /// Note: this static class will hold forever the references of the entities implementors. These references
  89. /// are not even cleared when the engines root is destroyed, as they are static references.
  90. /// It must be seen as an application-wide cache system. Honestly, I am not sure if this may cause leaking
  91. /// issues in some kind of applications. To remember.
  92. /// </summary>
  93. static class EntityViewComponentCache
  94. {
  95. internal static readonly FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>> cachedFields;
  96. internal static readonly Dictionary<Type, Type[]> cachedTypes;
  97. #if DEBUG && !PROFILE_SVELTO
  98. internal static readonly Dictionary<Type, ECSTuple<object, int>> implementorsByType;
  99. #else
  100. internal static readonly Dictionary<Type, object> implementorsByType;
  101. #endif
  102. static EntityViewComponentCache()
  103. {
  104. cachedFields = new FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>>();
  105. var type = typeof(T);
  106. var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
  107. for (var i = fields.Length - 1; i >= 0; --i)
  108. {
  109. var field = fields[i];
  110. if (field.FieldType.IsInterface == true)
  111. {
  112. var setter = FastInvoke<T>.MakeSetter(field);
  113. //for each interface, cache the setter for this type
  114. cachedFields.Add(new KeyValuePair<Type, FastInvokeActionCast<T>>(field.FieldType, setter));
  115. }
  116. }
  117. #if DEBUG && !PROFILE_SVELTO
  118. if (fields.Length == 0)
  119. Console.LogWarning($"No fields found in component {type}. Are you declaring only properties?");
  120. #endif
  121. cachedTypes = new Dictionary<Type, Type[]>();
  122. #if DEBUG && !PROFILE_SVELTO
  123. implementorsByType = new Dictionary<Type, ECSTuple<object, int>>();
  124. #else
  125. implementorsByType = new Dictionary<Type, object>();
  126. #endif
  127. }
  128. internal static void InitCache() { }
  129. }
  130. }
  131. }