150 lines
5.0 KiB
C#
150 lines
5.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace Encompass
|
|
{
|
|
internal abstract class TypedComponentStore
|
|
{
|
|
public abstract int Count { get; }
|
|
public abstract bool Has(int entity);
|
|
public abstract bool Remove(int entity, int priority);
|
|
public abstract void ForceRemove(int entity);
|
|
public abstract void Clear();
|
|
public abstract void ClearPriorities();
|
|
}
|
|
|
|
internal class TypedComponentStore<TComponent> : TypedComponentStore where TComponent : struct
|
|
{
|
|
private int _nextID = 0;
|
|
private readonly Dictionary<int, int> _entityIDToStorageIndex = new Dictionary<int, int>(128);
|
|
private readonly Dictionary<int, int> _priorities = new Dictionary<int, int>(128);
|
|
private Entity[] _storageIndexToEntities = new Entity[128];
|
|
private TComponent[] _components = new TComponent[128];
|
|
|
|
public override int Count { get => _entityIDToStorageIndex.Count; }
|
|
|
|
public ref TComponent Get(int entityID)
|
|
{
|
|
if (!_entityIDToStorageIndex.ContainsKey(entityID)) { throw new Exceptions.NoComponentOfTypeOnEntityException("No component of type {0} exists on Entity with ID {1}", typeof(TComponent), entityID); }
|
|
return ref _components[_entityIDToStorageIndex[entityID]];
|
|
}
|
|
|
|
public ref TComponent Singular()
|
|
{
|
|
return ref _components[0];
|
|
}
|
|
|
|
public ref Entity SingularEntity()
|
|
{
|
|
return ref _storageIndexToEntities[0];
|
|
}
|
|
|
|
public void Set(int entityID, in TComponent component)
|
|
{
|
|
InternalSet(entityID, component);
|
|
}
|
|
|
|
public bool Set(int entityID, in TComponent component, int priority)
|
|
{
|
|
if (!_priorities.ContainsKey(entityID) || priority <= _priorities[entityID]) // if priorities are equal that means it's the same engine
|
|
{
|
|
InternalSet(entityID, component);
|
|
_priorities[entityID] = priority;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void InternalSet(int entityID, in TComponent component)
|
|
{
|
|
if (!_entityIDToStorageIndex.ContainsKey(entityID))
|
|
{
|
|
var index = _nextID++;
|
|
if (index >= _components.Length)
|
|
{
|
|
System.Array.Resize(ref _components, _components.Length * 2);
|
|
System.Array.Resize(ref _storageIndexToEntities, _storageIndexToEntities.Length * 2);
|
|
}
|
|
_entityIDToStorageIndex[entityID] = index;
|
|
_storageIndexToEntities[index] = new Entity(entityID);
|
|
}
|
|
|
|
_components[_entityIDToStorageIndex[entityID]] = component;
|
|
}
|
|
|
|
public override bool Remove(int entityID, int priority)
|
|
{
|
|
if (!_priorities.ContainsKey(entityID) || priority <= _priorities[entityID]) // if priorities are equal that means it's the same engine
|
|
{
|
|
ForceRemove(entityID);
|
|
_priorities[entityID] = priority;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public override void ForceRemove(int entityID)
|
|
{
|
|
if (_entityIDToStorageIndex.ContainsKey(entityID))
|
|
{
|
|
var storageIndex = _entityIDToStorageIndex[entityID];
|
|
_entityIDToStorageIndex.Remove(entityID);
|
|
|
|
// move a component into the hole to maintain contiguous memory
|
|
if (_nextID > 1 && storageIndex != _nextID - 1)
|
|
{
|
|
var lastStorageIndex = _nextID - 1;
|
|
ref readonly var lastEntity = ref _storageIndexToEntities[lastStorageIndex];
|
|
|
|
_entityIDToStorageIndex[lastEntity.ID] = storageIndex;
|
|
_storageIndexToEntities[storageIndex] = lastEntity;
|
|
_components[storageIndex] = _components[lastStorageIndex];
|
|
|
|
}
|
|
|
|
_nextID--;
|
|
}
|
|
}
|
|
|
|
public override bool Has(int entityID)
|
|
{
|
|
return _entityIDToStorageIndex.ContainsKey(entityID);
|
|
}
|
|
|
|
public override void Clear()
|
|
{
|
|
_nextID = 0;
|
|
_entityIDToStorageIndex.Clear();
|
|
_priorities.Clear();
|
|
}
|
|
|
|
public override void ClearPriorities()
|
|
{
|
|
_priorities.Clear();
|
|
}
|
|
|
|
public ReadOnlySpan<Entity> AllEntities()
|
|
{
|
|
return new ReadOnlySpan<Entity>(_storageIndexToEntities, 0, _nextID);
|
|
}
|
|
|
|
public IEnumerable<Entity> AllEntitiesAsEnumerable()
|
|
{
|
|
return new ArraySegment<Entity>(_storageIndexToEntities, 0, _nextID);
|
|
}
|
|
|
|
public ReadOnlySpan<TComponent> AllComponents()
|
|
{
|
|
return new ReadOnlySpan<TComponent>(_components, 0, _nextID);
|
|
}
|
|
|
|
public IEnumerable<TComponent> AllComponentsAsEnumerable()
|
|
{
|
|
return new ArraySegment<TComponent>(_components, 0, _nextID);
|
|
}
|
|
}
|
|
}
|