Logo Khaganat
Traductions de cette page?:

Ceci est une ancienne révision du document !


Tout commence par le réseau

Introduction

Je vais vous parler de la partie communication entre le serveur et le client. Il s'agit d'une analyse de l'existant, de ce que j'ai compris, des compromis faits, mais aussi des améliorations possibles et mes suggestions.

Quelle est la communication entre le serveur et les clients. Comment sont définis la position, les zones, comment fait-on pour changer de zone, la communication (chat), quel sont les états.

Pourquoi écrire ce document, premièrement pour ce repérer dans le code, comprendre comment cela marche, et surtout mettre à plat tout ce petit monde afin de recadrer et voir vers ou l'on va.

Les grandes lignes

Quand on parle de communication, on parle en fait de deux étapes.

Etape 1: connexion & authentification

Etape 2: communication continue (bref, ici commence réellement le jeux)

Pourquoi a-t-il deux étapes?

Tout simplement la première étape concernant la vérification de l’utilisateur et de son mot de passe, s'ils sont correct, vous pouvez vous enfin communiquer (en permanence) avec le serveur.

– il envoie une clef/token afin de pouvoir s'authentifier dans l'étape 2.

Vue d'ensemble

  +---------+
  |         |
  |         +-------+                      +------------------+
  |         | 443   |  <---HTTPS/TCP-----> | Login / Register |
  |         +-------+                      +------------------+
  | Serveur |
  |         +-------+                +----------------------------+
  |         | xxxxx |  <---UDP-----> | Communication avec le jeux |
  |         +-------+                +----------------------------+
  |         |
  +---------+

Etape 0 : Enregistrer un nouveau compte

Cette étape exécuté qu'une fois, permet de créer un compte.

Dans les faits, on utilise le protocole https [TCP/IP] (ou http, oui s'est possible suivant la configuration du serveur, mais je ne conseille pas)

[url]/ams/index.php?page=register&Username=[username]&Password=[password]&ConfirmPass=[password]&Email=[email]&TaC=[tac]&function=add_user

Avec:

  • username : qui doit être unique
  • password : le mot de passe
  • email : un email
  • tac : toujours 'on' (comme quoi on accepte la licence ….)

Le serveur retourne une ligne:

  • [Status]:[commentaire]

si status est égale à 1, création effectué, sinon, une erreur est survenue, il faut regarder le commentaire.

Etape 1 : Connexion & authentification

Cette étape, permet de s'assurer que l'utilisateur est bien la bonne personne, via le couple utilisateur/mot passe. On utilise le protocole https [TCP/IP] (ou http, même commentaire qu'au dessus, ne pas utiliser http)

On envoie les informations suivantes :

*On peut remarquer qu'ici on communique directement avec l'interface (en php) qui s'occupe de faire la vérification avec la base de donnée puis renvoyer la clef d'authentification*

Client → Serveur

Demande le grain de sable (clef à utiliser pour l'envoie du mot de passe)

[url]/login/r2_login.php?cmd=ask&cp=2&login=[login]&lg=[LanguageCode]

Serveur → Client

Le serveur retourne une ligne:

  • [Status]:[commentaire ou sel]

si status est égale à 1, le deuxième paramètre est le sel. Une suite de chiffre utilisé avec le mot de passe pour générer une chaîne de hachage.

Si le status n'est pas égale à 1, le deuxième paramètre est un commentaire sur l'erreur.

Client → Serveur

Renvoie le compte & un clef permettant de vérifier que l'on connait le mot de passe.

Cette clef est en réalité un calcul réalisé avec le sel et le mot de passe [sha512_crypt], cela évite d'avoir à transmettre le mot de passe, donc plus sécurisé. Sachant que le serveur connait aussi le sel, il exécute aussi le même calcul afin de vérifier que vous connaissait le mot de passe.

Se connecter:

[url]/login/r2_login.php?cmd=login&login=[login]&password=[password]&clientApplication=[ClientApplication]&cp=[cp]&lg=[lg]

Serveur → Client

Le serveur retourne deux lignes:

  • state#cookie#fsaddr#ringmainurl#fartp
  • r2serverversion]#r2backuppatchurl#r2patchurl

Définition de certain paramètre:

  • fsaddr = khaganat_host:khaganat_port
  • cookie = user_addr|user_key|user_id

Ici, le serveur renvoie trois clef à utiliser pour se connecter, ainsi que l'adresse du serveur à contacter.

  • khaganat_host, khaganat_port : adresse à utiliser pour se connecter au serveur (en UDP)
  • user_addr : une chaîne de caractère qui traduit le code hexa (32 bits)
  • user_key : une chaîne de caractère qui traduit le code hexa (32 bits)
  • user_id : une chaîne de caractère qui traduit le code hexa (32 bits)

Ces clefs seront utile dans la première phase de communication avec le serveur.

Etape 2 : Communication avec le jeux

Vue générale

Première chose, on remarque que le protocole est UDP.

Il n'y a donc pas de synchronisation avec le serveur, on envoie les messages, ils arrivent dans n'importe quel ordre, c'est à l'application de faire le trie.

L’intérêt est que la communication est plus rapide, et que sur le principe d'un jeux “temps réel”, les actions passées ne sont pas importante, seul compte l'état actuelle.

Si on souhaite trouver une image, il faut voir le réseau comme une multitude d'autoroute et de péage, qui s’entremêle. Suivant votre chauffeur, vous irez plus ou moins vite, avec des raccourcis plus au moins chanceux. (et parfois des accidents)

Au départ, on souhaite envoyer une message du point A vers le point B (serveur → client ou client → serveur)

Les messages sorte les uns après les autres.

Arrivé au premier croisement (switch), certain parte à droite, d'autre à gauche.

Arrivé au péage (firewall), le message est bloqué pour analyse, par contre d'autre poursuive leur chemin

On continue sur le même principe.

mais des fois, nous perdons un paquet suite à un accident (collision avec un autre message).

Et enfin tous les messages restant arrive à destination (par forcément d'en l'ordre envoyé)

Ce mode de fonctionnement implique une gestion de la couche réseau côté applicatif. (au niveau du serveur et du client)

La communication est en fonction de l'état de la connexion

La communication s'effectue suivant différents état.

  • NotInitialised : Etat initiale
  • NotConnected : Etat non utilisé, réception du cookie
  • Authenticate : Etat non utilisé, authentification
  • Login : Etat login
  • Synchronize : Etat synchronisation
  • Connected : Etat connecté, ici, on est dans la phase communication du jeux,
  • Probe : Etat approbation, on demande de vérifier que le client est bien connecté
  • Stalled : Etat bloqué
  • Disconnect : Etat déconnecté
  • Quit : Etat quitter
  • ForceSynchronize : Etat force la synchronisation (non existant côté serveur)

Dans le code, l'idéal serait de géré l'état dans des classes différents (afin de gérer que l'état en cours et ne pas polluer le code de if/switch/case).

Paquet envoyé par le serveur

Maintenant, regardons un peu plus prêt chaque message envoyé par le serveur.

Corps du message

  +-------------------+------------+---
  | CurrentSendNumber | SystemMode | . . .
  |    32 bits        |  1 bit     |
  +-------------------+------------+---
                         1 -> system mode
                         0 -> normal mode

* CurrentSendNumber : un compteur qui s'incrémente tout le temps (permet d'ignorer les messages passés)

  Attention: quand le compteur aura atteint le maximum, le client va refuser tous les messages.

* SystemMode : Informe que le type de message est dit “système” ou “normal”

Message système

  +-------------------+------------+---------+---
  | CurrentSendNumber | SystemMode | Message | . . .
  |    32 bits        |  1 bit     | 8 Bits  |
  +-------------------+------------+---------+---
  |  xxxxxxxxxxxxxxxx |   1        |

Suivant la valeur du message, nous avons des paramètres spécifique.

Noter qu'ici nous utilisons 8 bits, on aurait pu réduire la taille afin d'être en adéquation avec les messages envoyés.

A savoir 5 types de messages provenant du client & 5 types de messages provenant du serveur. (soit une taille de 3 bits)

Message 1 : SYSTEM_SYNC_CODE

Message émis par le serveur.

Message utiliser pour synchroniser le client et vérifier que nous avons la même base de définition XML (msg.xml & database.xml)

  +-------------------+------------+---------+-------------+---------+------------+-------------------+------------------------+
  | CurrentSendNumber | SystemMode | Message | Synchronize | stime   | LatestSync | MsgData           | DatabaseData           |
  |    32 bits        |  1 bit     | 8 Bits  | 32 bits     | 64 bits | 32 bits    | 16 * 8 bits       | 16 * 8 bits            |
  |                   |            |         | unsigned    | signed  | unsigned   | md5sum of msg.xml | md5sum of database.xml |
  +-------------------+------------+---------+-------------+---------+------------+-------------------+------------------------+
  |  xxxxxxxxxxxxxxxx |   1        |    1    |         xxx |     xxx |        xxx |               xxx |                    xxx |
Message 3 : SYSTEM_PROBE_CODE

Message émis par le serveur. Message pour vérifier que le client reçoit bien les messages (le client va renvoyer un SYSTEM_ACK_PROBE_CODE, avec tous les PROBE envoyé)

  +-------------------+------------+---------+-------------+
  | CurrentSendNumber | SystemMode | Message | LatestProbe |
  |    32 bits        |  1 bit     | 8 Bits  | 32 bits     |
  |                   |            |         | unsigned    |
  +-------------------+------------+---------+-------------+
  |  xxxxxxxxxxxxxxxx |   1        |    3    |         xxx |
Message 6 : SYSTEM_STALLED_CODE

Message émis par le serveur.

  +-------------------+------------+---------+
  | CurrentSendNumber | SystemMode | Message |
  |    32 bits        |  1 bit     | 8 Bits  |
  |                   |            |         |
  +-------------------+------------+---------+
  |  xxxxxxxxxxxxxxxx |   1        |    6    |
Message 7 : SYSTEM_SERVER_DOWN_CODE

Message émis par le serveur.

  +-------------------+------------+---------+
  | CurrentSendNumber | SystemMode | Message |
  |    32 bits        |  1 bit     | 8 Bits  |
  |                   |            |         |
  +-------------------+------------+---------+
  |  xxxxxxxxxxxxxxxx |   1        |    7    |
Message 9 : SYSTEM_ACK_QUIT_CODE

Message émis par le serveur.

  +-------------------+------------+---------+
  | CurrentSendNumber | SystemMode | Message |
  |    32 bits        |  1 bit     | 8 Bits  |
  |                   |            |         |
  +-------------------+------------+---------+
  |  xxxxxxxxxxxxxxxx |   1        |    7    |
Message normal
  +-------------------+------------+-------------------+---------+-----------------+
  | CurrentSendNumber | SystemMode | last received ack | Factory | Visual Property |
  |    32 bits        |  1 bit     | 32 Bits           | X bits  | Z bits          |
  |                   |            | unsigned          |         |                 |
  +-------------------+------------+-------------------+---------+-----------------+
  |  xxxxxxxxxxxxxxxx |   0        |

Factory

Ici nous avons tout un système de boite afin de savoir dans quel rayon on lit le message. utilisation à voir, peut-être une méthode pour différencié les différents services du serveur.

A l'origine

On stocke les paquets suivant le paramètre CurrentSendNumber. Mais pour chaque paquet, on doit d'abord lire un bit pour identifié si on a des données ou pas.

Les différents niveaux:

  +----------+  +----------+  +----------+
  | Packet A |  | Packet B |  | Packet C |
  |   (0)    |  |   (0)    |  |   (0)    |
  +----------+  +----------+  +----------+
                +----------+  +----------+
                | Packet B |  | Packet C |
                |   (1)    |  |   (1)    |
                +----------+  +----------+
                              +----------+
                              | Packet C |
                              |   (2)    |
                              +----------+
                              +----------+
                              | Packet C |
                              |   (3)    |
                              +----------+

Suivant la valeur de CurrentSendNumber.

Si modulo CurrentSendNumber 4 == 0 :

  +---------+      +----------+----------+----------+
  | Factory |      | Packet A | Packet B | Packet C |
  |         | ===> | pos:0    | pos:0    | pos:0    |
  | X bits  |      | X bits   | X bits   | X bits   |
  +---------+      +----------+----------+----------+

Si modulo CurrentSendNumber 4 == 1 :

  +---------+      +----------+----------+----------+
  | Factory |      | Packet A | Packet B | Packet C |
  |         | ===> | pos:0    | pos:1    | pos:1    |
  | X bits  |      | X bits   | X bits   | X bits   |
  +---------+      +----------+----------+----------+

Si modulo CurrentSendNumber 4 == 2 :

  +---------+      +----------+----------+----------+
  | Factory |      | Packet A | Packet B | Packet C |
  |         | ===> | pos:0    | pos:0    | pos:2    |
  | X bits  |      | X bits   | X bits   | X bits   |
  +---------+      +----------+----------+----------+

Si modulo CurrentSendNumber 4 == 3 :

  +---------+      +----------+----------+----------+
  | Factory |      | Packet A | Packet B | Packet C |
  |         | ===> | pos:0    | pos:1    | pos:3    |
  | X bits  |      | X bits   | X bits   | X bits   |
  +---------+      +----------+----------+----------+

Pour le packet A:

 Tant que next est égale à 1, on lit le paquet (Level A)
  +----------+     +-------+-----------+-------+-----------+-------+
  | Packet A |     | next  | Factory A | next  | Factory A | next  | . . .
  | X bits   | --> | 1 bit |    (0)    | 1 bit |    (0)    | 1 bit |
  |          |     |       |           |       |           |       |
  +----------+     +-------+-----------+-------+-----------+-------+

Pour le packet B:

 Tant que next est égale à 1, on lit le paquet (Level B)
 La position x, dépend de CurrentSendNumber
  +----------+     +-------+-----------+-------+-----------+-------+
  | Packet B |     | next  | Factory B | next  | Factory B | next  | . . .
  | X bits   | --> | 1 bit |    (x)    | 1 bit |    (x)    | 1 bit |
  |          |     |       |           |       |           |       |
  +----------+     +-------+-----------+-------+-----------+-------+

Pour le packet C:

 Tant que next est egale à 1, on lit le paquet (Level C)
 La position y, dépend de CurrentSendNumber
  +----------+     +-------+-----------+-------+-----------+-------+
  | Packet C |     | next  | Factory C | next  | Factory C | next  | . . .
  | X bits   | --> | 1 bit |    (y)    | 1 bit |    (y)    | 1 bit |
  |          |     |       |           |       |           |       |
  +----------+     +-------+-----------+-------+-----------+-------+

Exemple:

ici CurrentSendNumber est égale à 7 (donc CurrentSendNumber % 4 = 3)

  +---------+      +-------+-----------+-------+-----------+-------+-------+-----------+-------+-------+-----------+-------+-----------+-------+ 
  |         |      |       | Action    |       | Action    |       |       | Action    |       |       | Action    |       | Action    |       |
  | Factory |      | next  | Factory A | next  | Factory A | next  | next  | Factory B | next  | next  | Factory C | next  | Factory C | next  |
  |         | ===> |       |    (0)    |       |    (0)    |       |       |   (1)     |       |       |   (3)     |       |   (3)     |       |
  | X bits  |      | 1 bit | X bits    | 1 bit | X bits    | 1 bit | 1 bit | X bits    | 1 bit | 1 bit | X bits    | 1 bit | X bits    | 1 bit |
  +---------+      +-------+-----------+-------+-----------+-------+-------+-----------+-------+-------+-----------+-------+-----------+-------+
                   | 1     |       xxx | 1     |      xxxx |     0 |    1  |       xxx |     0 |     1 |       xxx |     1 |       xxx |     0 |
                   | ----              Packet A               ---- | -----     Packet B   ---- | -----             Packet C               ---- |
Et maintenant

N'ayant pas la signification exact, je considère que tout à le même niveau (bref on lit au fil de l'eau)

On lit les trois paquets (A, B & C, ici tous nommé Z)

  +---------+      +----------+----------+----------+
  | Factory |      | Packet Z | Packet Z | Packet Z |
  | X bits  |      | X bits   | X bits   | X bits   |
  +---------+      +----------+----------+----------+

puis pour chaque paquet on lit paquet (tant que next égale 1, o n continue de lire

  +----------+     +-------+-----------------+-------+-----------------+-------+
  | Packet Z |     | next  | ActionFactory Z | next  | ActionFactory Z | next  | . . .
  | X bits   | --> | 1 bit | X bits          | 1 bit | X bits          | 1 bit |
  +----------+     +-------+-----------------+-------+-----------------+-------+
ActionFactory

Dans chaque ActionFactory, nous avons la structure suivante:

  +-----------------+     +-------+--------+
  | ActionFactory X | --> | Code  | Action |
  |                 |     | X bit | X Bit  |
  +-----------------+     +-------+--------+

On y découvre un code (qui identifié l'action à décoder) et l'action (bon le terme est mal choisi, mais il s'agit de la structure contenant le message)

Code

Ici, nous avons une petite structure pour définir ActionCode. en gros on décode se chiffre en 3 bits ou 9 bits. Sachant que le plus souvent on aura a décoder que 3 bits.

  +------+    +-----------+---------------------------+
  | Code | -> | ShortCode |        ActionCode         |
  |      |    |   1 bit   |  2 bits, si ShortCode = 1 |
  |      |    |           |  8 bits, si ShortCode = 0 |
  +------+    +-----------+---------------------------+

Action

Nous avons différents type Action:

  • ACTION_POSITION_CODE = 0 : Disponible en mode ShortCode = 1 ou 0
  • ACTION_GENERIC_CODE = 1 : Disponible en mode ShortCode = 1 ou 0
  • ACTION_GENERIC_MULTI_PART_CODE = 2 : Disponible en mode ShortCode = 1 ou 0
  • ACTION_SINT64 = 3 : Disponible en mode ShortCode = 1 ou 0
  • ACTION_SYNC_CODE = 10 : Disponible en mode ShortCode = 0
  • ACTION_DISCONNECTION_CODE = 11 : Disponible en mode ShortCode = 0
  • ACTION_ASSOCIATION_CODE = 12 : Disponible en mode ShortCode = 0
  • ACTION_LOGIN_CODE = 13 : Disponible en mode ShortCode = 0
  • ACTION_TARGET_SLOT_CODE = 40 : Disponible en mode ShortCode = 0
  • ACTION_DUMMY_CODE = 99 : Disponible en mode ShortCode = 0
ACTION_POSITION_CODE
  +----------+----------+----------+
  | px       | py       | pz       |
  | 16 bits  | 16 bits  | 16 bits  |
  | unsigned | unsigned | unsigned |
  +----------+----------+----------+
  +-------------------------------+
  | pz                            |
  | 14 bit                        |
  | | | | | | | | | | | | | | | | | | |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                                   + Interior
                                     + IsRelative
ACTION_GENERIC_CODE

On récupère une chaîne contenant le code impulse.

  +----------+------+------+-- / --+--------+        +---------+
  | size     | char | char |       | char   |        |         |
  | 32 bits  |   a    a+1            a+size |    ==> | Impulse |
  | unsigned |                              |        |         |
  +----------+------+------+-- / --+--------+        +---------+

size : nombre de caractère dans ce bloc char : les données

impulse est la concaténation de toutes les chaines : char [a, a+1, … , a+size]

ACTION_GENERIC_MULTI_PART_CODE

On récupère qu'une partie du code impulse, il faudra attendre de recevoir toutes les parties pour pouvoir décoder le code impulse

  +----------+----------+----------+----------+------+------+-- / --+--------+
  | Number   | Part     | NbBlock  | size     | char | char |       | char   |
  | 8 bits   | 16 bits  | 16 bits  | 32 bits  |   a    a+1            a+size |
  | unsigned | unsigned | unsigned | unsigned |                              |
  +----------+----------+----------+----------+------+------+-- / --+--------+

Number : Numéro de paquet (doit être unique du moins pendant une courte période) Part : position du bloc NbBlock : Nombre de bloc (total) size : nombre de caractère dans ce bloc char : les données

Pour décoder, il faut recevoir pour le même “Number” toutes les “Part” (blocs), les remettre dans l'ordre et lancer le décodage impulse.

Exemple :

Number : 1 NbBlock : 3

  +---------+---------+---------+      +---------+
  | Part 1  | Part 2  | Part 3  | ===> | Impulse |
  | | | | | | | | | | | | | | | |      |         |
  +---------+---------+---------+      +---------+
ACTION_SINT64

A voila un format/type qui faut retenir, il est utilisé dans la partie visual decode, mais pas comme son nom l'indique, en fait un s'agit d'une structure a taille variable suivant sa destination. Bref, on sent la réutilisation d'un code pour faire autre chose, dommage car vue la capacité, pourquoi ne pas avoir ajouter d'autre format/type.

ACTION_SYNC_CODE

Structure utiliser pour la synchronisation

  +----------+------------+
  | Sync     | BKEntityId |
  | 32 Bits  | 64 bits    |
  | unsigned | unsigned   |
  +----------+------------+
ACTION_DISCONNECTION_CODE

Code pour lancer une déconnexion. Il n'y a pas de paramètre.

ACTION_ASSOCIATION_CODE

Certainement pour s'associer une nouvelle zone.

  +----------+---------+
  | SheetId  | Replace |
  | 32 Bits  | 1 bit   |
  | unsigned |         |
  +----------+---------+
ACTION_LOGIN_CODE

Tient un code qui aurait du être utilisé pour l’authentification. Mais on ne l'utilise jamais ! On utilise la commande système SYSTEM_LOGIN_CODE. Bref les mystères de l'évolution du code.

  +-----------+----------+----------+
  | user addr | user key | user id  |
  | 32 Bits   | 32 bits  | 32 bits  |
  | unsigned  | unsigned | unsigned |
  +-----------+----------+----------+
ACTION_TARGET_SLOT_CODE

Un nouveau slot ?

  +----------+------------------+
  | Slot     | Target Or Pickup |
  | 8 Bits   | 2 bits           |
  | unsigned | unsigned         |
  +----------+------------------+
ACTION_DUMMY_CODE

Un code de test

  +-----------+----------+
  | Dummy 1   | Dummy 2  |
  | 32 Bits   | 32 bits  |
  | unsigned  | unsigned |
  +-----------+----------+

Impulse

Ici, nous allons utilisé la structure msg.xml pour pouvoir décoder le message. Bon, le décodage demande d'abord de comprendre comment lire le fichier “msg.xml”.

Lecture du fichier msg.xml

le fichier xml a une structure du style:

  <client_messages_description>
    <branch name=x1 param_a=y1 param_b=z1 position=0>
       <leaf name=x2 param_aa=y2 param_bb=z2 position=0/>
    </branch>
    <branch name=x3 param_a=y3 param_b=z3 position=1>
       <leaf name=x4 param_aa=y4 param_bb=z4 position=0/>
       <leaf name=x5 param_aa=y5 param_bb=z5 position=1/>
    </branch>
    <branch name=x6 param_a=y6 param_b=z6 position=2>
       <branch name=x7 param_a=y7 param_b=z7 position=0>
         <leaf name=x8 param_aa=y8 param_bb=z8 position=0/>
         <leaf name=x9 param_aa=y9 param_bb=z9 position=1/>
         <leaf name=x10 param_aa=y10 param_bb=z10 position=2/>
       </branch>
       <leaf name=x11 param_aa=y11 param_bb=z11 position=1/>
       <leaf name=x12 param_aa=y12 param_bb=z12 position=2/>
       <leaf name=x13 param_aa=y13 param_bb=z13 position=3/>
       <leaf name=x14 param_aa=y14 param_bb=z14 position=4/>
    </branch>
  </client_messages_description>

pour msg.xml, la première clef est 'client_messages_description'.

puis ensuite, nous avons de type de clef 'branch' ou la clef 'leaf'.

la clef 'branch' que l'on traduit par branche, permet d'indiqué qu'elle contient à l’intérieur d'autre clef (branch ou leaf).

la clef 'leaf' que l'on traduit par feuille, indique qu'elle ne contient que elle. (pas de sous branche ou de sous feuille).

pour décoder nous avons le code impulse, nous avons besoin dans chaque branche de compter le nombre de sous branch et sous feuille.

par exemple, ici la branch racine s'appelle client_messages_description, nous comptons 3 sous branches (appelé x1, x3 & x6) chaque branche/feuille a une position (on commence par zero, et on incrémente à chaque fois, ici j'ai ajouté le paramètre position juste pour suivre, il n'existe pas en réalité dans le code msg.xml)

la branch x1 (en position 0), nous comptons une seule sous-branche/feuille (appelé x2)

la branch x3 (en position 1), nous comptons 2 sous-branches/feuilles (appelé x4 & x5)

la branch x6 (en position 2), nous comptons 5 sous-branches/feuilles (appelé x7, x11, x12, x13 & x14)

la branch x7 (en position 0), nous comptons 3 sous-branches/feuilles (appelé x8, x9 & x10)

Ce résultat nous permettra d'avoir le nombre de possibilité (et aussi connaitre le nombre de bit accordé pour la branche en question. On répète le calcul jusqu’à arriver à une feuille qui termine et donne la fonction complète.

Exemple: (ici je ne mets que les bits)

  code: 010
   * on compte le nombre de branch/sous-branch sur la racine (ici on a en 3, donc le code tient sur 2 bits)
   * on décode les deux premier bit (ici 01, correspond à la position 1, qui équivaut à x3)
   * puis dans la branche x3, on compte le nombre de branche/sous branch, il y en à 1.
   * on décode un bit (ici 0) qui correspond à la position 0, qui équivaut à x4
   en résumé : 010 => 01.0 => 01 -> x3, 0 -> x4
   cela donne x3:x4
  code: 1000001
   * on compte le nombre de branche/sous-branche sur la racine (ici on a en 3, donc le code tient sur 2 bits)
   * on décode les deux premier bit (ici 10, correspond à la position 2, qui équivaut à x6)
   * puis dans la branche x6, on compte le nombre de branche/sous branche, il y en à 5 (donc le code tient sur 3 bits).
   * on décode un bit (ici 000) qui correspond à la position 0, qui équivaut à x7
   * puis dans la branche x7, on compte le nombre de branche/sous branche, il y en à 3 (donc le code tient sur 2 bits).
   en résumé : 1000001 => 10.000.01 => 10 -> x6, 000 -> x7, 01 -> x9
   cela donne x6:x7:x9

Maintenant, vous savez comment décoder l'entête des messages impulse. Attention, le reste du codage dans msg.xml, ne sert pas pour le client (mais certainement pour la communication entre les différents services du serveur).

Décodage Impulse

les messages impulses sont construit suivant le format suivant.

* premier champs contenant le code impulse * champs suivant les paramètres du code impulse

Cela donne le schéma suivant :

  +--------------+---- / -----+
  | code msg.xml | paramètres |
  | x bits       | x bits     |
  | unsigned     |            [
  +--------------+---- / -----+
STRING_MANAGER:RELOAD_CACHE

Commande utilisé pour initialisé le tableau de message. Ici, on vérifie que notre tableau interne au client à la même date que le tableau du serveur. Sinon, on efface le tableau interne du client, et à chaque nouveau message le client demandera à quoi il correspond.

Code actuel : STRING_MANAGER:RELOAD_CACHE ⇒ 011011.100

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, susceptible de changer)

  +----------------+--------------+------------------+
  | STRING_MANAGER | RELOAD_CACHE | timestamp        |
  | 6 bits         | 3 bits       | uint32           |
  | 011011         | 100          | 32 bits unsigned |
  +----------------+--------------+------------------+
  • timestamp (uint32) : date du tableau de message
STRING_MANAGER:PHRASE_SEND

Le serveur envoie un message (enfin le pointeur sur le message)

Code actuel : STRING_MANAGER:PHRASE_SEND ⇒ 011011.001

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, susceptible de changer)

  +----------------+--------------+------------------+------------------+
  | STRING_MANAGER | PHRASE_SEND  | dyn_id           | string_id        | string_id . . .
  | 6 bits         | 3 bits       | uint32           | uint32           | tant que l'on a au moins 32 bits, on lit un autre string_id
  | 011011         | 001          | 32 bits unsigned | 32 bits unsigned |
  +----------------+--------------+------------------+------------------+
  • dyn_id (Uint32) : l'ID du groupe de message
  • string_id (Uint32) : le pointeur sur le message
STRING_MANAGER:STRING_RQ

Le client demande le message complet en fonction du pointeur.

Code actuel : STRING_MANAGER:STRING_RQ ⇒ 011011.010

  +----------------+--------------+------------------+
  | STRING_MANAGER | STRING_RQ    | string_id        |
  | 6 bits         | 3 bits       | uint32           |
  | 011011         | 010          | 32 bits unsigned |
  +----------------+--------------+------------------+
  • string_id (Uint32) : le pointeur sur le message

Le serveur va répondre à ce message par STRING_MANAGER:STRING_RESP

STRING_MANAGER:STRING_RESP

Le serveur renvoie le message complet.

Code actuel : STRING_MANAGER:STRING_RESP ⇒ 011011.011

  +----------------+--------------+------------------+--------------+
  | STRING_MANAGER | STRING_RESP  | string_id        | MessageUtf8  |
  | 6 bits         | 3 bits       | uint32           | String-UTF-8 |
  | 011011         | 011          | 32 bits unsigned | X bits       |
  +----------------+--------------+------------------+--------------+
  • string_id (Uint32) : le pointeur sur le message
  • MessageUtf8 (String-UTF-8) : la chaîne de caractère en UTF-8.

On remarque ici l'utilisation de la chaîne de caractère au format UTF-8 (alors qu’ailleurs nous avons UTF-16)

CONNECTION:ASK_NAME

Le client donne le nom et son ID (zone ?) et demande une vérification côté serveur.

Code actuel : CONNECTION:ASK_NAME ⇒ 000001.01010

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, suceptible de changer)

  +----------------+--------------+------------------+------------------+
  | CONNECTION     | ASK_NAME     | Name             | HomeSessionId    |
  | 6 bits         | 5 bits       | X bits           | Uint32           |
  | 000001         | 01010        | String-UTF-16    | 32 bits unsigned |
  +----------------+--------------+------------------+------------------+
  • Name (String-UTF-16)
  • HomeSessionId (Uint32)

Retour attendu : CONNECTION:VALID_NAME

CONNECTION:VALID_NAME

Le serveur répond à une requête CONNECTION:ASK_NAME.

Code actuel : CONNECTION:VALID_NAME ⇒ 000001.01011

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, susceptible de changer)

  +----------------+--------------+-----------------+
  | CONNECTION     | VALID_NAME   | valide          |
  | 6 bits         | 5 bits       | 8 bits          |
  | 000001         | 01011        | 8 bits unsigned |
  +----------------+--------------+-----------------+
  • valide (Uint8) : 1 ⇒ valide, sinon non valide
CONNECTION:SELECT_CHAR

Le client selectionne un personnage.

Code actuel : CONNECTION:SELECT_CHAR ⇒ 000001.00100

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, susceptible de changer)

  +----------------+--------------+-----------------+
  | CONNECTION     | SELECT_CHAR  | SelectCharMsg   |
  | 6 bits         | 5 bits       | 8 bits          |
  | 000001         | 00100        | 8 bits unsigned |
  +----------------+--------------+-----------------+
  • SelectCharMsg (Uint8) : id du personnage (entre 0 et 4, actuellement on ne peut avoir que 5 personnages maximum)

En retour de cette commande, le serveur va répondre CONNECTION:USER_CHAR

CONNECTION:USER_CHAR

Le serveur répond à un CONNECTION:SELECT_CHAR, et renvoie les informations sur le personnage.

Code actuel : CONNECTION:USER_CHAR ⇒ 000001.00000

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, susceptible de changer)

  +----------------+--------------+------------------+------------------+------------------+------------------+--------+----------+--------------------------+--------------------+------------------+
  | CONNECTION     | USER_CHAR    | X                | Y                | Z                | Heading          | season | userRole | highestMainlandSessionId | firstConnectedTime | playedTime       |
  | 6 bits         | 5 bits       | 32 bits          | 32 bits          | 32 bits          | 32 bits          | 3 bits | 3 bits   | 32 bits                  | 32 bits            | 32 bits          |
  | 000001         | 00000        | 32 bits unsigned | 32 bits unsigned | 32 bits unsigned | float            |        |          | 32 bits unsigned         | 32 bits unsigned   | 32 bits unsigned |
  +----------------+--------------+------------------+------------------+------------------+------------------+--------+----------+--------------------------+--------------------+------------------+
  • X (Sint32) : position X
  • Y (Sint32) : position Y
  • Z (Sint32) : position Z
  • Heading (Float) : Angle (plan X/Y) du personnage (vers ou regarde le perso)
  • season (3 bits) : type de saison
  • userRole (3 bits)
  • highestMainlandSessionId (Uint32)
  • firstConnectedTime (Uint32)
  • playedTime (Uint32)
CONNECTION:READY

Le serveur informe au client qu'il est prêt. puis le client ensuite informe au serveur qu'il est prêt.

Code actuel : CONNECTION:READY ⇒ 000001.01000

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, susceptible de changer)

  +------------+------------+--------------+
  | CONNECTION | READY      | LanguageCode |
  | 6 bits     | 5 bits     | String       |
  | 000001     | 01000      |              |
  +------------+------------+--------------+
  • LanguageCode (String)
CONNECTION:USER_CHARS

Liste tous les paramètres de l'utilisateur, les personnages, les domaines, …

Code actuel : CONNECTION:USER_CHARS ⇒ 000001.00010

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, susceptible de changer)

  +------------+------------+--------------------+
  | CONNECTION | USER_CHARS | ServerPeopleActive |
  | 6 bits     | 5 bits     | uint8              | . . .
  | 000001     | 00010      | unsigned           |
  +------------+------------+--------------------+
  • ServerPeopleActive (uint8)
  • ServerPeopleActive (uint8)
  • CharacterSummaries_Len (Uint32) - les paramètres suivant dépend de la taille définit ici
    • Version (Uint8)
    • Mainland (Uint32)
    • Name (String-UTF-16)
    • People (Sint32)
    • Location (Uint32)
    • VisualPropA (Uint64) : en réalité on utilise moins de bit (mais ici on prend les 64 bits)
    • VisualPropB (Uint64) : en réalité on utilise moins de bit (mais ici on prend les 64 bits)
    • VisualPropC (Uint64) : en réalité on utilise moins de bit (mais ici on prend les 64 bits)
    • SheetId (Uint32)
    • Title (Sint32)
    • CharacterSlot (Uint8)
    • InRingSession (Bool)
    • HasEditSession (Bool)
    • InNewbieland (Bool)
  • shard_names_Len (Uint32)
    • session_id (String)
    • display_name (String)
    • short_name (String)
  • privileges (String)
  • free_trial (Bool)
  • mainlands_len (Uint32)
    • id (Uint32)
    • name (String-UTF-16)
    • description (String-UTF-16)
    • language_code (String)
    • online (Bool)
CONNECTION:CREATE_CHAR

Création d'un nouveau personnage

Code actuel : CONNECTION:CREATE_CHAR ⇒ 000001.00011

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, susceptible de changer)

  +------------+-------------+--------------------+
  | CONNECTION | CREATE_CHAR | Slot               |
  | 6 bits     | 5 bits      | uint8              | . . .
  | 000001     | 00011       | unsigned           |
  +------------+-------------+--------------------+
  • Slot (Uint8)
  • SheetId (Uint32)
  • CSessionId (Uint32)
  • name (String-UTF-16) - Attention il n'accepte qu'un nombre restreint de caractère [A-Za-z0-9]
  • People (Uint8)
  • Sex (Uint8)
  • NbPointFighter (Uint8)
  • NbPointCaster (Uint8)
  • NbPointCrafter (Uint8)
  • NbPointHarvester (Uint8)
  • StartPoint (Sint32)
  • HairType (Sint8)
  • HairColor (Sint8)
  • GabaritHeight (Sint8)
  • GabaritArmsWidth (Sint8)
  • GabaritLegsWidth (Sint8)
  • GabaritBreastSize (Sint8)
  • MorphTarget1 (Sint8)
  • MorphTarget2 (Sint8)
  • MorphTarget3 (Sint8)
  • MorphTarget4 (Sint8)
  • MorphTarget5 (Sint8)
  • MorphTarget6 (Sint8)
  • MorphTarget7 (Sint8)
  • MorphTarget8 (Sint8)
  • EyesColor (Sint8)
  • Tattoo (Sint8)
  • JacketColor (Sint8)
  • TrousersColor (Sint8)
  • HatColor (Sint8)
  • HandsColor (Sint8)
  • FeetColor (Sint8)

On remarquera ici que le type des différentes caractèristique et différent dans CONNECTION:USER_CHAR (ces propriétés sont définit dans VisualPropA, VisualPropB & VisualPropC, et on bien sur pas la même taille)

GUILD:USE_FEMALE_TITLES

le serveur signale que la guilde (?) utilise le féminin dans les titres.

Code actuel : GUILD:USE_FEMALE_TITLES ⇒ 011100.10010

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, susceptible de changer)

  +------------+-------------------+--------------------+
  | GUILD      | USE_FEMALE_TITLES | UseFemaleTitles    |
  | 6 bits     | 5 bits            | bool               |
  | 011100     | 10010             | 1 bit              |
  +------------+-------------------+--------------------+
  • UseFemaleTitles (bool) : 1 = Oui, 0 = Non
BOTCHAT:SET_FILTERS

Le client informe de certain filtre (a quoi servent-ils ?)

Code actuel : BOTCHAT:SET_FILTERS ⇒ 011001.001100

(<u>Attention:</u> dépend de la version que vous avez de msg.xml, susceptible de changer)

  +------------+-------------------+------------------+
  | BOTCHAT    | SET_FILTERS       | qualityMin       |
  | 6 bits     | 5 bits            | 32 bits          | . . .
  | 011001     | 001100            | 32 bits unsigned |
  +------------+-------------------+------------------+
  • qualityMin (Uint32)
  • qualityMax (Uint32)
  • priceMin (Uint32)
  • priceMax (Uint32)
  • classMin (Uint8)
  • classMax (Uint8)
  • itemPart (Uint8)
  • itemType (Uint8)

Visual Property

Et oui, nous avons encore une autre structure pour envoyer des informations du serveur vers le client.

Ici le codage/cryptage est différent, on utilise une arbre (avec des feuilles) pour savoir quelles sont les données à décrypter.

Paquet envoyé par le client

Corps du message

  +-------------------+------------+---
  | CurrentSendNumber | SystemMode | . . .
  |    32 bits        |  1 bit     |
  +-------------------+------------+---
                         1 -> system mode
                         0 -> normal mode

* CurrentSendNumber : un compteur qui s'incrémente tout le temps (permet d'ignorer les messages passés)

  Attention: quand le compteur aura atteint le maximum, le client va refuser tous les messages.

* SystemMode : Informe que le type de message est dit “système” ou “normal”

Message système

  +-------------------+------------+---------+---
  | CurrentSendNumber | SystemMode | Message | . . .
  |    32 bits        |  1 bit     | 8 Bits  |
  +-------------------+------------+---------+---
  |  xxxxxxxxxxxxxxxx |   1        |

Suivant la valeur du message, nous avons des paramètres spécifique.

Noter qu'ici nous utilisons 8 bits, on aurait pu réduire la taille afin d'être en adéquation avec les messages envoyés.

A savoir 5 types de messages provenant du client & 5 types de messages provenant du serveur. (soit une taille de 3 bits)

Message 0 : SYSTEM_LOGIN_CODE

Message émis par le client.

  +-------------------+------------+---------+-----------+----------+----------+-------- / ---------+
  | CurrentSendNumber | SystemMode | Message | User Addr | User Key | User ID  | Langue             |
  |    32 bits        |  1 bit     | 8 Bits  | 32 bits   | 32 bits  | 32 bits  | String    (x bits) |
  |                   |            |         | unsigned  | unsigned | unsigned |                    |
  +-------------------+------------+---------+-----------+----------+----------+-------- / ---------+
  |  xxxxxxxxxxxxxxxx |   1        |    0    |       xxx |      xxx |      xxx |                xxx |
Message 2 : SYSTEM_ACK_SYNC_CODE

Message émis par le client. Message utiliser pour acquitter d'une demande de synchroniser.

  +-------------------+------------+---------+-----------+----------+-----------------+----------+
  | CurrentSendNumber | SystemMode | Message | frontack  | backack  | longackbitfield | syncCode |
  |    32 bits        |  1 bit     | 8 Bits  | 32 bits   | 32 bits  | 1024 bits       | 32 bits  |
  |                   |            |         | unsigned  | unsigned | unsigned        | unsigned |
  +-------------------+------------+---------+-----------+----------+-----------------+----------+
  |  xxxxxxxxxxxxxxxx |   1        |    2    |       xxx |      xxx |             xxx |      xxx |

frontack : dernier message reçu (last_received_number) backack : last_ack_in_long_ack longackbitfield : suite de bit qui indique les messages normaux reçu (permettra de faire une synchronisation avec le serveur) syncCode : _server_sync

Message 4 : SYSTEM_ACK_PROBE_CODE

Message émis par le client. Acquitte des messages PROBE envoyé

  +-------------------+------------+---------+-------------+---------+---------+-- / --+---------+
  | CurrentSendNumber | SystemMode | Message | Taille : X  | Probe 1 | Probe 2 |       | Probe X |
  |    32 bits        |  1 bit     | 8 Bits  | 32 bits     | 32 bits | 32 bits |       | 32 bits |
  |                   |            |         | signed      | signed  | signed  |       | signed  |
  +-------------------+------------+---------+-------------+---------+---------+-- / --+---------+
  |  xxxxxxxxxxxxxxxx |   1        |    4    |
Message 5 : SYSTEM_DISCONNECTION_CODE

Message émis par le client.

  +-------------------+------------+---------+
  | CurrentSendNumber | SystemMode | Message |
  |    32 bits        |  1 bit     | 8 Bits  |
  |                   |            |         |
  +-------------------+------------+---------+
  |  xxxxxxxxxxxxxxxx |   1        |    5    |
Message 8 : SYSTEM_QUIT_CODE

Message émis par le client.

  +-------------------+------------+---------+---------+
  | CurrentSendNumber | SystemMode | Message | Quit Id |
  |    32 bits        |  1 bit     | 8 Bits  | 32 bits |
  |                   |            |         | signed  |
  +-------------------+------------+---------+---------+
  |  xxxxxxxxxxxxxxxx |   1        |    8    |

Message normal

  +-------------------+------------+---------+---
  | CurrentSendNumber | SystemMode | Message | . . .
  |    32 bits        |  1 bit     | 8 Bits  |
  +-------------------+------------+---------+---
  |  xxxxxxxxxxxxxxxx |   0        |

Annexe : Format des messages

bool : 1 bit

Juste un bit, vrai ou faux (true/false)

  +-------+
  | 1 bit |
  +-------+

uint8 : Unsigned int 8 bits

  +--------+
  | 8 bits |
  +--------+

uint16 : Unsigned int 16 bits

On écrit le chiffre en commençant par la partie la plus faible jusqu'au plus fort. Format little endian.

Ex. Valeur : 0x1234

  +--------+--------+
  | low    | high   |
  | 8 Bits | 8 Bits |
  +--------+--------+
  | 0x34   | 0x12   |

uint32 : Unsigned int 32 bits

On écrit le chiffre en commençant par la partie la plus faible jusqu'au plus fort. Format little endian.

Ex. Valeur : 0x12345678

  +--------+--------+--------+--------+
  | root   | low    | medium | high   |
  | 8 Bits | 8 Bits | 8 Bits | 8 Bits |
  +--------+--------+--------+--------+
  | 0x78   | 0x56   | Ox34   | Ox12   |

sint32 : int 32 bits

On écrit le chiffre en commençant par la partie la plus faible jusqu'au plus fort. Format little endian.

Ex. Valeur : 0x12345678

  +--------+--------+--------+--------+
  | root   | low    | medium | high   |
  | 8 Bits | 8 Bits | 8 Bits | 8 Bits |
  +--------+--------+--------+--------+
  | 0x78   | 0x56   | Ox34   | Ox12   |

uint64 : Unsigned int 64 bits

On écrit le chiffre en commençant par la partie la plus faible jusqu'au plus fort. Format little endian.

Ex. Valeur : 0x0123456789ABCDEF

  +--------+--------+--------+--------+--------+--------+--------+--------+
  | low    | low    | medium | medium | medium | high   | high   | high   |
  | 8 Bits | 8 Bits | 8 Bits | 8 Bits | 8 Bits | 8 Bits | 8 Bits | 8 Bits |
  +--------+--------+--------+--------+--------+--------+--------+--------+
  | 0xEF   | 0xCD   | OxAB   | Ox89   | Ox67   | Ox45   | Ox23   | Ox01   |

String : Chaîne de caractère

Une chaîne de caractère (on définit la taille, puis chaque caractère)

  +------------+---------+--------+------------+--------+
  | Taille : X | 1 char  | 2 char | . . .      | X char |
  | uint32     |  8 bits | 8 Bits |            | 8 bits |
  +------------+---------+--------+------------+--------+
                 1        2                       X == Taille

String-UTF-8 : Chaîne de caractère

Une chaîne de caractère (on définit la taille, puis chaque caractère)

  +------------+---------+--------+------------+--------+
  | Taille : X | 1 char  | 2 char | . . .      | X char |
  | uint32     |  8 bits | 8 Bits |            | 8 bits |
  +------------+---------+--------+------------+--------+
                 1        2                       X == Taille

String-UTF-16 : chaîne de caractère au format UTF-16

Une chaîne de caractère (on définit la taille, puis chaque caractère - ici un caractère tient sur 16 bits) Ce format est utilisé sous windows, nous préférons plus UTF-8, dans godot, mais une simple conversion suffit pour passer d'un format à l'autre.

  +------------+-------------+-------------+------------+-------------+
  | Taille : X | char utf 16 | char utf 16 | . . .      | char utf 16 |
  | uint32     | 16 bits     | 16 Bits     |            | 16 bits     |
  +------------+-------------+-------------+------------+-------------+
                 1             2                          X == Taille
CC Attribution-Share Alike 4.0 International Driven by DokuWiki
fr/toutcommenceparlereseau.1597443629.txt.gz · Dernière modification : 2021/12/03 19:18 (modification externe)

Licences Mentions légales Accueil du site Contact