Merge branch 'dev' into new_system_layers

This commit is contained in:
DCFApixels 2025-05-11 22:33:57 +08:00
commit 0c4a3a822f
21 changed files with 285 additions and 177 deletions

View File

@ -10,7 +10,7 @@
<RootNamespace>DCFApixels.DragonECS</RootNamespace>
<Title>DragonECS</Title>
<Version>0.9.9</Version>
<Version>0.9.10</Version>
<Authors>DCFApixels</Authors>
<Description>ECS Framework for Game Engines with C# and .Net Platform</Description>
<Copyright>DCFApixels</Copyright>

View File

@ -8,7 +8,7 @@
"displayName": "DragonECS",
"description": "C# Entity Component System Framework",
"unity": "2020.3",
"version": "0.9.9",
"version": "0.9.10",
"repository": {
"type": "git",
"url": "https://github.com/DCFApixels/DragonECS.git"

View File

@ -1,6 +1,7 @@
#if DISABLE_DEBUG
#undef DEBUG
#endif
using DCFApixels.DragonECS.Core.Unchecked;
using DCFApixels.DragonECS.Internal;
using System;
using System.Collections;

View File

@ -1,6 +1,7 @@
#if DISABLE_DEBUG
#undef DEBUG
#endif
using DCFApixels.DragonECS.Core.Unchecked;
using DCFApixels.DragonECS.Internal;
using System;
using System.Collections.Generic;

View File

@ -247,7 +247,7 @@ namespace DCFApixels.DragonECS
#region Static Constructor
static DebugService()
{
#if !UNITY_5_3_OR_NEWER
#if UNITY_5_3_OR_NEWER
Set(new NullDebugService());
#else
Set(new DefaultDebugService());

View File

@ -2,6 +2,7 @@
#undef DEBUG
#endif
using DCFApixels.DragonECS.Core;
using DCFApixels.DragonECS.Core.Unchecked;
using DCFApixels.DragonECS.Internal;
using DCFApixels.DragonECS.PoolsCore;
using System;

View File

@ -45,10 +45,15 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryGetWorld(short worldID, out EcsWorld world)
{// ts
if (worldID >= _worlds.Length)
{
world = null;
return false;
}
world = _worlds[worldID];
return
world != null &&
world.IsDestroyed != false &&
world.IsDestroyed == false &&
worldID != 0;
}

View File

@ -538,7 +538,7 @@ namespace DCFApixels.DragonECS.Internal
state ^= state >> 17;
state ^= state << 5;
return state;
};
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long NextXorShiftState(long state)

View File

@ -95,6 +95,7 @@ namespace DCFApixels.DragonECS
{
ref int itemIndex = ref _mapping[entityID];
#if DEBUG
if (entityID == EcsConsts.NULL_ENTITY_ID) { Throw.Ent_ThrowIsNotAlive(_source, entityID); }
if (_source.IsUsed(entityID) == false) { Throw.Ent_ThrowIsNotAlive(_source, entityID); }
if (itemIndex > 0) { EcsPoolThrowHelper.ThrowAlreadyHasComponent<T>(entityID); }
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
@ -144,6 +145,9 @@ namespace DCFApixels.DragonECS
}
public ref T TryAddOrGet(int entityID)
{
#if DEBUG
if (entityID == EcsConsts.NULL_ENTITY_ID) { Throw.Ent_ThrowIsNotAlive(_source, entityID); }
#endif
ref int itemIndex = ref _mapping[entityID];
if (itemIndex <= 0)
{ //Add block
@ -185,6 +189,7 @@ namespace DCFApixels.DragonECS
{
ref int itemIndex = ref _mapping[entityID];
#if DEBUG
if (entityID == EcsConsts.NULL_ENTITY_ID) { Throw.Ent_ThrowIsNotAlive(_source, entityID); }
if (itemIndex <= 0) { EcsPoolThrowHelper.ThrowNotHaveComponent<T>(entityID); }
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
#elif DRAGONECS_STABILITY_MODE
@ -237,9 +242,8 @@ namespace DCFApixels.DragonECS
#elif DRAGONECS_STABILITY_MODE
if (_isLocked) { return; }
#endif
_recycledItemsCount = 0; // спереди потому чтобы обнулялось, так как Del не обнуляет
_recycledItemsCount = 0; // ñïåðåäè ÷òîáû îáíóëÿëîñü, òàê êàê Del íå îáíóëÿåò
if (_itemsCount <= 0) { return; }
_itemsCount = 0;
var span = _source.Where(out SingleAspect<T> _);
foreach (var entityID in span)
{
@ -251,6 +255,8 @@ namespace DCFApixels.DragonECS
_listeners.InvokeOnDel(entityID, _listenersCachedCount);
#endif
}
_itemsCount = 0;
_recycledItemsCount = 0;
}
#endregion

8
src/Utils/Uncheked.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5f2e943735300fe40bdbff86b6089dad
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,44 @@
#if DISABLE_DEBUG
#undef DEBUG
#endif
namespace DCFApixels.DragonECS.UncheckedCore
{
public readonly struct EntitiesMatrix
{
private readonly EcsWorld _world;
public EntitiesMatrix(EcsWorld world)
{
_world = world;
}
public int PoolsCount
{
get { return _world.PoolsCount; }
}
public int EntitesCount
{
get { return _world.Capacity; }
}
public int GetEntityComponentsCount(int entityID)
{
return _world.GetComponentsCount(entityID);
}
public int GetEntityGen(int entityID)
{
return _world.GetGen(entityID);
}
public bool IsEntityUsed(int entityID)
{
return _world.IsUsed(entityID);
}
public bool this[int entityID, int poolID]
{
get
{
int entityStartChunkIndex = entityID << _world._entityComponentMaskLengthBitShift;
var chunkInfo = EcsMaskChunck.FromID(poolID);
return (_world._entityComponentMasks[entityStartChunkIndex + chunkInfo.chunkIndex] & chunkInfo.mask) != 0;
}
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 82a4a05728fb81b4b903d9893a85f77f

View File

@ -0,0 +1,137 @@
#if DISABLE_DEBUG
#undef DEBUG
#endif
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS.Core.Unchecked
{
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
[DebuggerTypeProxy(typeof(EntityDebuggerProxy))]
public struct EntitySlotInfo : IEquatable<EntitySlotInfo>
{
#if UNITY_EDITOR
[UnityEngine.SerializeField]
#endif
[FieldOffset(0)]
public long full; //Union
[FieldOffset(0), NonSerialized]
public int id;
[FieldOffset(4), NonSerialized]
public short gen;
[FieldOffset(6), NonSerialized]
public short worldID;
#region Properties
public EcsWorld World { get { return EcsWorld.GetWorld(worldID); } }
public StateFlag State { get { return full == 0 ? StateFlag.Null : World.IsAlive(id, gen) ? StateFlag.Alive : StateFlag.Dead; } }
#endregion
#region Constructors/Deconstructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EntitySlotInfo(long full) : this()
{
this.full = full;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EntitySlotInfo(int id, short gen, short world) : this()
{
this.id = id;
this.gen = gen;
worldID = world;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Deconstruct(out int id, out int gen, out int worldID)
{
id = this.id;
gen = this.gen;
worldID = this.worldID;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Deconstruct(out int id, out int worldID)
{
id = this.id;
worldID = this.worldID;
}
#endregion
#region Operators
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(EntitySlotInfo a, EntitySlotInfo b) { return a.full == b.full; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(EntitySlotInfo a, EntitySlotInfo b) { return a.full != b.full; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator EntitySlotInfo(entlong a) { return new EntitySlotInfo(a._full); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator entlong(EntitySlotInfo a) { return new entlong(a.full); }
#endregion
#region Other
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() { return unchecked(id ^ gen ^ (worldID * EcsConsts.MAGIC_PRIME)); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() { return $"slot(id:{id} g:{gen} w:{worldID} {(State == StateFlag.Null ? "null" : State == StateFlag.Alive ? "alive" : "not alive")})"; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj) { return obj is EntitySlotInfo other && this == other; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(EntitySlotInfo other) { return this == other; }
public enum StateFlag { Null, Dead, Alive, }
#endregion
}
internal class EntityDebuggerProxy
{
private List<object> _componentsList = new List<object>();
private EntitySlotInfo _info;
public long full { get { return _info.full; } }
public int id { get { return _info.id; } }
public short gen { get { return _info.gen; } }
public short worldID { get { return _info.worldID; } }
public EntitySlotInfo.StateFlag State { get { return _info.State; } }
public EcsWorld World { get { return _info.World; } }
public IEnumerable<object> Components
{
get
{
if (State == EntitySlotInfo.StateFlag.Alive)
{
World.GetComponentsFor(id, _componentsList);
return _componentsList;
}
return Array.Empty<object>();
}
set
{
if (State == EntitySlotInfo.StateFlag.Alive)
{
foreach (var component in value)
{
if (component == null) { continue; }
var componentType = component.GetType();
var world = World;
if (componentType.IsValueType && world.TryFindPoolInstance(componentType, out IEcsPool pool))
{
pool.SetRaw(id, component);
}
}
}
}
}
public EntityDebuggerProxy(EntitySlotInfo info)
{
_info = info;
}
public EntityDebuggerProxy(int entityID, short gen, short worldID)
{
_info = new EntitySlotInfo(entityID, gen, worldID);
}
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 76b422b663e6c9d488b5eb4fac26de61

View File

@ -1,13 +1,13 @@
#if DISABLE_DEBUG
#undef DEBUG
#endif
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS.UncheckedCore
{
[Obsolete("Use DCFApixels.DragonECS.Core.UncheckedUtility")]
public static class UncheckedCoreUtility
{
#region CreateEntLong
@ -70,42 +70,70 @@ namespace DCFApixels.DragonECS.UncheckedCore
}
#endregion
}
}
public readonly struct EntitiesMatrix
namespace DCFApixels.DragonECS.Core.Unchecked
{
private readonly EcsWorld _world;
public EntitiesMatrix(EcsWorld world)
public static class UncheckedUtility
{
_world = world;
}
public int PoolsCount
#region CreateEntLong
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static entlong CreateEntLong(int entityID, short gen, short worldID)
{
get { return _world.PoolsCount; }
return new entlong(entityID, gen, worldID);
}
public int EntitesCount
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static entlong CreateEntLong(long entityGenWorld)
{
get { return _world.Capacity; }
return new entlong(entityGenWorld);
}
public int GetEntityComponentsCount(int entityID)
#endregion
#region CreateSpan
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsSpan CreateSpan(short worldID, ReadOnlySpan<int> entitesArray)
{
return _world.GetComponentsCount(entityID);
return new EcsSpan(worldID, entitesArray);
}
public int GetEntityGen(int entityID)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsSpan CreateSpan(short worldID, int[] entitesArray, int startIndex, int length)
{
return _world.GetGen(entityID);
return new EcsSpan(worldID, entitesArray, startIndex, length);
}
public bool IsEntityUsed(int entityID)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsSpan CreateSpan(short worldID, int[] entitesArray, int length)
{
return _world.IsUsed(entityID);
return new EcsSpan(worldID, entitesArray, length);
}
public bool this[int entityID, int poolID]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsSpan CreateSpan(short worldID, int[] entitesArray)
{
get
return new EcsSpan(worldID, entitesArray);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsSpan CreateEmptySpan(short worldID)
{
int entityStartChunkIndex = entityID << _world._entityComponentMaskLengthBitShift;
var chunkInfo = EcsMaskChunck.FromID(poolID);
return (_world._entityComponentMasks[entityStartChunkIndex + chunkInfo.chunkIndex] & chunkInfo.mask) != 0;
return new EcsSpan(worldID, Array.Empty<int>());
}
public static bool CheckSpanValideDebug(EcsSpan span)
{
HashSet<int> set = new HashSet<int>();
foreach (var e in span)
{
if (set.Add(e) == false)
{
return false;
}
}
return true;
}
#endregion
#region EcsGroup
public static EcsGroup GetSourceInstance(EcsReadonlyGroup group)
{
return group.GetSource_Internal();
}
#endregion
}
}

View File

@ -3,9 +3,9 @@
#endif
#pragma warning disable IDE1006
#pragma warning disable CS8981
using DCFApixels.DragonECS.Core.Unchecked;
using DCFApixels.DragonECS.Internal;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -54,6 +54,11 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _full == 0L; }
}
public bool IsDeadOrNull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return IsAlive == false; }
}
public int ID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -370,152 +375,20 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(long other) { return _full == other; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int CompareTo(entlong other)
public int CompareTo(entlong other) { return Compare(_id, other._id); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Compare(entlong left, entlong right) { return left.CompareTo(right); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Compare(int left, int right)
{
// NOTE: Because _id cannot be less than 0,
// the case “_id - other._id > MaxValue” is impossible.
return _id - other._id;
return left - right;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Compare(entlong left, entlong right) { return left.CompareTo(right); }
internal class DebuggerProxy
internal class DebuggerProxy : EntityDebuggerProxy
{
private List<object> _componentsList = new List<object>();
private entlong _value;
public long full { get { return _value._full; } }
public int id { get { return _value._id; } }
public short gen { get { return _value._gen; } }
public short world { get { return _value._world; } }
public EntState State { get { return _value.IsNull ? EntState.Null : _value.IsAlive ? EntState.Alive : EntState.Dead; } }
public EcsWorld EcsWorld { get { return EcsWorld.GetWorld(world); } }
public IEnumerable<object> components
{
get
{
_value.World.GetComponentsFor(_value.ID, _componentsList);
return _componentsList;
}
}
public DebuggerProxy(entlong value)
{
_value = value;
}
public DebuggerProxy(EntitySlotInfo value)
{
_value = new entlong(value.id, value.gen, value.world);
}
public enum EntState { Null, Dead, Alive, }
}
#endregion
}
}
namespace DCFApixels.DragonECS
{
[DebuggerTypeProxy(typeof(DebuggerProxy))]
public readonly struct EntitySlotInfo : IEquatable<EntitySlotInfo>
{
private readonly long _full;
public readonly int id;
public readonly short gen;
public readonly short world;
#region Properties
private EcsWorld World { get { return EcsWorld.GetWorld(world); } }
private EntState State { get { return _full == 0 ? EntState.Null : World.IsAlive(id, gen) ? EntState.Alive : EntState.Dead; } }
#endregion
#region Constructors
public EntitySlotInfo(long full)
{
unchecked
{
ulong ufull = (ulong)full;
id = (int)((ufull >> 0) & 0x0000_0000_FFFF_FFFF);
gen = (short)((ufull >> 32) & 0x0000_0000_0000_FFFF);
world = (short)((ufull >> 48) & 0x0000_0000_0000_FFFF);
_full = full;
}
}
public EntitySlotInfo(int id, short gen, short world)
{
this.id = id;
this.gen = gen;
this.world = world;
_full = ((long)world << 48 | (long)gen << 32 | (long)id);
}
#endregion
#region Operators
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(EntitySlotInfo a, EntitySlotInfo b)
{
return a.id == b.id &&
a.gen == b.gen &&
a.world == b.world;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(EntitySlotInfo a, EntitySlotInfo b)
{
return a.id != b.id ||
a.gen != b.gen ||
a.world != b.world;
}
#endregion
#region Other
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() { return unchecked(id ^ gen ^ (world * EcsConsts.MAGIC_PRIME)); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() { return $"slot(id:{id} g:{gen} w:{world} {(State == EntState.Null ? "null" : State == EntState.Alive ? "alive" : "not alive")})"; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj) { return obj is EntitySlotInfo other && this == other; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(EntitySlotInfo other) { return this == other; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Deconstruct(out int id, out int gen, out int world)
{
id = this.id;
gen = this.gen;
world = this.world;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Deconstruct(out int id, out int world)
{
id = this.id;
world = this.world;
}
public enum EntState { Null, Dead, Alive, }
internal class DebuggerProxy
{
private List<object> _componentsList = new List<object>();
private EntitySlotInfo _source;
public long full { get { return _source._full; } }
public int id { get { return _source.id; } }
public short gen { get { return _source.gen; } }
public short world { get { return _source.world; } }
public EntState State { get { return _source.State; } }
public EcsWorld World { get { return _source.World; } }
public IEnumerable<object> Components
{
get
{
if (State == EntState.Alive)
{
World.GetComponentsFor(id, _componentsList);
return _componentsList;
}
return Array.Empty<object>();
}
}
public DebuggerProxy(EntitySlotInfo value)
{
_source = value;
}
public DebuggerProxy(entlong entity) : base(entity._id, entity._gen, entity._world) { }
}
#endregion
}