D2S est un analyseur binaire écrit en Go qui est utilisé pour analyser les fichiers .d2s . Il s'agit du format binaire que le jeu Diablo II utilise pour enregistrer toutes les informations sur un certain caractère.
Ce package a été conçu pour un serveur privé de Diablo II appelé Slash Diablo pour créer un armurerie pour tous les caractères du serveur. Où quelqu'un pouvait tout voir sur un personnage particulier à un moment donné. Voici quelques exemples.
$ go get github.com/nokka/d2s package main
import (
"fmt"
"log"
"os"
"github.com/nokka/d2s"
)
func main () {
path := "nokka.d2s"
file , err := os . Open ( path )
if err != nil {
log . Fatal ( "Error while opening .d2s file" , err )
}
defer file . Close ()
char , err := d2s . Parse ( file )
if err != nil {
log . Fatal ( err )
}
// Prints character name and class.
fmt . Println ( char . Header . Name )
fmt . Println ( char . Header . Class )
} L'en-tête est une structure long de 765 byte contenant la plupart des méta-données de caractère.
| Compenser | Octets | Description |
|---|---|---|
| 0 | 4 | Identifiant |
| 4 | 4 | ID de version |
| 8 | 4 | Taille de fichier |
| 12 | 4 | Somme de contrôle |
| 16 | 4 | Arme active |
| 20 | 16 | Nom de personnage |
| 36 | 1 | Statut de caractère |
| 37 | 1 | Progression du caractère |
| 38 | 2 | Inconnu |
| 40 | 1 | Classe de personnage |
| 41 | 2 | Inconnu |
| 43 | 1 | Niveau de caractère |
| 44 | 4 | Inconnu |
| 48 | 4 | Dernier joué |
| 52 | 4 | Inconnu |
| 56 | 64 | Compétences assignées |
| 120 | 4 | ID de compétence de bouton de souris gauche |
| 124 | 4 | ID de compétence de bouton de souris droite |
| 128 | 4 | ID de compétences de la compétence du bouton de souris de l'échange de gauche |
| 132 | 4 | ID de compétence de bouton de souris d'échange de droite |
| 136 | 32 | Apparence du menu du caractère |
| 168 | 3 | Difficulté |
| 171 | 4 | ID de carte |
| 175 | 2 | Inconnu |
| 177 | 2 | Mercenaire mort |
| 179 | 4 | ID de mercenaire |
| 183 | 2 | ID de nom de mercenaire |
| 185 | 2 | Type de mercenaire |
| 187 | 4 | Expérience de mercenaire |
| 191 | 144 | Inconnu |
| 335 | 298 | Quêtes |
| 633 | 81 | Waypoint |
| 714 | 51 | Présentations des PNJ |
Les noms de caractères sont stortés comme un [16]byte qui contiendra le nom, une lettre par byte . Le nom peut comporter 16 caractères, et un nom qui est plus court aura rembourré 0x00 derrière le nom jusqu'à ce que nous atteignions 16 bytes .
- ou _ . L'état du caractère est un byte où différents bits seront définis, en fonction de l'état du caractère. Je ne les ai toujours pas tous compris, mais voici les plus importants.
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|
| ? | Échelle | Expansion | ? | Décédé | Hardcore | ? | ? |
Non encore implémenté.
La valeur est incrémentée chaque fois que vous tuez un boss ACT.
| Valeur | Standard | Hardcore |
|---|---|---|
| 0-3 | - | - |
| 4-7 | Monsieur / dame | Compte / comtesse |
| 8-11 | Seigneur / Dame | Duc / duchesse |
| 12 | Baron / baronne | Roi / reine |
| Valeur | Expansion | Extension hardcore |
|---|---|---|
| 0-3 | - | - |
| 5-8 | Tuerre | Destructeur |
| 10-13 | Champion | Conquérant |
| 15 | Patriarche / matriarche | Tuteur |
La classe de caractères est un byte où différentes valeurs représentent une classe.
| Classe | Valeur |
|---|---|
| Amazone | 0x00 |
| Sorcière | 0x01 |
| Nécromancien | 0x02 |
| Paladin | 0x03 |
| Barbare | 0x04 |
| Druide | 0x05 |
| Assassin | 0x06 |
Le dernier jeu est enregistré comme un horodatage Unix unit32 par exemple 1495882861 .
La section des compétences attribuée est un tableau de 16 identifiants de compétence, chacun un entier 4 byte (Uint32). Si aucune compétence n'est attribuée, la valeur est 0x00 .
La structure de quêtes est 298 byte qui décrit toutes les quêtes du jeu mais contient également des données sur les voyages ACT et les introductions NPC. Chaque quête dure 2 byte .
| Compenser | Octets | Contenu |
|---|---|---|
| 335 | 4 | Courtiser! |
| 339 | 6 | Inconnu |
Une quête dure 2 byte , j'ai créé une structure quest générale qui contient les données les plus importantes d'une quête, si elle est terminée ou non. Chaque quête a beaucoup de bits uniques en fonction des différentes étapes de la quête. Par exemple, si vous avez consommé le parchemin de la résistance de la quête "Prison of Ice" ou non.
| Peu | Description |
|---|---|
| 0 | Quête terminée |
La prison de glace est la seule quête que j'ai pris la peine de mettre en œuvre, car je devais savoir si le personnage a augmenté les résistances du parchemin ou non.
| Peu | Description |
|---|---|
| 0 | Quête terminée |
| 7 | Parchemin consommé |
Cette structure se répète 3 fois, une fois pour la normale, le cauchemar et l'enfer. Le décalage est le décalage dans la structure de quête.
| Compenser | Octets | Description |
|---|---|---|
| 0 | 2 | Réglé sur 1 si vous avez été initié à Warriv dans l'acte I. |
| 2 | [6]quest | Les six quêtes de l'acte I. |
| 14 | 2 | Réglé sur 1 si vous avez voyagé à l'acte II. |
| 16 | 2 | Réglé sur 1 si vous avez été présenté à Jerhyn. |
| 18 | [6]quest | Les six quêtes de l'acte II. |
| 30 | 2 | Réglé sur 1 si vous avez voyagé à l'acte III. |
| 32 | 2 | Réglé sur 1 si vous avez été présenté à Hratli. |
| 34 | [6]quest | Les six quêtes de l'acte III. |
| 46 | 2 | Réglé sur 1 si vous avez voyagé à l'acte IV. |
| 48 | 2 | Réglé sur 1 si vous avez été présenté à l'acte IV. (que vous avez si vous avez voyagé) |
| 50 | [6]quest | L'acte IV n'a que 3 quêtes, donc la structure a 6 octets vides ici. |
| 62 | 2 | Réglé sur 1 si vous avez voyagé pour ACT V. |
| 64 | 2 | Semble être réglé sur 1 après avoir terminé la fin de la terreur et parler à Caïn dans l'acte IV. |
| 66 | 4 | Semble être une sorte de rembourrage. |
| 70 | [6]quest | Les six quêtes de l'acte V. |
| 82 | 14 | Une sorte de rembourrage après toutes les données de quête. |
Non implémenté
Non implémenté
Suivant l'en-tête se trouve la section Attributs, cette disposition des sections se compose d'un tableau d'ID d'attribut à 9 bit , suivi d'une valeur d'attribut de longueur n bit . La section est terminée par une valeur de 9 bit de 0x1ff . Il convient de mentionner que ces champs sont inversés. Fondamentalement, si vous trouvez les bits 00100111 ils sont inversés dans 11100100 .
| IDENTIFIANT | Attribut |
|---|---|
| 0 | Force |
| 1 | Énergie |
| 2 | Dextérité |
| 3 | Vitalité |
| 4 | Statistiques inutilisées |
| 5 | Compétences inutilisées |
| 6 | HP actuel |
| 7 | Max hp |
| 8 | Mana actuel |
| 9 | Mana max |
| 10 | Endurance actuelle |
| 11 | Endurance maximale |
| 12 | Niveau |
| 13 | Expérience |
| 14 | Or |
| 15 | Or caché |
| Longueur | Attribut |
|---|---|
| 10 | Force |
| 10 | Énergie |
| 10 | Dextérité |
| 10 | Vitalité |
| 10 | Statistiques inutilisées |
| 8 | Compétences inutilisées |
| 21 | HP actuel |
| 21 | Max hp |
| 21 | Mana actuel |
| 21 | Mana max |
| 21 | Endurance actuelle |
| 21 | Endurance maximale |
| 7 | Niveau |
| 32 | Expérience |
| 25 | Or |
| 25 | Or caché |
for {
// 1. read 9 bits id. (reverse them)
// 2. if the id is 0x1ff, terminate the loop
// 3. read bit length from attribute map for that id.
// 4. read bit length nr of bits.
} Les compétences sont une section 32 byte contenant un en-tête 2 byte avec la valeur if et 30 byte de données de compétence. Chaque classe a 30 compétences à leur disposition, donc chaque compétence obtient 1 byte chacune. La partie délicate de la cartographie des compétences est que chaque classe a un décalage différent dans la carte des compétences où commencent leurs compétences spécifiques à la classe, puis à 30 index dans la carte. Ainsi, par exemple, Assassin a un décalage de 251 . Ce qui signifie que les compétences d'assassin se situent entre les indices de 251 et 281 ce qui est exactement 30 index.
| Taper | Octets | Valeur |
|---|---|---|
| Tête | 2 | if |
| Compétences | 30 | [30] Compétence |
| Classe | Compenser |
|---|---|
| Amazone | 6 |
| Sorcière | 36 |
| Nécromancien | 66 |
| Paladin | 96 |
| Barbare | 126 |
| Druide | 221 |
| Assassin | 251 |
C'est de loin la partie la plus délicate à lire. La section des éléments commence avec un en-tête 4 byte , contenant la valeur JM et une valeur uint16 qui est actuellement le nombre d'éléments. Équipé, inventaire, cachette, cube et ceinture tous inclus.
La longueur d'octets de la section est inconnue avant de la lire dans son intégralité, car la longueur du bit de chaque élément varie en fonction de sa qualité, du nombre de prises et d'attributs magiques qu'il possède.
Chaque élément suit cependant un certain modèle, qui est:
Chaque élément commence avec 111 bits de données simples, que tous les éléments contiennent. Il s'agit d'informations comme le type d'article, si elle est à douille, ID de position comme équipé ou cachette et ainsi de suite.
Chaque élément a également un booléen appelé SimpleItem qui est 1 peu long, si cela est défini sur 1 , l'élément ne contient plus de bits et que l'élément suivant commence.
Si l'élément n'est pas un simple élément, cela signifie qu'il aura des tonnes de données après les 111 bits initiaux. Quelques exemples de ceci sont le niveau de rareté, le suffixe magique, les affixs magiques, s'il s'agit d'un runword, personnalisé, d'une partie d'un ensemble, spécifique à la classe, etc.
Enfin et surtout, si l'article a des listes de propriétés magiques selon que c'est un mot à paraître, magique, rare, fabriqué, une partie unique de l'ensemble et ainsi de suite.
Ces listes sont similaires à la section Attributs où nous lirons:
9 bit idn bits of magical properties0x1ff terminator Lorsque nous atteignons le terminateur 0x1ff l'élément suivant commence.
Une propriété magique est une propriété unique qui peut se produire sur un article, chaque propriété a une longueur de bits différente et la carte est énorme.
Il s'agit de la propriété magique avec ID 83 qui contient des champs 2 bits tous 3 bits de long.
83 : {Bits: [] uint { 3 , 3 }, Name : "+{1} to {0} Skill Levels" },Toutes les propriétés magiques sont mappées dans le fichier item.go.
Si votre personnage est actuellement mort et qu'un cadavre est au sol lorsque vous entrez dans un jeu, vos articles équipés seront dans cet article. Il s'agit d'un en-tête de cadavre 16 bytes contenant l'en-tête JM suivi d'un nombre d'articles similaire à la liste des éléments.
La lecture des éléments du cadavre se fait de la manière exacte comme la section précédente des éléments.
Si votre personnage est créé dans l'expansion seigneur de la destruction, si vous contiendra 2 sections supplémentaires.
Les sections mercenaires commencent avec un en-tête 2 byte avec la valeur jf et est suivie d'un en-tête d'article 4 byte contenant le nombre d'articles que le mercenaire porte actuellement. Les éléments sont lus comme toute autre liste d'articles.
Si votre personnage est à la fois un nécromancien et un caractère d'expansion, cette section commence avec un en-tête 3 byte , où les deux premiers octets sont l'en-tête kf suivis d'un booléen appelé hasGolem , si cette valeur est vraie, il y a une liste d'articles avec la longueur 1 suivant l'en-tête.
Veuillez consulter la contribution.md.