Struct EntityId
64-bit entity identifier: 48-bit monotonic EntityKey (upper) + 16-bit per-DB archetype routing id (lower). Routes to the correct per-archetype LinearHash and uniquely identifies an entity within the engine.
public readonly struct EntityId : IEquatable<EntityId>
- Implements
- Inherited Members
Remarks
EntityKey is monotonic per-archetype, never recycled — no ABA problem, no version field needed. 2^48 ≈ 281 T allocations per archetype.
ArchetypeId is the low 16 bits: the per-DB, engine-assigned archetype routing id (persisted in ArchetypeR1.RoutingId,
re-matched by name on reopen). Up to 65,536 archetypes composable into one database. The word-aligned 48/16 split needs no mask constant — the routing id
is (ushort)value and the key is value >> 16.
Fields
Null
The null entity sentinel.
public static readonly EntityId Null
Field Value
Properties
ArchetypeId
16-bit per-DB archetype routing id (low bits). Routes to the correct per-archetype storage instance for the owning engine.
public ushort ArchetypeId { get; }
Property Value
EntityKey
48-bit monotonic key, unique within the archetype's LinearHash.
public long EntityKey { get; }
Property Value
IsNull
True if this is the null/default entity (no entity).
public bool IsNull { get; }
Property Value
RawValue
Raw packed value: the 48-bit EntityKey in the upper bits and the 16-bit ArchetypeId in the lower bits.
public ulong RawValue { get; }
Property Value
Remarks
For carrying an identity somewhere the engine does not own — an application's own wire messages, its account or character rows in another store, its logs, its admin tooling, or a client's "target" field coming back in. Round-trips through FromRawValue(ulong).
Stable within one database, NOT across databases. ArchetypeId is the per-DB routing id persisted in
ArchetypeR1.RoutingId and re-matched by archetype NAME on reopen, so a raw value stays valid across restarts of the same database — and
means something different, or nothing, in another one. Renaming an archetype without setting
ArchetypeAttribute.PreviousName breaks the match and invalidates every raw value already persisted outside the engine: the name is the
durable identity, not the number.
Methods
Equals(object)
public override bool Equals(object obj)
Parameters
objobject
Returns
Equals(EntityId)
Returns true when other has the same packed identifier value.
public bool Equals(EntityId other)
Parameters
otherEntityId
Returns
FromParts(long, ushort)
Rebuilds an EntityId from the two parts EntityKey and ArchetypeId expose.
public static EntityId FromParts(long entityKey, ushort archetypeId)
Parameters
entityKeylongThe 48-bit monotonic key (see EntityKey). Must be non-negative and fit in 48 bits.
archetypeIdushortThe per-DB archetype routing id (see ArchetypeId).
Returns
- EntityId
The identifier.
Remarks
The range check is unconditional, unlike the internal constructor's. That one guards behind Enabled, which is off by default so the JIT folds it away — correct for a path the engine itself feeds with values it just produced. This one takes numbers from outside the engine, where the whole point is to reject a bad one, and a check that disappears in Release would hand back a silently corrupt identity.
Exceptions
- ArgumentOutOfRangeException
entityKeyis negative or does not fit in 48 bits.
FromRawValue(ulong)
public static EntityId FromRawValue(ulong rawValue)
Parameters
Returns
- EntityId
The identifier.
Remarks
Every bit pattern is a representable identifier, so this cannot fail and does not validate: a value that was not produced by RawValue yields an id that resolves to no entity rather than an exception. Read RawValue's remarks for what "the same database" means before persisting one.
GetHashCode()
Hash of the packed 64-bit identifier value.
public override int GetHashCode()
Returns
ToString()
Human-readable form, e.g. Entity(Key=42, Arch=3), or Entity(Null) for the null entity.
public override string ToString()
Returns
TryParse(ReadOnlySpan<char>, out EntityId)
Parses the form ToString() produces.
public static bool TryParse(ReadOnlySpan<char> text, out EntityId id)
Parameters
textReadOnlySpan<char>Either
Entity(Key=<key>, Arch=<routingId>)orEntity(Null).idEntityId
Returns
Remarks
Exists so a log line or a diagnostic dump is reversible: the id that appears in a trace can be fed back to a tool without the reader hand-extracting two integers. Culture-invariant, because ToString() is. Surrounding whitespace is tolerated; anything else in the string is not, so a half-matching line fails rather than silently parsing its prefix.
TryParse(string, out EntityId)
Parses the form ToString() produces.
public static bool TryParse(string text, out EntityId id)
Parameters
Returns
Operators
operator ==(EntityId, EntityId)
Value equality of two EntityId values.
public static bool operator ==(EntityId left, EntityId right)
Parameters
Returns
operator !=(EntityId, EntityId)
Value inequality of two EntityId values.
public static bool operator !=(EntityId left, EntityId right)