MoonTools.ECS/src/ComponentStorage.cs

141 lines
2.9 KiB
C#
Raw Normal View History

2022-04-08 05:52:03 +00:00
using System;
using System.Collections.Generic;
2023-11-03 19:40:26 +00:00
using MoonTools.ECS.Collections;
2022-03-05 02:01:44 +00:00
2022-04-08 05:52:03 +00:00
namespace MoonTools.ECS
2022-03-05 02:01:44 +00:00
{
2023-11-03 19:40:26 +00:00
internal unsafe class ComponentStorage : IDisposable
2022-03-05 02:01:44 +00:00
{
2023-11-03 19:40:26 +00:00
internal readonly Dictionary<Entity, int> EntityIDToStorageIndex = new Dictionary<Entity, int>(16);
internal readonly NativeArray Components;
internal readonly NativeArray<Entity> EntityIDs;
2022-03-05 02:01:44 +00:00
private bool disposed;
2023-11-03 19:40:26 +00:00
public ComponentStorage(int elementSize)
{
2023-11-03 19:40:26 +00:00
Components = new NativeArray(elementSize);
EntityIDs = new NativeArray<Entity>();
}
2022-03-05 02:01:44 +00:00
2022-04-08 05:52:03 +00:00
public bool Any()
{
2023-11-03 19:40:26 +00:00
return Components.Count > 0;
2022-04-08 05:52:03 +00:00
}
2022-03-05 02:01:44 +00:00
2023-11-03 19:40:26 +00:00
public bool Has(Entity entity)
2022-03-21 23:21:42 +00:00
{
2023-11-03 19:40:26 +00:00
return EntityIDToStorageIndex.ContainsKey(entity);
2022-03-21 23:21:42 +00:00
}
2023-11-03 19:40:26 +00:00
public ref T Get<T>(in Entity entity) where T : unmanaged
2022-03-05 02:01:44 +00:00
{
2023-11-03 19:40:26 +00:00
return ref Components.Get<T>(EntityIDToStorageIndex[entity]);
2022-04-08 05:52:03 +00:00
}
2022-03-05 02:01:44 +00:00
2023-11-03 19:40:26 +00:00
public ref T GetFirst<T>() where T : unmanaged
2022-04-08 05:52:03 +00:00
{
#if DEBUG
2023-11-03 19:40:26 +00:00
if (Components.Count == 0)
2022-03-05 02:01:44 +00:00
{
throw new IndexOutOfRangeException("Component storage is empty!");
2022-03-05 02:01:44 +00:00
}
2022-04-08 05:52:03 +00:00
#endif
2023-11-03 19:40:26 +00:00
return ref Components.Get<T>(0);
2022-03-05 02:01:44 +00:00
}
2023-11-03 19:40:26 +00:00
// Returns true if the entity had this component.
public bool Set<T>(in Entity entity, in T component) where T : unmanaged
2022-03-05 02:01:44 +00:00
{
2023-11-03 19:40:26 +00:00
if (EntityIDToStorageIndex.TryGetValue(entity, out var index))
2022-04-08 05:52:03 +00:00
{
2023-11-03 19:40:26 +00:00
Components.Set(index, component);
return true;
}
else
{
EntityIDToStorageIndex[entity] = Components.Count;
EntityIDs.Append(entity);
Components.Append(component);
return false;
2022-03-05 02:01:44 +00:00
}
}
// Returns true if the entity had this component.
2023-11-03 19:40:26 +00:00
public bool Remove(in Entity entity)
2022-04-08 05:52:03 +00:00
{
2023-11-03 19:40:26 +00:00
if (EntityIDToStorageIndex.TryGetValue(entity, out int index))
2022-04-08 05:52:03 +00:00
{
2023-11-03 19:40:26 +00:00
var lastElementIndex = Components.Count - 1;
2022-03-05 02:01:44 +00:00
2023-11-03 19:40:26 +00:00
var lastEntity = EntityIDs[lastElementIndex];
2022-03-21 23:21:42 +00:00
2022-04-08 05:52:03 +00:00
// move a component into the hole to maintain contiguous memory
2023-11-03 19:40:26 +00:00
Components.Delete(index);
EntityIDs.Delete(index);
EntityIDToStorageIndex.Remove(entity);
// update the index if it changed
if (lastElementIndex != index)
2022-04-08 05:52:03 +00:00
{
2023-11-03 19:40:26 +00:00
EntityIDToStorageIndex[lastEntity] = index;
2022-04-08 05:52:03 +00:00
}
return true;
2022-04-08 05:52:03 +00:00
}
return false;
2022-04-08 05:52:03 +00:00
}
2023-11-03 19:40:26 +00:00
public void Clear()
2022-04-08 05:52:03 +00:00
{
2023-11-03 19:40:26 +00:00
Components.Clear();
EntityIDs.Clear();
EntityIDToStorageIndex.Clear();
2022-04-08 05:52:03 +00:00
}
public Entity FirstEntity()
{
#if DEBUG
2023-11-03 19:40:26 +00:00
if (EntityIDs.Count == 0)
{
throw new IndexOutOfRangeException("Component storage is empty!");
}
#endif
2023-11-03 19:40:26 +00:00
return EntityIDs[0];
}
#if DEBUG
2023-11-03 19:40:26 +00:00
internal IEnumerable<Entity> Debug_GetEntities()
{
2023-11-03 19:40:26 +00:00
return EntityIDToStorageIndex.Keys;
}
2023-11-03 19:40:26 +00:00
#endif
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
2023-11-03 19:40:26 +00:00
Components.Dispose();
EntityIDs.Dispose();
disposed = true;
}
}
2023-11-03 19:40:26 +00:00
// ~ComponentStorage()
// {
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
// Dispose(disposing: false);
// }
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
2022-03-21 23:21:42 +00:00
}
2022-03-05 02:01:44 +00:00
}