EntityGID

Глобальный идентификатор сущности — стабильная ссылка на сущность, безопасная для хранения, сериализации и передачи по сети

  • Используется для событий, связей между сущностями, сериализации, сетевого взаимодействия
  • Содержит Id, Version и ClusterId — позволяет обнаружить устаревшие ссылки через проверку версии
  • Назначается автоматически при создании сущности или вручную через NewEntityByGID
  • Структура размером 8 байт (StructLayout.Explicit, поля перекрываются через Raw)

Получение:

// Свойство на сущности
EntityGID gid = entity.GID;

// Неявное преобразование Entity → EntityGID
EntityGID gid = entity;

// Через конструктор
EntityGID gid = new EntityGID(id: 0, version: 1, clusterId: 0);
EntityGID gid = new EntityGID(rawValue: 16777216UL);

Свойства:

EntityGID gid = entity.GID;

uint id = gid.Id;               // Внутренний индекс слота сущности
ushort version = gid.Version;   // Счётчик поколений (инкрементируется при переиспользовании слота)
ushort clusterId = gid.ClusterId; // Идентификатор кластера
uint chunk = gid.Chunk;         // Индекс чанка (вычисляемый)
ulong raw = gid.Raw;            // Сырое 8-байтное представление (все поля упакованы)

Проверка и распаковка:

EntityGID gid = entity.GID;

// Проверить статус GID: Active, NotActual или NotLoaded
GIDStatus status = gid.Status<WT>();

// Безопасная распаковка — вернёт true если сущность загружена и актуальна
if (gid.TryUnpack<WT>(out var entity)) {
    ref var pos = ref entity.Ref<Position>();
}

// С диагностикой причины неудачи
if (!gid.TryUnpack<WT>(out var entity, out GIDStatus status)) {
    // status == GIDStatus.NotActual → сущность не существует или версия/кластер не совпадают (устаревшая ссылка)
    // status == GIDStatus.NotLoaded → сущность существует и версия совпадает, но она выгружена
}

// Небезопасная распаковка — в DEBUG будет ошибка если не загружена или устарела
var entity = gid.Unpack<WT>();

Создание сущности с заданным GID:

// Создать сущность в конкретном слоте, определённом GID
// Используется при десериализации и сетевой синхронизации
var entity = W.NewEntityByGID<Default>(gid);

// Не-дженерик вариант (тип сущности известен в runtime как byte)
byte entityTypeId = EntityTypeInfo<Default>.Id;
var entity = W.NewEntityByGID(entityTypeId, gid);

Инвалидация:

// Инкрементировать версию без уничтожения сущности
// Все ранее полученные GID станут неактуальными (Status вернёт GIDStatus.NotActual)
entity.UpVersion();

Сравнение:

EntityGID a = entity1.GID;
EntityGID b = entity2.GID;

bool eq = a == b;           // Сравнение по Raw (8 байт)
bool eq = a.Equals(b);      // То же самое

// Кросс-тип сравнение с EntityGIDCompact
EntityGIDCompact compact = entity1.GIDCompact;
bool eq = a == compact;     // Сравнение по Id, Version, ClusterId
bool eq = a.Equals(compact);

// Явное сужающее преобразование в EntityGIDCompact
// В DEBUG будет ошибка если Chunk >= 4 или ClusterId >= 4
EntityGIDCompact compact = (EntityGIDCompact)gid;

EntityGIDCompact

Компактная версия EntityGID — 4 байта вместо 8, для сценариев с ограничениями по памяти

  • Битовая упаковка: [31..16] Version, [15..14] ClusterId (2 бита), [13..12] Chunk (2 бита), [11..0] индекс в чанке
  • Лимиты: макс 4 чанка (~16 384 сущностей), макс 4 кластера
  • В DEBUG будет ошибка при выходе за границы

Получение:

EntityGIDCompact gid = entity.GIDCompact;

// Явное преобразование Entity → EntityGIDCompact
EntityGIDCompact gid = (EntityGIDCompact)entity;

// Через конструктор
EntityGIDCompact gid = new EntityGIDCompact(id: 0, version: 1, clusterId: 0);
EntityGIDCompact gid = new EntityGIDCompact(raw: 16777216U);

Проверка и распаковка:

// API аналогичен EntityGID
GIDStatus status = gid.Status<WT>();

if (gid.TryUnpack<WT>(out var entity)) {
    // ...
}

var entity = gid.Unpack<WT>();

// Неявное расширяющее преобразование в EntityGID (всегда безопасно)
EntityGID full = gid;

Примеры использования

События:

public struct OnDamage : IEvent {
    public EntityGID Target;
    public float Amount;
}

// В системе:
foreach (var e in damageReceiver) {
    ref var data = ref e.Value;
    if (data.Target.TryUnpack<WT>(out var target)) {
        ref var health = ref target.Ref<Health>();
        health.Current -= data.Amount;
    }
}

Сетевое взаимодействие сервер-клиент:

GID можно использовать как идентификатор связи сущности между клиентом и сервером. Сервер создаёт сущность, передаёт GID клиенту, клиент создаёт сущность с тем же GID — дальнейшие команды с GID позволяют клиенту легко найти нужную сущность через TryUnpack.

public struct CreateEntityCommand {
    public EntityGID Id;
    public string Prefab;
}

// Сервер:
var serverEntity = W.NewEntity<Default>();
client.Send(new CreateEntityCommand { Id = serverEntity.GID, Prefab = "player" });

// Клиент:
var cmd = server.Receive<CreateEntityCommand>();
var clientEntity = ClientW.NewEntityByGID<Default>(cmd.Id);

This site uses Just the Docs, a documentation theme for Jekyll.