Okay les bambini aujourd'hui on va faire du très lourd : démystifier les secrets les plus deep de cette fameuse MapData.
Si si, grâce à Maxou, cet homme invisible que je ne connaîtrai probablement jamais de mon vivant, c'est possible ! Par contre mon cerveau ne le remercie pas, maintenant il ressemble à une mignonette Côte D'or (au Lait, bien sûr) laissée au soleil, merci maxou quoi… ^-^
Courrier du lecteur
Cliquez pour révéler
Cliquez pour masquer
Tazman59 Yep j'avais vu ce diagramme, mais il me semblait incomplet voire pas toujours très clair… ceci dit c'est vrai qu'y être retourné jeter un œil après tant de recherche et d'apprentissage, je dois avouer que je le trouve de plus en plus sensé ce p'tit diagramme, thx ! Comme quoi c'est bien en forgeant qu'o… bon ok j'arrête la philo ça me va pas :p
Pas de soucis c'est déjà cool de passer ici, et puis j'oserais jamais demander qu'on cherche à ma place (ce n'est même pas souhaitable pour moi). Par exemple l'idée c'était que si un dev qui travaille le parsing des map 1.29 passait par là, il m'aurait dit "tu trouveras ce que tu cherches dans le fichier Maphandler.vb de maxoubot".
5. Comment parser une map 1.29 ?
Vous voyez le dicton qui dit "Vaut mieux avoir une petite qui frétille ?" Eh ben là c'est le parfait contre-exemple, parce que notre question elle paraît petite mais en réalité elle est aussi grosse que celle de Rocco.
Commençons en douceur : en suivant notre méthodologie, DataProcessor.as nous a délicatement invité à chercher dans le fichier Game.as (du dossier Aks) duquel nous trouverons le code de cette fameuse fonction "onMapData". Rien de bien sorcier, elle split le paquet et envoie ça dans une nouvelle fonction.
this.api.kernel.MapsServersManager.loadMap(_loc4, _loc5, _loc6);
Du coup, on retrouve ce fichier MapsServerManager pour trouver le code de loadMap. Il prépare la clef du paquet et l'envoie dans loadData…
this.loadData(sID + "_" + sDate + (this._aKeys[Number(sID)] != undefined ? ("X") : ("")) + ".swf");
loadData ? Kézako ? Impossible de trouver le code de ce loadData… Et merde. Un cul de sac ! Bon, ma petite curiosité me force à scroll un peu tout de même et je tombe sur le code sympa de parseMap (dans le même fichier donc) qui, après déchiffrage de mapData à l'aide de decypherData, nous renvoie dans
this.api.gfx.buildMap(_loc3, _loc9, _loc10, _loc11, _loc12, _loc13, _loc21);
où _loc13 sont nos datas déchiffrées tandis que les autres sont essentiellement des données non chiffrées issus du fichier .swf de la map. Hélas je n'arrive pas à retrouver buildMap et je me retrouve dans un autre cul de sac.
Au moins on aura pu comprendre jusqu'ici la structure du paquet GDM à savoir un map_id, une date et une clef pour déchiffrer les données du fichier .swf de la map. On a pas tout tout compris mais pas grave non ? Ah si ? Quoi, vous me dites qu'un vrai dev ne se satisferait pas aussi vite ? rip
Pas le choix faut changer de stratégie : éplucher maxoubot. Et là, à force de chercher, bingo !
Alors je vais pas vous copy paste le code mais plutôt tenter de résumer la structure de ces fameuses mapData et comment elles sont traitées. Une fois la mapData déchiffrée, la fonction uncompressMap de Maphandler.vb (dossier Modules) nous indique qu'elle suit une organisation en multiple de 10 caractères où chaque multiple correspond aux données d'une cell_id.
mapData = "cell_data1" + "celldata2" + ... + "celldata_n"
où cell_data_n.length() = 10
Ensuite, la fonction uncompressCell du même fichier nous explique comment sont traitées chacune de ces cell_data et là ça se corse.
La chaîne de 10 caractères est décodée par la fonction hashCodes faisant correspondre un entier à chaque caractère. Plutôt drôle manière de faire mais why not. Ensuite on tombe sur ce genre de synthaxe:
_loc5.layerObject2Num = ((_loc8(0) And 2) << 12) + ((_loc8(7) And 1) << 12) + (_loc8(8) << 6) + _loc8(9)
Really ? =.='
Je vais pas vous cacher avoir mis le temps que les poules mettent à avoir des dents pour comprendre ce que sont les opérations bitwise/bitshift (cf tuto Microsoft). Je sais pas quel l'individu a été aussi fou chez Ankama pour obscurcir à ce point la représentation du contenu d'une cellule mais bon j'imagine que ça fait le café.
En regardant l'utilisation de ce layerObject2Num dans la fonction loadRessources de Maps.vb (dossier Fichier), on peut comprendre qu'en fait les ressources "non fauchées" se retrouvent dans le mapData avec leur layerObject2Num associé à leur cellule. Ce qui semble plutôt logique vu qu'aucun paquet ne me permettait de connaître les cell_id des ressources déjà dispo sur la map.
D'après maxoubot, ressource fauchée = pas de layerObject2Num de la ressource, ce que je trouve plutôt étrange vu qu'il y a un layerObject2Interactive mais bon… why not ? A tester in situ donc!
Nous pouvons compléter le raisonnement en regardant comment sont traités les paquets GDF. Si une ressource venait à être fauchée après que la map ait été chargée, le serveur envoie un paquet GDF qui sera traité avec:
this.api.gfx.setObject2Interactive(_loc6, _loc9, 2); //si ressource de nouveau dispo
// ou alors
this.api.gfx.setObject2Frame(_loc6, _loc7); //si la ressource n'est pas dispo
Même si je ne sais toujours pas comment trouver le code de toutes ces fonctions api.gfx (je suppose que Maxou a du y arriver lui), on peut facilement déduire par son appellation que ça mettra à jour le mapData.
Pour conclure, mapData contient le layerObject2Num des ressources à leur cell_id correspondant et sont par défaut "non fauchées". Lors de chaque changement de map, le client reçoit du serveur le paquet GDF avec toutes les ressources fauchées pour pouvoir être updated. Voilà, la boucle est bouclée ! Stylé hein ? :cool:
Il reste encore des petits mystères à résoudre comme le .movement propre à chaque cell mais les infos qu'on a déjà là nous permettrons de nous passer complètement de la détection pixel de nos arbres préférés.
Bien entendu, ce journal de bord manquerait de saveur si je terminais ce chapitre sans une danse invocatrice petite question à l'égard des vieux singes du forum en quête de divertissement:
Please dites moi où je peux trouver api.gfx ça me démange le kiki jpp :'(:'(:'(
Voilà c'est fini pour aujourd'hui. Comme d'habitude n'hésitez pas à venir lâcher un com et surtout me rectifier si je dis de la merde parce que y a de fortes chances que j'interprète trop vite ce que je démystifie. Si c'est pas clair dites le moi aussi comme ça j'améliore mes skills de synthèse et de communication. Prochain épisode: mise en pratique de toute cette théorie et adaptation des algorithmes de parsing en python, hell yeah baby!