D2S es un analizador binario escrito en GO que se usa para analizar archivos .d2s . Este es el formato binario que usa el juego Diablo II para guardar toda la información sobre un determinado personaje.
Este paquete fue creado para un servidor privado de Diablo II llamado Slash Diablo para construir una armería para todos los personajes del servidor. Donde alguien podía ver todo sobre un personaje en particular en cualquier momento dado. Aquí hay algunos ejemplos.
$ 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 )
} El encabezado es una estructura 765 byte de largo que contiene la mayoría de los meta datos de caracteres.
| Compensar | Bytes | Descripción |
|---|---|---|
| 0 | 4 | Identificador |
| 4 | 4 | ID de versión |
| 8 | 4 | Tamaño de archivo |
| 12 | 4 | Suma de verificación |
| 16 | 4 | Arma activa |
| 20 | 16 | Nombre del personaje |
| 36 | 1 | Estado del personaje |
| 37 | 1 | Progresión del personaje |
| 38 | 2 | Desconocido |
| 40 | 1 | Clase de carácter |
| 41 | 2 | Desconocido |
| 43 | 1 | Nivel de carácter |
| 44 | 4 | Desconocido |
| 48 | 4 | Última jugada |
| 52 | 4 | Desconocido |
| 56 | 64 | Habilidades asignadas |
| 120 | 4 | ID de habilidad del botón del mouse izquierdo |
| 124 | 4 | ID de habilidad del botón derecho del mouse |
| 128 | 4 | ID de habilidad del botón del mouse del mouse izquierdo |
| 132 | 4 | Intercambio correcto del botón del mouse ID de habilidad |
| 136 | 32 | Apariencia del menú de personajes |
| 168 | 3 | Dificultad |
| 171 | 4 | ID de mapa |
| 175 | 2 | Desconocido |
| 177 | 2 | Mercenary Dead |
| 179 | 4 | ID de mercenaria |
| 183 | 2 | ID de nombre mercenario |
| 185 | 2 | Tipo mercenario |
| 187 | 4 | Experiencia mercenario |
| 191 | 144 | Desconocido |
| 335 | 298 | Misiones |
| 633 | 81 | Punto de referencia |
| 714 | 51 | Presentaciones de NPC |
Los nombres de los personajes se estallan como un [16]byte que contendrá el nombre, una letra por byte . El nombre puede tener 16 caracteres, y un nombre que es más corto habrá acolchado 0x00 detrás del nombre hasta que llegamos a 16 bytes .
- o _ . El estado del personaje es un byte donde se establecerán diferentes bits, dependiendo del estado del personaje. Todavía no he descubierto todos, pero aquí están los más importantes.
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|
| ? | Escalera | Expansión | ? | Fallecido | Duro | ? | ? |
Aún no implementado.
El valor se incrementa cada vez que matas a un jefe de acto.
| Valor | Estándar | Duro |
|---|---|---|
| 0-3 | - | - |
| 4-7 | Señor/dama | Conte/condesa |
| 8-11 | Señor/Dama | Duque/duquesa |
| 12 | Barón/baronesa | Rey/Reina |
| Valor | Expansión | Expansión hardcore |
|---|---|---|
| 0-3 | - | - |
| 5-8 | Asesino | Destructor |
| 10-13 | Campeón | Conquistador |
| 15 | Patriarca/matriarca | Guardián |
La clase de caracteres es un byte donde diferentes valores representan una clase.
| Clase | Valor |
|---|---|
| Amazonas | 0x00 |
| Hechicera | 0x01 |
| Nigromante | 0x02 |
| Paladín | 0x03 |
| Bárbaro | 0x04 |
| druida | 0x05 |
| Asesino | 0x06 |
La última jugada se guarda como una marca de tiempo unit32 UNIX, por ejemplo, 1495882861 .
La sección de habilidades asignadas es una matriz de 16 identificaciones de habilidades, cada una de 4 byte entero (uint32). Si no se asigna habilidad, el valor es 0x00 .
La estructura de misiones es 298 byte que describe todas las misiones en el juego, pero también contiene datos sobre los viajes de ACT y las presentaciones de NPC. Cada búsqueda tiene 2 byte de largo.
| Compensar | Bytes | Contenido |
|---|---|---|
| 335 | 4 | ¡Cortejar! |
| 339 | 6 | Desconocido |
Una búsqueda es de 2 byte de largo, he creado una estructura quest general que contiene los datos más importantes de una misión, si se completa o no. Cada búsqueda tiene muchos bits únicos establecidos dependiendo de diferentes hitos de la búsqueda. Por ejemplo, si ha consumido el pergamino de la resistencia de la búsqueda "Prisión de Hielo" o no.
| Poco | Descripción |
|---|---|
| 0 | Búsqueda completada |
La prisión de hielo es la única búsqueda que me molesté en implementar, porque necesitaba saber si el personaje ha aumentado las resistencias del pergamino o no.
| Poco | Descripción |
|---|---|
| 0 | Búsqueda completada |
| 7 | Pergamino consumido |
Esta estructura se repite 3 veces, una vez para la pesadilla normal, y el infierno. El desplazamiento es el desplazamiento en la estructura de misiones.
| Compensar | Bytes | Descripción |
|---|---|---|
| 0 | 2 | Establecido en 1 si te han presentado a Warriv en el acto I. |
| 2 | [6]quest | Las seis misiones para el acto I. |
| 14 | 2 | Establecer en 1 si ha viajado a la Ley II. |
| 16 | 2 | Establecido en 1 si te han presentado a Jerhyn. |
| 18 | [6]quest | Las seis misiones para el Acto II. |
| 30 | 2 | Establecer en 1 si ha viajado al Acto III. |
| 32 | 2 | Establecido en 1 si ha sido presentado a Hratli. |
| 34 | [6]quest | Las seis misiones para el Acto III. |
| 46 | 2 | Establecido en 1 si ha viajado a la Ley IV. |
| 48 | 2 | Establecido en 1 si ha sido presentado a la Ley IV. (que tienes si has viajado) |
| 50 | [6]quest | Acto IV solo tiene 3 misiones, por lo que la estructura tiene 6 bytes vacíos aquí. |
| 62 | 2 | Establecer en 1 si ha viajado a ACT V. |
| 64 | 2 | Parece estar establecido en 1 después de completar el final del terror y hablar con Caín en el acto IV. |
| 66 | 4 | Parece ser algún tipo de relleno. |
| 70 | [6]quest | Las seis misiones para ACT V. |
| 82 | 14 | Algún tipo de relleno después de todos los datos de la búsqueda. |
No implementado
No implementado
Siguiendo el encabezado está la sección de atributos, este diseño de secciones consiste en una matriz de ID de atributo 9 bit , seguida de un valor de atributo de longitud n bit . La sección termina por un valor de 9 bit de 0x1ff . Vale la pena mencionar que estos campos se invierten un poco. Básicamente, si encuentra los bits 00100111 , se invierten en 11100100 .
| IDENTIFICACIÓN | Atributo |
|---|---|
| 0 | Fortaleza |
| 1 | Energía |
| 2 | Destreza |
| 3 | Vitalidad |
| 4 | Estadísticas no utilizadas |
| 5 | Habilidades no utilizadas |
| 6 | HP actual |
| 7 | Max HP |
| 8 | Maná actual |
| 9 | Max maná |
| 10 | Resistencia actual |
| 11 | Resistencia máxima |
| 12 | Nivel |
| 13 | Experiencia |
| 14 | Oro |
| 15 | Dorado |
| Longitud de bits | Atributo |
|---|---|
| 10 | Fortaleza |
| 10 | Energía |
| 10 | Destreza |
| 10 | Vitalidad |
| 10 | Estadísticas no utilizadas |
| 8 | Habilidades no utilizadas |
| 21 | HP actual |
| 21 | Max HP |
| 21 | Maná actual |
| 21 | Max maná |
| 21 | Resistencia actual |
| 21 | Resistencia máxima |
| 7 | Nivel |
| 32 | Experiencia |
| 25 | Oro |
| 25 | Dorado |
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.
} Las habilidades son una sección 32 byte que contiene un encabezado 2 byte con el valor if y 30 byte de datos de habilidades. Cada clase tiene 30 habilidades disponibles para ellos, por lo que cada habilidad obtiene 1 byte cada una. La parte difícil de la asignación de habilidades es que cada clase tiene un desplazamiento diferente en el mapa de habilidades donde comienzan sus habilidades específicas de clase, y luego ingresan 30 índices en el mapa. Entonces, por ejemplo, Assassin tiene una compensación de 251 . Lo que significa que las habilidades de asesino están entre los índices de 251 y 281 , que son exactamente 30 índices.
| Tipo | Bytes | Valor |
|---|---|---|
| Encabezamiento | 2 | if |
| Habilidades | 30 | [30] Habilidad |
| Clase | Compensar |
|---|---|
| Amazonas | 6 |
| Hechicera | 36 |
| Nigromante | 66 |
| Paladín | 96 |
| Bárbaro | 126 |
| druida | 221 |
| Asesino | 251 |
Esta es, con mucho, la parte más difícil de leer. La sección de elementos comienza con un encabezado 4 byte , que contiene el valor JM , y un valor uint16 , que es el recuento de elementos que su personaje tiene actualmente. Equipado, inventario, alijo, cubo y cinturón, todos incluidos.
La longitud de los bytes de la sección se desconoce antes de leerla en su totalidad, porque la longitud de bit de cada elemento varía según su calidad, número de enchufes y atributos mágicos que posee.
Sin embargo, cada elemento sigue un cierto patrón, que es:
Cada elemento comienza con 111 bits de datos simples, que todos los elementos contienen. Esta es información como el tipo de elemento, si está encogido, ID de posición como equipado o escondite, etc.
Cada elemento también tiene un booleano llamado SimpleItem que tiene 1 bits de largo, si esto se establece en 1 , el elemento no contiene más bits y el siguiente elemento comienza.
Si el elemento no es un elemento simple, esto significa que tendrá toneladas de datos después de los 111 bits iniciales. Algunos ejemplos de esto son el nivel de rareza, el sufijo mágico, el afijo mágico, si se trata de un raneño, personalizado, parte de un conjunto, clase específica, etc.
Por último, pero no menos importante, si el elemento tiene listas de propiedades mágicas, dependiendo de si es una parte runeword, mágica, rara, elaborada, única del set, etc.
Estas listas son similares a la sección de atributos donde leeremos:
9 bit idn bits of magical properties0x1ff terminator Cuando llegamos al Terminator 0x1ff comienza el siguiente elemento.
Una propiedad mágica es una propiedad única que puede ocurrir en un artículo, cada propiedad tiene una longitud de bits diferente y el mapa es enorme.
Esta es la propiedad mágica con ID 83 que contiene 2 bits cada 3 bits de largo.
83 : {Bits: [] uint { 3 , 3 }, Name : "+{1} to {0} Skill Levels" },Todas las propiedades mágicas se asignan en el archivo item.go.
Si tu personaje está actualmente muerto y un cadáver está en el suelo cuando ingresas a un juego, tus elementos equipados estarán en esta estructura de elementos. Es un encabezado de cadáver 16 bytes que contiene el encabezado JM seguido de un recuento de elementos similar a la lista de artículos.
La lectura de los elementos del cadáver se realiza de la manera exacta como la sección anterior de los elementos.
Si tu personaje se crea en la expansión Señor de la destrucción si contendrá 2 secciones más.
Las secciones mercenarias comienzan con un encabezado 2 byte con el valor jf y es seguido por un encabezado de elementos 4 byte que contiene el número de artículos que el mercenario está usando actualmente. Los elementos se leen como cualquier otra lista de artículos.
Si tu personaje es tanto un nigromante como un carácter de expansión, esta sección comienza con un encabezado 3 byte , donde los dos primeros bytes son el encabezado kf seguido de un booleano llamado hasGolem , si este valor es verdadero, hay una lista de elementos con la longitud 1 después del encabezado.
Consulte la contribuyente.md.