Портал разработчиков
Экспериментально Платформа для ботов и приложений активно развивается. Поддержка собственных серверов вышла 13.08.2026, и функций там пока меньше, чем в облаке. Посмотрите, что поддерживается.
← Документация

Snowflake

GameVox возвращает ID в формате 64-битных snowflake Discord везде, где это сделал бы API Discord. Раскладка битов, порядок сортировки и формулы извлечения временной метки идентичны, так что ваш существующий код разбора snowflake работает без изменений.

Формат

Такой же, как в Discord: 42-битная временная метка + 5-битный worker + 5-битный process + 12-битный инкремент, big-endian внутри 64-битного беззнакового целого.

┌─ 42 bits ─────────────────┬─ 5 ─┬─ 5 ─┬─ 12 ────────┐
│ мс от эпохи GameVox       │ wkr │ prc │ increment   │
└───────────────────────────┴─────┴─────┴─────────────┘
 63                       22  21 17 16 12 11           0

Каждый сегмент совпадает с Discord:

  • Временная метка (42 бита): миллисекунды от эпохи GameVox, см. ниже.
  • Worker ID (5 бит): назначается каждой запущенной задаче api при старте через атомарный счётчик в Redis.
  • Process ID (5 бит): в паре с worker образует уникальный пул генерации.
  • Инкремент (12 бит): последовательность на каждую миллисекунду для каждой пары (worker, process).

Эпоха

GameVox использует ту же эпоху, что и Discord: 1420070400000 (2015-01-01 00:00:00 UTC). Парсер snowflake, написанный для Discord, работает с ID GameVox без изменений: никакую константу менять не нужно.

const SNOWFLAKE_EPOCH = 1420070400000n;

Формат передачи

Каждый snowflake в REST и шлюзе сериализуется как строка JSON, а не число. JavaScript теряет точность выше Number.MAX_SAFE_INTEGER (253-1), а snowflake регулярно превышает это значение. Если нужны вычисления, всегда разбирайте через BigInt, а в остальных местах храните как строку.

// Правильно
const id = BigInt(message.id);

// Неправильно: тихая потеря точности
const id = Number(message.id);

Извлечение временной метки

JavaScript

function snowflakeToDate(snowflake) {
  const EPOCH = 1420070400000n;          // как в Discord
  const ms = Number((BigInt(snowflake) >> 22n) + EPOCH);
  return new Date(ms);
}

console.log(snowflakeToDate('182955831900192769'));
// → объект Date: когда был создан этот snowflake

Python

from datetime import datetime, timezone

SNOWFLAKE_EPOCH = 1420070400000

def snowflake_to_dt(snowflake):
    ms = (int(snowflake) >> 22) + SNOWFLAKE_EPOCH
    return datetime.fromtimestamp(ms / 1000, tz=timezone.utc)

Java

long SNOWFLAKE_EPOCH = 1420070400000L;
long ms = (Long.parseUnsignedLong(snowflake) >>> 22) + SNOWFLAKE_EPOCH;
Instant when = Instant.ofEpochMilli(ms);

Порядок сортировки

Поскольку временная метка находится в старших битах, лексикографическое сравнение двух snowflake как строк упорядочивает их хронологически, как и в Discord. Поэтому пагинация before / after / around в эндпоинте сообщений работает без отдельного поля с временной меткой.

// В массиве сообщений, от старых к новым:
messages.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);

Собственные данные и таблица псевдонимов

Внутри собственные объекты GameVox (серверы, каналы, пользователи, сообщения и т. д.) используют UUIDv4. Слой совместимости для ботов создаёт стабильный snowflake при первом показе объекта боту и сохраняет эту пару в таблице snowflake_aliases. Все последующие обращения к этому объекту, через REST или шлюз, используют тот же snowflake.

Для сообщений snowflake заполняются задним числом с created_at сообщения в качестве исходной временной метки, так что старые сообщения правильно сортируются, когда бот впервые заходит в канал. Для всего остального псевдоним создаётся лениво при первом показе с NOW() в качестве временной метки, поэтому snowflake отражает момент, когда бот увидел объект, а не обязательно момент его создания.

Хеш для шардинга

Стандартная формула шардов Discord работает как есть:

shardId = (BigInt(guildId) >> 22n) % BigInt(numShards);

Боты, у которых меньше 2500 серверов, работают на одном шарде ([0, 1]), и им не нужно об этом думать. Более крупные боты получают такое же почти равномерное распределение хеша, как в Discord, потому что старшие 42 бита монотонно растут со временем, а не случайны.

Подводные камни

  • Не сравнивайте snowflake через == с числовым литералом. При передаче это строки: сравнивайте со строкой или приводите оба значения к BigInt.
  • 42-битная временная метка переполнится примерно через 139 лет после эпохи. Snowflake GameVox будут действительны до 2165 года.
  • Не определяйте время создания сервера, канала или роли по snowflake. Собственные объекты, появившиеся до платформы ботов, получили snowflake при первом показе боту, а не при создании. Исключение составляют сообщения (заполнены по created_at).

← Назад к документации