Entwicklerportal
Experimentell Die Bot- & App-Plattform wird aktiv weiterentwickelt. Die Unterstützung für selbst gehostete Server ist am 13.08.2026 erschienen und bietet weniger Funktionen als die Cloud. Sieh dir an, was unterstützt wird.
← Doku

Snowflakes

GameVox gibt IDs überall dort im 64-Bit-Snowflake-Format von Discord zurück, wo die Discord-API es täte. Bit-Aufteilung, Sortierreihenfolge und die Mathematik zur Zeitstempel-Extraktion sind identisch — dein bestehender Snowflake-Parsing-Code funktioniert unverändert.

Format

Identisch mit Discord: 42-Bit-Zeitstempel + 5-Bit-Worker + 5-Bit-Prozess + 12-Bit-Zähler, Big-Endian innerhalb einer vorzeichenlosen 64-Bit-Ganzzahl.

┌─ 42 bits ─────────────────┬─ 5 ─┬─ 5 ─┬─ 12 ────────┐
│ ms seit GameVox-Epoche    │ wkr │ prc │ increment   │
└───────────────────────────┴─────┴─────┴─────────────┘
 63                       22  21 17 16 12 11           0

Jedes Segment entspricht Discord:

  • Zeitstempel (42 Bit) — Millisekunden seit der GameVox-Epoche, siehe unten.
  • Worker-ID (5 Bit) — wird pro laufendem api-Task beim Start über einen atomaren Redis-Zähler vergeben.
  • Prozess-ID (5 Bit) — bildet zusammen mit dem Worker einen eindeutigen Erzeugungspool.
  • Zähler (12 Bit) — Sequenz pro Millisekunde je (Worker, Prozess).

Epoche

GameVox nutzt dieselbe Epoche wie Discord: 1420070400000 (01.01.2015 00:00:00 UTC). Ein für Discord geschriebener Snowflake-Parser funktioniert unverändert mit GameVox-IDs — keine Konstante zum Austauschen.

const SNOWFLAKE_EPOCH = 1420070400000n;

Wire-Format

Jede Snowflake auf dem REST-/Gateway-Kanal wird als JSON-String serialisiert, nicht als Zahl. JavaScript verliert oberhalb von Number.MAX_SAFE_INTEGER (253-1) an Genauigkeit, und eine Snowflake überschreitet das regelmäßig. Parse immer über BigInt, wenn du rechnen musst, und speichere sonst als String.

// Richtig
const id = BigInt(message.id);

// Falsch — stiller Genauigkeitsverlust
const id = Number(message.id);

Zeitstempel extrahieren

JavaScript

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

console.log(snowflakeToDate('182955831900192769'));
// → Date-Objekt — wann diese Snowflake erzeugt wurde

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);

Sortierreihenfolge

Weil der Zeitstempel in den höherwertigen Bits steht, ordnet ein lexikografischer String-Vergleich zweier Snowflakes sie chronologisch — genau wie bei Discord. Deshalb funktioniert die Paginierung mit before / after / around am Nachrichten-Endpunkt ohne eigenes Zeitstempelfeld.

// In einem Nachrichten-Array, älteste → neueste:
messages.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);

Native Daten und die Alias-Tabelle

Intern nutzen GameVox-native Objekte (Server, Kanäle, Benutzer, Nachrichten usw.) UUIDv4. Die Bot-Kompatibilitätsschicht erzeugt beim ersten Kontakt eines Objekts mit einem Bot eine stabile Snowflake und speichert die Zuordnung in der Tabelle snowflake_aliases. Jede weitere Referenz auf dieses Objekt — über REST oder Gateway — nutzt dieselbe Snowflake.

Für Nachrichten füllen wir Snowflakes rückwirkend mit dem created_at der Nachricht als Quellzeitstempel, damit historische Nachrichten korrekt sortieren, wenn ein Bot einem Kanal erstmals beitritt. Für alles andere wird der Alias beim ersten Kontakt mit NOW() als Zeitstempel erzeugt, sodass die Snowflake widerspiegelt, wann der Bot das Objekt gesehen hat — nicht zwingend, wann es erstellt wurde.

Sharding-Hash

Die übliche Discord-Shard-Formel funktioniert unverändert:

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

Bots mit weniger als 2.500 Servern laufen auf einem einzigen Shard ([0, 1]) und müssen sich darüber keine Gedanken machen. Größere Bots erhalten dieselbe einigermaßen gleichmäßige Hash-Verteilung wie bei Discord, weil die oberen 42 Bit zeitlich monoton und nicht zufällig sind.

Stolperfallen

  • Vergleiche Snowflakes nicht mit == gegen ein Zahlenliteral. Auf dem Wire sind es Strings — vergleiche mit einem String oder konvertiere beide zu BigInt.
  • Der 42-Bit-Zeitstempel läuft nach etwa 139 Jahren ab der Epoche über. Die Snowflakes von GameVox reichen bis 2165.
  • Leite aus der Snowflake eines Servers / Kanals / einer Rolle nicht die Erstellungszeit ab. Native Objekte, die älter als die Bot-Plattform sind, haben ihre Snowflake beim ersten Bot-Kontakt erhalten, nicht bei der Erstellung. Nachrichten sind die Ausnahme (rückwirkend mit created_at befüllt).

← Zurück zur Doku