Documentation du protocole de serveur utilisé par les Serveurs Minecraft Classic.
Communication avec Minecraft.net[]
Heartbeats[]
Pour pouvoir se connecter à un serveur Minecraft Classic à partir de la liste des serveurs, le serveur doit envoyer à minecraft.net un "heartbeat" (traduisez par "battement de coeur") toutes les minutes, environ.
Le serveur stocke ce battement de coeur pendant 45 secondes.
Le "battement de coeur" prends la forme d'une requête HTTP sur http://www.minecraft.net/heartbeat.jsp. Après avoir envoyé le battement de coeur, l'URL pour le serveur est retourné.
Cela peut être une requête de type POST ou de type GET. Voici le tableau des paramètres ci-dessous :
Name | Details |
---|---|
port | Le port serveur. Par défaut, c'est 25565 |
max | Le quota maximal de joueurs sur le serveur. |
name | Le nom du serveur. |
public | Si le serveur est public (c'est-à-dire s'il apparaît dans la liste) ou non. Cela peut être True ou False (même forme). |
version | Historique des versions, normalement, la version doit être 0x07. |
salt | Un clé aléatoire de 16 caractères en base 62 (appelée "salt", ou "grain de sel") |
users | Le nombre de joueurs actuellement connectés sur le serveur. |
La façon la plus simple d'envoyer un battement de coeur est d'ouvrir un socket TCP sur le port 80 à l'adresse suivante : www.minecraft.net, et envoyer les valeurs (qui doivent être modifiées, évidemment)
GET /heartbeat.jsp?port=25565&max=32&name=My%20Server&public=True&version=7&salt=wo6kVAHjxoJcInKx&users=0, avec un CRLF (Carriage-return and Line feed, traduisez par Retour Chariot et Saut de Ligne).
Assurez-vous que toutes les chaînes de caractères sont échappées, c'est-à-dire un retour chariot en fin de ligne.
Dans le corps de la réponse, vous allez pouvoir récupérer l'URL. Sinon, vous allez recevoir une erreur HTML, souvent limitée à un simple "<html>" dans la version Client.
(Nota bene: Aucun header est retourné si vous utilisez le format de requête HTTP/0.9 comme montré avant, rend cette méthode plus simple qu'elle ne l'était avant.)
Authentification de l'utilisateur[]
La clé qui est donnée quand un utilisateur rejoint le serveur doit être comparée à la vérification du MD5 du "salt" du serveur avec le nom d'utilisateur pour vérifier que l'utilisateur est enregistré sur minecraft.net avec ce nom d'utilisateur. Grâce à ça, le nom du joueur devient un critère suffisamment fiable pour bannir ou grader par nom.
if( player.key == md5( server.salt + player.name ) ) { // le joueur est enregistré sur Minecraft.net } else { // le joueur n'est pas enregistré. }
N.B.: Cela signifie que votre "grain de sel" doit être gardé secret et doit seulement être partagé avec heartbeat.jsp. Si le "grain de sel" de votre serveur est visible n'importe où par n'importe quel utilisateur, ça devient un jeu d'enfant pour les pirates de fabriquer une clef qui a l'air valide, sans pour autant avoir besoin de s'authentifier à minecraft.net.
Skins[]
Les Skins pour un joueur sont téléchargés par le client à l'adresse suivante : https://s3.amazonaws.com/MinecraftSkins/skinname.png et à http://minecraft.net/skin/skinname.png, ou "skinname" est le nom du joueur. Cela veut dire que le nom du joueur peut être faux pour donner à un joueur un skin spécial.
Codes Couleurs[]
Les messages envoyés par le serveur au joueur peuvent contenir des couleur, ce qui autorise de colorer le texte pour différentes utilisations.
Une esperluette (&) suivi par une valeur héxadécimale dans le message indique au client quelle couleur utiliser.
Les couleurs ne marcheront que si l'ID du joueur est plus bas que 127. Si c'est 127 ou plus, le jeu va ajouter automatiquement un &e (couleur jaune) avant le message, qui va devenir jaune. Toutefois, les codes couleur après le premier caractère fonctionnent toujours. Si vous utilisez un ID plus bas que 127, cela n'ajoutera pas de code couleur, donc vous pouvez choisir n'importe quelle couleur.
Il est important de noter que si une esperluette à la fin d'un message n'est pas suivie par un valeur héxadécimale, tous les clients qui reçoivent cette valeur vont planter. Il faut donc vous assurer des données que le serveur envoie.
Couleur | Code | Nom commun | Couleur du texte | Couleur de l'ombre | ||||
---|---|---|---|---|---|---|---|---|
R | G | B | R | G | B | |||
&0 | Noir | 0 | 0 | 0 | 0 | 0 | 0 | |
&1 | Bleu foncé | 0 | 0 | 191 | 0 | 0 | 47 | |
&2 | Vert foncé | 0 | 191 | 0 | 0 | 47 | 0 | |
&3 | Turquoise foncé | 0 | 191 | 191 | 0 | 47 | 47 | |
&4 | Rouge foncé | 191 | 0 | 0 | 47 | 0 | 0 | |
&5 | Violet | 191 | 0 | 191 | 47 | 0 | 47 | |
&6 | Or | 191 | 191 | 0 | 47 | 47 | 0 | |
&7 | Gris | 191 | 191 | 191 | 47 | 47 | 47 | |
&8 | Gris foncé | 64 | 64 | 64 | 16 | 16 | 16 | |
&9 | Bleu | 64 | 64 | 255 | 16 | 16 | 63 | |
&a | Vert clair | 64 | 255 | 64 | 16 | 63 | 16 | |
&b | Turquoise | 64 | 255 | 255 | 16 | 63 | 63 | |
&c | Rouge | 255 | 64 | 64 | 63 | 16 | 16 | |
&d | Rose | 255 | 64 | 255 | 63 | 16 | 63 | |
&e | Jaune | 255 | 255 | 64 | 63 | 63 | 16 | |
&f | Blanc | 255 | 255 | 255 | 63 | 63 | 63 |
Protocole de paquets[]
Chaque paquet démarre avec une variable de type "byte" qui représente l'ID du paquet.
Protocol Data Types[]
Type | Taille[octets] | Description |
---|---|---|
Byte | 1 | Un octet représentant un entier non signé (0 à 255) |
SByte | 1 | Un octet représentant un entier signé (-128 à 127) |
Short | 2 | Un entier signé, network order (-32768 to 32767) |
String | 64 | US-ASCII/ISO646-US : chaîne de caractères encodée complétée avec des espaces (0x20) |
Byte array | 1024 | Données binaires complétées avec des "octets nuls" (0x00) |
Paquets Client -> Serveur[]
Id du paquet | Affectation | Description | Type | Notes |
---|---|---|---|---|
0x00 | Identification du joueur | ID du paquet | Byte | Envoyé par un joueur avec des informations pertinentes. Le protocole de Minecraft Classic est en version 0x07. |
Version du protocole | Byte | |||
Nom d'utilisateur | String | |||
Clé de vérification | String | |||
Non utilisé | Byte | |||
0x05 | Set Block | ID du paquet | Byte | Est envoyé lorsqu'un joueur modifie un bloc. Le mode 0x01 indique que le bloc est posé, 0x00 indique que le bloc est détruit.
Le type du bloc est toujours le type du bloc que le joueur a en main. Le client assume que ce paquet réussit toujours, et donc crée le nouveau bloc immédiatement. Pour interdire la création de blocs, le serveur doit répondre par un paquet Set Block pour modifier ce bloc avec l'ancien type de bloc. Les coordonnées XYZ du bloc sont juste des entiers qui représentent les coordonnées du bloc. (A l'opposé des coordonnées du joueur dont les 5 premiers bits représentent la partie décimale). |
X | Short | |||
Y | Short | |||
Z | Short | |||
Mode | Byte | |||
Type de bloc | Byte | |||
0x08 | Position et orientation | ID du paquet | Byte | Envoyé fréquemment (même si le joueur ne bouge pas) par le joueur avec la position du joueur et l'orientation. L'ID du joueur est toujours 255, qui se réfère à lui même. Les coordonnées du joueur sont des points-fixés (5 bits) qui représentent la position fractionnée (astuce : divisez par 32 pour obtenir la position actuelle). Le paramètre "angle" est mis à l'échelle de façon à ce qu'une valeur de 256 doit correspondre à 360°. |
Id du joueur | Byte | |||
X | Short | |||
Y | Short | |||
Z | Short | |||
Yaw (Heading) | Byte | |||
Pitch | Byte | |||
0x0d | Message | ID du paquet | Byte | Contient les messages du joueur envoyés dans le chat. |
Non utilisé, peut être les couleurs du message. | Byte (0xFF) | |||
Message | String |
Server → Client packets[]
ID du paquet | Affectation | Description | Type | Notes |
---|---|---|---|---|
0x00 | Identification du serveur | ID du paquet | Byte | La réponse à un joueur qui tente de rejoindre le serveur. Le type d'utilisateur indique si le joueur est un opérateur (0x64) ou non (0x00). La version du protocole à l'heure actuelle est 0x07. |
Version du protocole | Byte | |||
Nom du serveur | String | |||
MOTD du serveur | String | |||
Type de l'utilisateur | Byte | |||
0x01 | Ping | ID du paquet | Byte | Est envoyé aux clients périodiquement. Le seul moyen de se déconnecter pour un client est de forcer la déconnexion, mais dans ce cas-là, le serveur ne sait pas si le joueur n'est plus là ou encore connecté. Le paquet ping est utilisé pour déterminer si la connexion est toujours ouverte. |
0x02 | Initialisation du niveau | ID du paquet | Byte | Notifie le joueur que des données de la map arrivent. Dès lors le client affiche un écran de chargement. |
0x03 | Données du niveau du tronçon | ID du paquet | Byte | Ce paquet permet d'envoyer au client un fragment des données de la map. Les données de la map sont présentées sous la forme d'un tableau d'octets compressé au format GZip comprenant :
Chaque tronçon est un fragment des données de la map de 1024 octets. Si la taille du tronçon est inférieure à 1024, il est complété avec des 0x00. |
Longueur du tronçon | Short | |||
Données du tronçon | Byte Array | |||
Pourcentage complété | Byte | |||
0x04 | Finalisation du niveau | Id du paquet | Byte | Ce paquet est envoyé après le dernier tronçon, et contient la taille de la carte. Il a pour effet d'enlever l'écran de chargement du client. |
Taille X | Short | |||
Taille Y | Short | |||
Taille Z | Short | |||
0x06 | Modification de bloc (serveur) | ID du paquet | Byte | Envoyé pour indiquer un changement de bloc par des évènements physiques ou des joueurs. Le paquet doit être envoyé à tous les joueurs sur la même carte. |
X | Short | |||
Y | Short | |||
Z | Short | |||
Type du bloc | Byte | |||
0x07 | Apparition du joueur | ID du paquet | Byte | Est envoyé pour indiquer qu'un nouveau utilisateur apparaît sur le monde. L'ID est généré au hasard par le serveur et doit être unique pour chaque joueur sur la même carte. La position et l'orientation sont encodés pareils, comme le paquet 0x08 plus haut.
Ce paquet doit également être envoyé au client lorsqu'il apparaît sur la carte, avec pour ID de joueur 255 (lui-même). Cela définit sa position d'apparition. |
Id du joueur | SByte | |||
Nom du joueur | String | |||
X | Short | |||
Y | Short | |||
Z | Short | |||
Yaw (Heading) | Byte | |||
Pitch | Byte | |||
0x08 | Mise à jour absolue de la position et de l'orientation du joueur. | ID du paquet | Byte | Ce paquet permet de téléporter le joueur à la position (X; Y; Z) et de l'orienter. S'il s'agit du client connecté, l'ID du joueur doit être 255. Il est également utilisé pour signaler au client les mouvements des autres joueurs.
Dans ce dernier cas, il est nécessaire d'envoyer ce paquet lorsque le joueur s'est déplacé d'un nombre de blocs strictement inférieur à -4.00 (-128 ou encore 0xFF en SByte), ou d'une position supérieure ou égale à 4.00 (+127 ou encore 0x7F en SByte). Si le joueur ne s'est déplacé que d'un petit nombre de blocs (inférieur à -4.00 ou supérieur ou égal à 4.00), il est préférable d'envoyer le paquet n°9 pour économiser de la bande passante, bien que cela ne soit pas obligatoire. |
ID du joueur | SByte | |||
X | Short | |||
Y | Short | |||
Z | Short | |||
Yaw (Heading) | Byte | |||
Pitch | Byte | |||
0x09 | Mise à jour de :
|
ID du paquet | Byte | Ce paquet permet de mettre à jour la position du joueur de manière relative, ainsi que son orientation. Utiliser ce paquet à la place du paquet n°8 permet d'économiser 3 octets, mais seulement sous la condition que la position du joueur n'ait été modifiée que d'un nombre de blocs strictement inférieur à 4.00 ou supérieur ou égal à 4.00. Si cette condition n'est pas respectée, il faut utiliser le paquet n°8 à la place. |
ID du joueur | SByte | |||
Changements en X | SByte | |||
Changements en Y | SByte | |||
Changements en Z | SByte | |||
Yaw (Heading) | Byte | |||
Pitch | Byte | |||
0x0a | Mise à jour de la position du joueur (relative à son ancienne position) | ID du paquet | Byte | Ce paquet permet de mettre à jour la position du joueur de manière relative. Ce paquet peut être utilisé lorsque le joueur n'a pas tourné sa tête et qu'il ne s'est déplacé que d'un nombre de blocs strictement inférieur à 4.00 ou supérieur ou égal à 4.00. Si cette condition n'est pas respectée, il faut utiliser le paquet n°8 à la place. |
Player ID | SByte | |||
Changements en X | SByte | |||
Changements en Y | SByte | |||
Changements en | SByte | |||
0x0b | Mise à jour de l'orientation du joueur | ID du paquet | Byte | Ce paquet permet de mettre à jour l'orientation du joueur. Ce paquet peut être utilisé lorsque seule l'orientation du joueur a été modifiée, et non sa position. |
ID du joueur | SByte | |||
Yaw (Heading) | Byte | |||
Pitch | Byte | |||
0x0c | Disparition de joueur | ID du paquet | Byte | Envoyé lorsqu'un joueur se déconnecte. |
Player ID | SByte | |||
0x0d | Message | ID du paquet | Byte | Messages envoyés par le chat ou par la console. |
Player ID | SByte | |||
Message | String | |||
0x0e | Déconnexion du joueur. | ID du paquet | Byte | Ce paquet a pour effet de déconnecter le client et d'afficher sur son écran la raison de la déconnexion. |
Raison de la déconnexion | String | |||
0x0f | Mise à jour du type de l'utilisateur. | ID du paquet | Byte | Ce paquet est envoyé lorsque le statut du joueur change (type=0x64 lorsque le joueur devient op, type=0x00 lorsque le joueur redevient un joueur normal). |
Type d'utilisateur | Byte |
Position du joueur[]
Point fixe[]
La position du joueur est représentée par les points fixes X,Y,Z. La portion fractionnée est de 5 bits, donc diviser les entiers de type "short" dans la mise-à-jour de la position par 32, vous avez une variable qui contient les coordonnées du joueur. Cette position représente le centre de la vue du joueur.
Sur un block[]
Le bas des pieds du joueur est localisé en 1.59375 (point: 51) unité avant le centre. Donc, la position du joueur sur un block particulier doit vous envoyer un paquet "téléport" (0x08) avec une valeur Y basé sur la position du block comme (Y x 32 + 51)
Orientation[]
Une valeur 'Yaw' de 0 veut dire que le joueur regarde dans une direction négative de Z (Z=0). Cette valeur incrémente une direction dans un sens horaire, comme dit précédemment. Si on appelle une direction Z négative "North", le "Yaw" de 64 est l'Est, 128 est le Sud, et 192 est l'Ouest.
Une valeur pitch de 0 veux dire "level" et cette valeur augmente dans une direction opposé. 64 en bas, et 192 est en haut. Les valeurs de 65 à 191 ne devraient pas être rencontrées car le joueur ne peut regarder que dans l'intervalle [64; 191]. Cependant, Minecraft Classic prend en compte les valeurs invalides, donc il est possible de retourner la tête des joueurs.