mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-17 09:24:37 +08:00
Update WIP
This commit is contained in:
parent
80458d2e70
commit
491e8069c3
14
DragonECS.asmdef
Normal file
14
DragonECS.asmdef
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "DCFApixels.DragonECS",
|
||||
"rootNamespace": "DCFApixels",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
7
DragonECS.asmdef.meta
Normal file
7
DragonECS.asmdef.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abb125fa67fff1e45914d0825236f608
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
src.meta
Normal file
8
src.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0192fd952d3f4a24d8057af65f35d8e1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
13
src/EcsEntityTable.cs
Normal file
13
src/EcsEntityTable.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public interface IEcsEntityTable
|
||||
{
|
||||
|
||||
}
|
||||
}
|
11
src/EcsEntityTable.cs.meta
Normal file
11
src/EcsEntityTable.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d395d007b9c7c24c9f1f4c09f16e04c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
84
src/EcsEntityTableManager.cs
Normal file
84
src/EcsEntityTableManager.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public class EcsEntityTableManager
|
||||
{
|
||||
private int _count;
|
||||
private IEcsFieldPool[] _fieldPools;
|
||||
|
||||
private int _idIncrement;
|
||||
private Dictionary<IDKey, int> _ids;
|
||||
|
||||
public EcsEntityTableManager(int capacity)
|
||||
{
|
||||
_fieldPools = new IEcsFieldPool[capacity];
|
||||
_ids = new Dictionary<IDKey, int>(capacity);
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
public EcsFieldPool<T> GetFieldPool<T>(int id)
|
||||
{
|
||||
if(id < _count)
|
||||
return (EcsFieldPool<T>)_fieldPools[id];
|
||||
|
||||
_count++;
|
||||
if(_fieldPools.Length < _count)
|
||||
{
|
||||
Array.Resize(ref _fieldPools, _fieldPools.Length << 1);
|
||||
}
|
||||
EcsFieldPool<T> newPool = new EcsFieldPool<T>(7);
|
||||
_fieldPools[id] = newPool;
|
||||
return newPool;
|
||||
}
|
||||
|
||||
public void ResizeFieldPool(int id)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public int GetFieldID(string name, int index)
|
||||
{
|
||||
IDKey key = new IDKey(name, index);
|
||||
if (_ids.TryGetValue(key, out int id))
|
||||
return id;
|
||||
|
||||
id = _idIncrement++;
|
||||
_ids.Add(key, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
private struct IDKey
|
||||
{
|
||||
public string name;
|
||||
public int index;
|
||||
|
||||
public IDKey(string name, int index)
|
||||
{
|
||||
this.name = name;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is IDKey key &&
|
||||
name == key.name &&
|
||||
index == key.index;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(name, index);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return name + "_" + index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
src/EcsEntityTableManager.cs.meta
Normal file
11
src/EcsEntityTableManager.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f568bc9f583414c4188526dfade20358
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
17
src/EcsField.cs
Normal file
17
src/EcsField.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public struct EcsField<T>
|
||||
{
|
||||
private EcsFieldPool<T> _pool;
|
||||
public ref T this[int index]
|
||||
{
|
||||
get => ref _pool[index];
|
||||
}
|
||||
}
|
||||
}
|
11
src/EcsField.cs.meta
Normal file
11
src/EcsField.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2fa97ad86c494a40939307a2cfaca36
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
51
src/EcsFieldPool.cs
Normal file
51
src/EcsFieldPool.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public interface IEcsFieldPool
|
||||
{
|
||||
public bool Has(int index);
|
||||
public void Add(int index);
|
||||
}
|
||||
public class EcsFieldPool<T> : IEcsFieldPool
|
||||
{
|
||||
private SparseSet _sparseSet;
|
||||
private T[] _denseItems;
|
||||
|
||||
public EcsFieldPool(int capacity)
|
||||
{
|
||||
_denseItems = new T[capacity];
|
||||
_sparseSet = new SparseSet(capacity);
|
||||
}
|
||||
|
||||
public ref T this[int index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => ref _denseItems[_sparseSet[index]];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref T Add(int index)
|
||||
{
|
||||
_sparseSet.Add(index);
|
||||
_sparseSet.Normalize(ref _denseItems);
|
||||
return ref _denseItems[_sparseSet.IndexOf(index)];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int index)
|
||||
{
|
||||
return _sparseSet.Contains(index);
|
||||
}
|
||||
|
||||
#region IEcsFieldPool
|
||||
void IEcsFieldPool.Add(int index)
|
||||
{
|
||||
Add(index);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
11
src/EcsFieldPool.cs.meta
Normal file
11
src/EcsFieldPool.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b523e51b8d5f4c4c969e0ffec1b8b6f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
119
src/EcsSession.cs
Normal file
119
src/EcsSession.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
|
||||
public class EcsSession
|
||||
{
|
||||
private List<IEcsSystem> _allSystems;
|
||||
private ReadOnlyCollection<IEcsSystem> _ecsSystemsSealed;
|
||||
|
||||
private bool _isInit = false;
|
||||
private bool _isDestoryed = false;
|
||||
|
||||
private int _worldIdIncrement;
|
||||
private Dictionary<string, EcsWorld> _worldsDict = new Dictionary<string, EcsWorld>();
|
||||
private List<EcsWorld> _worlds = new List<EcsWorld>();
|
||||
|
||||
private Dictionary<Type, IEcsSystemsRunner> _runners;
|
||||
private Dictionary<Type, IEcsSystemsMessenger> _messengers;
|
||||
private EcsSystemsRunner<_Run> _runRunnerCache;
|
||||
|
||||
#region Properties
|
||||
public ReadOnlyCollection<IEcsSystem> AllSystems => _ecsSystemsSealed;
|
||||
|
||||
#endregion
|
||||
|
||||
#region React Runners/Messengers
|
||||
public EcsSystemsRunner<TDoTag> GetRunner<TDoTag>()
|
||||
where TDoTag : IEcsDoTag
|
||||
{
|
||||
Type type = typeof(TDoTag);
|
||||
if (_runners.TryGetValue(type, out IEcsSystemsRunner result))
|
||||
{
|
||||
return (EcsSystemsRunner<TDoTag>)result;
|
||||
}
|
||||
result = new EcsSystemsRunner<TDoTag>(this);
|
||||
_runners.Add(type, result);
|
||||
return (EcsSystemsRunner<TDoTag>)result;
|
||||
}
|
||||
|
||||
public EcsSystemsMessenger<TMessege> GetMessenger<TMessege>()
|
||||
where TMessege : IEcsMessage
|
||||
{
|
||||
Type type = typeof(TMessege);
|
||||
if (_messengers.TryGetValue(type, out IEcsSystemsMessenger result))
|
||||
{
|
||||
return (EcsSystemsMessenger<TMessege>)result;
|
||||
}
|
||||
result = new EcsSystemsMessenger<TMessege>(this);
|
||||
_messengers.Add(type, result);
|
||||
return (EcsSystemsMessenger<TMessege>)result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Configuration
|
||||
public EcsSession Add(IEcsSystem system)
|
||||
{
|
||||
CheckInitForMethod(nameof(AddWorld));
|
||||
|
||||
_allSystems.Add(system);
|
||||
return this;
|
||||
}
|
||||
public EcsSession AddWorld(string name)
|
||||
{
|
||||
CheckInitForMethod(nameof(AddWorld));
|
||||
|
||||
//_worlds.Add(new EcsWorld(_worldIdIncrement++));
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LifeCycle
|
||||
public void Init()
|
||||
{
|
||||
CheckInitForMethod(nameof(Init));
|
||||
_ecsSystemsSealed = _allSystems.AsReadOnly();
|
||||
_isInit = true;
|
||||
|
||||
GetRunner<_PreInit>().Run();
|
||||
GetRunner<_Init>().Run();
|
||||
|
||||
_runRunnerCache = GetRunner<_Run>();
|
||||
}
|
||||
public void Run()
|
||||
{
|
||||
CheckDestroyForMethod(nameof(Run));
|
||||
|
||||
|
||||
_runRunnerCache.Run();
|
||||
}
|
||||
public void Destroy()
|
||||
{
|
||||
CheckDestroyForMethod(nameof(Run));
|
||||
_isDestoryed = true;
|
||||
GetRunner<_Destroy>().Run();
|
||||
GetRunner<_PostDestroy>().Run();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region StateChecks
|
||||
private void CheckInitForMethod(string methodName)
|
||||
{
|
||||
if (_isInit)
|
||||
throw new MethodAccessException($"Запрещено вызывать метод {methodName}, после инициализации {nameof(EcsSession)}");
|
||||
}
|
||||
private void CheckDestroyForMethod(string methodName)
|
||||
{
|
||||
if (_isInit)
|
||||
throw new MethodAccessException($"Запрещено вызывать метод {methodName}, после уничтожения {nameof(EcsSession)}");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
11
src/EcsSession.cs.meta
Normal file
11
src/EcsSession.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ae31658c78bbf04cb755ac72be367dd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
83
src/EcsWorld.cs
Normal file
83
src/EcsWorld.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public class EcsWorld
|
||||
{
|
||||
public const int MAX_WORLDS = byte.MaxValue; //Номер последнего мира 254
|
||||
public const int DEAD_WORLD_ID = byte.MaxValue; //Зарезервированный номер мира для мертвых сущьностей
|
||||
|
||||
private byte _id = DEAD_WORLD_ID;
|
||||
|
||||
private Dictionary<Type, IEcsFieldPool> _pools;
|
||||
private SparseSet _entities = new SparseSet();
|
||||
private short[] _gens;
|
||||
private byte[] _components;
|
||||
|
||||
//private Dictionary<Type, IEcsEntityTable> _tables;
|
||||
|
||||
#region Properties
|
||||
public int ID => _id;
|
||||
public bool IsAlive => _id != DEAD_WORLD_ID;
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public EcsWorld()
|
||||
{
|
||||
_pools = new Dictionary<Type, IEcsFieldPool>();
|
||||
_entities = new SparseSet();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ID
|
||||
internal void SetId(byte id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetPool
|
||||
public EcsFieldPool<T> GetPool<T>()
|
||||
{
|
||||
Type type = typeof(T);
|
||||
if (_pools.TryGetValue(type, out IEcsFieldPool pool))
|
||||
{
|
||||
return (EcsFieldPool<T>)pool;
|
||||
}
|
||||
|
||||
//pool = new EcsPool<T>();
|
||||
_pools.Add(type, pool);
|
||||
return (EcsFieldPool<T>)pool;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region NewEntity
|
||||
public ent NewEntity()
|
||||
{
|
||||
int entityID = _entities.GetFree();
|
||||
_entities.Normalize(ref _gens);
|
||||
_entities.Normalize(ref _components);
|
||||
_gens[entityID]++;
|
||||
|
||||
|
||||
return new ent(entityID, _gens[entityID], _id, _components[entityID]);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Destroy
|
||||
public void Destroy()
|
||||
{
|
||||
_id = Consts.DEAD_WORLD_ID;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void Resize()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
11
src/EcsWorld.cs.meta
Normal file
11
src/EcsWorld.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b045d6a8b5bcf654f9c2be8012a526f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
2
src/INFO.txt
Normal file
2
src/INFO.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Мервтый мир - значение byte 255, зарезервированный адишник мира, все что ссылается на мертвый мир считается так же мертвым.
|
||||
|
7
src/INFO.txt.meta
Normal file
7
src/INFO.txt.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39030d83d78d46048982adceaa08bfbd
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
src/Interfaces.meta
Normal file
8
src/Interfaces.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ed6f2439b576f34eaefee5b9d0978bf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
29
src/Interfaces/IEcsSystem.cs
Normal file
29
src/Interfaces/IEcsSystem.cs
Normal file
@ -0,0 +1,29 @@
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public interface IEcsSystem { }
|
||||
|
||||
public interface IEcsDoTag { }
|
||||
public struct _PreInit : IEcsDoTag { }
|
||||
public struct _Init : IEcsDoTag { }
|
||||
public struct _Run : IEcsDoTag { }
|
||||
public struct _Destroy : IEcsDoTag { }
|
||||
public struct _PostDestroy : IEcsDoTag { }
|
||||
public interface IEcsDo<TTag> : IEcsSystem
|
||||
where TTag : IEcsDoTag
|
||||
{
|
||||
public void Do(EcsSession engine);
|
||||
}
|
||||
|
||||
public interface IEcsMessage { }
|
||||
public interface IEcsDoMessege<TMessage> : IEcsSystem
|
||||
where TMessage : IEcsMessage
|
||||
{
|
||||
public void Do(EcsSession engine, in TMessage message);
|
||||
}
|
||||
|
||||
public interface IEcsSimpleCycleSystem :
|
||||
IEcsDo<_Init>,
|
||||
IEcsDo<_Run>,
|
||||
IEcsDo<_Destroy>
|
||||
{ }
|
||||
}
|
11
src/Interfaces/IEcsSystem.cs.meta
Normal file
11
src/Interfaces/IEcsSystem.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c440e40c9802ce54fb7a84fda930b22d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
src/React.meta
Normal file
8
src/React.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0c409d38416ea840b358d614c3e62a4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
41
src/React/EcsSystemsMessenger.cs
Normal file
41
src/React/EcsSystemsMessenger.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public interface IEcsSystemsMessenger
|
||||
{
|
||||
public EcsSession Source { get; }
|
||||
}
|
||||
public class EcsSystemsMessenger<TMessage> : IEcsSystemsMessenger
|
||||
where TMessage : IEcsMessage
|
||||
{
|
||||
private EcsSession _source;
|
||||
private IEcsDoMessege<TMessage>[] _systems;
|
||||
|
||||
public EcsSession Source => _source;
|
||||
public IReadOnlyList<IEcsDoMessege<TMessage>> Systems => _systems;
|
||||
|
||||
internal EcsSystemsMessenger(EcsSession source)
|
||||
{
|
||||
_source = source;
|
||||
List<IEcsDoMessege<TMessage>> list = new List<IEcsDoMessege<TMessage>>();
|
||||
|
||||
foreach (var item in _source.AllSystems)
|
||||
{
|
||||
if (item is IEcsDoMessege<TMessage> targetItem)
|
||||
{
|
||||
list.Add(targetItem);
|
||||
}
|
||||
}
|
||||
_systems = list.ToArray();
|
||||
}
|
||||
|
||||
public void Send(in TMessage message)
|
||||
{
|
||||
foreach (var item in _systems)
|
||||
{
|
||||
item.Do(_source, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
src/React/EcsSystemsMessenger.cs.meta
Normal file
11
src/React/EcsSystemsMessenger.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc514cbb93c3f3049adf666ad237c6ee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
42
src/React/EcsSystemsRunner.cs
Normal file
42
src/React/EcsSystemsRunner.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public interface IEcsSystemsRunner
|
||||
{
|
||||
public EcsSession Source { get; }
|
||||
public void Run();
|
||||
}
|
||||
public class EcsSystemsRunner<TDoTag> : IEcsSystemsRunner
|
||||
where TDoTag : IEcsDoTag
|
||||
{
|
||||
private EcsSession _source;
|
||||
private IEcsDo<TDoTag>[] _systems;
|
||||
|
||||
public EcsSession Source => _source;
|
||||
public IReadOnlyList<IEcsDo<TDoTag>> Systems => _systems;
|
||||
|
||||
internal EcsSystemsRunner(EcsSession source)
|
||||
{
|
||||
_source = source;
|
||||
List<IEcsDo<TDoTag>> list = new List<IEcsDo<TDoTag>>();
|
||||
|
||||
foreach (var item in _source.AllSystems)
|
||||
{
|
||||
if (item is IEcsDo<TDoTag> targetItem)
|
||||
{
|
||||
list.Add(targetItem);
|
||||
}
|
||||
}
|
||||
_systems = list.ToArray();
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
foreach (var item in _systems)
|
||||
{
|
||||
item.Do(_source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
src/React/EcsSystemsRunner.cs.meta
Normal file
11
src/React/EcsSystemsRunner.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37fabd05090af0843a67e6c8046ad374
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
src/Utils.meta
Normal file
8
src/Utils.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16b79c30e1b668e47bd35de518796871
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
12
src/Utils/ComponentTypeID.cs
Normal file
12
src/Utils/ComponentTypeID.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public class ComponentTypeID
|
||||
{
|
||||
protected static int _incerement = 0;
|
||||
}
|
||||
public class TypeID<T> : ComponentTypeID
|
||||
where T : struct
|
||||
{
|
||||
public static readonly int id = _incerement++;
|
||||
}
|
||||
}
|
11
src/Utils/ComponentTypeID.cs.meta
Normal file
11
src/Utils/ComponentTypeID.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5af477721d789f498a0de809e753321
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
264
src/Utils/GrowingSparseCollection.cs
Normal file
264
src/Utils/GrowingSparseCollection.cs
Normal file
@ -0,0 +1,264 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
|
||||
namespace DCFApixels
|
||||
{
|
||||
public class GrowingSparseCollection<TValue>
|
||||
{
|
||||
private const int EMPTY = -1;
|
||||
|
||||
private int[] _buckets = Array.Empty<int>();
|
||||
private Entry[] _entries = Array.Empty<Entry>();
|
||||
|
||||
private int _capacity;
|
||||
private int _count;
|
||||
|
||||
#region Properties
|
||||
public TValue this[int key]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _entries[FindEntry(key)].value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Add
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Add(int key, TValue value)
|
||||
{
|
||||
#if DEBUG
|
||||
if (Contains(key))
|
||||
throw new ArgumentException("Contains(key) is true");
|
||||
#endif
|
||||
Insert(key, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Getter
|
||||
public bool TryGetValue(int key, out TValue value)
|
||||
{
|
||||
int index = IndexOfKey(key);
|
||||
if (index < 0)
|
||||
{
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
value = _entries[index].value;
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public GrowingSparseCollection(int capacity)
|
||||
{
|
||||
Initialize(capacity);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Initialize
|
||||
private void Initialize(int capacity)
|
||||
{
|
||||
_capacity = HashHelpers.GetPrime(capacity);
|
||||
_buckets = new int[_capacity];
|
||||
|
||||
for (int i = 0; i < _capacity; i++)
|
||||
_buckets[i] = EMPTY;
|
||||
|
||||
_entries = new Entry[_capacity];
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Clear
|
||||
public void Clear()
|
||||
{
|
||||
if (_count > 0)
|
||||
{
|
||||
for (int i = 0; i < _buckets.Length; i++)
|
||||
{
|
||||
_buckets[i] = -1;
|
||||
}
|
||||
Array.Clear(_entries, 0, _count);
|
||||
_count = 0;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Contains
|
||||
public bool Contains(int key)
|
||||
{
|
||||
return IndexOfKey(key) >= 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IndexOfKey/Find/Insert
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int IndexOfKey(int key)
|
||||
{
|
||||
key &= ~int.MinValue;
|
||||
for (int i = _buckets[key % _capacity]; i >= 0; i = _entries[i].next)
|
||||
{
|
||||
if (_entries[i].key == key)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int FindEntry(int key)
|
||||
{
|
||||
key &= ~int.MinValue;
|
||||
for (int i = _buckets[key % _capacity]; i >= 0; i = _entries[i].next)
|
||||
{
|
||||
if (_entries[i].key == key)
|
||||
return i;
|
||||
}
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
||||
private void Insert(int key, TValue value)
|
||||
{
|
||||
key &= ~int.MinValue;
|
||||
int targetBucket = key % _capacity;
|
||||
|
||||
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
|
||||
{
|
||||
if (_entries[i].key == key)
|
||||
{
|
||||
_entries[i].value = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_count >= _entries.Length)
|
||||
{
|
||||
Resize();
|
||||
targetBucket = key % _capacity;
|
||||
}
|
||||
int index = _count;
|
||||
_count++;
|
||||
|
||||
_entries[index].next = _buckets[targetBucket];
|
||||
_entries[index].key = key;
|
||||
_entries[index].value = value;
|
||||
_buckets[targetBucket] = index;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Resize
|
||||
private void Resize()
|
||||
{
|
||||
Resize(HashHelpers.ExpandPrime(_count), false);
|
||||
}
|
||||
private void Resize(int newSize, bool forceNewHashCodes)
|
||||
{
|
||||
_capacity = newSize;
|
||||
Contract.Assert(newSize >= _entries.Length);
|
||||
int[] newBuckets = new int[newSize];
|
||||
for (int i = 0; i < newBuckets.Length; i++)
|
||||
{
|
||||
newBuckets[i] = EMPTY;
|
||||
}
|
||||
Entry[] newEntries = new Entry[newSize];
|
||||
Array.Copy(_entries, 0, newEntries, 0, _count);
|
||||
if (forceNewHashCodes)
|
||||
{
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
if (newEntries[i].key != -1)
|
||||
{
|
||||
newEntries[i].key = newEntries[i].key;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
if (newEntries[i].key >= 0)
|
||||
{
|
||||
int bucket = newEntries[i].key % newSize;
|
||||
newEntries[i].next = newBuckets[bucket];
|
||||
newBuckets[bucket] = i;
|
||||
}
|
||||
}
|
||||
_buckets = newBuckets;
|
||||
_entries = newEntries;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Utils
|
||||
private struct Entry
|
||||
{
|
||||
public int next; // Index of next entry, -1 if last
|
||||
public int key; // key & hash
|
||||
public TValue value;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
#region HashHelpers
|
||||
internal static class HashHelpers
|
||||
{
|
||||
public const int MaxPrimeArrayLength = 0x7FEFFFFD;
|
||||
public static readonly int[] primes = {
|
||||
3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
|
||||
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
|
||||
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
|
||||
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
|
||||
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
public static bool IsPrime(int candidate)
|
||||
{
|
||||
if ((candidate & 1) != 0)
|
||||
{
|
||||
int limit = (int)Math.Sqrt(candidate);
|
||||
for (int divisor = 3; divisor <= limit; divisor += 2)
|
||||
{
|
||||
if ((candidate % divisor) == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return (candidate == 2);
|
||||
}
|
||||
|
||||
public static int ExpandPrime(int oldSize)
|
||||
{
|
||||
int newSize = 2 * oldSize;
|
||||
|
||||
if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
|
||||
{
|
||||
Contract.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
|
||||
return MaxPrimeArrayLength;
|
||||
}
|
||||
|
||||
return GetPrime(newSize);
|
||||
}
|
||||
internal const int HashtableHashPrime = 101;
|
||||
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
|
||||
public static int GetPrime(int min)
|
||||
{
|
||||
if (min < 0)
|
||||
{
|
||||
throw new ArgumentException("min < 0"); //TODO
|
||||
}
|
||||
Contract.EndContractBlock();
|
||||
|
||||
for (int i = 0; i < primes.Length; i++)
|
||||
{
|
||||
int prime = primes[i];
|
||||
if (prime >= min)
|
||||
return prime;
|
||||
}
|
||||
|
||||
for (int i = (min | 1); i < int.MaxValue; i += 2)
|
||||
{
|
||||
if (IsPrime(i) && ((i - 1) % HashtableHashPrime != 0))
|
||||
return i;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
11
src/Utils/GrowingSparseCollection.cs.meta
Normal file
11
src/Utils/GrowingSparseCollection.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0862221477782744a98863ae86648660
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1036
src/Utils/IntSet.cs
Normal file
1036
src/Utils/IntSet.cs
Normal file
File diff suppressed because it is too large
Load Diff
11
src/Utils/IntSet.cs.meta
Normal file
11
src/Utils/IntSet.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cad30d5b37df1d48bc2abe5d1743649
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
489
src/Utils/SparseSet.cs
Normal file
489
src/Utils/SparseSet.cs
Normal file
@ -0,0 +1,489 @@
|
||||
// _sparse[value] == index
|
||||
// _dense[index] == value
|
||||
//
|
||||
// int[] _dense => |2|4|1|_|_|
|
||||
// int[] _sparse => |_|2|0|_|1|
|
||||
//
|
||||
// indexator => [0]2, [1]4, [2]1
|
||||
//
|
||||
// can use foreach
|
||||
// implements IEnumerable<int>
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public class SparseSet : IEnumerable<int>, ICollection<int>, IReadOnlyCollection<int>
|
||||
{
|
||||
public const int DEFAULT_CAPACITY = 16;
|
||||
|
||||
private int[] _dense;
|
||||
private int[] _sparse;
|
||||
|
||||
private int _count;
|
||||
|
||||
#region Properties
|
||||
public int Count => _count;
|
||||
public int Capacity => _dense.Length;
|
||||
|
||||
public int this[int index]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#if DEBUG
|
||||
get
|
||||
{
|
||||
ThrowHalper.CheckOutOfRange(this, index);
|
||||
return _dense[index];
|
||||
}
|
||||
#else
|
||||
get => _dense[index];
|
||||
#endif
|
||||
}
|
||||
|
||||
public IndexesCollection Indexes => new IndexesCollection(_sparse);
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public SparseSet() : this(DEFAULT_CAPACITY) { }
|
||||
public SparseSet(int capacity)
|
||||
{
|
||||
#if DEBUG
|
||||
ThrowHalper.CheckCapacity(capacity);
|
||||
#endif
|
||||
_dense = new int[capacity];
|
||||
_sparse = new int[capacity];
|
||||
for (int i = 0; i < _sparse.Length; i++)
|
||||
{
|
||||
_dense[i] = i;
|
||||
_sparse[i] = i;
|
||||
}
|
||||
_count = 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Add/AddRange/GetFree
|
||||
public void Add<T>(int value, ref T[] normalizedArray)
|
||||
{
|
||||
Add(value);
|
||||
Normalize(ref normalizedArray);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Add(int value)
|
||||
{
|
||||
#if DEBUG
|
||||
ThrowHalper.CheckValueIsPositive(value);
|
||||
ThrowHalper.CheckValueNotContained(this, value);
|
||||
#endif
|
||||
|
||||
int neadedSpace = _dense.Length;
|
||||
while (value >= neadedSpace)
|
||||
neadedSpace <<= 1;
|
||||
|
||||
if (neadedSpace != _dense.Length)
|
||||
Resize(neadedSpace);
|
||||
|
||||
if (Contains(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Swap(value, _count++);
|
||||
}
|
||||
|
||||
public bool TryAdd<T>(int value, ref T[] normalizedArray)
|
||||
{
|
||||
if (Contains(value))
|
||||
return false;
|
||||
|
||||
Add(value, ref normalizedArray);
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryAdd(int value)
|
||||
{
|
||||
if (Contains(value))
|
||||
return false;
|
||||
|
||||
Add(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddRange<T>(IEnumerable<int> range, ref T[] normalizedArray)
|
||||
{
|
||||
foreach (var item in range)
|
||||
{
|
||||
if (Contains(item))
|
||||
continue;
|
||||
|
||||
Add(item);
|
||||
}
|
||||
Normalize(ref normalizedArray);
|
||||
}
|
||||
|
||||
public void AddRange(IEnumerable<int> range)
|
||||
{
|
||||
foreach (var item in range)
|
||||
{
|
||||
if (Contains(item))
|
||||
continue;
|
||||
|
||||
Add(item);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a value between 0 and Capacity to the array and returns it.
|
||||
/// </summary>
|
||||
/// <returns>Value between 0 and Capacity</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int GetFree<T>(ref T[] normalizedArray)
|
||||
{
|
||||
int result = GetFree();
|
||||
Normalize(ref normalizedArray);
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a value between 0 and Capacity to the array and returns it.
|
||||
/// </summary>
|
||||
/// <returns>Value between 0 and Capacity</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int GetFree()
|
||||
{
|
||||
if (++_count >= _dense.Length)
|
||||
AddSpaces();
|
||||
|
||||
return _dense[_count - 1];
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Contains
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Contains(int value)
|
||||
{
|
||||
return value >= 0 && value < Capacity && _sparse[value] < _count;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Remove
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Remove(int value)
|
||||
{
|
||||
#if DEBUG
|
||||
ThrowHalper.CheckValueContained(this, value);
|
||||
#endif
|
||||
Swap(_sparse[value], --_count);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryRemove(int value)
|
||||
{
|
||||
if (!Contains(value))
|
||||
return false;
|
||||
|
||||
Remove(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
#if DEBUG
|
||||
ThrowHalper.CheckOutOfRange(this, index);
|
||||
#endif
|
||||
Remove(_dense[index]);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Normalize<T>(ref T[] array)
|
||||
{
|
||||
if (array.Length != _dense.Length)
|
||||
Array.Resize(ref array, _dense.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int IndexOf(int value)
|
||||
{
|
||||
if (value < 0 || !Contains(value))
|
||||
return -1;
|
||||
|
||||
return _sparse[value];
|
||||
}
|
||||
|
||||
public void Sort()
|
||||
{
|
||||
int increment = 0;
|
||||
for (int i = 0; i < Capacity; i++)
|
||||
{
|
||||
if (_sparse[i] < _count)
|
||||
{
|
||||
_sparse[i] = increment;
|
||||
_dense[increment++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void HardSort()
|
||||
{
|
||||
int inc = 0;
|
||||
int inc2 = _count;
|
||||
for (int i = 0; i < Capacity; i++)
|
||||
{
|
||||
if (_sparse[i] < _count)
|
||||
{
|
||||
_sparse[i] = inc;
|
||||
_dense[inc++] = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
_sparse[i] = inc2;
|
||||
_dense[inc2++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyTo(SparseSet other)
|
||||
{
|
||||
other._count = _count;
|
||||
if (Capacity != other.Capacity)
|
||||
{
|
||||
other.Resize(Capacity);
|
||||
}
|
||||
_dense.CopyTo(other._dense, 0);
|
||||
_sparse.CopyTo(other._sparse, 0);
|
||||
}
|
||||
|
||||
public void CopyTo(int[] array, int arrayIndex)
|
||||
{
|
||||
#if DEBUG
|
||||
if (arrayIndex < 0)
|
||||
throw new ArgumentException("arrayIndex is less than 0");
|
||||
if (arrayIndex + _count >= array.Length)
|
||||
throw new ArgumentException("The number of elements in the source List<T> is greater than the available space from arrayIndex to the end of the destination array.");
|
||||
#endif
|
||||
for (int i = 0; i < _count; i++, arrayIndex++)
|
||||
{
|
||||
array[arrayIndex] = this[i];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Clear/Reset
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Clear()
|
||||
{
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Clear();
|
||||
for (int i = 0; i < _dense.Length; i++)
|
||||
{
|
||||
_dense[i] = i;
|
||||
_sparse[i] = i;
|
||||
}
|
||||
}
|
||||
public void Reset(int newCapacity)
|
||||
{
|
||||
#if DEBUG
|
||||
ThrowHalper.CheckCapacity(newCapacity);
|
||||
#endif
|
||||
Reset();
|
||||
Resize(newCapacity);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region AddSpace/Resize
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void AddSpaces() => Resize(_count << 1);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void Resize(int newSpace)
|
||||
{
|
||||
int oldspace = _dense.Length;
|
||||
Array.Resize(ref _dense, newSpace);
|
||||
Array.Resize(ref _sparse, newSpace);
|
||||
|
||||
for (int i = oldspace; i < newSpace; i++)
|
||||
{
|
||||
_dense[i] = i;
|
||||
_sparse[i] = i;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Swap
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void Swap(int fromIndex, int toIndex)
|
||||
{
|
||||
int value = _dense[toIndex];
|
||||
int oldValue = _dense[fromIndex];
|
||||
|
||||
_dense[toIndex] = oldValue;
|
||||
_dense[fromIndex] = value;
|
||||
_sparse[_dense[fromIndex]] = fromIndex;
|
||||
_sparse[_dense[toIndex]] = toIndex;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Enumerator
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public RefEnumerator GetEnumerator() => new RefEnumerator(_dense, _count);
|
||||
|
||||
public ref struct RefEnumerator
|
||||
{
|
||||
private readonly int[] _dense;
|
||||
private readonly int _count;
|
||||
private int _index;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public RefEnumerator(int[] values, int count)
|
||||
{
|
||||
_dense = values;
|
||||
_count = count;
|
||||
_index = -1;
|
||||
}
|
||||
|
||||
public int Current
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _dense[_index];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Dispose() { }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool MoveNext() => ++_index < _count;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Reset() => _index = -1;
|
||||
}
|
||||
|
||||
IEnumerator<int> IEnumerable<int>.GetEnumerator() => new Enumerator(_dense, _count);
|
||||
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dense, _count);
|
||||
public struct Enumerator : IEnumerator<int> //to implement the IEnumerable interface and use the ref structure, 2 Enumerators were created.
|
||||
{
|
||||
private readonly int[] _dense;
|
||||
private readonly int _count;
|
||||
private int _index;
|
||||
public Enumerator(int[] values, int count)
|
||||
{
|
||||
_dense = values;
|
||||
_count = count;
|
||||
_index = -1;
|
||||
}
|
||||
public int Current => _dense[_index];
|
||||
object IEnumerator.Current => _dense[_index];
|
||||
public void Dispose() { }
|
||||
public bool MoveNext() => ++_index < _count;
|
||||
public void Reset() => _index = -1;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Utils
|
||||
public ref struct IndexesCollection
|
||||
{
|
||||
private readonly int[] _indexes;
|
||||
|
||||
public IndexesCollection(int[] indexes)
|
||||
{
|
||||
_indexes = indexes;
|
||||
}
|
||||
|
||||
public int this[int value]
|
||||
{
|
||||
get => _indexes[value];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ICollection
|
||||
bool ICollection<int>.IsReadOnly => false;
|
||||
|
||||
bool ICollection<int>.Remove(int value) => TryRemove(value);
|
||||
#endregion
|
||||
|
||||
#region Debug
|
||||
public string Log()
|
||||
{
|
||||
StringBuilder logbuild = new StringBuilder();
|
||||
for (int i = 0; i < Capacity; i++)
|
||||
{
|
||||
logbuild.Append(_dense[i] + ", ");
|
||||
}
|
||||
logbuild.Append("\n\r");
|
||||
for (int i = 0; i < Capacity; i++)
|
||||
{
|
||||
logbuild.Append(_sparse[i] + ", ");
|
||||
}
|
||||
logbuild.Append("\n\r --------------------------");
|
||||
logbuild.Append("\n\r");
|
||||
for (int i = 0; i < Capacity; i++)
|
||||
{
|
||||
logbuild.Append((i < _count ? _dense[i].ToString() : "_") + ", ");
|
||||
}
|
||||
logbuild.Append("\n\r");
|
||||
for (int i = 0; i < Capacity; i++)
|
||||
{
|
||||
logbuild.Append((_sparse[i] < _count ? _sparse[i].ToString() : "_") + ", ");
|
||||
}
|
||||
logbuild.Append("\n\r Count: " + _count);
|
||||
logbuild.Append("\n\r Capacity: " + Capacity);
|
||||
logbuild.Append("\n\r IsValide: " + IsValide_Debug());
|
||||
|
||||
logbuild.Append("\n\r");
|
||||
return logbuild.ToString();
|
||||
}
|
||||
|
||||
public bool IsValide_Debug()
|
||||
{
|
||||
bool isPass = true;
|
||||
for (int index = 0; index < Capacity; index++)
|
||||
{
|
||||
int value = _dense[index];
|
||||
isPass = isPass && _sparse[value] == index;
|
||||
}
|
||||
return isPass;
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG
|
||||
private static class ThrowHalper
|
||||
{
|
||||
public static void CheckCapacity(int capacity)
|
||||
{
|
||||
if (capacity < 0)
|
||||
throw new ArgumentException("Capacity cannot be a negative number");
|
||||
}
|
||||
public static void CheckValueIsPositive(int value)
|
||||
{
|
||||
if (value < 0)
|
||||
throw new ArgumentException("The SparseSet can only contain positive numbers");
|
||||
}
|
||||
public static void CheckValueContained(SparseSet source, int value)
|
||||
{
|
||||
if (!source.Contains(value))
|
||||
throw new ArgumentException($"Value {value} is not contained");
|
||||
}
|
||||
public static void CheckValueNotContained(SparseSet source, int value)
|
||||
{
|
||||
if (source.Contains(value))
|
||||
throw new ArgumentException($"Value {value} is already contained");
|
||||
}
|
||||
public static void CheckOutOfRange(SparseSet source, int index)
|
||||
{
|
||||
if (index < 0 || index >= source.Count)
|
||||
throw new ArgumentOutOfRangeException($"Index {index} was out of range. Must be non-negative and less than the size of the collection.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
}
|
||||
}
|
11
src/Utils/SparseSet.cs.meta
Normal file
11
src/Utils/SparseSet.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d46dabbefb72a224bbf8e74eb12fc455
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
113
src/ent.cs
Normal file
113
src/ent.cs
Normal file
@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
|
||||
public readonly struct ent : IEquatable<long>, IEquatable<ent>
|
||||
{
|
||||
//private const int ID_BITS = 32;
|
||||
//private const int GEN_BITS = 16;
|
||||
//private const int WORLD_BITS = 8;
|
||||
//private const int COM_BITS = 8;
|
||||
|
||||
public readonly long _full;
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public int id
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => (int)(_full >> 32);
|
||||
}
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public short gen
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => (short)((_full << 32) >> 48);
|
||||
|
||||
}
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public byte world
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => (byte)((_full << 48) >> 56);
|
||||
|
||||
}
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public byte com
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => (byte)((_full << 56) >> 56);
|
||||
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public ent(int id, short gen, byte world, byte com)
|
||||
{
|
||||
_full = ((long)id) << 32;
|
||||
_full += ((long)gen) << 16;
|
||||
_full += ((long)world) << 8;
|
||||
_full += com;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ent(long value)
|
||||
{
|
||||
_full = value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public TypeCode GetTypeCode()
|
||||
{
|
||||
return TypeCode.Int64;
|
||||
}
|
||||
|
||||
#region GetHashCode
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return unchecked((int)(_full)) ^ (int)(_full >> 32);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Equals
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(in ent other)
|
||||
{
|
||||
return _full == other._full;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is ent other && Equals(in other);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(ent other)
|
||||
{
|
||||
return _full == other._full;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(long other)
|
||||
{
|
||||
return _full == other;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region operators
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(in ent left, in ent right) => left.Equals(in right);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(in ent left, in ent right) => !left.Equals(in right);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator long(in ent eent) => eent._full;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator ent(in long value) => new ent(value);
|
||||
#endregion
|
||||
}
|
||||
}
|
11
src/ent.cs.meta
Normal file
11
src/ent.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24f0d55c3815f3c429a749511f5d3837
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
test.meta
Normal file
8
test.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3776f76149b634c48a0bf7a7f98ee0c5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
23
test/TestSystem.cs
Normal file
23
test/TestSystem.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public class TestSystem : IEcsDo<_Init>, IEcsDo<_Run>, IEcsDo<_Destroy>
|
||||
{
|
||||
void IEcsDo<_Init>.Do(EcsSession engine)
|
||||
{
|
||||
}
|
||||
|
||||
void IEcsDo<_Run>.Do(EcsSession engine)
|
||||
{
|
||||
}
|
||||
|
||||
void IEcsDo<_Destroy>.Do(EcsSession engine)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
11
test/TestSystem.cs.meta
Normal file
11
test/TestSystem.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: affa952a9e445864ebfe2ca2388e76de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
12
test/TransformTable.cs
Normal file
12
test/TransformTable.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public struct TransformTable
|
||||
{
|
||||
}
|
||||
}
|
11
test/TransformTable.cs.meta
Normal file
11
test/TransformTable.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6c6320184f942444b499e3f027a72a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Reference in New Issue
Block a user