65 lines
1.9 KiB
C#
65 lines
1.9 KiB
C#
namespace OECS;
|
|
|
|
/// <summary>
|
|
/// An opaque handle to an entity in the ECS world.
|
|
/// Combines a 24-bit identifier with an 8-bit version to prevent
|
|
/// use-after-free bugs when entity IDs are recycled.
|
|
/// </summary>
|
|
public readonly struct Entity : IEquatable<Entity>
|
|
{
|
|
private const uint IdMask = 0x00FF_FFFF; // lower 24 bits
|
|
private const uint VersionMask = 0xFF00_0000; // upper 8 bits
|
|
private const int VersionShift = 24;
|
|
private const uint MaxId = IdMask;
|
|
private const uint MaxVersion = 0xFF;
|
|
|
|
/// <summary>
|
|
/// A sentinel value representing a null or invalid entity.
|
|
/// </summary>
|
|
public static readonly Entity Null = new(0);
|
|
|
|
private readonly uint _value;
|
|
|
|
internal Entity(uint id, uint version)
|
|
{
|
|
_value = (id & IdMask) | ((version & MaxVersion) << VersionShift);
|
|
}
|
|
|
|
private Entity(uint value)
|
|
{
|
|
_value = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The 24-bit entity identifier.
|
|
/// </summary>
|
|
public uint Id => _value & IdMask;
|
|
|
|
/// <summary>
|
|
/// The 8-bit generation version. Incremented each time the ID is recycled.
|
|
/// </summary>
|
|
public uint Version => (_value & VersionMask) >> VersionShift;
|
|
|
|
/// <summary>
|
|
/// Returns true if this entity is the null sentinel.
|
|
/// </summary>
|
|
public bool IsNull => _value == 0;
|
|
|
|
/// <summary>
|
|
/// Creates a new entity with the given version, keeping the same ID.
|
|
/// </summary>
|
|
internal Entity WithVersion(uint version) => new(Id, version);
|
|
|
|
public bool Equals(Entity other) => _value == other._value;
|
|
|
|
public override bool Equals(object? obj) => obj is Entity other && Equals(other);
|
|
|
|
public override int GetHashCode() => _value.GetHashCode();
|
|
|
|
public override string ToString() => $"Entity({Id}:v{Version})";
|
|
|
|
public static bool operator ==(Entity left, Entity right) => left.Equals(right);
|
|
|
|
public static bool operator !=(Entity left, Entity right) => !left.Equals(right);
|
|
}
|