ecs framework

This commit is contained in:
szy73711 committed 2022-11-12 05:27:24 +08:00
1 parent 6d59d7f23f
commit 3a1e97df6f
20 files changed
+653 -2

No files matched your search

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4ebb82ca8005849b48d82e7b2799da17
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,48 @@
using System;
namespace GameCore.TinyECS
{
public readonly struct Entity<TEnum> : IEquatable<Entity<TEnum>> where TEnum : unmanaged
{
public readonly TEnum type;
public readonly int index;
public readonly int generation;
public Entity(TEnum type, int index, int generation)
{
this.type = type;
this.index = index;
this.generation = generation;
}
public override string ToString()
{
return $"Entity<{type}>({index},{generation})";
}
public bool Equals(Entity<TEnum> other)
{
return type.Equals(other.type) && index == other.index && generation == other.generation;
}
public override bool Equals(object obj)
{
return obj is Entity<TEnum> other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine(type, index, generation);
}
public static bool operator ==(Entity<TEnum> lhs, Entity<TEnum> rhs)
{
return lhs.Equals(rhs);
}
public static bool operator !=(Entity<TEnum> lhs, Entity<TEnum> rhs)
{
return !(lhs == rhs);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ad57411486945444c95e8a0aec2cf8b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,129 @@
using System;
using Unity.Collections;
using System.Diagnostics;
namespace GameCore.TinyECS
{
public struct EntityCollection<TEnum> : IDisposable where TEnum : unmanaged
{
private struct Buffer
{
public int index;
public int generation;
}
private NativeList<Buffer> entityBuffer;
private NativeList<int> entityIndexToDataIndex;
private TEnum entityType;
public EntityCollection(TEnum type, int capacity, Allocator allocator)
{
entityType = type;
entityBuffer = new (capacity, allocator);
entityIndexToDataIndex = new (capacity, allocator);
}
public void Dispose()
{
entityBuffer.Dispose();
entityIndexToDataIndex.Dispose();
}
public int Count => entityBuffer.Length;
public Entity<TEnum> this[int index]
{
get
{
var buf = entityBuffer[index];
return new(entityType, buf.index, buf.generation);
}
}
public int Add(Entity<TEnum> entity)
{
CheckEntityType(entity);
var dataIndex = entityBuffer.Length;
var oldEntityCount = entityIndexToDataIndex.Length;
if (entity.index >= oldEntityCount)
{
entityIndexToDataIndex.Resize(entity.index + 1, NativeArrayOptions.UninitializedMemory);
for (int i = oldEntityCount, e = entity.index - 1; i < e; ++i)
{
entityIndexToDataIndex[i] = -1;
}
}
entityIndexToDataIndex[entity.index] = dataIndex;
entityBuffer.Add(new Buffer{index = entity.index, generation = entity.generation });
return dataIndex;
}
public bool TryGetIndex(Entity<TEnum> entity, out int index)
{
CheckEntityType(entity);
index = 0;
if (entity.index >= entityIndexToDataIndex.Length)
{
return false;
}
index = entityIndexToDataIndex[entity.index];
if (index < 0 || index >= entityBuffer.Length)
{
return false;
}
var buf = entityBuffer[index];
return buf.index == entity.index && buf.generation == entity.generation;
}
public bool Remove(Entity<TEnum> entity, out int index, out bool removeFromBack)
{
CheckEntityType(entity);
if (!TryGetIndex(entity, out index))
{
removeFromBack = false;
return false;
}
removeFromBack = RemoveInternal(entity, index);
return true;
}
private bool RemoveInternal(Entity<TEnum> entity, int index)
{
entityIndexToDataIndex[entity.index] = -1;
var backIndex = entityBuffer.Length - 1;
if (index == backIndex)
{
entityBuffer.Resize(backIndex, NativeArrayOptions.UninitializedMemory);
return true;
}
var backBuf = entityBuffer[backIndex];
entityBuffer.RemoveAtSwapBack(index);
entityIndexToDataIndex[backBuf.index] = index;
return false;
}
[Conditional("DEBUG")]
void CheckEntityType(Entity<TEnum> entity)
{
if (!entity.type.Equals(entityType))
throw new Exception($"Wrong entity type: {entity.type}");
}
public void Clear()
{
entityBuffer.Clear();
entityIndexToDataIndex.Clear();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c788a2d204aeb46b188a801ae66ab4ce
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,79 @@
using System;
using Unity.Collections;
using Unity.Mathematics;
namespace GameCore.TinyECS
{
public struct EntityGenerator<TEnum> : IDisposable where TEnum : unmanaged
{
private NativeList<int> indexToGeneration;
private int beginSearchIndex;
private int freeCount;
private TEnum entityType;
public EntityGenerator(TEnum type, int capacity, Allocator allocator)
{
indexToGeneration = new(capacity, allocator) { 0 };
beginSearchIndex = 1;
freeCount = 0;
entityType = type;
}
public void Dispose()
{
indexToGeneration.Dispose();
}
public Entity<TEnum> Create()
{
if (freeCount == 0)
{
var index = indexToGeneration.Length;
indexToGeneration.Add(1);
return new(entityType, index, 1);
}
var count = indexToGeneration.Length;
for (var i = beginSearchIndex; i < count; ++i)
{
var oldGeneration = indexToGeneration[i];
if (oldGeneration >= 0)
continue;
beginSearchIndex = i + 1;
freeCount--;
var generation = 1 - oldGeneration;
indexToGeneration[i] = generation;
return new(entityType, i, generation);
}
throw new Exception("Impossible");
}
public void Delete(Entity<TEnum> entity)
{
var generation = indexToGeneration[entity.index];
if (generation != entity.generation)
{
throw new Exception($"Invalid entity: {entity}");
}
indexToGeneration[entity.index] = -generation;
freeCount++;
beginSearchIndex = math.min(beginSearchIndex, entity.index);
}
public bool IsValid(Entity<TEnum> entity)
{
var generation = indexToGeneration[entity.index];
return generation == entity.generation;
}
public void Clear()
{
indexToGeneration.Resize(1, NativeArrayOptions.UninitializedMemory);
beginSearchIndex = 1;
freeCount = 0;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d1bf40e20fa3e4ea69d9a9896a297fe1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,33 @@
{
"name": "TinyECS.Runtime",
"rootNamespace": "",
"references": [
"Unity.Collections",
"Unity.Mathematics"
],
"includePlatforms": [
"Android",
"Editor",
"iOS",
"LinuxStandalone64",
"Lumin",
"macOSStandalone",
"PS4",
"Stadia",
"Switch",
"tvOS",
"WSA",
"WebGL",
"WindowsStandalone32",
"WindowsStandalone64",
"XboxOne"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c2bd585c8e44341079d076e23cd9d3eb
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,14 @@
{
"name": "com.nimin.tinyecs",
"displayName": "Tiny ECS",
"version": "0.1.0",
"unity": "2021.3",
"description": "Data oriented ECS famework",
"dependencies": {
"com.unity.collections": "1.2.4",
"com.unity.burst": "1.8.1"
},
"keywords": [
"ECS", "JobSystem"
]
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: afdf6be686c684f4c8190a688038f1ca
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: