add EcsWorldConfig

This commit is contained in:
Mikhail 2024-02-03 01:12:53 +08:00
parent df24a2d26a
commit a248f4fc34
10 changed files with 218 additions and 44 deletions

View File

@ -1,5 +1,13 @@
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
public sealed class EcsDefaultWorld : EcsWorld { } public sealed class EcsDefaultWorld : EcsWorld
public sealed class EcsEventWorld : EcsWorld { } {
public EcsDefaultWorld() : base(null) { }
public EcsDefaultWorld(IEcsWorldConfig config) : base(config) { }
}
public sealed class EcsEventWorld : EcsWorld
{
public EcsEventWorld() : base(null) { }
public EcsEventWorld(IEcsWorldConfig config) : base(config) { }
}
} }

View File

@ -74,7 +74,7 @@ namespace DCFApixels.DragonECS
static EcsComponentCopyHandler() static EcsComponentCopyHandler()
{ {
T def = default; T def = default;
if(def is IEcsComponentCopy<T> intrf) if (def is IEcsComponentCopy<T> intrf)
{ {
instance = intrf; instance = intrf;
} }

View File

@ -41,6 +41,11 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void PrintWarning(object v) => Print(EcsConsts.DEBUG_WARNING_TAG, v); public static void PrintWarning(object v) => Print(EcsConsts.DEBUG_WARNING_TAG, v);
public static void PrintError(object v) => Print(EcsConsts.DEBUG_ERROR_TAG, v); public static void PrintError(object v) => Print(EcsConsts.DEBUG_ERROR_TAG, v);
public static void PrintErrorAndBreak(object v)
{
Print(EcsConsts.DEBUG_ERROR_TAG, v);
Break();
}
public static void PrintPass(object v) => Print(EcsConsts.DEBUG_PASS_TAG, v); public static void PrintPass(object v) => Print(EcsConsts.DEBUG_PASS_TAG, v);
public static void Print() public static void Print()
{ {

View File

@ -3,12 +3,14 @@ using DCFApixels.DragonECS.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using static Leopotam.EcsLite.EcsWorld;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
public abstract partial class EcsWorld public abstract partial class EcsWorld
{ {
public readonly short id; public readonly short id;
private IEcsWorldConfig _config;
private bool _isDestroyed; private bool _isDestroyed;
@ -36,6 +38,11 @@ namespace DCFApixels.DragonECS
private readonly PoolsMediator _poolsMediator; private readonly PoolsMediator _poolsMediator;
#region Properties #region Properties
public IEcsWorldConfig Config
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _config; }
}
public bool IsDestroyed public bool IsDestroyed
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -84,13 +91,15 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Constructors/Destroy #region Constructors/Destroy
public EcsWorld() : this(true) { } public EcsWorld(IEcsWorldConfig config) : this(config, true) { }
internal EcsWorld(bool isIndexable) private EcsWorld(IEcsWorldConfig config, bool isIndexable)
{ {
const int POOLS_CAPACITY = 512; if (config == null)
_poolsMediator = new PoolsMediator(this); {
config = EmptyConfig.Instance;
_entitesCapacity = 512; }
config.Lock();
_config = config;
if (isIndexable) if (isIndexable)
{ {
@ -102,13 +111,15 @@ namespace DCFApixels.DragonECS
Worlds[id] = this; Worlds[id] = this;
} }
_poolsMediator = new PoolsMediator(this);
_entityDispenser = new IntDispenser(0); _entityDispenser = new IntDispenser(0);
_pools = new IEcsPoolImplementation[POOLS_CAPACITY];
_poolComponentCounts = new int[POOLS_CAPACITY]; int poolsCapacity = config.Get_PoolsCapacity();
//_sortedPoolIds = new int[POOLS_CAPACITY]; _pools = new IEcsPoolImplementation[poolsCapacity];
//_sortedPoolIdsMapping = new int[POOLS_CAPACITY]; _poolComponentCounts = new int[poolsCapacity];
ArrayUtility.Fill(_pools, _nullPool); ArrayUtility.Fill(_pools, _nullPool);
_entitesCapacity = config.Get_EntitiesCapacity();
_gens = new short[_entitesCapacity]; _gens = new short[_entitesCapacity];
_componentCounts = new short[_entitesCapacity]; _componentCounts = new short[_entitesCapacity];
@ -116,9 +127,11 @@ namespace DCFApixels.DragonECS
_delEntBufferCount = 0; _delEntBufferCount = 0;
_delEntBuffer = new int[_entitesCapacity]; _delEntBuffer = new int[_entitesCapacity];
_entitiesComponentMasks = new int[_entitesCapacity][]; _entitiesComponentMasks = new int[_entitesCapacity][];
int maskLength = _pools.Length / 32 + 1;
for (int i = 0; i < _entitesCapacity; i++) for (int i = 0; i < _entitesCapacity; i++)
{ {
_entitiesComponentMasks[i] = new int[_pools.Length / 32 + 1]; _entitiesComponentMasks[i] = new int[maskLength];
} }
_delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE); _delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE);
@ -264,7 +277,9 @@ namespace DCFApixels.DragonECS
_entitiesCount++; _entitiesCount++;
if (_gens.Length <= entityID) if (_gens.Length <= entityID)
Upsize(); {
Upsize(_gens.Length << 1);
}
_gens[entityID] &= GEN_BITS; _gens[entityID] &= GEN_BITS;
_allEntites.Add(entityID); _allEntites.Add(entityID);
@ -432,24 +447,31 @@ namespace DCFApixels.DragonECS
#region Upsize #region Upsize
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
private void Upsize() public void Upsize(int minSize)
{ {
Array.Resize(ref _gens, _gens.Length << 1); if (minSize < Capacity)
Array.Resize(ref _componentCounts, _gens.Length); {
Array.Resize(ref _delEntBuffer, _gens.Length); return;
Array.Resize(ref _entitiesComponentMasks, _gens.Length); }
for (int i = _entitesCapacity; i < _gens.Length; i++)
int newSize = 1 << (BitsUtility.GetHighBitNumber(minSize - 1) + 1);
Array.Resize(ref _gens, newSize);
Array.Resize(ref _componentCounts, newSize);
Array.Resize(ref _delEntBuffer, newSize);
Array.Resize(ref _entitiesComponentMasks, newSize);
for (int i = _entitesCapacity; i < newSize; i++)
_entitiesComponentMasks[i] = new int[_pools.Length / 32 + 1]; _entitiesComponentMasks[i] = new int[_pools.Length / 32 + 1];
_delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE); _delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE);
ArrayUtility.Fill(_gens, DEATH_GEN_BIT, _entitesCapacity); ArrayUtility.Fill(_gens, DEATH_GEN_BIT, _entitesCapacity);
_entitesCapacity = _gens.Length; _entitesCapacity = newSize;
for (int i = 0; i < _groups.Count; i++) for (int i = 0; i < _groups.Count; i++)
{ {
if (_groups[i].TryGetTarget(out EcsGroup group)) if (_groups[i].TryGetTarget(out EcsGroup group))
{ {
group.OnWorldResize(_gens.Length); group.OnWorldResize(newSize);
} }
else else
{ {
@ -459,9 +481,11 @@ namespace DCFApixels.DragonECS
} }
} }
foreach (var item in _pools) foreach (var item in _pools)
item.OnWorldResize(_gens.Length); {
item.OnWorldResize(newSize);
}
_listeners.InvokeOnWorldResize(_gens.Length); _listeners.InvokeOnWorldResize(newSize);
} }
#endregion #endregion
@ -538,6 +562,21 @@ namespace DCFApixels.DragonECS
} }
} }
#endregion #endregion
#region EmptyConfig
private class EmptyConfig : IEcsWorldConfig
{
public static readonly EmptyConfig Instance = new EmptyConfig();
private EmptyConfig() { }
public bool IsLocked => true;
public T Get<T>(string valueName) { return default; }
public bool Has(string valueName) { return false; }
public void Lock() { }
public void Remove(string valueName) { }
public void Set<T>(string valueName, T value) { }
public bool TryGet<T>(string valueName, out T value) { value = default; return false; }
}
#endregion
} }
#region Callbacks Interface #region Callbacks Interface

View File

@ -25,7 +25,7 @@ namespace DCFApixels.DragonECS
public bool IsComponentTypeDeclared(Type type) => _componentIds.Contains(EcsTypeCode.Get(type)); public bool IsComponentTypeDeclared(Type type) => _componentIds.Contains(EcsTypeCode.Get(type));
public bool IsComponentTypeDeclared(int componentTypeID) public bool IsComponentTypeDeclared(int componentTypeID)
{ {
if(componentTypeID >= 0 && componentTypeID < _pools.Length) if (componentTypeID >= 0 && componentTypeID < _pools.Length)
{ {
return _pools[componentTypeID] != _nullPool; return _pools[componentTypeID] != _nullPool;
} }

View File

@ -22,14 +22,14 @@ namespace DCFApixels.DragonECS
private const int DEL_ENT_BUFFER_MIN_SIZE = 64; private const int DEL_ENT_BUFFER_MIN_SIZE = 64;
private static EcsWorld[] Worlds = new EcsWorld[4]; private static EcsWorld[] Worlds = new EcsWorld[4];
private static IdDispenser _worldIdDispenser = new IdDispenser(0); private static IdDispenser _worldIdDispenser = new IdDispenser(4);
private static List<DataReleaser> _dataReleaseres = new List<DataReleaser>(); private static List<DataReleaser> _dataReleaseres = new List<DataReleaser>();
//public static int Copacity => Worlds.Length; //public static int Copacity => Worlds.Length;
static EcsWorld() static EcsWorld()
{ {
Worlds[0] = new EcsNullWorld(); Worlds[0] = new NullWorld();
} }
private static void ReleaseData(int worldID) private static void ReleaseData(int worldID)
{ {
@ -121,9 +121,9 @@ namespace DCFApixels.DragonECS
} }
} }
} }
} private sealed class NullWorld : EcsWorld
internal sealed class EcsNullWorld : EcsWorld {
{ internal NullWorld() : base(EmptyConfig.Instance, false) { }
internal EcsNullWorld() : base(false) { } }
} }
} }

124
src/EcsWorldConfig.cs Normal file
View File

@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
namespace DCFApixels.DragonECS
{
public interface IEcsWorldConfig
{
bool IsLocked { get; }
void Lock();
void Set<T>(string valueName, T value);
bool Has(string valueName);
T Get<T>(string valueName);
bool TryGet<T>(string valueName, out T value);
void Remove(string valueName);
}
public class EcsWorldConfig : IEcsWorldConfig
{
private Dictionary<string, object> _storage = new Dictionary<string, object>();
private bool _isLocked = false;
public bool IsLocked { get { return _isLocked; } }
public void Lock()
{
_isLocked = true;
}
public T Get<T>(string valueName)
{
return (T)_storage[valueName];
}
public bool Has(string valueName)
{
return _storage.ContainsKey(valueName);
}
public void Remove(string valueName)
{
_storage.Remove(valueName);
}
public void Set<T>(string valueName, T value)
{
if (_isLocked)
{
throw new InvalidOperationException();
}
_storage[valueName] = value;
}
public bool TryGet<T>(string valueName, out T value)
{
bool result = _storage.TryGetValue(valueName, out object rawValue);
value = rawValue == null ? default : (T)rawValue;
return result;
}
}
public static class EcsWorldConfigExtensions
{
public static T GetOrDefault<T>(this IEcsWorldConfig self, string valueName, T defaultValue)
{
if (self.TryGet(valueName, out T value))
{
return value;
}
return defaultValue;
}
private const string ENTITIES_CAPACITY = nameof(ENTITIES_CAPACITY);
private const int ENTITIES_CAPACITY_DEFAULT = 512;
public static TConfig Set_EntitiesCapacity<TConfig>(this TConfig self, int value)
where TConfig : IEcsWorldConfig
{
self.Set(ENTITIES_CAPACITY, value);
return self;
}
public static int Get_EntitiesCapacity(this IEcsWorldConfig self)
{
return self.GetOrDefault(ENTITIES_CAPACITY, ENTITIES_CAPACITY_DEFAULT);
}
//private const string RECYCLED_ENTITIES_CAPACITY = nameof(RECYCLED_ENTITIES_CAPACITY);
//public static void Set_RecycledEntitiesCapacity(this IEcsWorldConfig self, int value)
//{
// self.Set(RECYCLED_ENTITIES_CAPACITY, value);
//}
//public static int Get_RecycledEntitiesCapacity(this IEcsWorldConfig self)
//{
// return self.GetOrDefault(RECYCLED_ENTITIES_CAPACITY, self.Get_EntitiesCapacity() / 2);
//}
private const string POOLS_CAPACITY = nameof(POOLS_CAPACITY);
private const int POOLS_CAPACITY_DEFAULT = 512;
public static TConfig Set_PoolsCapacity<TConfig>(this TConfig self, int value)
where TConfig : IEcsWorldConfig
{
self.Set(POOLS_CAPACITY, value);
return self;
}
public static int Get_PoolsCapacity(this IEcsWorldConfig self)
{
return self.GetOrDefault(POOLS_CAPACITY, POOLS_CAPACITY_DEFAULT);
}
private const string COMPONENT_POOL_CAPACITY = nameof(COMPONENT_POOL_CAPACITY);
private const int COMPONENT_POOL_CAPACITY_DEFAULT = 512;
public static TConfig Set_PoolComponentsCapacity<TConfig>(this TConfig self, int value)
where TConfig : IEcsWorldConfig
{
self.Set(COMPONENT_POOL_CAPACITY, value);
return self;
}
public static int Get_PoolComponentsCapacity(this IEcsWorldConfig self)
{
return self.GetOrDefault(COMPONENT_POOL_CAPACITY, COMPONENT_POOL_CAPACITY_DEFAULT);
}
private const string POOL_RECYCLED_COMPONENTS_CAPACITY = nameof(POOL_RECYCLED_COMPONENTS_CAPACITY);
public static TConfig Set_PoolRecycledComponentsCapacity<TConfig>(this TConfig self, int value)
where TConfig : IEcsWorldConfig
{
self.Set(POOL_RECYCLED_COMPONENTS_CAPACITY, value);
return self;
}
public static int Get_PoolRecycledComponentsCapacity(this IEcsWorldConfig self)
{
return self.GetOrDefault(POOL_RECYCLED_COMPONENTS_CAPACITY, self.Get_PoolComponentsCapacity() / 2);
}
}
}

View File

@ -143,12 +143,10 @@ namespace DCFApixels.DragonECS
_componentTypeID = componentTypeID; _componentTypeID = componentTypeID;
_maskBit = EcsMaskChunck.FromID(componentTypeID); _maskBit = EcsMaskChunck.FromID(componentTypeID);
const int capacity = 512;
_mapping = new int[world.Capacity]; _mapping = new int[world.Capacity];
_recycledItems = new int[128]; _recycledItems = new int[world.Config.Get_PoolRecycledComponentsCapacity()];
_recycledItemsCount = 0; _recycledItemsCount = 0;
_items = new T[capacity]; _items = new T[world.Config.Get_PoolComponentsCapacity()];
_itemsCount = 0; _itemsCount = 0;
} }
void IEcsPoolImplementation.OnWorldResize(int newSize) void IEcsPoolImplementation.OnWorldResize(int newSize)

View File

@ -81,6 +81,11 @@ namespace DCFApixels.DragonECS.Internal
else else
throw new EcsFrameworkException($"The {entity} is not alive."); throw new EcsFrameworkException($"The {entity} is not alive.");
} }
[MethodImpl(MethodImplOptions.NoInlining)]
internal static void UndefinedException()
{
throw new Exception();
}
} }
} }

View File

@ -14,12 +14,7 @@ namespace DCFApixels.DragonECS.Utils
#endregion #endregion
#region Constructor #region Constructor
public IntDispenser() public IntDispenser(int startIncrement = 0)
{
_freeInts = new ConcurrentQueue<int>();
_increment = 0;
}
public IntDispenser(int startIncrement)
{ {
_freeInts = new ConcurrentQueue<int>(); _freeInts = new ConcurrentQueue<int>();
_increment = startIncrement; _increment = startIncrement;