整理EntityDatabase代码

This commit is contained in:
sunqinzhe committed 2025-12-18 19:42:22 +08:00
1 parent 6c8108e3ea
commit d9b66edd89
18 files changed
+221 -58

No files matched your search

@@ -1,25 +1,30 @@
using System;
using Unity.Burst;
namespace GameCore.TinyECS
{
public struct ComponentId
internal static class ComponentIdHelper
{
struct Inner<T> where T : unmanaged
public static int currentId;
}
public struct ComponentId<T>
{
public int id;
public static readonly SharedStatic<ComponentId<T>> Instance = SharedStatic<ComponentId<T>>.GetOrCreate<ComponentId<T>>();
[BurstDiscard]
static void EnsureInitialized()
{
public int id;
private Inner(int i) => id = i;
public static Inner<T> Instance = default;
if (Instance.Data.id == 0)
{
Instance.Data.id = ++ComponentIdHelper.currentId;
}
}
static int currentId;
public static int Get<T>() where T : unmanaged
public static int Get()
{
if (Inner<T>.Instance.id == 0)
{
Inner<T>.Instance.id = ++currentId;
}
return Inner<T>.Instance.id;
EnsureInitialized();
return Instance.Data.id;
}
}
}
@@ -1,9 +1,10 @@
using System;
using GameCore.LowLevel;
using Unity.Collections.LowLevel.Unsafe;
namespace GameCore.TinyECS
{
public readonly struct Entity<TEnum> : IEquatable<Entity<TEnum>> where TEnum : unmanaged
public readonly struct Entity<TEnum> : IEquatable<Entity<TEnum>> where TEnum : unmanaged, IConvertible
{
public readonly TEnum type;
public readonly int index;
@@ -19,7 +20,7 @@ namespace GameCore.TinyECS
public override string ToString() => $"Entity<{type}>({index},{generation})";
public bool Equals(Entity<TEnum> other) => type.Equals(other.type) && index == other.index && generation == other.generation;
public override bool Equals(object obj) => obj is Entity<TEnum> other && Equals(other);
public override int GetHashCode() => LowLevelUtility.HashCombine(type.GetHashCode(), index, generation);
public override int GetHashCode() => LowLevelUtility.HashCombine(UnsafeUtility.EnumToInt(type), index, generation);
public static bool operator ==(Entity<TEnum> lhs, Entity<TEnum> rhs) => lhs.Equals(rhs);
public static bool operator !=(Entity<TEnum> lhs, Entity<TEnum> rhs) => !(lhs == rhs);
@@ -1,10 +1,12 @@
using System;
using Unity.Collections;
using System.Diagnostics;
using Unity.Collections.LowLevel.Unsafe;
namespace GameCore.TinyECS
{
public struct EntityCollection<TEnum> : IDisposable where TEnum : unmanaged
public struct EntityCollection<TEnum> : IDisposable
where TEnum : unmanaged, IConvertible
{
private struct Buffer
{
@@ -60,6 +62,25 @@ namespace GameCore.TinyECS
return dataIndex;
}
public int GetIndex(Entity<TEnum> entity)
{
CheckEntityType(entity);
if (entity.index >= entityIndexToDataIndex.Length)
{
throw new Exception($"Invalid entity: {entity}");
}
var index = entityIndexToDataIndex[entity.index];
var buf = entityBuffer[index];
if (buf.index != entity.index || buf.generation != entity.generation)
{
throw new Exception($"Invalid entity: {entity}");
}
return index;
}
public bool TryGetIndex(Entity<TEnum> entity, out int index)
{
CheckEntityType(entity);
@@ -115,7 +136,7 @@ namespace GameCore.TinyECS
[Conditional("DEBUG")]
void CheckEntityType(Entity<TEnum> entity)
{
if (!entity.type.Equals(entityType))
if (!UnsafeUtility.EnumEquals(entityType, entity.type))
throw new Exception($"Wrong entity type: {entity.type}");
}
@@ -29,7 +29,7 @@ namespace GameCore.TinyECS
public bool IsFull => elementCount == MaxElementCount;
public bool IsEmpty => elementCount == 0;
public EntityDataBlockChain(EntityDataBlockMeta blockMeta, int maxElementCountPerBlock)
public EntityDataBlockChain(EntityDataBlockMeta blockMeta, int maxElementCountPerBlock = 1024)
{
this.blockMeta = blockMeta;
blockPtrList = default;
@@ -72,7 +72,7 @@ namespace GameCore.TinyECS
void* ComponentPtrAt<T>(int elementIndex) where T : unmanaged
{
var componentId = ComponentId.Get<T>();
var componentId = ComponentId<T>.Get();
var componentIndex = blockMeta.componentIdToIndex[componentId];
if (componentIndex > 0)
{
@@ -133,7 +133,16 @@ namespace GameCore.TinyECS
elementCount--;
}
public ref T GetData<T>(int index) where T : unmanaged
public T GetData<T>(int index) where T : unmanaged
{
CheckElementIndex(index);
var pComponent = ComponentPtrAt<T>(index);
if (pComponent == null)
throw new Exception($"Invalid component type: {typeof(T)}");
return UnsafeUtility.AsRef<T>(pComponent);
}
public ref T GetDataRef<T>(int index) where T : unmanaged
{
CheckElementIndex(index);
var pComponent = ComponentPtrAt<T>(index);
@@ -150,7 +159,7 @@ namespace GameCore.TinyECS
}
}
public unsafe readonly struct EntityDataBlockView
public readonly unsafe struct EntityDataBlockView
{
private readonly void* ptr;
public readonly EntityDataBlockMeta meta;
@@ -172,7 +181,7 @@ namespace GameCore.TinyECS
void* ComponentPtrAt<T>(int elementIndex) where T : unmanaged
{
var componentId = ComponentId.Get<T>();
var componentId = ComponentId<T>.Get();
var componentIndex = meta.componentIdToIndex[componentId];
if (componentIndex > 0)
{
@@ -15,7 +15,7 @@ namespace GameCore.TinyECS
meta.componentIdToIndex.Length = meta.componentIdToIndex.Capacity;
meta.componentIdToOffset.Length = meta.componentIdToOffset.Capacity;
var id1 = ComponentId.Get<T1>();
var id1 = ComponentId<T1>.Get();
meta.componentIdToIndex[id1] = 1;
meta.componentIdToOffset[id1] = 0;
meta.elementSize = UnsafeUtility.SizeOf<T1>();
@@ -31,8 +31,8 @@ namespace GameCore.TinyECS
meta.componentIdToIndex.Length = meta.componentIdToIndex.Capacity;
meta.componentIdToOffset.Length = meta.componentIdToOffset.Capacity;
var id1 = ComponentId.Get<T1>();
var id2 = ComponentId.Get<T2>();
var id1 = ComponentId<T1>.Get();
var id2 = ComponentId<T2>.Get();
meta.componentIdToIndex[id1] = 1;
meta.componentIdToIndex[id2] = 2;
meta.componentIdToOffset[id1] = (short)LowLevelUtility.OffsetOf<(T1, T2), T1>();
@@ -6,5 +6,8 @@ namespace GameCore.TinyECS
{
void Add();
void Remove(int index);
T GetData<T>(int index) where T : unmanaged;
ref T GetDataRef<T>(int index) where T : unmanaged;
}
}
@@ -4,12 +4,23 @@ using Unity.Mathematics;
namespace GameCore.TinyECS
{
public struct EntityDatabase<TEnum, TData> : IDisposable where TEnum : unmanaged where TData : unmanaged, IEntityDataStruct
public struct EntityDatabase<TEnum, TData> : IDisposable
where TEnum : unmanaged, IConvertible
where TData : unmanaged, IEntityDataStruct
{
public TData dataStruct;
public EntityGenerator<TEnum> generator;
public EntityCollection<TEnum> collection;
public int Count => collection.Count;
public EntityDatabase(TEnum type, TData dataStruct, int capacity = 16)
{
generator = new (type, capacity, Allocator.Persistent);
collection = new (type, capacity, Allocator.Persistent);
this.dataStruct = dataStruct;
}
public Entity<TEnum> AddEntity()
{
var entity = generator.Create();
@@ -25,6 +36,18 @@ namespace GameCore.TinyECS
dataStruct.Remove(index);
}
public T GetData<T>(Entity<TEnum> entity) where T : unmanaged
{
var index = collection.GetIndex(entity);
return dataStruct.GetData<T>(index);
}
public ref T GetDataRef<T>(Entity<TEnum> entity) where T : unmanaged
{
var index = collection.GetIndex(entity);
return ref dataStruct.GetDataRef<T>(index);
}
public void Dispose()
{
generator.Dispose();
@@ -4,7 +4,8 @@ using Unity.Mathematics;
namespace GameCore.TinyECS
{
public struct EntityGenerator<TEnum> : IDisposable where TEnum : unmanaged
public struct EntityGenerator<TEnum> : IDisposable
where TEnum : unmanaged, IConvertible
{
private NativeList<int> indexToGeneration;
private int beginSearchIndex;
@@ -4,25 +4,10 @@
"references": [
"Unity.Collections",
"Unity.Mathematics",
"nimin.lowlevel"
],
"includePlatforms": [
"Android",
"Editor",
"iOS",
"LinuxStandalone64",
"Lumin",
"macOSStandalone",
"PS4",
"Stadia",
"Switch",
"tvOS",
"WSA",
"WebGL",
"WindowsStandalone32",
"WindowsStandalone64",
"XboxOne"
"nimin.lowlevel",
"Unity.Burst"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": false,