Diablo II speichert Ihren Spielcharakter auf der Festplatte als .D2S -Datei. Dies ist ein Binärdateiformat, das alle Statistiken, Elemente, Namen und andere Datenstücke codiert.
Ganzzahlen werden in Little Endian Byte Order aufbewahrt, der einheimischen Byte -Order auf einem X86 -Architektur -Diablo II basiert.
Jede .D2S -Datei beginnt mit einem 765 -Byte -Header, woraufhin die Daten variabler Länge haben.
| Verhexen | Byte | Länge | Vor |
|---|---|---|---|
| 0x00 | 0 | 4 | Signatur (0xaa55aa55) |
| 0x04 | 4 | 4 | Version ID |
| 0x08 | 8 | 4 | Dateigröße |
| 0x0c | 12 | 4 | Überprüfung |
| 0x10 | 16 | 4 | Aktive Waffe |
| 0x14 | 20 | 16 | Charaktername |
| 0x24 | 36 | 1 | Charakterstatus |
| 0x25 | 37 | 1 | Charakter -Fortschritt |
| 0x26 | 38 | 2 | ? |
| 0x28 | 40 | 1 | Charakterklasse |
| 0x29 | 41 | 2 | ? |
| 0x2b | 43 | 1 | Ebene |
| 0x2c | 44 | 4 | ? |
| 0x30 | 48 | 4 | Zeit |
| 0x34 | 52 | 4 | ? |
| 0x38 | 56 | 64 | Hotkeys |
| 0x78 | 120 | 4 | Linke Maus |
| 0x7c | 124 | 4 | Rechte Maus |
| 0x80 | 128 | 4 | Linke Maus (Waffenschalter) |
| 0x84 | 132 | 4 | Rechte Maus (Waffenschalter) |
| 0x88 | 136 | 32 | Zeichenmenü Erscheinungsbild |
| 0xa8 | 168 | 3 | Schwierigkeit |
| 0xab | 171 | 4 | Karte |
| 0xaf | 175 | 2 | ? |
| 0xb1 | 177 | 2 | Merc tot? |
| 0xb3 | 179 | 4 | Merc Seed? |
| 0xb7 | 183 | 2 | Merc Name ID |
| 0xb9 | 185 | 2 | Merc -Typ |
| 0xbb | 187 | 4 | Merc -Erfahrung |
| 0xbf | 191 | 144 | ? |
| 0x14f | 335 | 298 | Suche |
| 0x279 | 633 | 81 | Wegpunkt |
| 0x2ca | 714 | 51 | NPC |
| 0x2fd | 765 | Statistiken | |
| Artikel |
Dateiversion. Die folgenden Werte sind bekannt:
71 ist 1,00 bis v1.0687 ist 1,07 oder Expansionssatz V1.0889 ist Standard -Spiel V1.0892 ist v1.09 (sowohl das Standardspiel als auch der Erweiterungssatz).96 ist v1.10+So berechnen Sie den Schecksummen, setzen Sie den Wert in den .d2s-Daten auf Null und iterieren Sie alle Bytes in den Daten, die eine 32-Bit-Prüfsumme berechnen:
sum = ( sum << 1 ) + data [ i ];Quelle: #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 ) ) ;
} ) ;Quelle: https://github.com/gucio321/d2d2s/blob/66f91e2af7b3949ca7f279aae397bd8904519e2d/pkg/d2s/d2sgo#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 ]
}
}Wenn die Prüfsumme ungültig ist, öffnet Diablo II die Speicherdatei nicht.
Todo
Zeichennamen werden als Array von 16 Zeichen gespeichert, die einen mit 0x00 gepolsterten NULL -Kennzeichen für die verbleibenden Bytes enthalten. Die Zeichen werden als 8-Bit-ASCII gespeichert, aber denken Sie daran, dass die Gültigkeit folgenden Regeln folgen muss:
- ) oder einem Unterstrich ( _ ) enthaltenDies ist ein 8-Bit-Feld:
| Bisschen | Vor |
|---|---|
| 0 | ? |
| 1 | ? |
| 2 | Hardcore |
| 3 | Gestorben |
| 4 | ? |
| 5 | Erweiterung |
| 6 | ? |
| 7 | ? |
Todo
| AUSWEIS | Klasse |
|---|---|
| 0 | Amazonas |
| 1 | Zauberin |
| 2 | Nekromant |
| 3 | Paladin |
| 4 | Barbar |
| 5 | Druide |
| 6 | Attentäter |
Dieser Levelwert ist nur im Zeichenbildschirm aus dem Zeichen ausgewählt und muss dem Abschnitt mit Statistiken übereinstimmen.
Todo
32 Byte-Struktur, die definiert, wie der Charakter im Menü aussieht
3 Datenbytes, die angeben, welche der drei Schwierigkeiten der Charakter entsperrt hat. Jedes Byte ist für eine der Schwierigkeiten. In dieser Reihenfolge: Normal, Albtraum und Hölle. Jedes Byte ist ein solches Bitfield:
| 7 | 6 | 5 | 4 | 3 | 2, 1, 0 |
|---|---|---|---|---|---|
| Aktiv? | Unbekannt | Unbekannt | Unbekannt | Unbekannt | Welcher Akt (0-4)? |
Todo
Todo
Wegpunktdaten beginnen mit 2 Zeichen "WS" und 6 unbekannten Bytes, immer = {0x01, 0x00, 0x00, 0x00, 0x50, 0x00}
Für jede Schwierigkeit sind drei Strukturen vorhanden, bei Offsets 641, 665 und 689.
Der Inhalt dieser Struktur ist wie folgt
| Byte | Byteze | Inhalt |
|---|---|---|
| 0 | 2 Bytes | {0x02, 0x01} Unbekannter Zweck |
| 2 | 5 Bytes | Wegpunkt Bitfield in der Reihenfolge des am wenigsten bedeutenden Bits |
| 7 | 17 Bytes | unbekannt |
Im Wegpunkt Bitfield bedeutet ein Bitwert von 1, dass der Wegpunkt aktiviert ist, dass er in einer Reihenfolge von niedrigsten bis zum höchsten ist, sodass 0 das Rogue -Lager (Akt I) usw. ist. Der erste Wegpunkt in jeder Schwierigkeit wird immer aktiviert.
Todo
Todo (9-Bit-Codierung)
Die Elemente werden in Listen gespeichert, die von diesem Header beschrieben wurden:
| Byte | Größe | Vor |
|---|---|---|
| 0 | 2 | "JM" |
| 2 | 2 | Artikelanzahl |
Danach kommen n Artikel. Jeder Artikel beginnt mit einer einfachen 14-Byte-Struktur. Viele Felder in dieser Struktur sind nicht "byte-ausgerichtet" und werden durch ihre Bitposition und ihre Größen beschrieben.
| Bisschen | Größe | Vor |
|---|---|---|
| 0 | 16 | "JM" (getrennt vom Listenheader) |
| 16 | 4 | ? |
| 20 | 1 | Identifiziert |
| 21 | 6 | ? |
| 27 | 1 | Sockeled |
| 28 | 1 | ? |
| 29 | 1 | Seit dem letzten Save abgeholt |
| 30 | 2 | ? |
| 32 | 1 | Ohr |
| 33 | 1 | Starterausrüstung |
| 34 | 3 | ? |
| 37 | 1 | Kompakt |
| 38 | 1 | Ätherisch |
| 39 | 1 | ? |
| 40 | 1 | Personalisiert |
| 41 | 1 | ? |
| 42 | 1 | Runeword |
| 43 | 15 | ? |
| 58 | 3 | Elternteil |
| 61 | 4 | Ausgestattet |
| 65 | 4 | Spalte |
| 69 | 3 | Reihe |
| 72 | 1 | ? |
| 73 | 3 | Versteck |
| 76 | 4 | ? |
| 80 | 24 | Geben Sie Code ein (3 Buchstaben) |
| 108 | Erweiterte Elementdaten |
Wenn das Element als Compact markiert ist (Bit 37 ist festgelegt), gibt es keine erweiterten Artikelinformationen und das Element ist abgeschlossen.
Elemente mit erweiterten Informationsspeicherbits basierend auf Informationen im Artikelkopf. Beispielsweise speichert ein als Socketed markiertes Element eine zusätzliche 3-Bit-Ganzzahl, die die Anzahl der Steckdosen des Artikels hat.
| Bisschen | Größe | Vor |
|---|---|---|
| 108 | Steckdosen | |
| Benutzerdefinierte Grafiken | ||
| Klassenspezifisch | ||
| Qualität | ||
| Mods |
Benutzerdefinierte Grafiken werden mit einem einzigen Bit bezeichnet, was bei der festgelegten Anzahl eine 3-Bit-Nummer für den folgenden Grafikindex bedeutet. Wenn das Bit nicht festgelegt ist, sind die 3-Bits nicht vorhanden.
| Bisschen | Größe | Vor |
|---|---|---|
| 0 | 1 | Artikel verfügt über benutzerdefinierte Grafiken |
| 1 | 3 | Alternativer Grafikindex |
Klassenartikel wie Barbarhelme oder Amazon -Bögen haben spezielle Eigenschaften, die für diese Art von Artikeln spezifisch sind. Wenn das erste Bit leer ist, sind die verbleibenden 11 Bit nicht vorhanden.
| Bisschen | Größe | Vor |
|---|---|---|
| 0 | 1 | Element hat klassenspezifische Daten |
| 1 | 11 | Klassenspezifische Bits |
Die Artikelqualität wird als 4-Bit-Ganzzahl kodiert.
Nach jedem Element ist eine Liste von Mods. Die Liste ist eine Reihe von Schlüsselwertpaaren, bei denen der Schlüssel eine 9-Bit-Zahl ist und der Wert vom Schlüssel abhängt. Die Liste endet, wenn der Schlüssel 511 ( 0x1ff ) gefunden wird, der alle 9-Bit-festgelegt wird.
Verwenden Sie die Datei ItemStatCost.txt als tab delimitierte CSV-Datei, die die Spalte ID extrahieren können, die den 9-Bit-Tasten abbildet. Die Spalten Save Bits und Param Bits , wie groß der Mod ist.
Die einzige Ausnahme sind Modifikatoren im Min-Max-Stil, die die nächste Reihe im CSV verwenden, um den "maximalen" Teil des Mods zu speichern. Die Bitgrößen dieser beiden können unterschiedlich sein und Sie sollten sie zusammenfassen, um die Gesamtgröße zu erhalten.
Todo
Alle Artikel befinden sich irgendwo und haben einen "Elternteil", der ein weiterer Gegenstand sein kann, z. B. beim Einfügen eines Juwelen.
| Wert | Vor |
|---|---|
| 0 | Gelagert |
| 1 | Ausgestattet |
| 2 | Gürtel |
| 4 | Cursor |
| 6 | Artikel |
Für Artikel, die "gespeichert" sind, beschreibt eine 3-Bit-Ganzzahl, die ab Bit 73 codiert, wo der Artikel gespeichert werden soll:
| Wert | Vor |
|---|---|
| 1 | Inventar |
| 4 | Horadric Cute |
| 5 | Versteck |
Artikel, die ausgestattet sind, beschreiben ihren Slot:
| Wert | Slot |
|---|---|
| 1 | Helm |
| 2 | Amulett |
| 3 | Rüstung |
| 4 | Waffe (rechts) |
| 5 | Waffe (links) |
| 6 | Ring (rechts) |
| 7 | Ring (links) |
| 8 | Gürtel |
| 9 | Stiefel |
| 10 | Handschuhe |
| 11 | Alternative Waffe (rechts) |
| 12 | Alternative Waffe (links) |