using System; using System.Collections.Generic; using System.Collections.Specialized; using Microsoft.Xna.Framework; using MonoGame.Extended.Collections; using MonoGame.Extended.Entities.Systems; namespace MonoGame.Extended.Entities { public interface IComponentMapperService { ComponentMapper GetMapper() where T : class; } public class ComponentManager : UpdateSystem, IComponentMapperService { public ComponentManager() { _componentMappers = new Bag(); _componentTypes = new Dictionary(); } private readonly Bag _componentMappers; private readonly Dictionary _componentTypes; public Action ComponentsChanged; private ComponentMapper CreateMapperForType(int componentTypeId) where T : class { // 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. if (componentTypeId >= 32) throw new InvalidOperationException("Component type limit exceeded. We currently only allow 32 component types for performance reasons."); var mapper = new ComponentMapper(componentTypeId, ComponentsChanged); _componentMappers[componentTypeId] = mapper; return mapper; } public ComponentMapper GetMapper(int componentTypeId) { return _componentMappers[componentTypeId]; } public ComponentMapper GetMapper() where T : class { var componentTypeId = GetComponentTypeId(typeof(T)); if (_componentMappers[componentTypeId] != null) return _componentMappers[componentTypeId] as ComponentMapper; return CreateMapperForType(componentTypeId); } public int GetComponentTypeId(Type type) { if (_componentTypes.TryGetValue(type, out var id)) return id; id = _componentTypes.Count; _componentTypes.Add(type, id); return id; } public BitVector32 CreateComponentBits(int entityId) { var componentBits = new BitVector32(); var mask = BitVector32.CreateMask(); for (var componentId = 0; componentId < _componentMappers.Count; componentId++) { componentBits[mask] = _componentMappers[componentId]?.Has(entityId) ?? false; mask = BitVector32.CreateMask(mask); } return componentBits; } public void Destroy(int entityId) { foreach (var componentMapper in _componentMappers) componentMapper?.Delete(entityId); } public override void Update(GameTime gameTime) { } } }