DragonECS/src/entlong.cs

196 lines
6.3 KiB
C#
Raw Normal View History

2023-05-26 04:25:09 +08:00
#pragma warning disable IDE1006
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;
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))]
public readonly struct entlong : IEquatable<long>, IEquatable<entlong>
{
public static readonly entlong NULL = default;
[FieldOffset(0)]
internal readonly long full; //Union
[FieldOffset(0)]
internal readonly int id;
[FieldOffset(4)]
internal readonly short gen;
[FieldOffset(6)]
internal readonly short world;
#region Properties
public bool IsAlive
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-06-22 02:02:43 +08:00
get => EcsWorld.GetWorld(world).IsAlive(id, gen);
}
public bool IsNull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-06-26 01:57:50 +08:00
get => 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
2023-06-26 01:57:50 +08:00
if (!IsAlive) Throw.Ent_ThrowIsNotAlive(this);
#endif
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
2023-06-26 01:57:50 +08:00
if (!IsAlive) Throw.Ent_ThrowIsNotAlive(this);
#endif
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
2023-06-26 01:57:50 +08:00
if (!IsAlive) Throw.Ent_ThrowIsNotAlive(this);
#endif
2023-06-22 02:02:43 +08:00
return EcsWorld.GetWorld(world);
}
}
public short WorldID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if (!IsAlive) Throw.Ent_ThrowIsNotAlive(this);
#endif
return world;
}
}
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public entlong(int id, short gen, short world) : this()
{
this.id = id;
this.gen = gen;
this.world = world;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal entlong(long full) : this()
{
this.full = full;
}
#endregion
#region TryGetters
public bool TryGetID(out int id)
{
id = this.id;
return IsAlive;
}
public bool TryGetWorld(out EcsWorld world)
{
2023-06-22 02:02:43 +08:00
world = EcsWorld.GetWorld(this.world);
return IsAlive;
}
2023-07-03 02:40:13 +08:00
public bool TryGetWorldID(out int worldID)
{
worldID = world;
return IsAlive;
}
public void Unpack(out EcsWorld world, out int id)
{
world = EcsWorld.GetWorld(this.world);
id = this.id;
}
public void Unpack(out int worldID, out int id)
{
worldID = world;
id = this.id;
}
public bool TryUnpack(out EcsWorld world, out int id)
{
2023-06-22 02:02:43 +08:00
world = EcsWorld.GetWorld(this.world);
id = this.id;
return IsAlive;
}
2023-07-03 02:40:13 +08:00
public bool TryUnpack(out int worldID, out int id)
{
worldID = world;
id = this.id;
return IsAlive;
}
#endregion
#region Equals
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(entlong other) => full == other.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(long other) => full == other;
#endregion
#region Object
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => unchecked((int)full) ^ (int)(full >> 32);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-05-26 04:25:09 +08:00
public override string ToString() => $"entity(id:{id} g:{gen} w:{world} {(IsNull ? "null" : IsAlive ? "alive" : "not alive")})";
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj) => obj is entlong other && full == other.full;
#endregion
#region operators
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(in entlong a, in entlong b) => a.full == b.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(in entlong a, in entlong b) => a.full != b.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator long(in entlong a) => a.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator entlong(in long a) => new entlong(a);
#endregion
#region DebuggerProxy
internal class DebuggerProxy
{
private List<object> _componentsList;
private entlong _value;
public long full => _value.full;
public int id => _value.id;
public int gen => _value.gen;
public int world => _value.world;
public EntState State => _value.IsNull ? EntState.Null : _value.IsAlive ? EntState.Alive : EntState.Dead;
public EcsWorld EcsWorld => _value.World;
public IEnumerable<object> components
{
get
{
_value.World.GetComponents(_value.ID, _componentsList);
return _componentsList;
}
}
public DebuggerProxy(entlong value)
{
_value = value;
_componentsList = new List<object>();
}
public enum EntState { Null, Dead, Alive, }
}
#endregion
}
}