Diablo II stocke votre personnage de jeu sur le disque en tant que fichier .d2s. Il s'agit d'un format de fichier binaire qui code toutes les statistiques, éléments, noms et autres données.
Les entiers sont stockés dans un petit ordre d'octet endian, qui est la commande d'octets natifs sur une architecture x86 diablo II sur.
Chaque fichier .d2s commence par un en-tête de 765 octets, après quoi les données sont de longueur variable.
| Hexagonal | Octet | Longueur | Dessiner |
|---|---|---|---|
| 0x00 | 0 | 4 | Signature (0xAA55AA55) |
| 0x04 | 4 | 4 | ID de version |
| 0x08 | 8 | 4 | Taille de fichier |
| 0x0c | 12 | 4 | Somme de contrôle |
| 0x10 | 16 | 4 | Arme active |
| 0x14 | 20 | 16 | Nom de personnage |
| 0x24 | 36 | 1 | Statut de caractère |
| 0x25 | 37 | 1 | Progression du caractère |
| 0x26 | 38 | 2 | ? |
| 0x28 | 40 | 1 | Classe de personnage |
| 0x29 | 41 | 2 | ? |
| 0x2b | 43 | 1 | Niveau |
| 0x2c | 44 | 4 | ? |
| 0x30 | 48 | 4 | Temps |
| 0x34 | 52 | 4 | ? |
| 0x38 | 56 | 64 | Lourdeur |
| 0x78 | 120 | 4 | Souris gauche |
| 0x7c | 124 | 4 | Souris droite |
| 0x80 | 128 | 4 | Maison gauche (interrupteur d'arme) |
| 0x84 | 132 | 4 | Souris droite (interrupteur d'armes) |
| 0x88 | 136 | 32 | Apparence du menu du caractère |
| 0xa8 | 168 | 3 | Difficulté |
| 0xab | 171 | 4 | Carte |
| 0xaf | 175 | 2 | ? |
| 0xb1 | 177 | 2 | Merc mort? |
| 0xb3 | 179 | 4 | Merc Seed? |
| 0xb7 | 183 | 2 | Merc Nom ID |
| 0xb9 | 185 | 2 | Type à merc |
| 0xbb | 187 | 4 | Expérience Merc |
| 0xbf | 191 | 144 | ? |
| 0x14f | 335 | 298 | Quête |
| 0x279 | 633 | 81 | Waypoint |
| 0x2ca | 714 | 51 | PNJ |
| 0x2fd | 765 | Statistiques | |
| Articles |
Version du fichier. Les valeurs suivantes sont connues:
71 est de 1,00 à V1.0687 est 1,07 ou un ensemble d'expansion V1.0889 est le jeu standard v1.0892 est V1.09 (le jeu standard et l'ensemble d'extension.)96 est v1.10 +Pour calculer la somme de contrôle, définissez la valeur de l'informatique dans les données .d2s à zéro et parcourez tous les octets dans les données calculant une somme de contrôle 32 bits:
sum = ( sum << 1 ) + data [ i ];Source: # 5
const fs = require ( "fs" ) ;
const path = require ( "path" ) ;
const file = path . join ( process . cwd ( ) , "path_to_save.d2s" ) ;
function calculateSum ( data ) {
let sum = 0 ;
for ( let i = 0 ; i < data . length ; i ++ ) {
let ch = data [ i ] ;
if ( i >= 12 && i < 16 ) {
ch = 0 ;
}
ch += sum < 0 ;
sum = ( sum << 1 ) + ch ;
}
return sum ;
}
function littleToBigEndian ( number ) {
return new DataView (
Int32Array . of (
new DataView ( Int32Array . of ( number ) . buffer ) . getUint32 ( 0 , true )
) . buffer
) ;
}
function ashex ( buffer ) {
return buffer . getUint32 ( 0 , false ) . toString ( 16 ) ;
}
async function readSafeFile ( ) {
return await new Promise ( ( resolve , reject ) => {
fs . readFile ( file , ( err , data ) => {
if ( err ) return reject ( err ) ;
return resolve ( data ) ;
} ) ;
} ) ;
}
async function writeCheckSumToSafeFile ( data ) {
return await new Promise ( ( resolve , reject ) => {
fs . writeFile ( file , data , err => {
if ( err ) reject ( err ) ;
resolve ( ) ;
} ) ;
} ) ;
}
readSafeFile ( ) . then ( data => {
const sum = calculateSum ( data ) ;
const bufferSum = littleToBigEndian ( sum ) ;
const hex = ashex ( bufferSum ) ;
const newData = data ;
for ( let i = 0 ; i < 4 ; i ++ ) {
newData [ 12 + i ] = bufferSum . getInt8 ( i ) ;
}
writeCheckSumToSafeFile ( newData ) . then ( ( ) => console . log ( hex ) ) ;
} ) ;Source: https://github.com/gucio321/d2d2s/blob/66f91e2af7b3949ca7f279aae397bd8904519e2d/pkg/d2s/d2s.go#l397
// CalculateChecksum calculates a checksum and saves in a byte slice
func CalculateChecksum ( data * [] byte ) {
var sum uint32
for i := range * data {
sum = (( sum << 1 ) % math . MaxUint32 ) | ( sum >> ( int32Size * byteLen - 1 ))
sum += uint32 (( * data )[ i ])
}
sumBytes := make ([] byte , int32Size )
binary . LittleEndian . PutUint32 ( sumBytes , sum )
const (
int32Size = 4
checksumPosition = 12
)
for i := 0 ; i < int32Size ; i ++ {
( * data )[ checksumPosition + i ] = sumBytes [ i ]
}
}Si la somme de contrôle n'est pas valide, Diablo II n'ouvre pas le fichier de sauvegarde.
FAIRE
Les noms de caractères sont stockés comme un tableau de 16 caractères qui contiennent une chaîne terminée nulle rembourrée avec 0x00 pour les octets restants. Les caractères sont stockés comme ASCII 8 bits, mais n'oubliez pas que le valide doit suivre ces règles:
- ) ou de souligner ( _ )Ceci est un champ 8 bits:
| Peu | Dessiner |
|---|---|
| 0 | ? |
| 1 | ? |
| 2 | Hardcore |
| 3 | Décédé |
| 4 | ? |
| 5 | Expansion |
| 6 | ? |
| 7 | ? |
FAIRE
| IDENTIFIANT | Classe |
|---|---|
| 0 | Amazone |
| 1 | Sorcière |
| 2 | Nécromancien |
| 3 | Paladin |
| 4 | Barbare |
| 5 | Druide |
| 6 | Assassin |
Cette valeur de niveau est visible uniquement dans l'écran de sélection de caractères et doit être la même que celle-ci dans la section des statistiques.
FAIRE
Structure de 32 octets qui définit l'apparence du caractère dans le menu ne change pas l'aspect dans le jeu
3 octets de données qui indiquent les trois difficultés que le personnage a déverrouillées. Chaque octet est représentatif de l'une des difficultés. Dans cet ordre: normal, cauchemar et enfer. Chaque octet est un Bitfield structuré comme ceci:
| 7 | 6 | 5 | 4 | 3 | 2, 1, 0 |
|---|---|---|---|---|---|
| Actif? | Inconnu | Inconnu | Inconnu | Inconnu | Quel acte (0-4)? |
FAIRE
FAIRE
Les données de waypoint commencent par 2 caractères "ws" et 6 octets inconnus, toujours = {0x01, 0x00, 0x00, 0x00, 0x50, 0x00}
Trois structures sont en place pour chaque difficulté, aux décalages 641, 665 et 689.
Le contenu de cette structure est le suivant
| octet | bytesize | contenu |
|---|---|---|
| 0 | 2 octets | {0x02, 0x01} Objectif inconnu |
| 2 | 5 octets | Waypoint bitfield dans l'ordre du moins significatif |
| 7 | 17 octets | inconnu |
Dans le Waypoint Bitfield, une valeur un peu de 1 signifie que le waypoint est activé, il est dans une commande du plus bas au plus haut, donc 0 est le campement voyou (ACT I) etc. Le premier point de waypoint de chaque difficulté est toujours activé.
FAIRE
TODO (codage 9 bits)
Les éléments sont stockés dans les listes décrites par cet en-tête:
| Octet | Taille | Dessiner |
|---|---|---|
| 0 | 2 | "JM" |
| 2 | 2 | Nombre d'articles |
Après cela, n objets. Chaque élément commence par une structure de base de 14 octets. De nombreux champs de cette structure ne sont pas "alignés par des octets" et sont décrits par leur position et leurs tailles de bit.
| Peu | Taille | Dessiner |
|---|---|---|
| 0 | 16 | "JM" (séparé de l'en-tête de liste) |
| 16 | 4 | ? |
| 20 | 1 | Identifié |
| 21 | 6 | ? |
| 27 | 1 | À crampon |
| 28 | 1 | ? |
| 29 | 1 | Ramassé depuis la dernière sauvegarde |
| 30 | 2 | ? |
| 32 | 1 | Oreille |
| 33 | 1 | Équipement de démarrage |
| 34 | 3 | ? |
| 37 | 1 | Compact |
| 38 | 1 | Éthéré |
| 39 | 1 | ? |
| 40 | 1 | Personnalisé |
| 41 | 1 | ? |
| 42 | 1 | Runweword |
| 43 | 15 | ? |
| 58 | 3 | Mère |
| 61 | 4 | Équipé |
| 65 | 4 | Colonne |
| 69 | 3 | Rangée |
| 72 | 1 | ? |
| 73 | 3 | Planque |
| 76 | 4 | ? |
| 80 | 24 | Type Code (3 lettres) |
| 108 | Données d'élément étendu |
Si l'élément est marqué en Compact (le bit 37 est défini), aucune information étendue ne existe et l'élément est terminé.
Articles avec des informations étendues stocker des bits en fonction des informations de l'en-tête de l'article. Par exemple, un élément marqué en Socketed stockera un encodage entier 3 bits supplémentaire du nombre de prises de l'élément.
| Peu | Taille | Dessiner |
|---|---|---|
| 108 | Prises | |
| Graphiques personnalisés | ||
| Spécifique à la classe | ||
| Qualité | ||
| Mods |
Les graphiques personnalisés sont désignés par un seul bit, ce qui, s'il est défini, signifie qu'un numéro 3 bits pour l'index graphique suit. Si le bit n'est pas défini, les 3 bits ne sont pas présents.
| Peu | Taille | Dessiner |
|---|---|---|
| 0 | 1 | L'article a des graphiques personnalisés |
| 1 | 3 | Index graphique alternatif |
Les articles de classe comme Barbarian Helms ou Amazon Bows ont des propriétés spéciales spécifiques à ce type d'articles. Si le premier bit est vide, les 11 bits restants ne seront pas présents.
| Peu | Taille | Dessiner |
|---|---|---|
| 0 | 1 | L'élément a des données spécifiques à la classe |
| 1 | 11 | Bits spécifiques de classe |
La qualité de l'article est codée comme un entier 4 bits.
Une fois que chaque élément est une liste de mods. La liste est une série de paires de valeurs de clé où la clé est un numéro 9 bits et la valeur dépend de la clé. La liste se termine lorsque la clé 511 ( 0x1ff ) est trouvée, ce qui est tous les 9 bits.
En utilisant le fichier ItemStatCost.txt en tant que fichier CSV délimité par l'onglet, vous pouvez extraire la colonne ID qui mappe aux touches 9 bits. Les Save Bits colonnes et Param Bits décrivent la taille du mod.
La seule exception est les modificateurs de style Min-Max qui utilisent la ligne suivante dans le CSV pour stocker la partie "Max" du mod. Les tailles de bit de ces deux peuvent être différentes et vous devez les résumer pour obtenir la taille totale.
FAIRE
Tous les articles sont situés quelque part et ont un "parent" qui peut être un autre article, comme lors de l'insertion d'un bijou.
| Valeur | Dessiner |
|---|---|
| 0 | Stocké |
| 1 | Équipé |
| 2 | Ceinture |
| 4 | Curseur |
| 6 | Article |
Pour les articles qui sont "stockés", un entier 3 bits codé à partir du bit 73 décrit où stocker l'article:
| Valeur | Dessiner |
|---|---|
| 1 | Inventaire |
| 4 | Cube horadrique |
| 5 | Planque |
Les articles équipés décrivent leur machine à sous:
| Valeur | Fente |
|---|---|
| 1 | Casque |
| 2 | Amulette |
| 3 | Armure |
| 4 | Arme (à droite) |
| 5 | Arme (à gauche) |
| 6 | Anneau (à droite) |
| 7 | Anneau (à gauche) |
| 8 | Ceinture |
| 9 | Bottes |
| 10 | Gants |
| 11 | Arme alternative (à droite) |
| 12 | Arme alternative (à gauche) |