Snowflakes
GameVox renvoie des ID au format snowflake 64 bits de Discord partout où l’API Discord le ferait. La disposition des bits, l’ordre de tri et le calcul d’extraction de l’horodatage sont identiques — votre code d’analyse existant fonctionne sans modification.
Format
Identique à Discord : horodatage 42 bits + worker 5 bits + processus 5 bits + compteur 12 bits, big-endian dans un entier 64 bits non signé.
┌─ 42 bits ─────────────────┬─ 5 ─┬─ 5 ─┬─ 12 ────────┐
│ ms depuis l’époque GameVo │ wkr │ prc │ increment │
└───────────────────────────┴─────┴─────┴─────────────┘
63 22 21 17 16 12 11 0 Chaque segment correspond à Discord :
- Horodatage (42 bits) — millisecondes depuis l’époque GameVox, voir ci-dessous.
- ID de worker (5 bits) — attribué à chaque tâche api au démarrage via un compteur atomique Redis.
- ID de processus (5 bits) — associé au worker pour former un pool de génération unique.
- Compteur (12 bits) — séquence par milliseconde et par (worker, processus).
Époque
GameVox utilise la même époque que Discord : 1420070400000 (01/01/2015 00:00:00 UTC). Un analyseur de snowflakes écrit pour Discord fonctionne sur les ID GameVox sans modification — aucune constante à changer.
const SNOWFLAKE_EPOCH = 1420070400000n; Format de transport
Chaque snowflake sur le canal REST / gateway est sérialisée en chaîne JSON, pas en nombre. JavaScript perd en précision au-delà de Number.MAX_SAFE_INTEGER (253-1), et une snowflake dépasse régulièrement cette valeur. Analysez toujours via BigInt quand vous devez calculer, et stockez-la comme chaîne partout ailleurs.
// Correct
const id = BigInt(message.id);
// Incorrect — perte de précision silencieuse
const id = Number(message.id); Extraire l’horodatage
JavaScript
function snowflakeToDate(snowflake) {
const EPOCH = 1420070400000n; // identique à Discord
const ms = Number((BigInt(snowflake) >> 22n) + EPOCH);
return new Date(ms);
}
console.log(snowflakeToDate('182955831900192769'));
// → objet Date — quand cette snowflake a été générée 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); Ordre de tri
Comme l’horodatage occupe les bits de poids fort, une comparaison lexicographique de deux snowflakes les classe chronologiquement — exactement comme sur Discord. C’est pour cela que la pagination before / after / around de l’endpoint des messages fonctionne sans champ d’horodatage explicite.
// Dans un tableau de messages, du plus ancien au plus récent :
messages.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0); Données natives et table d’alias
En interne, les objets natifs de GameVox (serveurs, salons, utilisateurs, messages, etc.) utilisent des UUIDv4. La couche de compatibilité génère une snowflake stable la première fois qu’un objet est exposé à un bot et enregistre la correspondance dans la table snowflake_aliases. Toute référence ultérieure à cet objet — via REST ou gateway — utilise la même snowflake.
Pour les messages, nous renseignons rétroactivement les snowflakes avec le created_at du message comme horodatage source, afin que les messages anciens se trient correctement lorsqu’un bot rejoint un salon pour la première fois. Pour tout le reste, l’alias est généré paresseusement à la première exposition avec NOW() comme horodatage : la snowflake reflète donc le moment où le bot a vu l’objet, pas nécessairement sa création.
Hachage de sharding
La formule de shard standard de Discord fonctionne telle quelle :
shardId = (BigInt(guildId) >> 22n) % BigInt(numShards); Les bots présents sur moins de 2 500 serveurs tournent sur un seul shard ([0, 1]) et n’ont pas à s’en préoccuper. Les bots plus gros obtiennent la même répartition à peu près uniforme que sur Discord, car les 42 bits de poids fort sont monotones dans le temps, pas aléatoires.
Pièges
- Ne comparez pas une snowflake avec
==à un littéral numérique. Sur le canal, ce sont des chaînes — comparez à une chaîne ou convertissez les deux enBigInt. - L’horodatage 42 bits déborde environ 139 ans après l’époque. Les snowflakes de GameVox sont valables jusqu’en 2165.
- Ne déduisez pas la date de création d’un serveur / salon / rôle à partir de sa snowflake. Les objets natifs antérieurs à la plateforme de bots ont reçu leur snowflake à la première exposition à un bot, pas à leur création. Les messages font exception (renseignés avec
created_at).