D2S é um analisador binário escrito em Go que é usado para analisar arquivos .d2s . Este é o formato binário que o jogo Diablo II usa para salvar todas as informações sobre um determinado personagem.
Este pacote foi criado para um servidor privado de Diablo II chamado Slash Diablo para construir um arsenal para todos os caracteres no servidor. Onde qualquer um poderia ver tudo sobre um personagem específico em qualquer momento. Aqui estão alguns exemplos.
$ 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 )
} O cabeçalho é de 765 byte longas, contendo a maioria dos meta -dados do caractere.
| Desvio | Bytes | Descrição |
|---|---|---|
| 0 | 4 | Identificador |
| 4 | 4 | ID da versão |
| 8 | 4 | Tamanho do arquivo |
| 12 | 4 | Soma de verificação |
| 16 | 4 | Arma ativa |
| 20 | 16 | Nome do personagem |
| 36 | 1 | Status do personagem |
| 37 | 1 | Progressão do personagem |
| 38 | 2 | Desconhecido |
| 40 | 1 | Classe de personagem |
| 41 | 2 | Desconhecido |
| 43 | 1 | Nível de personagem |
| 44 | 4 | Desconhecido |
| 48 | 4 | Última jogada |
| 52 | 4 | Desconhecido |
| 56 | 64 | Habilidades atribuídas |
| 120 | 4 | ID de habilidade do botão do mouse esquerdo |
| 124 | 4 | ID de habilidade do botão do mouse direito |
| 128 | 4 | ID de habilidade do botão de troca de troca à esquerda |
| 132 | 4 | ID de habilidade do botão de troca direita do mouse |
| 136 | 32 | Aparência do menu do personagem |
| 168 | 3 | Dificuldade |
| 171 | 4 | ID do mapa |
| 175 | 2 | Desconhecido |
| 177 | 2 | Mercenário morto |
| 179 | 4 | ID do mercenário |
| 183 | 2 | Nome do mercenário ID |
| 185 | 2 | Tipo de mercenário |
| 187 | 4 | Experiência mercenária |
| 191 | 144 | Desconhecido |
| 335 | 298 | Missões |
| 633 | 81 | Waypoints |
| 714 | 51 | NPC Introduções |
Os nomes dos caracteres são fictados como um [16]byte que conterá o nome, uma letra por byte . O nome pode ter 16 caracteres, e um nome mais curto terá preenchido o 0x00 por trás do nome até chegarmos a 16 bytes .
- ou _ . O status do caractere é um byte em que diferentes bits serão definidos, dependendo do status do caractere. Ainda não os descobri, mas aqui estão os mais importantes.
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|
| ? | Escada | Expansão | ? | Morreu | Hardcore | ? | ? |
Ainda não implementado.
O valor é incrementado toda vez que você mata um chefe do ACT.
| Valor | Padrão | Hardcore |
|---|---|---|
| 0-3 | - | - |
| 4-7 | Senhor/dame | Contagem/condessa |
| 8-11 | Senhor/Senhora | Duque/Duquesa |
| 12 | Barão/Baronesa | Rei/rainha |
| Valor | Expansão | Expansão Hardcore |
|---|---|---|
| 0-3 | - | - |
| 5-8 | Assassino | Destruidor |
| 10-13 | Campeão | Conquistador |
| 15 | Patriarca/Matriarca | Guardião |
A classe de caracteres é um byte em que diferentes valores representam uma classe.
| Aula | Valor |
|---|---|
| Amazon | 0x00 |
| Feiticeira | 0x01 |
| Necromante | 0x02 |
| Paladino | 0x03 |
| Bárbaro | 0x04 |
| druida | 0x05 |
| Assassino | 0x06 |
O último jogo é salvo como um timestamp unit32 Unix, por exemplo, 1495882861 .
A seção de habilidades atribuídas é uma matriz de 16 IDs de habilidades, cada uma de 4 byte (UINT32). Se nenhuma habilidade for atribuída, o valor for 0x00 .
A estrutura do Quests é uma seção 298 byte que descreve todas as missões no jogo, mas também contém dados sobre as introduções de viagens e NPC. Cada missão tem 2 byte de comprimento.
| Desvio | Bytes | Contente |
|---|---|---|
| 335 | 4 | Woo! |
| 339 | 6 | Desconhecido |
Uma missão tem 2 byte de comprimento, criei uma estrutura quest geral que possui os dados mais importantes de uma missão, se for concluída ou não. Cada missão tem muitos bits exclusivos, dependendo de diferentes marcos da missão. Por exemplo, se você consumiu o pergaminho da resistência da busca "Prisão do Gelo" ou não.
| Pedaço | Descrição |
|---|---|
| 0 | Missão concluída |
A prisão de gelo é a única busca que me preocupei em implementar, porque precisava saber se o personagem aumentou as resistências do pergaminho ou não.
| Pedaço | Descrição |
|---|---|
| 0 | Missão concluída |
| 7 | Rolagem consumida |
Essa estrutura se repete 3 vezes, uma vez para o normal, pesadelo e inferno. O deslocamento é o deslocamento na estrutura da missão.
| Desvio | Bytes | Descrição |
|---|---|---|
| 0 | 2 | Definido como 1 se você foi apresentado ao Warriv no Ato I. |
| 2 | [6]quest | Todas as seis missões para o Ato I. |
| 14 | 2 | Defina como 1 se você viajou para o Ato II. |
| 16 | 2 | Defina como 1 se você foi apresentado a Jerhyn. |
| 18 | [6]quest | Todas as seis missões para o Ato II. |
| 30 | 2 | Defina como 1 se você viajou para o Ato III. |
| 32 | 2 | Defina como 1 se você foi apresentado ao hratli. |
| 34 | [6]quest | Todas as seis missões para o Ato III. |
| 46 | 2 | Defina como 1 se você viajou para o Ato IV. |
| 48 | 2 | Defina como 1 se você foi apresentado ao Ato IV. (que você tem se você viajou) |
| 50 | [6]quest | O Ato IV tem apenas 3 missões, então a estrutura tem 6 bytes vazios aqui. |
| 62 | 2 | Defina como 1 se você viajou para agir V. |
| 64 | 2 | Parece estar definido como 1 depois de completar o final do terror e conversar com Cain no Ato IV. |
| 66 | 4 | Parece ser algum tipo de preenchimento. |
| 70 | [6]quest | Todas as seis missões para o Ato V. |
| 82 | 14 | Algum tipo de preenchimento depois de todos os dados da missão. |
Não implementado
Não implementado
Seguindo o cabeçalho está a seção de atributos, este layout da seção consiste em uma matriz de ID de atributo 9 bit , seguida por um valor de atributo de comprimento n bit . A seção é encerrada por um valor de 9 bit de 0x1ff . Vale ressaltar que esses campos são revertidos. Basicamente, se você encontrar os bits 00100111 eles serão revertidos em 11100100 .
| EU IA | Atributo |
|---|---|
| 0 | Força |
| 1 | Energia |
| 2 | Destreza |
| 3 | Vitalidade |
| 4 | Estatísticas não utilizadas |
| 5 | Habilidades não utilizadas |
| 6 | HP atual |
| 7 | Max HP |
| 8 | Mana atual |
| 9 | Max Mana |
| 10 | Resistência atual |
| 11 | Max resistência |
| 12 | Nível |
| 13 | Experiência |
| 14 | Ouro |
| 15 | Ouro escondido |
| Comprimento de bit | Atributo |
|---|---|
| 10 | Força |
| 10 | Energia |
| 10 | Destreza |
| 10 | Vitalidade |
| 10 | Estatísticas não utilizadas |
| 8 | Habilidades não utilizadas |
| 21 | HP atual |
| 21 | Max HP |
| 21 | Mana atual |
| 21 | Max Mana |
| 21 | Resistência atual |
| 21 | Max resistência |
| 7 | Nível |
| 32 | Experiência |
| 25 | Ouro |
| 25 | Ouro escondido |
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.
} As habilidades são uma seção 32 byte que contém um cabeçalho 2 byte com o valor if e 30 byte de dados de habilidade. Cada classe possui 30 habilidades disponíveis para eles; portanto, cada habilidade obtém 1 byte cada. A parte complicada sobre o mapeamento de habilidades é que cada classe tem um deslocamento diferente no mapa de habilidades onde as habilidades específicas de sua classe começam e, em seguida, entre 30 índices no mapa. Assim, por exemplo, assassino tem um deslocamento de 251 . O que significa que as habilidades de assassino estão entre os índices de 251 e 281 que são exatamente 30 índices.
| Tipo | Bytes | Valor |
|---|---|---|
| Cabeçalho | 2 | if |
| Habilidades | 30 | [30] Habilidade |
| Aula | Desvio |
|---|---|
| Amazon | 6 |
| Feiticeira | 36 |
| Necromante | 66 |
| Paladino | 96 |
| Bárbaro | 126 |
| druida | 221 |
| Assassino | 251 |
Esta é de longe a parte mais complicada de ler. A seção de itens começa com um cabeçalho 4 byte , contendo o valor JM e um valor uint16 , que é a contagem de itens que seu personagem atualmente possui. Equipado, inventário, esconderijo, cubo e cinto, todos incluídos.
O comprimento do byte da seção é desconhecido antes de lê -lo na íntegra, porque o comprimento de cada item varia dependendo de sua qualidade, número de soquetes e atributos mágicos que possui.
Cada item segue um certo padrão, que é:
Cada item começa com 111 bits de dados simples, que todos os itens contêm. Esta é uma informação como o tipo de item, se for tombada, a identificação de posição como equipada ou esconderia e assim por diante.
Cada item também possui um booleano chamado SimpleItem , que é 1 pouco de comprimento, se estiver definido como 1 , o item não contém mais bits e o próximo item inicia.
Se o item não for um itens simples, isso significa que ele terá toneladas de dados seguindo os 111 bits iniciais. Alguns exemplos disso são o nível de raridade, sufixo mágico, afixo mágico, se for um esgotamento, personalizado, parte de um conjunto, específico da classe e assim por diante.
Por último, mas não menos importante, se o item tiver listas de propriedades mágicas, dependendo de se for uma parte do RunEword, mágica, rara, criada e única do conjunto e assim por diante.
Essas listas são semelhantes à seção de atributos, onde vamos ler:
9 bit idn bits of magical properties0x1ff terminator Quando atingimos o Terminator 0x1ff o próximo item começa.
Uma propriedade mágica é uma propriedade única que pode ocorrer em um item, cada propriedade tem um comprimento de bit diferente e o mapa é enorme.
Esta é a propriedade mágica com ID 83 , que contém campos de 2 bits a cada 3 bits de comprimento.
83 : {Bits: [] uint { 3 , 3 }, Name : "+{1} to {0} Skill Levels" },Todas as propriedades mágicas são mapeadas no arquivo item.go.
Se seu personagem estiver morto e um cadáver estiver no terreno quando você entra em um jogo, seus itens equipados estarão nesta estrutura de itens. É um cabeçalho de cadáver 16 bytes que contêm o cabeçalho JM seguido de uma contagem de itens semelhante à lista de itens.
A leitura dos itens do cadáver é feita da maneira exata como a seção anterior dos itens.
Se seu personagem for criado na expansão Senhor da destruição, se conter mais 2 seções.
As seções mercenárias começam com um cabeçalho 2 byte com o valor jf e é seguido por um cabeçalho 4 byte que contém o número de itens que o mercenário está usando atualmente. Os itens são lidos como qualquer outra lista de itens.
Se o seu personagem é um caráter de necromante e expansão, esta seção começa com um cabeçalho 3 byte , onde os dois primeiros bytes são o kf de cabeçalho seguido por um booleano chamado hasGolem , se esse valor for verdadeiro, há uma lista de itens com o comprimento 1 após o cabeçalho.
Por favor, consulte contribuindo.md.