Buenas, os dejo por aquí un write up de ingeniería inversa de modelos y animaciones de Pokémon Stadium 2 (N64) que he añadido en mi importer para Unity "StadiumGS2Unity" como .md. Este post separa las observaciones confirmadas de las hipótesis de trabajo y mencionar que no habría sido posible sin el Scaevolus y todo el repositorio de Pret y aquellos que lo contribuyen, así que muchísimas gracias por la ayuda. A modo de ejercicio se decidió usar a Pikachu por ser el Pokémon más clásico (025 en la PokéDex) pero es funcional para todos los modelos de la ROM.
Nota: Los offsets hacen referencia a la ROM utilizada durante esta investigación, siendo ésta la versión USA recomendada por Pret para el proyecto de decompilación pokestadiumgs, con md-5: fe05fb7a1e76adcf8942b24a97748939.
1. Resumen ejecutivo
Pokemon Stadium 2 / Pokemon Stadium GS no almacena la representación completa de un modelo de batalla dentro de una única entrada de archivo. El modelo conceptual útil es:
El descubrimiento crítico fue que el valor “239” visto durante la investigación inicial del offset “0x02D7D000” no es el número de entradas del archivo. El número real es el valor de 32 bits big-endian situado en “+0x0C” respecto al inicio del archivo; para esta tabla es 282. Una vez entendido esto, la entrada de modelo Pokémon “N” ya pudo emparejarse directamente con la entrada “N” del archivo de animaciones.
Para Pikachu ("entrada 25"), esto acabó produciendo las 12 animaciones de batalla, y el decodificador de animaciones de "estilo Stadium" existente pudo reutilizarse una vez que los canales se enlazaron mediante "Bone.Channel" en lugar de mediante el índice del hueso dentro del array.
2. Archivos de recursos relevantes de la ROM
Una tabla de recursos observada en la ROM en "0x00437620" contiene 19 offsets de ROM. Las entradas relevantes para el trabajo con modelos incluyen:
Existen otros slots en la tabla de recursos, pero quedan fuera del alcance de este documento sobre modelos.
3. Estructura genérica de los archivos
Los recursos de modelos de batalla y de animaciones de batalla utilizan una estructura de archivo en la que el número real de entradas se almacena en "+0x0C" y los descriptores comienzan en "+0x10".
La rutina del juego responsable de esta búsqueda es:
4. Archivo de modelos Pokémon de batalla ("0x027ED000")
El archivo principal de modelos de batalla contiene 282 entradas. Las entradas "0..251" incluyen la secuencia de Pokémon/modelos utilizada por el juego, con entradas adicionales no estándar, de depuración o alternativas después del roster normal.
En las herramientas actuales, las etiquetas extra conocidas incluyen:
4.1 Entrada de referencia de Pikachu
Pikachu es el ejemplo canónico validado:
Lo importante no son las direcciones hardcodeadas de Pikachu en sí, sino la fórmula del descriptor:
5. Representación de modelo FRAGMENT
El payload del modelo se parsea como un grafo de objetos de estilo "FRAGMENT". El importer reconstruido lo normaliza aproximadamente en esta estructura:
Esta distinción es importante: el FRAGMENT contiene la información del lado del modelo necesaria para interpretar las animaciones, pero el banco de animaciones esqueléticas de batalla es externo y se encuentra en "0x02D7D000".
5.1 Esqueleto
Cada hueso parseado contiene al menos:
El resultado clave de la ingeniería inversa es "Bone.Channel".
No enlaces los grupos XYZ de animación de batalla mediante el índice del hueso en el array. Un hueso con "Channel = C" consume los canales de animación:
Esos tres registros corresponden a los ejes X/Y/Z de los datos de transformación de ese hueso. Los huesos con "Channel == -1" no tienen pista de animación y conservan su transformación bind/default.
Este mapeo se validó con Pikachu: el conjunto de canales de su modelo coincidía con los grupos de canales de animación de batalla decodificados, y utilizarlo produjo movimiento esquelético correcto.
6. Archivo de animaciones de batalla ("0x02D7D000")
Este archivo es paralelo al archivo de modelos de batalla :
Su número real de entradas es:
Los descriptores utilizan un stride de "0x10" y comienzan en "archive + 0x10".
6.1 Referencia del banco de animaciones de Pikachu
La entrada del archivo de animaciones es a su vez un "banco de animaciones", es decir, otra tabla de descriptores.
7. Estructura del banco de animaciones
El parser de trabajo trata el banco como otro archivo de recursos:
Para cada descriptor de animación:
Por tanto:
Para Pikachu, el banco contiene 12 animaciones.
8. Payload de animación de batalla
El decodificador actual lee primero un offset de 32 bits en "payload + 0x00". Este apunta al header real de la animación dentro del payload.
Los campos del header validados y utilizados por el decodificador son:
Todos los valores multibyte son big endian.
Una validación estructural útil es:
Por tanto, el número de grupos de transformación XYZ es:
9. Descriptores de canales
Cada registro de canal ocupa "0x0A" bytes:
Los campos "n*" y "o*" controlan el muestreo desde los bloques de datos de escala, rotación y traslación. La implementación actual reutiliza la lógica de sampling de estilo Stadium; el avance específico de GS fue encontrar el recurso correcto y enlazarlo con "Bone.Channel".
Conceptualmente, la decodificación es:
Comenzar desde la transformación bind es importante porque no todos los componentes proporcionan necesariamente valores animados en todas las situaciones.
10. Por qué fueron importantes los modelos de minijuegos
Los modelos animados de "0x02000000" ya se decodificaban correctamente antes de encontrar las animaciones de batalla. Este fue un resultado diagnóstico muy importante: demostraba que el decodificador básico de modelos y animaciones Stadium/GS era viable.
Por tanto, el problema de los modelos de batalla era principalmente de "resolución de recursos", y no una prueba de que Stadium 2 utilizara un formato de animación esquelética completamente distinto.
Una vez suministrada la entrada correcta de "0x02D7D000" a los conceptos de decodificación existentes, Pikachu se animó correctamente.
11. Animaciones de materiales / texturas
La animación esquelética es solo la mitad de una animación de Pokémon en Stadium. Ojos, bocas y otras texturas que cambian se representan por separado como "AuxAnimations" asociadas al FRAGMENT del modelo.
La representación normalizada es:
Las primitivas referencian canales de animación de textura mediante su campo "TextureAnimation".
"AnimationData" contiene:
de modo que un clip esquelético puede emparejarse con la correspondiente animación de materiales.
11.1 Mapeo de Pikachu
Para Pikachu, comparar los números de frames y comprobar que la AuxAnimation realmente afecta a canales de animación de textura referenciados por el modelo produjo los siguientes mapeos inequívocos:
La animación de batalla "00" tiene 40 frames y no presentó una coincidencia única exacta de número de frames con ninguna AuxAnimation durante la pasada de diagnóstico. Aux 05 tiene 42 frames y parecía superficialmente plausible, pero ya es la coincidencia exacta para la animación de batalla 06, por lo que NO debe asignarse a la animación 00 sin evidencias más sólidas.
Las AuxAnimations 09, 10 y 13 tampoco tuvieron una correspondencia directa con clips de batalla en la prueba de Pikachu. Esto demuestra que no debe asumirse que las AuxAnimations forman un array estrictamente 1:1 paralelo a las animaciones esqueléticas de batalla.
11.2 Asociación automática segura
La regla conservadora actual es:
1. recopilar los canales de animación de textura realmente referenciados por las primitivas del modelo;
2. considerar únicamente AuxAnimations que contengan datos para al menos uno de esos canales;
3. exigir una coincidencia exacta de "FrameCount" con el clip esquelético;
4. asignar únicamente cuando exactamente una AuxAnimation cumpla esas condiciones;
5. en caso contrario, dejar `AuxAnimation = -1`.
Esto produjo animaciones correctas de ojos/materiales en los clips de Pikachu validados sin realizar suposiciones en los casos ambiguos.
12. Algoritmo práctico del importer
Ahora puede implementarse aproximadamente una importación de Pokémon de batalla del siguiente modo:
13. Modos de fallo importantes
- Tratar "239" como el número de entradas del archivo
Esta fue la principal pista falsa. Para "0x02D7D000", utiliza el campo de número de entradas en "+0x0C": 282
Buscar las animaciones de batalla dentro de la entrada del modelo
El FRAGMENT contiene metadatos del lado del modelo para animación/materiales, pero el banco real de animaciones esqueléticas de batalla se encuentra en el archivo paralelo separado "0x02D7D000".
- Enlazar mediante índice de hueso
Esto puede producir una animación que parece plausible pero es incorrecta. Utiliza "Bone.Channel".
Suponer que cada AuxAnimation corresponde 1:1 a una animación de batalla
Pikachu demuestra que esta suposición es falsa. Utiliza evidencias como el número de frames y los canales de textura referenciados, y deja sin asignar los clips ambiguos.
- Recolorear materiales estáticos pero no las referencias animadas a materiales
Los ojos/materiales de la variante volverán a los normales cada vez que la curva de animación cambie de material. Clona/remapea primero las referencias de materiales de la animación.
- Suponer que las tablas HUE de Stadium 1 son completas para Stadium 2
Son útiles como guía, no como prueba para las entradas de Generación II. Mantén separados los datos verificados del juego de los fallbacks del importer.
14. Confirmado frente a todavía provisional
Confirmado / fuertemente validado:
- Archivo de modelos de batalla en "0x027ED000".
- El número de entradas en "+0x0C" es 282.
- Archivo de animaciones de batalla en "0x02D7D000".
- Relación directa por índice de entrada entre modelo de batalla y banco de animaciones, validada con Pikachu y utilizada por el importer genérico.
- Stride de descriptor de "0x10" y direccionamiento relativo de payload utilizado por el parser funcional.
- Descriptor/payload del modelo de Pikachu y descriptor/payload de su banco de animaciones indicados anteriormente.
- El banco de Pikachu se decodifica en las 12 animaciones esqueléticas de batalla .
- "Bone.Channel" es el mecanismo correcto de enlace de canales de transformación.
- Las AuxAnimations controlan cambios de material/textura como los ojos.
- Los 11 mapeos exactos de Pikachu entre animaciones esqueléticas/Aux indicados anteriormente funcionan visualmente.
- El archivo de minijuegos "0x02000000" contiene modelos importables/animables de forma independiente.
Provisional / incompleto
- Nombres semánticos completos para todos los campos genéricos de los descriptores de archivo más allá de offset/size.
- Significado exacto de todos los flags del header de animación y variantes de interpolación.
- Asociación de animación de materiales para la animación de batalla 00 de Pikachu.
- Propósito de cada AuxAnimation sin correspondencia.
- Reglas exactas de generación HUE/color de Stadium 2 para todas las especies de Generación II.
- Semántica completa del archivo de color/LUT "0x03FD5000".
- Etiquetas para muchas entradas de modelo no estándar posteriores al roster normal.
15. Referencia: Pikachu de principio a fin
Este ejemplo es útil como objetivo conocido y correcto al implementar un extractor desde cero: si la entrada 25 no resuelve a estos recursos para la misma revisión de ROM, corrige primero el direccionamiento del archivo antes de depurar el sampler de animaciones.
16. Resultado
Como una imagen vale más que mil palabras, aquí está el resultado de toda esta investigación:

17. Créditos
La investigación se realizó de forma independiente durante el desarrollo de StadiumGS2Unity, comparando con la implementación de Pokemon Stadium 1 y con la decompilación incompleta "pret/pokestadiumgs". Scaevolus, colaborador del proyecto pokestadiumgs de Pret, proporcionó la información decisiva de que la tabla "0x02D7D000" contiene las animaciones de batalla, que su número real de entradas se encuentra en "+0x0C" (282), las direcciones conocidas y correctas de los recursos de Pikachu y la referencia "GetOrLoadResourceArchiveEntry @ 0x80104A40". Estas pistas se validaron posteriormente contra la ROM y se integraron en el importer funcional. Una vez más, mil gracias a todo el equipo que se dedica horas y horas a hacer ingeniería inversa de todas nuestras ROMs favoritas.
Nota: Los offsets hacen referencia a la ROM utilizada durante esta investigación, siendo ésta la versión USA recomendada por Pret para el proyecto de decompilación pokestadiumgs, con md-5: fe05fb7a1e76adcf8942b24a97748939.
1. Resumen ejecutivo
Pokemon Stadium 2 / Pokemon Stadium GS no almacena la representación completa de un modelo de batalla dentro de una única entrada de archivo. El modelo conceptual útil es:
Código:
Entrada de Pokémon N
|
+-- archivo de modelos 0x027ED000, entrada N
| +-- modelo FRAGMENT
| +-- esqueleto / mapeo Bone.Channel
| +-- meshes / datos de display-list
| +-- texturas + TLUTs
| +-- AuxAnimations (datos de animación de materiales / texturas)
|
+-- archivo de animaciones de batalla 0x02D7D000, entrada N
+-- banco de animaciones
+-- animación 0
+-- animación 1
+-- ...
Para Pikachu ("entrada 25"), esto acabó produciendo las 12 animaciones de batalla, y el decodificador de animaciones de "estilo Stadium" existente pudo reutilizarse una vez que los canales se enlazaron mediante "Bone.Channel" en lugar de mediante el índice del hueso dentro del array.
2. Archivos de recursos relevantes de la ROM
Una tabla de recursos observada en la ROM en "0x00437620" contiene 19 offsets de ROM. Las entradas relevantes para el trabajo con modelos incluyen:
Código:
| Recurso | Offset ROM | Notas |
|---|---:|---|
| Archivo de modelos de minijuegos / miscelánea | `0x02000000` | 227 entradas en el importer actual; los modelos animados de minijuegos fueron los primeros modelos GS importados correctamente. |
| Archivo de modelos Pokémon de batalla| `0x027ED000` | 282 entradas. Recursos principales FRAGMENT/modelo de Pokémon. |
| Archivo de animaciones de batalla| `0x02D7D000` | 282 entradas; la entrada `N` corresponde a la entrada `N` del modelo de batalla. |
| Archivo relacionado con color / LUT | `0x03FD5000` | Relevante para el trabajo de color/HUE de Stadium; su semántica exacta no está completamente documentada aquí. |
3. Estructura genérica de los archivos
Los recursos de modelos de batalla y de animaciones de batalla utilizan una estructura de archivo en la que el número real de entradas se almacena en "+0x0C" y los descriptores comienzan en "+0x10".
Código:
struct ResourceArchive {
// los campos en +0x00 .. +0x0B no están completamente descritos aquí
u32 count; // +0x0C, big endian
ResourceEntry entries[];// +0x10
};
struct ResourceEntry {
u32 offset; // +0x00, relativo a la base del archivo/banco
u32 paddedSize; // +0x04
u32 unknown08; // +0x08
u32 unknown0C; // +0x0C
}; // 0x10 bytes
Código:
GetOrLoadResourceArchiveEntry @ runtime 0x80104A40
El archivo principal de modelos de batalla contiene 282 entradas. Las entradas "0..251" incluyen la secuencia de Pokémon/modelos utilizada por el juego, con entradas adicionales no estándar, de depuración o alternativas después del roster normal.
En las herramientas actuales, las etiquetas extra conocidas incluyen:
Código:
- `252` - Substitute Doll (muñeco sustituto estilo Rhydon)
- `253` - Egg
- `254..278` - Unown (formas alternativas del alfabeto)
- `279` - Pikachu (posiblemente debug)
- `280` - Poke Ball
- `281` - Ho-Oh (posiblemente debug)
Pikachu es el ejemplo canónico validado:
Código:
Archivo de modelos: 0x027ED000
Entrada: 25
Descriptor de entrada: 0x027ED1A0
Payload del modelo: 0x02893A20
Tamaño padded del modelo: 0x00007FA0
Código:
descriptor = archive + 0x10 + entryIndex * 0x10
payload = archive + descriptor.offset
El payload del modelo se parsea como un grafo de objetos de estilo "FRAGMENT". El importer reconstruido lo normaliza aproximadamente en esta estructura:
Código:
FragmentModel
{
int Species;
string Name;
Vector3 RootScale;
List<BoneData> Bones;
List<TextureRecord> Textures;
List<TlutRecord> Tluts;
List<PrimitiveData> Primitives;
List<AnimationData> Animations;
List<AuxAnimationData> AuxAnimations;
}
5.1 Esqueleto
Cada hueso parseado contiene al menos:
Código:
BoneData
{
int Parent;
int BoneId;
int Channel;
byte Flags;
Vector3 Translation;
Vector3 RotationUnits;
Vector3 Scale;
}
No enlaces los grupos XYZ de animación de batalla mediante el índice del hueso en el array. Un hueso con "Channel = C" consume los canales de animación:
Código:
C*3 + 0
C*3 + 1
C*3 + 2
Este mapeo se validó con Pikachu: el conjunto de canales de su modelo coincidía con los grupos de canales de animación de batalla decodificados, y utilizarlo produjo movimiento esquelético correcto.
6. Archivo de animaciones de batalla ("0x02D7D000")
Este archivo es paralelo al archivo de modelos de batalla :
Código:
entrada N del archivo de modelos <--> entrada N del archivo de animaciones
Código:
BE32(0x02D7D000 + 0x0C) = 282
6.1 Referencia del banco de animaciones de Pikachu
Código:
Archivo de animaciones: 0x02D7D000
Entrada: 25
Descriptor de entrada: 0x02D7D1A0
Payload del banco de animaciones: 0x02F5A100
Tamaño padded del banco: 0x0001A0B0
7. Estructura del banco de animaciones
El parser de trabajo trata el banco como otro archivo de recursos:
Código:
bank + 0x0C -> animationCount (BE32)
bank + 0x10 + i * 0x10 -> descriptor de animación i
Código:
+0x00 -> payloadOffset, relativo a la base del banco
+0x04 -> payloadSize
Código:
animationPayloadROM = bankROM + payloadOffset
8. Payload de animación de batalla
El decodificador actual lee primero un offset de 32 bits en "payload + 0x00". Este apunta al header real de la animación dentro del payload.
Código:
u32 headerOffset = BE32(payload + 0x00);
Código:
| Offset del header | Tipo | Significado |
|---|---|---|
| `+0x00` | `u8` | flags |
| `+0x06` | `u16` | inicio del loop |
| `+0x08` | `u16` | número de canales |
| `+0x0A` | `u16` | número de frames |
| `+0x0C` | `u32` | offset de la tabla de canales |
| `+0x10` | `u32` | offset de datos de escala |
| `+0x14` | `u32` | offset de datos de rotación |
| `+0x18` | `u32` | offset de datos de traslación |
Una validación estructural útil es:
Código:
channelCount > 0
channelCount % 3 == 0
frameCount > 0
Código:
xyzGroupCount = channelCount / 3
Cada registro de canal ocupa "0x0A" bytes:
Código:
struct AnimationChannel {
u8 nScale; // +0x00
u8 nRotation; // +0x01
u8 nTranslation; // +0x02
u8 interpolation; // +0x03
u16 oScale; // +0x04
u16 oRotation; // +0x06
u16 oTranslation; // +0x08
};
Conceptualmente, la decodificación es:
Código:
para cada hueso del modelo:
si bone.Channel < 0:
continuar
firstChannel = bone.Channel * 3
para cada frame:
comenzar con translation / rotation / scale bind del hueso
para axis X,Y,Z:
descriptor = channelTable + (firstChannel + axis) * 0x0A
samplear translation
samplear rotation
samplear scale
almacenar TrackData[bone][frame]
10. Por qué fueron importantes los modelos de minijuegos
Los modelos animados de "0x02000000" ya se decodificaban correctamente antes de encontrar las animaciones de batalla. Este fue un resultado diagnóstico muy importante: demostraba que el decodificador básico de modelos y animaciones Stadium/GS era viable.
Por tanto, el problema de los modelos de batalla era principalmente de "resolución de recursos", y no una prueba de que Stadium 2 utilizara un formato de animación esquelética completamente distinto.
Una vez suministrada la entrada correcta de "0x02D7D000" a los conceptos de decodificación existentes, Pikachu se animó correctamente.
11. Animaciones de materiales / texturas
La animación esquelética es solo la mitad de una animación de Pokémon en Stadium. Ojos, bocas y otras texturas que cambian se representan por separado como "AuxAnimations" asociadas al FRAGMENT del modelo.
La representación normalizada es:
Código:
AuxAnimationData
{
int Index;
int FrameCount;
int LoopStart;
byte Flags;
int[][] Channels;
}
"AnimationData" contiene:
Código:
int AuxAnimation = -1;
11.1 Mapeo de Pikachu
Para Pikachu, comparar los números de frames y comprobar que la AuxAnimation realmente afecta a canales de animación de textura referenciados por el modelo produjo los siguientes mapeos inequívocos:
Código:
| Animación de batalla | Frames | AuxAnimation | Frames |
|---:|---:|---:|---:|
| 01 | 122 | 03 | 122 |
| 02 | 80 | 00 | 80 |
| 03 | 107 | 01 | 107 |
| 04 | 71 | 02 | 71 |
| 05 | 103 | 04 | 103 |
| 06 | 42 | 05 | 42 |
| 07 | 83 | 06 | 83 |
| 08 | 94 | 08 | 94 |
| 09 | 200 | 07 | 200 |
| 10 | 120 | 11 | 120 |
| 11 | 90 | 12 | 90 |
Las AuxAnimations 09, 10 y 13 tampoco tuvieron una correspondencia directa con clips de batalla en la prueba de Pikachu. Esto demuestra que no debe asumirse que las AuxAnimations forman un array estrictamente 1:1 paralelo a las animaciones esqueléticas de batalla.
11.2 Asociación automática segura
La regla conservadora actual es:
1. recopilar los canales de animación de textura realmente referenciados por las primitivas del modelo;
2. considerar únicamente AuxAnimations que contengan datos para al menos uno de esos canales;
3. exigir una coincidencia exacta de "FrameCount" con el clip esquelético;
4. asignar únicamente cuando exactamente una AuxAnimation cumpla esas condiciones;
5. en caso contrario, dejar `AuxAnimation = -1`.
Esto produjo animaciones correctas de ojos/materiales en los clips de Pikachu validados sin realizar suposiciones en los casos ambiguos.
12. Algoritmo práctico del importer
Ahora puede implementarse aproximadamente una importación de Pokémon de batalla del siguiente modo:
Código:
INPUT: entrada de Pokémon N
1. Leer el archivo de modelos 0x027ED000.
2. Leer el descriptor en 0x027ED000 + 0x10 + N*0x10.
3. Decodificar/parsear su payload FRAGMENT.
4. Construir esqueleto, meshes, texturas, TLUTs, primitivas y AuxAnimations.
5. Leer el archivo de animaciones 0x02D7D000.
6. Verificar N < BE32(archive + 0x0C).
7. Leer el descriptor del banco de animaciones en archive + 0x10 + N*0x10.
8. Abrir el banco en archive + descriptor.offset.
9. Leer animationCount en bank + 0x0C.
10. Para cada descriptor de animación del banco:
a. localizar el payload relativo a la base del banco;
b. leer el offset interno del header desde payload +0x00;
c. parsear frame count, loop, tabla de canales y bloques S/R/T;
d. para cada hueso, utilizar Bone.Channel*3 como su grupo XYZ;
e. samplear los frames en TrackData.
11. Sustituir/adjuntar la lista de animaciones esqueléticas del modelo.
12. Emparejar de forma conservadora las AuxAnimations útiles con los clips esqueléticos.
13. Exportar meshes/materiales/texturas.
14. Crear clips de animación de Unity y curvas/callbacks de animación de materiales.
15. Crear el prefab.
- Tratar "239" como el número de entradas del archivo
Esta fue la principal pista falsa. Para "0x02D7D000", utiliza el campo de número de entradas en "+0x0C": 282
Buscar las animaciones de batalla dentro de la entrada del modelo
El FRAGMENT contiene metadatos del lado del modelo para animación/materiales, pero el banco real de animaciones esqueléticas de batalla se encuentra en el archivo paralelo separado "0x02D7D000".
- Enlazar mediante índice de hueso
Esto puede producir una animación que parece plausible pero es incorrecta. Utiliza "Bone.Channel".
Suponer que cada AuxAnimation corresponde 1:1 a una animación de batalla
Pikachu demuestra que esta suposición es falsa. Utiliza evidencias como el número de frames y los canales de textura referenciados, y deja sin asignar los clips ambiguos.
- Recolorear materiales estáticos pero no las referencias animadas a materiales
Los ojos/materiales de la variante volverán a los normales cada vez que la curva de animación cambie de material. Clona/remapea primero las referencias de materiales de la animación.
- Suponer que las tablas HUE de Stadium 1 son completas para Stadium 2
Son útiles como guía, no como prueba para las entradas de Generación II. Mantén separados los datos verificados del juego de los fallbacks del importer.
14. Confirmado frente a todavía provisional
Confirmado / fuertemente validado:
- Archivo de modelos de batalla en "0x027ED000".
- El número de entradas en "+0x0C" es 282.
- Archivo de animaciones de batalla en "0x02D7D000".
- Relación directa por índice de entrada entre modelo de batalla y banco de animaciones, validada con Pikachu y utilizada por el importer genérico.
- Stride de descriptor de "0x10" y direccionamiento relativo de payload utilizado por el parser funcional.
- Descriptor/payload del modelo de Pikachu y descriptor/payload de su banco de animaciones indicados anteriormente.
- El banco de Pikachu se decodifica en las 12 animaciones esqueléticas de batalla .
- "Bone.Channel" es el mecanismo correcto de enlace de canales de transformación.
- Las AuxAnimations controlan cambios de material/textura como los ojos.
- Los 11 mapeos exactos de Pikachu entre animaciones esqueléticas/Aux indicados anteriormente funcionan visualmente.
- El archivo de minijuegos "0x02000000" contiene modelos importables/animables de forma independiente.
Provisional / incompleto
- Nombres semánticos completos para todos los campos genéricos de los descriptores de archivo más allá de offset/size.
- Significado exacto de todos los flags del header de animación y variantes de interpolación.
- Asociación de animación de materiales para la animación de batalla 00 de Pikachu.
- Propósito de cada AuxAnimation sin correspondencia.
- Reglas exactas de generación HUE/color de Stadium 2 para todas las especies de Generación II.
- Semántica completa del archivo de color/LUT "0x03FD5000".
- Etiquetas para muchas entradas de modelo no estándar posteriores al roster normal.
15. Referencia: Pikachu de principio a fin
Código:
Pokémon: Pikachu
Entrada: 25
MODELO
archivo 0x027ED000
descriptor 0x027ED1A0
payload 0x02893A20
tamaño padded 0x00007FA0
ANIMACIONES DE BATALLA
archivo 0x02D7D000
descriptor 0x02D7D1A0
payload del banco 0x02F5A100
tamaño padded 0x0001A0B0
animaciones 12
CARGADOR DE RECURSOS
runtime GetOrLoadResourceArchiveEntry @ 0x80104A40
16. Resultado
Como una imagen vale más que mil palabras, aquí está el resultado de toda esta investigación:

17. Créditos
La investigación se realizó de forma independiente durante el desarrollo de StadiumGS2Unity, comparando con la implementación de Pokemon Stadium 1 y con la decompilación incompleta "pret/pokestadiumgs". Scaevolus, colaborador del proyecto pokestadiumgs de Pret, proporcionó la información decisiva de que la tabla "0x02D7D000" contiene las animaciones de batalla, que su número real de entradas se encuentra en "+0x0C" (282), las direcciones conocidas y correctas de los recursos de Pikachu y la referencia "GetOrLoadResourceArchiveEntry @ 0x80104A40". Estas pistas se validaron posteriormente contra la ROM y se integraron en el importer funcional. Una vez más, mil gracias a todo el equipo que se dedica horas y horas a hacer ingeniería inversa de todas nuestras ROMs favoritas.
Última edición: