mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 09:54:35 +08:00
update
This commit is contained in:
parent
c0c089ec01
commit
f15de024f5
@ -3,6 +3,7 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
[DebugColor(DebugColor.White)]
|
||||
public struct Parent : IEcsAttachComponent
|
||||
{
|
||||
public entlong entity;
|
||||
@ -36,7 +37,7 @@ namespace DCFApixels.DragonECS
|
||||
public static bool TryGetRoot(this EcsAttachPool<Parent> parents, EcsSubject conditionSubject, int entityID, out int rootEntityID)
|
||||
{
|
||||
rootEntityID = entityID;
|
||||
while (parents.Has(rootEntityID) && parents.Read(rootEntityID).entity.TryGetID(out int child) && conditionSubject.IsMatches(child))
|
||||
while (parents.Has(rootEntityID) && parents.Read(rootEntityID).entity.TryGetID(out int child) && !conditionSubject.IsMatches(child))
|
||||
rootEntityID = child;
|
||||
return rootEntityID != entityID;
|
||||
}
|
||||
@ -47,5 +48,25 @@ namespace DCFApixels.DragonECS
|
||||
rootEntityID = child;
|
||||
return rootEntityID != entityID;
|
||||
}
|
||||
|
||||
public static bool TryFindParentWithSubject(this EcsAttachPool<Parent> parents, EcsSubject conditionSubject, int entityID, out int resultEntityID)
|
||||
{
|
||||
resultEntityID = entityID;
|
||||
while (parents.Has(resultEntityID) && parents.Read(resultEntityID).entity.TryGetID(out int child) && !conditionSubject.IsMatches(resultEntityID))
|
||||
resultEntityID = child;
|
||||
return conditionSubject.IsMatches(resultEntityID);
|
||||
}
|
||||
public static bool TryFindParentWith<TComponent>(this EcsAttachPool<Parent> parents, int entityID, out int resultEntityID) where TComponent : struct
|
||||
{
|
||||
var pool = parents.World.AllPools[parents.World.GetComponentID<TComponent>()];
|
||||
resultEntityID = entityID;
|
||||
while (!pool.Has(resultEntityID) &&
|
||||
parents.Has(resultEntityID) &&
|
||||
parents.Read(resultEntityID).entity.TryGetID(out int child))
|
||||
{
|
||||
resultEntityID = child;
|
||||
}
|
||||
return pool.Has(resultEntityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,13 +67,31 @@ namespace DCFApixels.DragonECS
|
||||
/// <summary> Magenta. RGB is (255, 0, 255)</summary>
|
||||
Magenta = (255 << 24) + (000 << 16) + (255 << 8),
|
||||
|
||||
/// <summary> Yellow. RGB is (255, 127, 0)</summary>
|
||||
Orange = (255 << 24) + (127 << 16) + (000 << 8),
|
||||
|
||||
/// <summary> Yellow. RGB is (255, 165, 0)</summary>
|
||||
Orange = (255 << 24) + (165 << 16) + (000 << 8),
|
||||
/// <summary> Yellow. RGB is (255, 69, 0)</summary>
|
||||
OrangeRed = (255 << 24) + (69 << 16) + (000 << 8),
|
||||
/// <summary> Lime. RGB is (125, 255, 0)</summary>
|
||||
Lime = (125 << 24) + (255 << 16) + (000 << 8),
|
||||
/// <summary> Lime. RGB is (127, 255, 212)</summary>
|
||||
Aquamarine = (127 << 24) + (255 << 16) + (212 << 8),
|
||||
/// <summary> Lime. RGB is (218, 165, 32)</summary>
|
||||
Goldenrod = (218 << 24) + (165 << 16) + (32 << 8),
|
||||
/// <summary> Yellow. RGB is (255, 105, 180)</summary>
|
||||
DeepPink = (255 << 24) + (105 << 16) + (180 << 8),
|
||||
/// <summary> Yellow. RGB is (220, 20, 60)</summary>
|
||||
Crimson = (220 << 24) + (20 << 16) + (60 << 8),
|
||||
/// <summary> Yellow. RGB is (138, 43, 226)</summary>
|
||||
BlueViolet = (138 << 24) + (43 << 16) + (226 << 8),
|
||||
/// <summary> Yellow. RGB is (255, 3, 62)</summary>
|
||||
AmericanRose = (255 << 24) + (3 << 16) + (62 << 8),
|
||||
|
||||
/// <summary> Grey/Gray. RGB is (127, 127, 127)</summary>
|
||||
Gray = (127 << 24) + (127 << 16) + (127 << 8),
|
||||
/// <summary> Grey/Gray. RGB is (127, 127, 127)</summary>
|
||||
Grey = Gray,
|
||||
/// <summary> Grey/Gray. RGB is (192, 192, 192)</summary>
|
||||
Silver = (192 << 24) + (192 << 16) + (192 << 8),
|
||||
/// <summary> White. RGB is (255, 255, 255)</summary>
|
||||
White = -1,
|
||||
/// <summary> Black. RGB is (0, 0, 0)</summary>
|
||||
|
55
src/Debug/EcsDebugUtility.cs
Normal file
55
src/Debug/EcsDebugUtility.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public static class EcsDebugUtility
|
||||
{
|
||||
public static string GetGenericTypeName<T>(int maxDepth = 2) => GetGenericTypeName(typeof(T), maxDepth);
|
||||
public static string GetGenericTypeName(Type type, int maxDepth = 2)
|
||||
{
|
||||
#if (DEBUG && !DISABLE_DEBUG)
|
||||
string friendlyName = type.Name;
|
||||
if (!type.IsGenericType || maxDepth == 0)
|
||||
return friendlyName;
|
||||
|
||||
int iBacktick = friendlyName.IndexOf('`');
|
||||
if (iBacktick > 0)
|
||||
friendlyName = friendlyName.Remove(iBacktick);
|
||||
|
||||
friendlyName += "<";
|
||||
Type[] typeParameters = type.GetGenericArguments();
|
||||
for (int i = 0; i < typeParameters.Length; ++i)
|
||||
{
|
||||
string typeParamName = GetGenericTypeName(typeParameters[i], maxDepth - 1);
|
||||
friendlyName += (i == 0 ? typeParamName : "," + typeParamName);
|
||||
}
|
||||
friendlyName += ">";
|
||||
return friendlyName;
|
||||
#else
|
||||
return type.Name;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static string GetName<T>() => GetName(typeof(T));
|
||||
public static string GetName(Type type)
|
||||
{
|
||||
var atr = type.GetCustomAttribute<DebugNameAttribute>();
|
||||
return atr != null ? atr.name : GetGenericTypeName(type);
|
||||
}
|
||||
|
||||
public static string GetDescription<T>() => GetDescription(typeof(T));
|
||||
public static string GetDescription(Type type)
|
||||
{
|
||||
var atr = type.GetCustomAttribute<DebugDescriptionAttribute>();
|
||||
return atr != null ? atr.description : string.Empty;
|
||||
}
|
||||
|
||||
public static (byte, byte, byte) GetColorRGB<T>() => GetColorRGB(typeof(T));
|
||||
public static (byte, byte, byte) GetColorRGB(Type type)
|
||||
{
|
||||
var atr = type.GetCustomAttribute<DebugColorAttribute>();
|
||||
return atr != null ? (atr.r, atr.g, atr.b) : ((byte)255, (byte)255, (byte)255);
|
||||
}
|
||||
}
|
||||
}
|
@ -184,6 +184,13 @@ namespace DCFApixels.DragonECS
|
||||
AddInternal(system, layerName, true);
|
||||
return this;
|
||||
}
|
||||
public Builder Remove<TSystem>()
|
||||
{
|
||||
_uniqueTypes.Remove(typeof(TSystem));
|
||||
foreach (var list in _systems.Values)
|
||||
list.RemoveAll(o => o is TSystem);
|
||||
return this;
|
||||
}
|
||||
private void AddInternal(IEcsSystem system, string layerName, bool isUnique)
|
||||
{
|
||||
if (layerName == null) layerName = _basicLayer;
|
||||
|
@ -44,7 +44,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
internal static class EcsRunnerActivator
|
||||
{
|
||||
private static Dictionary<Guid, Type> _runnerHandlerTypes; //interface guid/Runner handler type pairs;
|
||||
private static Dictionary<Type, Type> _runnerHandlerTypes; //interface base type/Runner handler type pairs;
|
||||
|
||||
static EcsRunnerActivator()
|
||||
{
|
||||
@ -69,11 +69,12 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
}
|
||||
#endif
|
||||
_runnerHandlerTypes = new Dictionary<Guid, Type>();
|
||||
_runnerHandlerTypes = new Dictionary<Type, Type>();
|
||||
foreach (var item in runnerHandlerTypes)
|
||||
{
|
||||
Type interfaceType = item.BaseType.GenericTypeArguments[0];
|
||||
_runnerHandlerTypes.Add(interfaceType.GUID, item);
|
||||
// if(!_runnerHandlerTypes.ContainsKey(interfaceType.GUID))//TODO это кажется костыль, изначально все работало без этого ифа
|
||||
_runnerHandlerTypes.Add(interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType, item);
|
||||
}
|
||||
|
||||
if (delayedExceptions.Count > 0)
|
||||
@ -112,14 +113,8 @@ namespace DCFApixels.DragonECS
|
||||
internal static void InitFor<TInterface>() where TInterface : IEcsSystem
|
||||
{
|
||||
Type interfaceType = typeof(TInterface);
|
||||
Type nonGenericInterfaceType = interfaceType;
|
||||
if (nonGenericInterfaceType.IsGenericType)
|
||||
{
|
||||
nonGenericInterfaceType = nonGenericInterfaceType.GetGenericTypeDefinition();
|
||||
}
|
||||
Guid interfaceGuid = nonGenericInterfaceType.GUID;
|
||||
|
||||
if (!_runnerHandlerTypes.TryGetValue(interfaceGuid, out Type runnerType))
|
||||
if (!_runnerHandlerTypes.TryGetValue(interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType, out Type runnerType))
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
public sealed override TPool Exclude<TComponent, TPool>()
|
||||
{
|
||||
|
||||
ExcludeImplicit<TComponent>();
|
||||
return _world.GetPool<TComponent, TPool>();
|
||||
}
|
||||
public sealed override TPool Optional<TComponent, TPool>()
|
||||
|
132
src/EcsWorld.cs
132
src/EcsWorld.cs
@ -39,6 +39,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
internal IEcsPoolImplementation[] pools;
|
||||
private EcsNullPool _nullPool;
|
||||
private int _poolsCount = 0;
|
||||
|
||||
private EcsSubject[] _subjects;
|
||||
private EcsQueryExecutor[] _executors;
|
||||
@ -58,7 +59,8 @@ namespace DCFApixels.DragonECS
|
||||
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
||||
public EcsPipeline Pipeline => _pipeline;
|
||||
public EcsReadonlyGroup Entities => _allEntites.Readonly;
|
||||
public ReadOnlySpan<IEcsPoolImplementation> AllPools => pools;
|
||||
public ReadOnlySpan<IEcsPoolImplementation> AllPools => pools;// new ReadOnlySpan<IEcsPoolImplementation>(pools, 0, _poolsCount);
|
||||
public int PoolsCount => _poolsCount;
|
||||
#endregion
|
||||
|
||||
#region Constructors/Destroy
|
||||
@ -151,7 +153,7 @@ namespace DCFApixels.DragonECS
|
||||
var pool = new TPool();
|
||||
pools[uniqueID] = pool;
|
||||
pool.OnInit(this, uniqueID);
|
||||
|
||||
_poolsCount++;
|
||||
//EcsDebug.Print(pool.GetType().FullName);
|
||||
}
|
||||
|
||||
@ -289,7 +291,7 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
|
||||
#region Entity
|
||||
public int NewEntity()
|
||||
public int NewEmptyEntity()
|
||||
{
|
||||
int entityID = _entityDispenser.GetFree();
|
||||
_entitiesCount++;
|
||||
@ -316,15 +318,16 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
foreach (var item in pools)
|
||||
item.OnWorldResize(_gens.Length);
|
||||
|
||||
}
|
||||
_gens[entityID] &= GEN_BITS;
|
||||
_entityCreate.OnEntityCreate(entityID);
|
||||
_allEntites.Add(entityID);
|
||||
return entityID;
|
||||
}
|
||||
public entlong NewEntityLong()
|
||||
public entlong NewEmptyEntityLong()
|
||||
{
|
||||
int e = NewEntity();
|
||||
int e = NewEmptyEntity();
|
||||
return GetEntityLong(e);
|
||||
}
|
||||
|
||||
@ -355,7 +358,7 @@ namespace DCFApixels.DragonECS
|
||||
_delEntBufferCount = 0;
|
||||
}
|
||||
public short GetGen(int entityID) => _gens[entityID];
|
||||
public short GetComponentCount(int entityID) => _componentCounts[entityID];
|
||||
public short GetComponentsCount(int entityID) => _componentCounts[entityID];
|
||||
public void DeleteEmptyEntites()
|
||||
{
|
||||
foreach (var e in _allEntites)
|
||||
@ -365,6 +368,30 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyEntity(int fromEntityID, int toEntityID)
|
||||
{
|
||||
foreach (var pool in pools)
|
||||
{
|
||||
if(pool.Has(fromEntityID))
|
||||
pool.Copy(fromEntityID, toEntityID);
|
||||
}
|
||||
}
|
||||
public int CloneEntity(int fromEntityID)
|
||||
{
|
||||
int newEntity = NewEmptyEntity();
|
||||
CopyEntity(fromEntityID, newEntity);
|
||||
return newEntity;
|
||||
}
|
||||
public void CloneEntity(int fromEntityID, int toEntityID)
|
||||
{
|
||||
CopyEntity(fromEntityID, toEntityID);
|
||||
foreach (var pool in pools)
|
||||
{
|
||||
if (!pool.Has(fromEntityID)&& pool.Has(toEntityID))
|
||||
pool.Del(toEntityID);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal void IncrementEntityComponentCount(int entityID)
|
||||
{
|
||||
@ -374,7 +401,7 @@ namespace DCFApixels.DragonECS
|
||||
internal void DecrementEntityComponentCount(int entityID)
|
||||
{
|
||||
var count = --_componentCounts[entityID];
|
||||
if(count == 0)
|
||||
if(count == 0 && _allEntites.Has(entityID))
|
||||
DelEntity(entityID);
|
||||
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
@ -406,39 +433,55 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
|
||||
#region Debug
|
||||
// public int GetComponents(int entity, ref object[] list)
|
||||
// {
|
||||
// var entityOffset = GetRawEntityOffset(entity);
|
||||
// var itemsCount = _entities[entityOffset + RawEntityOffsets.ComponentsCount];
|
||||
// if (itemsCount == 0) { return 0; }
|
||||
// if (list == null || list.Length < itemsCount)
|
||||
// {
|
||||
// list = new object[_pools.Length];
|
||||
// }
|
||||
// var dataOffset = entityOffset + RawEntityOffsets.Components;
|
||||
// for (var i = 0; i < itemsCount; i++)
|
||||
// {
|
||||
// list[i] = _pools[_entities[dataOffset + i]].GetRaw(entity);
|
||||
// }
|
||||
// return itemsCount;
|
||||
// }
|
||||
//
|
||||
// public int GetComponentTypes(int entity, ref Type[] list)
|
||||
// {
|
||||
// var entityOffset = GetRawEntityOffset(entity);
|
||||
// var itemsCount = _entities[entityOffset + RawEntityOffsets.ComponentsCount];
|
||||
// if (itemsCount == 0) { return 0; }
|
||||
// if (list == null || list.Length < itemsCount)
|
||||
// {
|
||||
// list = new Type[_pools.Length];
|
||||
// }
|
||||
// var dataOffset = entityOffset + RawEntityOffsets.Components;
|
||||
// for (var i = 0; i < itemsCount; i++)
|
||||
// {
|
||||
// list[i] = _pools[_entities[dataOffset + i]].GetComponentType();
|
||||
// }
|
||||
// return itemsCount;
|
||||
// }
|
||||
public void GetComponents(int entityID, List<object> list)
|
||||
{
|
||||
list.Clear();
|
||||
var itemsCount = GetComponentsCount(entityID);
|
||||
if (itemsCount == 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < pools.Length; i++)
|
||||
{
|
||||
if (pools[i].Has(entityID))
|
||||
list.Add(pools[i].GetRaw(entityID));
|
||||
if (list.Count >= itemsCount)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// public int GetComponents(int entity, ref object[] list)
|
||||
// {
|
||||
// var entityOffset = GetRawEntityOffset(entity);
|
||||
// var itemsCount = _entities[entityOffset + RawEntityOffsets.ComponentsCount];
|
||||
// if (itemsCount == 0) { return 0; }
|
||||
// if (list == null || list.Length < itemsCount)
|
||||
// {
|
||||
// list = new object[_pools.Length];
|
||||
// }
|
||||
// var dataOffset = entityOffset + RawEntityOffsets.Components;
|
||||
// for (var i = 0; i < itemsCount; i++)
|
||||
// {
|
||||
// list[i] = _pools[_entities[dataOffset + i]].GetRaw(entity);
|
||||
// }
|
||||
// return itemsCount;
|
||||
// }
|
||||
|
||||
// public int GetComponentTypes(int entity, ref Type[] list)
|
||||
// {
|
||||
// var entityOffset = GetRawEntityOffset(entity);
|
||||
// var itemsCount = _entities[entityOffset + RawEntityOffsets.ComponentsCount];
|
||||
// if (itemsCount == 0) { return 0; }
|
||||
// if (list == null || list.Length < itemsCount)
|
||||
// {
|
||||
// list = new Type[_pools.Length];
|
||||
// }
|
||||
// var dataOffset = entityOffset + RawEntityOffsets.Components;
|
||||
// for (var i = 0; i < itemsCount; i++)
|
||||
// {
|
||||
// list[i] = _pools[_entities[dataOffset + i]].GetComponentType();
|
||||
// }
|
||||
// return itemsCount;
|
||||
// }
|
||||
#endregion
|
||||
}
|
||||
|
||||
@ -577,4 +620,13 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// #region Callbacks Interface //TODO
|
||||
// public interface IWorldCallbacks
|
||||
// {
|
||||
// void OnWorldResize(int newSize);
|
||||
// void OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer);
|
||||
// void OnWorldDestroy();
|
||||
// }
|
||||
// #endregion
|
||||
}
|
||||
|
@ -67,6 +67,11 @@ namespace DCFApixels.DragonECS
|
||||
#endif
|
||||
return group.GetEnumerator();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return group.ToString();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -132,6 +132,16 @@ namespace DCFApixels.DragonECS
|
||||
else
|
||||
Add(toEntityID, Read(fromEntityID).Target);
|
||||
}
|
||||
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||
{
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||
#endif
|
||||
if (Has(toEntityID))
|
||||
toWorld.GetPool<T>().Set(toEntityID, Read(fromEntityID).Target);
|
||||
else
|
||||
toWorld.GetPool<T>().Add(toEntityID, Read(fromEntityID).Target);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region WorldCallbacks
|
||||
|
@ -38,6 +38,7 @@ namespace DCFApixels.DragonECS
|
||||
_count = 0;
|
||||
|
||||
_componentResetHandler = EcsComponentResetHandler<T>.instance;
|
||||
_componentCopyHandler = EcsComponentCopyHandler<T>.instance;
|
||||
_poolRunners = new PoolRunners(world.Pipeline);
|
||||
}
|
||||
#endregion
|
||||
@ -63,6 +64,10 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref Write(toEntityID));
|
||||
}
|
||||
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||
{
|
||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref toWorld.GetPool<T>().Write(toEntityID));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Callbacks
|
||||
|
@ -147,10 +147,14 @@ namespace DCFApixels.DragonECS
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||
#endif
|
||||
if (Has(toEntityID))
|
||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref Write(toEntityID));
|
||||
else
|
||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref Add(toEntityID));
|
||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref TryAddOrWrite(toEntityID));
|
||||
}
|
||||
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||
{
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||
#endif
|
||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref toWorld.GetPool<T>().TryAddOrWrite(toEntityID));
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using DCFApixels.DragonECS.Internal;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
@ -21,6 +22,7 @@ namespace DCFApixels.DragonECS
|
||||
object GetRaw(int entityID);
|
||||
void SetRaw(int entityID, object dataRaw);
|
||||
void Copy(int fromEntityID, int toEntityID);
|
||||
void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID);
|
||||
#endregion
|
||||
}
|
||||
public interface IEcsPool<T>
|
||||
@ -76,7 +78,7 @@ namespace DCFApixels.DragonECS
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsNullOrDummy(this IEcsPool self)
|
||||
{
|
||||
return self == null || self is Internal.EcsNullPool;
|
||||
return self == null || self == EcsNullPool.instance;
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,11 +91,11 @@ namespace DCFApixels.DragonECS
|
||||
public static EcsNullPool instance => new EcsNullPool();
|
||||
|
||||
#region Properties
|
||||
int IEcsPool.ComponentID => throw new NotImplementedException();
|
||||
int IEcsPool.ComponentID => -1;
|
||||
Type IEcsPool.ComponentType => typeof(NullComponent);
|
||||
EcsWorld IEcsPool.World => throw new NotImplementedException();
|
||||
public int Count => 0;
|
||||
public int Capacity => 0;
|
||||
public int Count => -1;
|
||||
public int Capacity => -1;
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
@ -103,6 +105,7 @@ namespace DCFApixels.DragonECS
|
||||
object IEcsPool.GetRaw(int entityID) => throw new NotImplementedException();
|
||||
void IEcsPool.SetRaw(int entity, object dataRaw) => throw new NotImplementedException();
|
||||
void IEcsPool.Copy(int fromEntityID, int toEntityID) => throw new NotImplementedException();
|
||||
void IEcsPool.Copy(int fromEntityID, EcsWorld toWorld, int toEntityID) => throw new NotImplementedException();
|
||||
ref NullComponent IEcsPool<NullComponent>.Add(int entityID) => throw new NotImplementedException();
|
||||
ref readonly NullComponent IEcsPool<NullComponent>.Read(int entityID) => throw new NotImplementedException();
|
||||
ref NullComponent IEcsPool<NullComponent>.Write(int entityID) => throw new NotImplementedException();
|
||||
|
@ -105,6 +105,13 @@ namespace DCFApixels.DragonECS
|
||||
#endif
|
||||
TryAddOrWrite(toEntityID);
|
||||
}
|
||||
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||
{
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||
#endif
|
||||
toWorld.GetPool<T>().TryAddOrWrite(toEntityID);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Callbacks
|
||||
|
@ -87,6 +87,13 @@ namespace DCFApixels.DragonECS
|
||||
#endif
|
||||
TryAdd(toEntityID);
|
||||
}
|
||||
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||
{
|
||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||
#endif
|
||||
toWorld.GetPool<T>().TryAdd(toEntityID);
|
||||
}
|
||||
public void Set(int entityID, bool isHas)
|
||||
{
|
||||
if (isHas)
|
||||
@ -100,6 +107,13 @@ namespace DCFApixels.DragonECS
|
||||
Del(entityID);
|
||||
}
|
||||
}
|
||||
public void Toggle(int entityID)
|
||||
{
|
||||
if (Has(entityID))
|
||||
Del(entityID);
|
||||
else
|
||||
Add(entityID);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Callbacks
|
||||
|
@ -1,42 +1,49 @@
|
||||
using System;
|
||||
//SparseArray. Analogous to Dictionary<int, T>, but faster.
|
||||
//Benchmark result of indexer.get speed test with 300 elements:
|
||||
//[Dictinary: 5.786us] [SparseArray: 2.047us].
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public class SparseArray<TValue>
|
||||
{
|
||||
public const int MIN_CAPACITY = 16;
|
||||
public const int MIN_CAPACITY_BITS_OFFSET = 4;
|
||||
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
|
||||
private const int EMPTY = -1;
|
||||
|
||||
private int[] _buckets = Array.Empty<int>();
|
||||
private Entry[] _entries = Array.Empty<Entry>();
|
||||
private int[] _dense;
|
||||
|
||||
private int _count;
|
||||
|
||||
private int _freeList;
|
||||
private int _freeCount;
|
||||
|
||||
private int _modBitMask;
|
||||
|
||||
#region Properties
|
||||
public TValue this[int key]
|
||||
public ref TValue this[int key]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _entries[FindEntry(key)].value;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set => Insert(key, value);
|
||||
get => ref _entries[FindEntry(key)].value;
|
||||
//set => Insert(key, value);
|
||||
}
|
||||
|
||||
public int Count => _count;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public SparseArray(int capacity = MIN_CAPACITY)
|
||||
public SparseArray(int minCapacity = MIN_CAPACITY)
|
||||
{
|
||||
_buckets = new int[capacity];
|
||||
for (int i = 0; i < capacity; i++)
|
||||
minCapacity = NormalizeCapacity(minCapacity);
|
||||
_buckets = new int[minCapacity];
|
||||
for (int i = 0; i < minCapacity; i++)
|
||||
_buckets[i] = EMPTY;
|
||||
_entries = new Entry[capacity];
|
||||
_entries = new Entry[minCapacity];
|
||||
_modBitMask = (minCapacity - 1) & 0x7FFFFFFF;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -53,19 +60,16 @@ namespace DCFApixels
|
||||
#endregion
|
||||
|
||||
#region Find/Insert/Remove
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int FindEntry(int key)
|
||||
{
|
||||
key &= 0x7FFFFFFF;
|
||||
for (int i = _buckets[key % _buckets.Length]; i >= 0; i = _entries[i].next)
|
||||
{
|
||||
for (int i = _buckets[key & _modBitMask]; i >= 0; i = _entries[i].next)
|
||||
if (_entries[i].hashKey == key) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private void Insert(int key, TValue value)
|
||||
{
|
||||
key &= 0x7FFFFFFF;
|
||||
int targetBucket = key % _buckets.Length;
|
||||
int targetBucket = key & _modBitMask;
|
||||
|
||||
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
|
||||
{
|
||||
@ -88,10 +92,9 @@ namespace DCFApixels
|
||||
if (_count == _entries.Length)
|
||||
{
|
||||
Resize();
|
||||
targetBucket = key % _buckets.Length;
|
||||
targetBucket = key & _modBitMask;
|
||||
}
|
||||
index = _count;
|
||||
_count++;
|
||||
index = _count++;
|
||||
}
|
||||
|
||||
_entries[index].next = _buckets[targetBucket];
|
||||
@ -101,8 +104,7 @@ namespace DCFApixels
|
||||
}
|
||||
public bool Remove(int key)
|
||||
{
|
||||
key &= 0x7FFFFFFF;
|
||||
int bucket = key % _buckets.Length;
|
||||
int bucket = key & _modBitMask;
|
||||
int last = -1;
|
||||
for (int i = _buckets[bucket]; i >= 0; last = i, i = _entries[i].next)
|
||||
{
|
||||
@ -168,6 +170,7 @@ namespace DCFApixels
|
||||
private void Resize()
|
||||
{
|
||||
int newSize = _buckets.Length << 1;
|
||||
_modBitMask = (newSize - 1) & 0x7FFFFFFF;
|
||||
|
||||
Contract.Assert(newSize >= _entries.Length);
|
||||
int[] newBuckets = new int[newSize];
|
||||
@ -188,14 +191,67 @@ namespace DCFApixels
|
||||
_buckets = newBuckets;
|
||||
_entries = newEntries;
|
||||
}
|
||||
|
||||
private int NormalizeCapacity(int capacity)
|
||||
{
|
||||
int result = MIN_CAPACITY;
|
||||
while (result < capacity) result <<= 1;
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
//#region Enumerator
|
||||
// public Enumerator GetEnumerator() => new Enumerator(this);
|
||||
// public struct Enumerator
|
||||
// {
|
||||
// private SparseArray<TValue> _source;
|
||||
// private int index;
|
||||
// private int curretnItmeIndex;
|
||||
//
|
||||
// public ref readonly TValue Current
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return ref _source._entries[curretnItmeIndex].value;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public Enumerator(SparseArray<TValue> source)
|
||||
// {
|
||||
// _source = source;
|
||||
// index = 0;
|
||||
// curretnItmeIndex = 0;
|
||||
// }
|
||||
//
|
||||
// public bool MoveNext()
|
||||
// {
|
||||
// // Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
|
||||
// // dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
|
||||
// while ((uint)index < (uint)_source.count)
|
||||
// {
|
||||
// if (dictionary.entries[index].hashCode >= 0)
|
||||
// {
|
||||
// current = new KeyValuePair<TKey, TValue>(dictionary.entries[index].key, dictionary.entries[index].value);
|
||||
// index++;
|
||||
// return true;
|
||||
// }
|
||||
// index++;
|
||||
// }
|
||||
//
|
||||
// index = dictionary.count + 1;
|
||||
// current = new KeyValuePair<TKey, TValue>();
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
#region Utils
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
private struct Entry
|
||||
{
|
||||
public int next; // Index of next entry, -1 if last
|
||||
public int hashKey;
|
||||
public int hashKey;
|
||||
public TValue value;
|
||||
}
|
||||
#endregion
|
||||
|
Loading…
Reference in New Issue
Block a user