DragonECS/src/entlong.cs

457 lines
16 KiB
C#
Raw Normal View History

2023-05-26 04:25:09 +08:00
#pragma warning disable IDE1006
2024-01-25 20:11:28 +08:00
#pragma warning disable CS8981
2023-06-26 02:53:55 +08:00
using DCFApixels.DragonECS.Internal;
2023-05-26 04:25:09 +08:00
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
2024-04-16 12:45:55 +08:00
//using System.Runtime.Serialization;
namespace DCFApixels.DragonECS
{
2023-05-26 04:25:09 +08:00
// [ id 32 | gen 16 | world 16 ]
/// <summary>Strong identifier/Permanent entity identifier</summary>
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
[DebuggerTypeProxy(typeof(DebuggerProxy))]
2024-04-16 12:45:55 +08:00
//[DataContract]
2023-07-17 15:54:28 +08:00
[Serializable]
#if UNITY_EDITOR
public
#else
public readonly
#endif
2025-03-10 20:10:08 +08:00
struct entlong : IEquatable<long>, IEquatable<entlong>, IComparable<entlong>
{
public static readonly entlong NULL = default;
2024-04-16 12:45:55 +08:00
//[DataMember]
[FieldOffset(0)]
#if UNITY_EDITOR
[UnityEngine.SerializeField]
internal
#else
internal readonly
#endif
long _full; //Union
2023-07-17 15:54:28 +08:00
[FieldOffset(0), NonSerialized]
2024-04-16 12:45:55 +08:00
internal readonly int _id;
2023-07-17 15:54:28 +08:00
[FieldOffset(4), NonSerialized]
2024-04-16 12:45:55 +08:00
internal readonly short _gen;
2023-07-17 15:54:28 +08:00
[FieldOffset(6), NonSerialized]
2024-04-16 12:45:55 +08:00
internal readonly short _world;
#region Properties
public bool IsAlive
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
get { return EcsWorld.GetWorld(_world).IsAlive(_id, _gen); }
}
public bool IsNull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
get { return _full == 0L; }
}
public int ID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-28 01:20:35 +08:00
if (!IsAlive) { Throw.Ent_ThrowIsNotAlive(this); }
#endif
2024-04-16 12:45:55 +08:00
return _id;
}
}
public short Gen
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-28 01:20:35 +08:00
if (!IsAlive) { Throw.Ent_ThrowIsNotAlive(this); }
#endif
2024-04-16 12:45:55 +08:00
return _gen;
}
}
public EcsWorld World
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-28 01:20:35 +08:00
if (!IsAlive) { Throw.Ent_ThrowIsNotAlive(this); }
#endif
2024-04-16 12:45:55 +08:00
return GetWorld_Internal();
}
}
public short WorldID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-28 01:20:35 +08:00
if (!IsAlive) { Throw.Ent_ThrowIsNotAlive(this); }
#endif
2024-04-16 12:45:55 +08:00
return _world;
}
}
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public entlong(int id, short gen, short world) : this()
{
2024-04-16 12:45:55 +08:00
_id = id;
_gen = gen;
_world = world;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal entlong(long full) : this()
{
2024-04-16 12:45:55 +08:00
_full = full;
}
2023-11-21 10:43:02 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe entlong NewUnsafe(long id, long gen, long world)
{
long x = id << 48 | gen << 32 | id;
return *(entlong*)&x;
}
#endregion
2024-04-16 12:45:55 +08:00
#region Unpacking
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetID(out int id)
{
2024-04-16 12:45:55 +08:00
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetWorld(out EcsWorld world)
{
2024-04-16 12:45:55 +08:00
world = EcsWorld.GetWorld(_world);
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-10 19:21:52 +08:00
public bool TryGetWorldID(out short worldID)
2023-07-03 02:40:13 +08:00
{
2024-04-16 12:45:55 +08:00
worldID = _world;
2023-07-03 02:40:13 +08:00
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-03 00:28:02 +08:00
public void Unpack(out int id, out EcsWorld world)
2023-07-03 02:40:13 +08:00
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!IsAlive) { Throw.Ent_ThrowIsNotAlive(this); }
#endif
2024-04-16 12:45:55 +08:00
world = EcsWorld.GetWorld(_world);
id = _id;
2023-07-03 02:40:13 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-03 22:46:09 +08:00
public void Unpack(out int id, out short gen, out EcsWorld world)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!IsAlive) { Throw.Ent_ThrowIsNotAlive(this); }
#endif
2024-04-16 12:45:55 +08:00
world = EcsWorld.GetWorld(_world);
gen = _gen;
id = _id;
2024-03-03 22:46:09 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-10 19:21:52 +08:00
public void Unpack(out int id, out short worldID)
2023-07-03 02:40:13 +08:00
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!IsAlive) { Throw.Ent_ThrowIsNotAlive(this); }
#endif
2024-04-16 12:45:55 +08:00
worldID = _world;
id = _id;
2023-07-03 02:40:13 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-03 00:28:02 +08:00
public void Unpack(out int id, out short gen, out short worldID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!IsAlive) { Throw.Ent_ThrowIsNotAlive(this); }
#endif
2024-04-16 12:45:55 +08:00
worldID = _world;
gen = _gen;
id = _id;
2024-03-03 00:28:02 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-03 00:28:02 +08:00
public bool TryUnpack(out int id, out EcsWorld world)
{
2024-04-16 12:45:55 +08:00
world = GetWorld_Internal();
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-03 22:46:09 +08:00
public bool TryUnpack(out int id, out short gen, out EcsWorld world)
{
2024-04-16 12:45:55 +08:00
world = GetWorld_Internal();
gen = _gen;
id = _id;
2024-03-03 22:46:09 +08:00
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-10 19:21:52 +08:00
public bool TryUnpack(out int id, out short worldID)
2024-03-03 00:28:02 +08:00
{
2024-04-16 12:45:55 +08:00
worldID = _world;
id = _id;
2024-03-03 00:28:02 +08:00
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-03 00:28:02 +08:00
public bool TryUnpack(out int id, out short gen, out short worldID)
2023-07-03 02:40:13 +08:00
{
2024-04-16 12:45:55 +08:00
worldID = _world;
gen = _gen;
id = _id;
2023-07-03 02:40:13 +08:00
return IsAlive;
}
2024-04-16 12:45:55 +08:00
#endregion
2024-04-16 12:45:55 +08:00
#region Unpacking
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetIDUnchecked()
{
2024-04-16 12:45:55 +08:00
return _id;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsWorld GetWorldUnchecked()
{
2024-04-16 12:45:55 +08:00
return EcsWorld.GetWorld(_world);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public short GetWorldIDUnchecked()
{
2024-04-16 12:45:55 +08:00
return _world;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UnpackUnchecked(out int id, out EcsWorld world)
{
2024-04-16 12:45:55 +08:00
world = EcsWorld.GetWorld(_world);
id = _id;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UnpackUnchecked(out int id, out short gen, out EcsWorld world)
{
2024-04-16 12:45:55 +08:00
world = EcsWorld.GetWorld(_world);
gen = _gen;
id = _id;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UnpackUnchecked(out int id, out short worldID)
{
2024-04-16 12:45:55 +08:00
worldID = _world;
id = _id;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UnpackUnchecked(out int id, out short gen, out short worldID)
{
2024-04-16 12:45:55 +08:00
worldID = _world;
gen = _gen;
id = _id;
}
#endregion
2024-02-28 01:20:35 +08:00
#region Operators
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
public static bool operator ==(entlong a, entlong b) { return a._full == b._full; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
public static bool operator !=(entlong a, entlong b) { return a._full != b._full; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
public static implicit operator entlong((int entityID, EcsWorld world) a) { return Combine_Internal(a.entityID, a.world); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
public static implicit operator entlong((EcsWorld world, int entityID) a) { return Combine_Internal(a.entityID, a.world); }
2023-07-17 15:54:28 +08:00
2024-04-16 12:45:55 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator entlong((entlong entity, EcsWorld world) a) { return Combine_Internal(a.entity._id, a.world); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator entlong((EcsWorld world, entlong entity) a) { return Combine_Internal(a.entity._id, a.world); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static entlong Combine_Internal(int entityID, EcsWorld world)
{
return world == null ? new entlong(entityID, 0, 0) : world.GetEntityLong(entityID);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator long(entlong a) { return a._full; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator entlong(long a) { return new entlong(a); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-02-28 01:20:35 +08:00
public static explicit operator int(entlong a) { return a.ID; }
#endregion
2024-04-16 12:45:55 +08:00
#region Deconstruct
2024-02-28 01:20:35 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
public void Deconstruct(out int id, out short gen, out short worldID) { Unpack(out id, out gen, out worldID); }
2024-02-28 01:20:35 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
public void Deconstruct(out int id, out EcsWorld world) { Unpack(out id, out world); }
#endregion
#region Other
2024-02-28 01:20:35 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
private EcsWorld GetWorld_Internal() { return EcsWorld.GetWorld(_world); }
2024-02-28 01:20:35 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
public override int GetHashCode() { return unchecked((int)_full) ^ (int)(_full >> 32); }
2024-02-28 01:20:35 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
public override string ToString() { return $"entity(id:{_id} g:{_gen} w:{_world} {(IsNull ? "null" : IsAlive ? "alive" : "not alive")})"; }
2024-01-26 18:58:54 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
public override bool Equals(object obj) { return obj is entlong other && _full == other._full; }
2024-01-26 18:58:54 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-04-16 12:45:55 +08:00
public bool Equals(entlong other) { return _full == other._full; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(long other) { return _full == other; }
2025-03-10 20:10:08 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int CompareTo(entlong other)
{
// NOTE: Because _id cannot be less than 0,
// the case “_id - other._id > MaxValue” is impossible.
return _id - other._id;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Compare(entlong left, entlong right) { return left.CompareTo(right); }
2023-11-15 17:47:11 +08:00
2024-02-29 03:28:13 +08:00
internal class DebuggerProxy
{
2024-02-29 03:28:13 +08:00
private List<object> _componentsList = new List<object>();
private entlong _value;
2024-04-16 12:45:55 +08:00
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; } }
2024-02-28 01:20:35 +08:00
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
{
2024-03-07 03:30:18 +08:00
_value.World.GetComponentsFor(_value.ID, _componentsList);
return _componentsList;
}
}
public DebuggerProxy(entlong value)
{
_value = value;
2024-02-29 03:28:13 +08:00
}
public DebuggerProxy(EntitySlotInfo value)
{
_value = new entlong(value.id, value.gen, value.world);
}
public enum EntState { Null, Dead, Alive, }
}
#endregion
}
2024-04-16 12:45:55 +08:00
}
2024-02-29 03:28:13 +08:00
2024-04-16 12:45:55 +08:00
namespace DCFApixels.DragonECS
{
2024-03-01 22:02:36 +08:00
[DebuggerTypeProxy(typeof(DebuggerProxy))]
2024-02-29 03:28:13 +08:00
public readonly struct EntitySlotInfo : IEquatable<EntitySlotInfo>
{
2024-05-01 14:09:15 +08:00
private readonly long _full;
2024-02-29 03:28:13 +08:00
public readonly int id;
public readonly short gen;
public readonly short world;
2024-05-01 14:09:15 +08:00
#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
2024-02-29 03:28:13 +08:00
#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;
}
}
2024-02-29 03:28:13 +08:00
public EntitySlotInfo(int id, short gen, short world)
{
this.id = id;
this.gen = gen;
this.world = world;
2024-05-01 14:09:15 +08:00
_full = ((long)world << 48 | (long)gen << 32 | (long)id);
2024-02-29 03:28:13 +08:00
}
#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)]
2024-05-01 14:09:15 +08:00
public override string ToString() { return $"slot(id:{id} g:{gen} w:{world} {(State == EntState.Null ? "null" : State == EntState.Alive ? "alive" : "not alive")})"; }
2024-02-29 03:28:13 +08:00
[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;
}
2024-05-01 14:09:15 +08:00
public enum EntState { Null, Dead, Alive, }
2024-03-01 22:02:36 +08:00
internal class DebuggerProxy
{
private List<object> _componentsList = new List<object>();
2024-05-01 14:09:15 +08:00
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
2024-03-01 22:02:36 +08:00
{
get
{
2024-05-01 14:29:01 +08:00
if (State == EntState.Alive)
2024-05-01 14:09:15 +08:00
{
World.GetComponentsFor(id, _componentsList);
return _componentsList;
}
return Array.Empty<object>();
2024-03-01 22:02:36 +08:00
}
}
public DebuggerProxy(EntitySlotInfo value)
{
2024-05-01 14:09:15 +08:00
_source = value;
2024-03-01 22:02:36 +08:00
}
}
2024-04-16 12:45:55 +08:00
#endregion
2024-02-29 03:28:13 +08:00
}
}