Bonjour à tous !
Me revoilà aujourd'hui pour vous faire part de l'avancement de Past qui est maintenant en version 0.0.0.4 ! Je me suis pas mis d'accord avec skeezr concernant les versions mais j'ai fais des backup et un changelog (c'est plus un repère qu'autre chose, ça n'a pas de réel intérêt en soi) pour chaque versions que vous trouverez ici. (le changelog, pas les versions :p)
Comme vous pouvez le voir, on a dupliqué le protocole de connexion officiel dans le GameClient et sans grande surprise la map ne s'affiche toujours pas jeu.
Cependant cela nous a permis de "debug" des interfaces, elles sont visible en jeu mais pas utilisable.
Une petite vidéo pour vous montrer ce qui fonctionne en jeu : (en réalité ça fonctionne pas, mais c'est affiché, ce qui n'était pas le cas avant)
Working
Cliquez pour révéler
Cliquez pour masquer
Loading Image
Les paquets sont envoyé dans l'ordre suivant :
GameClient
Cliquez pour révéler
Cliquez pour masquer
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;
using Past.Protocol.Enums;
using System.Threading;
namespace Past.Network.Login
{
public class GameClient
{
private Client Game { get; set; }
public GameClient(Client client)
{
Game = client;
Game_OnClientSocketConnected();
Game.OnClientSocketClosed += Game_OnClientSocketClosed;
Game.OnClientReceivedData += Game_OnClientReceivedData;
}
private void Game_OnClientSocketConnected() // Quand quelqu'un se connecte au Game
{
Send(new HelloGameMessage());
}
private void Game_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)
{
//read the incoming packet
using (BigEndianReader reader = new BigEndianReader(data))
{
int header = reader.ReadShort();
int id = header >> 2;
int typeLen = header & 3;
int length = 0;
switch (typeLen)
{
case 0:
break;
case 1:
length = reader.ReadByte();
break;
case 2:
length = reader.ReadUShort();
break;
case 3:
length = ((reader.ReadSByte() & 255) << 16) + ((reader.ReadByte() & 255) << 8) + (reader.ReadByte() & 255);
break;
}
ConsoleUtils.Write(ConsoleUtils.type.DEBUG, "Header {0} Id {1} TypeLen {2} Length {3}...", header, id, typeLen, length);
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) // CharactersListRequestMessage
{
Send(new CharactersListMessage(false, false, new CharacterBaseInformations[] { new CharacterBaseInformations(1, "admin", 200, look, 1, false) }));
}
ObjectEffect effects = new ObjectEffect(1);
ObjectItem potionrappel = new ObjectItem(63, 6965, new ObjectEffect[0], 144, 10);
ObjectItem solomonk = new ObjectItem(6, 7143, new ObjectEffect[2], 123, 1);
SpellItem spells = new SpellItem(1, 0, 1);
if (id == 152) // CharacterSelectionMesage
{
Send(new NotificationListMessage(new int[0]));
Send(new CharacterSelectedSuccessMessage(new CharacterBaseInformations(1, "admin", 200, look, 1, false)));
Send(new InventoryContentMessage(new ObjectItem[0], 1000000));
Send(new EmoteListMessage(new sbyte[0]));
Send(new JobDescriptionMessage(new JobDescription[0]));
Send(new JobExperienceMultiUpdateMessage(new JobExperience[0]));
Send(new AlignmentRankUpdateMessage(10, false));
// Send(new GuildMembershipMessage("Nameless Guild", new GuildEmblem[0], 1);
Send(new EnabledChannelsMessage(new sbyte[0], new sbyte[0]));
Send(new SpellListMessage(true, new SpellItem[0]));
Send(new InventoryWeightMessage(0, 5000));
Send(new FriendWarnOnConnectionStateMessage(true));
Send(new FriendWarnOnLevelGainStateMessage(true));
Send(new TextInformationMessage((sbyte)TextInformationTypeEnum.TEXT_INFORMATION_ERROR, 89, new string[0]));
Send(new StartupActionsListMessage(new StartupActionAddObject[0]));
}
FriendInformations friendsList = new FriendInformations("admin", 1, 0);
IgnoredInformations ignoredList = new IgnoredInformations("admin");
if (id == 4001) // FriendsGetListMessage
{
Send(new FriendsListMessage(new FriendInformations[0]));
}
if (id == 5676) // IgnoredGetListMessage
{
Send(new IgnoredListMessage(new IgnoredInformations[0]));
}
if (id == 250) // GameContextCreateRequestMessage
{
Send(new BasicNoOperationMessage());
Send(new GameContextDestroyMessage());
Send(new GameContextCreateMessage((sbyte)Past.Protocol.Enums.GameContextEnum.ROLE_PLAY));
Send(new LifePointsRegenBeginMessage(1));
Send(new CurrentMapMessage(0));
Send(new CharacterStatsListMessage(new CharacterCharacteristicsInformations(0, 0, 0, 1000000, 0, 0, new ActorExtendedAlignmentInformations(0, 0, 0, 0, 0, 0, false), 55, 55, 0, 0, 7, 3, new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), 0, new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterBaseCharacteristic(0, 0, 0, 0), new CharacterSpellModification[0])));
Send(new BasicNoOperationMessage());
Send(new QuestListMessage(new short[0], new short[0]));
}
if (id == 225) // MapInformationsRequestMessage
{
Send(new BasicNoOperationMessage());
Send(new MapComplementaryInformationsDataMessage(5120, 1, new HouseInformations[0], new GameRolePlayActorInformations[0], new InteractiveElement[0], new StatedElement[0], new MapObstacle[0], new FightCommonInformations[0]));
Send(new SetCharacterRestrictionsMessage(new ActorRestrictionsInformations(false, false, false, false, false, false, false, false, true, false, false, false, false, true, true, true, false, false, false, false, false)));
}
}
ConsoleUtils.Write(ConsoleUtils.type.RECEIV, "{0} ...", Functions.ByteArrayToString(data));
}
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());
}
}
}
}
La partie qui nous intéresse est celle contenu dans Game_OnClientReceivedData puisqu'elle permet, à la réception d'un paquet spécifié (if (id == paquetid)) exécuter un bloc de code (envoi de paquet par exemple).
L'émulateur ne gère pas le SQL, nous utilisons des arguments pour le faire fonctionner en local. Le problème se situe peut-être au niveau des arguments ?
Quoi qu'il en soit, j'ai sniffé le client officiel de Dofus 2.35 avec les logs de Mufibot afin de voir dans quel ordre sont envoyé les paquets (je parle bien d'ordre et non de timing).
J'ai donc reproduis à la lettre l'ordre d'envoi des paquets conformément aux logs de Mufibot (en passant au paquet suivant s'il n'existe pas dans le protocole de Dofus 2.0.0, par exemple des paquet pas encore implanté comme la gestion des conquêtes de guilde, puis qu'à cette version c'est les conquêtes des cités, enfin bref).
C'est à ce moment là que je me suis rendu compte que les interfaces sont maintenant visualisable, mais la map elle ne s'affiche toujours pas..
Maintenant j'ai plusieurs question à poser après cette brève introduction :
- L'ordre des paquet est-il bon ?
- Le timing d'envoi des paquets pourrait-il permettre d'afficher la map ?
- Les arguments à l'envoi des paquets sont-ils les bons ?