ComponentManager.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Collections.Specialized;
  5. using System.Reflection;
  6. using Microsoft.Xna.Framework;
  7. using MonoGame.Extended.Collections;
  8. using MonoGame.Extended.ECS.Systems;
  9. namespace MonoGame.Extended.ECS
  10. {
  11. public interface IComponentMapperService : IEnumerable<ComponentMapper>
  12. {
  13. ComponentMapper<T> GetMapper<T>() where T : class;
  14. ComponentMapper this[Type type] { get; }
  15. }
  16. public class ComponentManager : UpdateSystem, IComponentMapperService, IEnumerable<ComponentMapper>
  17. {
  18. public ComponentManager()
  19. {
  20. _componentMappers = new Bag<ComponentMapper>();
  21. _componentTypes = new Dictionary<Type, int>();
  22. }
  23. internal readonly Bag<ComponentMapper> _componentMappers;
  24. internal readonly Dictionary<Type, int> _componentTypes;
  25. public Action<int> ComponentsChanged;
  26. private ComponentMapper CreateMapperForType(Type type, int componentTypeId)
  27. {
  28. if (!type.IsClass)
  29. throw new ArgumentException("Type must be a class type.", nameof(type));
  30. // TODO: We can probably do better than this without a huge performance penalty by creating our own bit vector that grows after the first 32 bits.
  31. if (componentTypeId >= 32)
  32. throw new InvalidOperationException("Component type limit exceeded. We currently only allow 32 component types for performance reasons.");
  33. var mapperType = typeof(ComponentMapper<>).MakeGenericType(type);
  34. var mapper = Activator.CreateInstance(mapperType, args: new object[] { componentTypeId, ComponentsChanged });
  35. _componentMappers[componentTypeId] = (ComponentMapper)mapper;
  36. return (ComponentMapper)mapper;
  37. }
  38. private ComponentMapper<T> CreateMapperForType<T>(int componentTypeId)
  39. where T : class
  40. {
  41. // TODO: We can probably do better than this without a huge performance penalty by creating our own bit vector that grows after the first 32 bits.
  42. if (componentTypeId >= 32)
  43. throw new InvalidOperationException("Component type limit exceeded. We currently only allow 32 component types for performance reasons.");
  44. var mapper = new ComponentMapper<T>(componentTypeId, ComponentsChanged);
  45. _componentMappers[componentTypeId] = mapper;
  46. return mapper;
  47. }
  48. public ComponentMapper GetMapper(int componentTypeId)
  49. {
  50. return _componentMappers[componentTypeId];
  51. }
  52. public ComponentMapper<T> GetMapper<T>()
  53. where T : class
  54. {
  55. var componentTypeId = GetComponentTypeId(typeof(T));
  56. if (_componentMappers[componentTypeId] != null)
  57. return _componentMappers[componentTypeId] as ComponentMapper<T>;
  58. return CreateMapperForType<T>(componentTypeId);
  59. }
  60. public int GetComponentTypeId(Type type)
  61. {
  62. if (_componentTypes.TryGetValue(type, out var id))
  63. return id;
  64. id = _componentTypes.Count;
  65. _componentTypes.Add(type, id);
  66. return id;
  67. }
  68. public BitVector32 CreateComponentBits(int entityId)
  69. {
  70. var componentBits = new BitVector32();
  71. var mask = BitVector32.CreateMask();
  72. for (var componentId = 0; componentId < _componentMappers.Count; componentId++)
  73. {
  74. componentBits[mask] = _componentMappers[componentId]?.Has(entityId) ?? false;
  75. mask = BitVector32.CreateMask(mask);
  76. }
  77. return componentBits;
  78. }
  79. public void Destroy(int entityId)
  80. {
  81. foreach (var componentMapper in _componentMappers)
  82. componentMapper?.Delete(entityId);
  83. }
  84. public override void Update(GameTime gameTime)
  85. {
  86. }
  87. public ComponentMapper this[Type type]
  88. {
  89. get
  90. {
  91. var componentTypeId = GetComponentTypeId(type);
  92. if (_componentMappers[componentTypeId] != null)
  93. return _componentMappers[componentTypeId];
  94. return CreateMapperForType(type, componentTypeId);
  95. }
  96. }
  97. IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
  98. public IEnumerator<ComponentMapper> GetEnumerator() => new ComponentMapperEnumerator(this);
  99. public struct ComponentMapperEnumerator : IEnumerator<ComponentMapper>
  100. {
  101. private readonly ComponentManager _componentManager;
  102. private IEnumerator<ComponentMapper> _enumerator;
  103. internal ComponentMapperEnumerator(ComponentManager componentManager)
  104. {
  105. _componentManager = componentManager;
  106. _enumerator = _componentManager._componentMappers.GetEnumerator();
  107. }
  108. public bool MoveNext()
  109. {
  110. return _enumerator.MoveNext();
  111. }
  112. public void Reset()
  113. {
  114. _enumerator.Reset();
  115. }
  116. object IEnumerator.Current => _enumerator.Current;
  117. public ComponentMapper Current => _enumerator.Current;
  118. public void Dispose()
  119. {
  120. _enumerator?.Dispose();
  121. }
  122. }
  123. }
  124. }