¡Buenas una vez más! Hoy vengo con otro pequeño proyecto de ingeniería inversa, esta vez centrado en Pokémon Dash, uno de los primeros títulos de Pokémon publicados para Nintendo DS y desarrollado por la mítica "Ambrella". En esta ocasión se ha investigado con la ROM europea (PAL) del juego, ya que me interesaba ver cómo almacena sus gráficos, modelos 3D, texturas y sonidos. El objetivo de esta investigación, una vez más, ha sido desarrollar un importer en Unity Engine que me permita extraer y, valga la redundancia, importar los recursos desde la ROM y ver cómo se organizan dentro del juego de Nintendo DS.
1. Estructura general
Como ocurre con otros juegos de Nintendo DS, Pokémon Dash utiliza
Por tanto en la cabecera completa podemos encontrar:
Cada entrada de la
2. Modelos 3D y archivos RelocMod
Una de las partes más interesantes es la forma en la que Pokémon Dash almacena sus modelos 3D. En lugar de utilizar directamente archivos
Este archivo comienza con la firma
Cada entrada ocupa 12 bytes:
Dentro encontramos archivos
¿Qué es un RelocMod?
Se trata de un módulo que agrupa datos binarios junto con una tabla de reubicaciones. En lugar de interpretar todos sus valores como direcciones absolutas, el juego dispone de una lista que identifica las posiciones donde se encuentran las referencias internas.
La cabecera contiene los siguientes campos relevantes:
Cada entrada de la tabla de reubicaciones ocupa 4 bytes y señala una posición dentro del bloque de datos que contiene una referencia.
Algunas de estas estructuras pueden encontrarse comprimidas mediante
Este esquema representa la organización lógica de los datos, no necesariamente su disposición física exacta dentro de cada módulo.
3. Geometría y comandos GX
Otra peculiaridad es que la geometría no se almacena simplemente como una lista convencional de vértices e índices. Los modelos contienen listas de comandos GX, que corresponden al sistema gráfico de Nintendo DS. Estas instrucciones describen operaciones como establecer coordenadas, normales, colores, coordenadas de textura y comenzar o finalizar primitivas geométricas.
Entre los comandos identificados encontramos:
En este sistema, los comandos se empaquetan en palabras de 32 bits, con hasta cuatro identificadores de instrucción por palabra, seguidos de sus respectivos parámetros.
Para reconstruir un modelo es necesario interpretar esta secuencia, recuperar los vértices y convertir las primitivas gráficas en triángulos. Además, un mismo módulo puede contener varias piezas geométricas relacionadas con diferentes texturas o materiales. Por tanto, no siempre existe una correspondencia directa entre un archivo
4. Texturas y paletas de Nintendo DS
Las texturas de los modelos utilizan formatos compatibles con el hardware gráfico de Nintendo DS.
A diferencia de una imagen convencional de 24 o 32 bits por píxel, muchas de estas texturas están indexadas mediante paletas de colores. Esto significa que los datos gráficos almacenan índices y que los colores reales se obtienen consultando una paleta independiente.
Entre los formatos contemplados encontramos:
Las paletas utilizan colores de 16 bits, con componentes RGB de 5 bits. También existen formatos que combinan índices de paleta con distintos niveles de transparencia. En los recursos vistos parseando la ROM, los descriptores de textura contienen información sobre el tamaño de los datos, sus dimensiones y el formato utilizado.
Algunas texturas también pueden almacenar sus píxeles mediante compresión
Cabe señalar que el formato comprimido de texturas
5. Audio: Nitro Sound y archivos SDAT
En el apartado sonoro, Pokémon Dash utiliza
Los recursos están agrupados en archivos
En la cabecera del
La tabla
Música mediante secuencias
Un detalle importante es que la música no tiene por qué almacenarse como una grabación de audio completa. Los archivos
Los archivos
Muestras de sonido SWAR
Cada archivo
En la estructura analizada, el número de muestras se encuentra en
Las muestras incluyen información sobre su codificación, frecuencia de reproducción y puntos de repetición.
Los formatos de codificación identificados son
Este último utiliza compresión diferencial para reducir el tamaño de las muestras. Por ello, recuperar los sonidos originales implica reconstruir las muestras PCM a partir de los datos comprimidos y sus parámetros de predicción.
6. Localización de los recursos en la ROM PAL
Una vez entendidas estas estructuras, podemos localizar los modelos y sonidos sin depender de direcciones absolutas previamente conocidas. Para los modelos, el recorrido es:
La dirección absoluta de un módulo se calcula sumando el offset de
De manera equivalente, la dirección absoluta de un recurso sonoro se obtiene sumando la posición del archivo
7. Resultado
Como una imagen vale más que mil palabras, aquí está el resultado de toda esta investigación:
¡Y nada más por ahora! Espero que este pequeño vistazo a las entrañas de Pokémon Dash resulte interesante para quienes disfrutan investigando los formatos y sistemas internos de Nintendo DS (Ya nos hemos casi movido entre todas las plataformas
).
1. Estructura general
Como ocurre con otros juegos de Nintendo DS, Pokémon Dash utiliza
NitroFS para organizar sus archivos. Este sistema dispone de una tabla de nombres y directorios bien documentados (FNT) y una tabla de asignación de archivos (FAT), que permiten localizar los recursos dentro de la ROM. En la versión europea, el identificador del juego es APDP, almacenado en el offset 0x0C de la cabecera. Por tanto en la cabecera completa podemos encontrar:
Código:
Offset Tamaño Contenido
0x00 12 Título: POKEMON_DASH
0x0C 4 Game Code: APDP
0x1E 1 Revisión de la ROM
0x40 4 Offset de la FNT
0x44 4 Tamaño de la FNT
0x48 4 Offset de la FAT
0x4C 4 Tamaño de la FAT
0x15E 2 CRC16 de la cabecera
FAT ocupa 8 bytes, divididos en dos valores de 32 bits que indican el inicio y el final de un archivo dentro de la ROM. Esto es importante porque los recursos no tienen por qué encontrarse en posiciones fijas entre distintas versiones del juego: su ubicación se obtiene a través de estas tablas.2. Modelos 3D y archivos RelocMod
Una de las partes más interesantes es la forma en la que Pokémon Dash almacena sus modelos 3D. En lugar de utilizar directamente archivos
NSBMD convencionales, los modelos identificados hasta ahora se encuentran dentro de un archivo llamado archive.archive, que actúa como contenedor de múltiples recursos.Este archivo comienza con la firma
NITRO Archive 1 y dispone de una tabla que permite localizar cada uno de sus miembros.
Código:
Offset Tamaño Contenido
0x00 16 Firma: NITRO Archive 1
0x10 4 Número de entradas
0x20 12 × N Tabla de entradas
Código:
+0x00 u32 Offset del nombre
+0x04 u32 Offset de los datos
+0x08 u32 Tamaño del recurso
.rel, entre ellos recursos cuyos nombres comienzan por mdl_, utilizados para almacenar modelos. Estos archivos contienen otra estructura identificada mediante la firma NITRO RelocMod 1.¿Qué es un RelocMod?
Se trata de un módulo que agrupa datos binarios junto con una tabla de reubicaciones. En lugar de interpretar todos sus valores como direcciones absolutas, el juego dispone de una lista que identifica las posiciones donde se encuentran las referencias internas.
La cabecera contiene los siguientes campos relevantes:
Código:
Offset Tamaño Contenido
0x00 16 Firma: NITRO RelocMod 1
0x10 4 Offset del bloque de datos
0x14 4 Tamaño descomprimido
0x20 4 Offset de tabla de reubicación
0x24 4 Número de reubicaciones
0x30 4 Indicador de compresión
Algunas de estas estructuras pueden encontrarse comprimidas mediante
LZ10, por lo que primero es necesario recuperar los datos originales.
Código:
archive.archive
├── Tabla de archivos
├── mdl_*.rel
│ └── NITRO RelocMod 1
│ ├── Cabecera
│ ├── Tabla de reubicaciones
│ └── Bloque de datos
│ ├── Geometría GX
│ ├── Texturas
│ ├── Paletas
│ └── Referencias internas
└── Otros recursos
3. Geometría y comandos GX
Otra peculiaridad es que la geometría no se almacena simplemente como una lista convencional de vértices e índices. Los modelos contienen listas de comandos GX, que corresponden al sistema gráfico de Nintendo DS. Estas instrucciones describen operaciones como establecer coordenadas, normales, colores, coordenadas de textura y comenzar o finalizar primitivas geométricas.
Entre los comandos identificados encontramos:
Código:
Código Comando Función
0x20 COLOR Color del vértice
0x21 NORMAL Normal del vértice
0x22 TEXCOORD Coordenadas UV
0x23 VTX_16 Posición del vértice
0x40 BEGIN_VTXS Inicio de primitiva
0x41 END_VTXS Fin de primitiva
Para reconstruir un modelo es necesario interpretar esta secuencia, recuperar los vértices y convertir las primitivas gráficas en triángulos. Además, un mismo módulo puede contener varias piezas geométricas relacionadas con diferentes texturas o materiales. Por tanto, no siempre existe una correspondencia directa entre un archivo
.rel y una única malla.4. Texturas y paletas de Nintendo DS
Las texturas de los modelos utilizan formatos compatibles con el hardware gráfico de Nintendo DS.
A diferencia de una imagen convencional de 24 o 32 bits por píxel, muchas de estas texturas están indexadas mediante paletas de colores. Esto significa que los datos gráficos almacenan índices y que los colores reales se obtienen consultando una paleta independiente.
Entre los formatos contemplados encontramos:
Código:
Código Formato
1 A3I5
2 Paleta de 4 colores
3 Paleta de 16 colores
4 Paleta de 256 colores
5 Textura comprimida 4x4
6 A5I3
7 Color directo
Código:
Offset Tipo Contenido
+0x00 u32 Referencia a píxeles
+0x04 u32 Tamaño de los datos
+0x08 u16 Ancho
+0x0A u16 Alto
+0x0C u32 Formato de textura
LZ10.Cabe señalar que el formato comprimido de texturas
4x4 todavía no está resuelto en el código analizado, por lo que no todos los recursos gráficos pueden considerarse completamente documentados.5. Audio: Nitro Sound y archivos SDAT
En el apartado sonoro, Pokémon Dash utiliza
Nitro Sound, el sistema de audio de Nintendo DS.Los recursos están agrupados en archivos
.sdat, identificados mediante la firma SDAT. Estos contenedores reúnen secuencias musicales, bancos de instrumentos, muestras de sonido y otros datos necesarios para la reproducción.
Código:
SDAT
├── SYMB Nombres de recursos
├── INFO Información y referencias
├── FAT Localización de archivos
└── FILE Datos de sonido
├── SSEQ Secuencias musicales
├── SSAR Archivos de secuencias
├── SBNK Bancos de instrumentos
└── SWAR Bancos de muestras
SDAT encontramos, entre otros, estos offsets:
Código:
Offset Tipo Contenido
0x00 4 Firma SDAT
0x04 u16 BOM
0x08 u32 Tamaño total
0x10 u32 Offset de SYMB
0x18 u32 Offset de INFO
0x20 u32 Offset de FAT
0x24 u32 Tamaño de FAT
FAT del contenedor de sonido contiene registros de 16 bytes, de los cuales los primeros ocho indican el offset y el tamaño del recurso.Música mediante secuencias
Un detalle importante es que la música no tiene por qué almacenarse como una grabación de audio completa. Los archivos
SSEQ contienen instrucciones musicales que indican qué notas deben reproducirse, con qué instrumentos y bajo qué condiciones. Los instrumentos se definen en bancos SBNK, mientras que sus muestras de sonido se encuentran en archivos SWAR. De esta manera, una misma muestra puede reutilizarse en diferentes notas, instrumentos o composiciones, reduciendo considerablemente el espacio necesario en la ROM.Los archivos
SSAR permiten agrupar varias secuencias dentro de un mismo recurso. En los nombres identificados aparecen categorías relacionadas con música, efectos de sonido y voces de Pikachu.Muestras de sonido SWAR
Cada archivo
SWAR contiene una tabla de referencias a muestras individuales.En la estructura analizada, el número de muestras se encuentra en
+0x38 respecto al inicio del archivo, seguido de una tabla de offsets de 32 bits a partir de +0x3C.Las muestras incluyen información sobre su codificación, frecuencia de reproducción y puntos de repetición.
Código:
Offset Tipo Contenido
+0x00 u8 Tipo de codificación
+0x01 u8 Indicador de loop
+0x02 u16 Frecuencia de muestreo
+0x06 u16 Inicio del loop
+0x08 u32 Longitud restante
+0x0C ... Datos de audio
PCM8, PCM16 y ADPCM.Este último utiliza compresión diferencial para reducir el tamaño de las muestras. Por ello, recuperar los sonidos originales implica reconstruir las muestras PCM a partir de los datos comprimidos y sus parámetros de predicción.
6. Localización de los recursos en la ROM PAL
Una vez entendidas estas estructuras, podemos localizar los modelos y sonidos sin depender de direcciones absolutas previamente conocidas. Para los modelos, el recorrido es:
Código:
Cabecera NDS
└── FNT / FAT
└── archive.archive
└── Tabla de entradas
└── mdl_*.rel
└── RelocMod
└── Datos GX
archive.archive en la ROM y el desplazamiento de la entrada dentro de ese archivo. En el caso del audio:
Código:
Cabecera NDS
└── FNT / FAT
└── Archivo .sdat
└── FAT de SDAT
└── SSEQ / SSAR / SBNK / SWAR
.sdat dentro de la ROM y el offset indicado por su propia tabla FAT. Esto permite trabajar con los archivos originales de la versión europea y reconstruir las relaciones entre los diferentes recursos sin tener que extraerlos manualmente uno por uno.7. Resultado
Como una imagen vale más que mil palabras, aquí está el resultado de toda esta investigación:
¡Y nada más por ahora! Espero que este pequeño vistazo a las entrañas de Pokémon Dash resulte interesante para quienes disfrutan investigando los formatos y sistemas internos de Nintendo DS (Ya nos hemos casi movido entre todas las plataformas