Past 0.0.0.2 | Kick après envoi de l' "AuthenticationTicketAcceptedMessage"

Inscrit
25 Novembre 2015
Messages
169
Reactions
20
#1
Bonjour, tout d'abord je tiens à remercier skeezr qui m'a beaucoup aidé dans l’implantation de solution fonctionnel au sein de son émulateur (past). En effet, après plusieurs test j'ai été en mesure (grâce à skeezr) d'implanter le GameServer dans Past.

Pour information, la version 0.0.0.1 de Past, partagé sur le GitHub n'intègre que le LoginServer, qui ne permet la connexion qu'au serveur.
Afin d'entrer dans le jeu (world) il faut intégré le GameServer, c'est-à-dire le serveur qui permet de gérer les paquets relatif au world.

Concernant le Login, il est déjà géré par Past dans Past/Network/Login/LoginClient.cs à savoir :

- A la connexion d'un client en socket (Login_OnClientSocketConnected) on envoi 2 paquet : le ProtocolRequired et le HelloConnectMessage.
- Lorsque l'on reçoit le paquet Id 4 (IdentificationMessage) on envoi l' "IdentificationSuccessMessage" permettant la connexion au serveur (avec les login et pswd rentrée dans le Client, tous les login fonctionne puisque l'émulateur ne gère pas encore les bases de données mysql). Puis on envoi le paquet ServersListMessage permettant d'afficher la liste des serveurs en fonction de la communauté défini dans l' "IdentificationSuccessMessage".
- Lorsque l'on reçoit le paquet Id 40 (ServerSelectionMessage) qui correspond à la sélection d'un serveur (double clic sur un serveur dans le Client) on envoi le "SelectedServerDataMessage" qui contiens les informations relative au serveur séléctionné sur le client avec le ticket, l'ID du serveur, le port du serveur etc... Puis on ferme le LoginServer, la suite du processus se passant dans le GameClient.

Le processus illustré dans la console :


Voilà donc ce qui se passe lorsque dans l'ordre je : me connecte avec des identifiant sur le client, double-clic sur un serveur de jeu.

Le LoginClient est donc 100% fonctionnel et gère toute les connexions (voir le code) : plusieurs personnes peuvent se connecter simultanément sur le serveur (cf. illustration).
La connexion au serveur étant parfaitement géré, nous n'avons plus besoin de revenir dessus, tout se passera dorénavant dans le GameServer et le GameClient.

Le GameServer est une copie conforme du LoginServer et se trouve dans Past/Network/Game/GameServer.cs, vous trouverez son code ici

Passons au GameClient, là où les paquets vont être envoyé et reçu. Voici mon code :

Code:
using Past.Protocol;
using Past.Protocol.IO;
using Past.Protocol.Messages;
using Past.Protocol.Types;
using Past.Utils;
using System;
using System.Net.Sockets;
using Past.Network;

namespace Past.Network.Login
{
    public class GameClient
    {
        private Client Game { get; set; }

        public GameClient(Client client)
        {
            Game = client;
            Game_OnClientSocketConnected();
            Game.OnClientSocketClosed += Login_OnClientSocketClosed;
            Game.OnClientReceivedData += Game_OnClientReceivedData;
        }

        private void Game_OnClientSocketConnected() // Quand quelqu'un se connecte au Game
        {
            Send(new HelloGameMessage());
        }

        private void Login_OnClientSocketClosed()
        {
            Past.Network.Game.GameServer.Clients.Remove(this);
            Game.Close();
            ConsoleUtils.Write(ConsoleUtils.type.INFO, "Client disconnected from GameServer ...");
        }

        private void Game_OnClientReceivedData(byte[] data)
        {
            {
                int Header;
                int Id;
                int Size = 0;

                using (BigEndianReader reader = new BigEndianReader(data))
                {
                    Header = reader.ReadShort(); //header
                    Id = Header >> 2;
                    var typeLen = Functions.ComputeTypeLen((uint)data.Length);
                    if (typeLen == 1)
                    {
                        Size = reader.ReadByte();
                    }
                    else if (typeLen == 2)
                    {
                        Size = reader.ReadShort();
                    }
                    else if (typeLen == 3)
                    {
                        Size = ((reader.ReadByte() & 255) >> 16) + ((reader.ReadByte() & 255) >> 8) + (reader.ReadByte() & 255);
                    }

                    while (data.Length - 3 <= Size)
                    {
                        ConsoleUtils.Write(ConsoleUtils.type.RECEIV, "Receiv Packet ID {0} Header {1} {2}", Id, Header, Size);
                        if (Id == 110) //AuthenticationTicketMessage
                        {
                            Send(new AuthenticationTicketAcceptedMessage());
                        }
                        EntityLook look = new EntityLook(1, new short[] { 10 }, new int[0], new short[] { 125 }, new SubEntity[0]);
                        if (Id == 150) //CharacterListRequestMessage
                        {
                            Send(new CharactersListMessage(false, false, new CharacterBaseInformations[] { new CharacterBaseInformations(1, "Unknown", 1, look, 1, false)}));
                        }
                        if (Id == 152) //
                        {
                            Send(new CharacterSelectedSuccessMessage(new CharacterBaseInformations(1, "Unknown", 1, look, 1, false)));
                        }
                        if (data.Length - 3 == Size)
                        {
                            ConsoleUtils.Write(ConsoleUtils.type.RECEIV, "{0} ...", Functions.ByteArrayToString(data));
                            return;
                        }
                    }
                }
            }
        }

        public void Send(NetworkMessage message)
        {
            try
            {
                using (BigEndianWriter writer = new BigEndianWriter())
                {
                    message.Pack(writer);
                    Game.Send(writer.Data);
                }
                ConsoleUtils.Write(ConsoleUtils.type.SEND, "{0} to client {1}:{2} ...", message.ToString(), Game.Ip, Game.Port);
            }
            catch (Exception ex)
            {
                ConsoleUtils.Write(ConsoleUtils.type.ERROR, ex.ToString());
            }
        }
    }
}

Ce que fais ce code :

- A la connexion d'un client en socket (Game_OnClientSocketConnected), on envoi le HelloConnectMessage conformément à tout processus de connexion
- Lorsque l'on reçois le paquet Id 110 (AuthenticationTicketMessage), on envoi le AuthenticationTicketAcceptedMessage

Et c'est à cet endroit que ça merde. En effet, lorsque j'arrive à ce stade, le serveur me kick et j'obtient une erreur "connexion interrompu" sur mon client comme ci-dessous :



Donc je reçois le paquet Id 110 (AuthenticationTicketMessage), j'envoi le AuthenticationTicketAcceptedMessage puis je re-reçois le paquet Id 110 et à ce moment là je suis kick du GameServer.

Donc la j'ai plusieurs théories :

1 - Je renvoi pas le bon paquet
2 - Je renvoi pas les bons arguments avec le bon paquet
3 - Probleme dans le protocole de l'émulateur ( AuthenticationTicketAcceptedMessage vide)

Merci de votre aide !
Unknown.
 

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
150
#2
Partage nous un rapport d'erreur, on y verra plus clair côté client.

Sinon toutes tes démarches semblent correctes.
 
Inscrit
16 Mars 2014
Messages
214
Reactions
30
#3
c'est regler, juste un problème avec une mauvaise variable qu'il envoyer dans un packet
 
Inscrit
25 Novembre 2015
Messages
169
Reactions
20
#4
En effet, l'erreur se trouvait dans l'envoi du paquet SelectedServerDataMessage dans le LoginClient : j'y avais mis une variable read pour l'id du serveur sélectionné alors qu'il faut le mettre manuellement (ex j'affiche que le serveur 111 et le SelectedServerDataMessage n'accepte que la connexion au 111) comme suit :

Code:
                            Send(new SelectedServerDataMessage(111, "127.0.0.1", 5555, true, ticket));
Du coup je me connecte correctement au serveur et ça affiche la liste des personnages comme ci-dessous :


On peut même afficher plusieurs personnages avec des looks différents :



On peut aussi accéder à l'interface de création des personnages :


Ou retourner à la sélection de serveur en cliquant sur "Changer de serveur"


Enfin bref tout ça c'est bien beau mais comment on fais pour la suite ?
En sélectionnant un personnage je peux rentrer dans le monde comme ci-dessous :


Et nous voilà donc dans Dofus ! Enfin pas tout à fait... Comme vous pouvez le voir la map ne s'affiche pas, ce qui signifie que je n'envoi pas les bons paquet après la réception du paquet Id 250 (j'envoi le 251).

Peut-être que quelqu'un connais le protocole du jeu et peux nous dire quoi envoyer à la réception du paquet 250 ?

J'avais pensé aux autres paquet de type Game[...]Message : GameContextCreateMessage, GameContextReadyMessage, GameEntityDispositionMessage etc...
Je pourrai aussi envoyer le paquet avec les informations relative aux caractéristiques de mon personnage (pour que la vie et les PA/PM s'affichent) mais pour trouver ce paquet il faut que je fouille dans les sources du jeu et/ou le protocole de l'émulateur n'est-ce pas ?

Je suis sur la bonne voie ?
 

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
150
#5
Rien de mieux que de sniffer pour connaitre l'ordre des paquets.
 
Inscrit
25 Novembre 2015
Messages
169
Reactions
20
#6
J'attends la MAJ de ton sniffer ^^'
 
Inscrit
16 Mars 2014
Messages
214
Reactions
30
#7
Rien de mieux que de sniffer pour connaitre l'ordre des paquets.
L'ordre semble être bon le contenu aussi mais pourtant pas moyen d'afficher la map sauf 1 fois http://puu.sh/pNcTv/315f9b209a.jpg mais sans raison particulière ni sans avoir changer quoi que se soit, par contre les coord ne sont pas bonne malgré le fait que j'envoi bien la mapId 0 avec la subaeraId à 1 qui correspond à celle du screen
 
Dernière édition par un modérateur:
Inscrit
16 Mars 2014
Messages
214
Reactions
30
#8
Alors toujours aucune infos de pourquoi la map ne veut pas s'afficher mais par contre je viens de faire une découverte en mettant le client sur le mode "event" dans la config :
Code:
<entry key="eventMode">false</entry>
donc en mettant ceci sur true j'arrive a avoir ma map qui s'affiche et ceux tous le temps sans aucun problème ...
Mode event true :

Mode event false :
 
Haut Bas