Registrarse

[Decomp-GBA] Formato de los mapas de pokeemerald para la creación de herramientas.

Driox24

Usuario de platino
Hola!! Llevo unos días programando un lector de mapas de gba (que ya ha sido terminado y funciona), el cual genera la imagen del mapa indicado del repositorio. Este lo planeo utilizar en otro proyecto más grande, si tengo tiempo.

Pero la razon de crear este tema, es para dar a conocer el formato de los binarios que tienen los mapas de pokemon esmeralda decompilado, ya que son archivos que se deben leer en hexadecimal, y hasta donde yo se no se almacenan en otro archivo más legible que esos binarios (y si no me he estado complicando la vida innecesariamente xDD). Esto lo hago con el propósito de que la gente se ahorre el investigar por si misma estos archivos, cuando quiera desarrollar un programa que pueda interpretarlos, ya que aun que no son demasiado complejos, es un poco tedioso andar entendiendo su estructura desde cero.

- Antes de comenzar quiero aclarar varias cosas:
  • La información que voy a dar a continuación ha sido comprobada en pokeemerald, desconozco sin en pokeruby o pokefirered las estructuras serán las mismas, pero si en un futuro lo compruebo lo pondré aquí, si es posible.
  • Con esta información se da a conocer como leer los metatiles que se usan para formar el mapa y como leer los metatiles que contiene un tileset.
  • Solo voy a dar la información de como están escritos los archivos .bin pertinentes, pero no como leerlos mediante un código, ya que eso depende del lenguaje de programación que use cada uno y sus conocimientos sobre este.
  • Se necesitan conocimientos básicos de hexadecimal para entender bien esta información.
Para comenzar, es necesario entender la forma de la que se organizan los mapas en pokeemerald.

Tenemos los siguientes directorios y archivos:
  • "tuRepositorio\data\maps\": en este directorio, lo que nos importa son las carpetas correspondientes a cada mapa, estas tienen el nombre del mapa que almacenan. Dentro de ella encontramos un archivo necesario para obtener información del mapa que hace falta para lerlo más adelante, el cual es el "map.json". Este archivo contiene la información básica del mapa, como nombres internos, música que utiliza, eventos, etc... Pero de aquí la que nos interesa es la propiedad "layout".

    La propiedad layout contiene el identificador del layout del mapa en cuestión, que es el que contiene la información como los tiles de ancho y alto del mapa, que pueden ser de utilidad para distintas cosas, como por ejemplo, generar una imagen del mismo.

  • "tuRepositorio/data/layouts/": en este directorio, al igual que en el anterior, encontramos una carpeta correspondiente a cada mapa, y otro archivo, llamado "layouts.json". Dentro de este archivo Json, se encuentra un grupo con la etiqueta "layouts", el cual contiene propiedades de cada mapa como el identificador del layout o id (que se corresponde a la propiedad "layout" mencionada en el anterior punto, y mediante la cual podremos buscar las propiedades del mapa que deseamos leer), y otras propiedades muy importantes como su tileset primario ("primary_tileset"), secundario ("secondary_tileset"), el directorio del archivo map.bin ("blockdata_filepath"), su borde ("border_filepath"), sus tiles de ancho ("width") y sus tiles de alto ("height").

    Con los datos obtenidos de este archivo json, podemos determinar por ejemplo el tamaño que debe tener nuestra imagen del mapa, en caso de querer generarla, con la siguiente "fórmula":
    Tamaño de imagen (ancho, alto) = (tilesAncho * 16, tilesAlto * 16).

    Pero lo que más nos interesa aquí son los tres siguientes datos: el directorio del layout.bin del mapa, su tileset primario, y su tileset secundario.

  • "map.bin": este archivo que hemos podido obtener con la información del punto anterior, es uno de los archivos binarios cuyo funcionamiento voy a explicar después. Contiene la información de los metatiles que componen el mapa, y los permisos que tiene este.

  • "tuRepositorio/data/tilesets/": en este directorio, se encuentran los tilesets que utilizan los mapas, es necesario leer algunos archivos de estos para poder generar una imagen del mapa. En este directorio se encuentran dos carpetas, una llamada "primary" que contiene los tilesets primarios, y otra llamada "secondary" que contiene los tilesets secundarios.

  • "tuRepositorio/data/tilesets/(primary_o_secondary)/nombreDelTileset/": dentro de la carpeta de un tileset, encontramos lo siguiente:
    • Un archivo llamado "metatiles.bin", que contiene la información de cada metatile que posee el tileset.
    • Un archivo (imagen .png) "tiles.png", que contiene los bloques del tileset. Cabe aclarar que los metatiles son las piezas con las que se dibujan los mapas (16x16px) y están formados por tiles (8x8px) con una paleta determinada, ambos correspondientes al tileset en cuestión.
    • Una carpeta "palettes", que contiene las paletas que utiliza el tileset, en archivos .pal.
Una vez sabiendo esta información, paso a explicar la estructura de los archivos .bin ya nombrados:
El archivo map.bin, es un archivo en el que se encuentra la información de los metatiles que conforman el mapa y los permisos que tienen asignados.

Por cada metatile, tenemos una pareja de bytes (2 Bytes), es decir, que si por ejemplo tuviesemos un mapa que mide 10 tiles de ancho x 10 de alto, tendríamos:
10 x 10 = 100 x 2 = 200 Bytes en el archivo.

Los metatiles que utiliza el mapa se definen desde la esquina superior izquierda, hasta la inferior derecha, recorriendo el mapa de forma horizontal, empezando siempre por la izquierda.

A continuación, explicaré como interpretar cada pareja de bytes o metatile:

Sabiendo que un metatile es una pareja de bytes, tenemos XX YY. (Byte XX y Byte YY).
  • El byte XX, indica las dos ultimas cifras del offset del metatile usado en esa posición. Es decir, que si XX fuese D0, el offset sería 0x?D0, pero, ¿dónde se encuentra la primera cifra del offset? La respuesta está en el byte YY.

  • El byte YY, es más complejo que el XX, debido a que este contiene información sobre el permiso de la casilla del mapa, y la primera cifra del offset del metatile.
    Para entender el byte YY, vamos a separar su dos cifras, siendo su primera cifra A, y su segunda cifra B.
    Según sean la cifra A y B se pueden dar dos casos:
    • Cifra A es un valor entre 0 y F, y cifra B es un valor entre 0 y 3: en este caso, la casilla del mapa es caminable, la cifra A indica el permiso asignado (de la columna izquierda de permisos de porymap), y la cifra B, la primera cifra del offset del metatile.

      Cifra A ---> Permiso
      --------------------------
      0 ----------> Transition between elevations
      1 ----------> Surf
      2 ----------> Passable elevation 2
      3 ----------> Passable elevation 3
      4 ----------> Passable elevation 4
      5 ----------> Passable elevation 5
      6 ----------> Passable elevation 6
      7 ----------> Passable elevation 7
      8 ----------> Passable elevation 8
      9 ----------> Passable elevation 9
      A ----------> Passable elevation 10
      B ----------> Passable elevation 11
      C ----------> Passable elevation 12
      D ----------> Passable elevation 13
      E ----------> Passable elevation 14
      F ----------> Multi-Level Bridge

    • Cifra A es un valor entre 0 y F, y la cifra B es 4, 5, 6 o 7: en este caso, la casilla del mapa NO es caminable, la cifra A indica el permiso asignado (de la columna derecha de permisos del porymap), y la cifra B, indica la primera cifra del offset del metatile, interpretandose según lo siguiente:

      Cifra B ---> Valor
      ----------------------
      4 ---------------> 0
      5 ---------------> 1
      6 ---------------> 2
      7 ---------------> 3

      Cifra A ---> Permiso
      --------------------------
      0 ----------> Impassable elevation 0 (Red X)
      1 ----------> Impassable elevation 1
      2 ----------> Impassable elevation 2
      3 ----------> Impassable elevation 3
      4 ----------> Impassable elevation 4
      5 ----------> Impassable elevation 5
      6 ----------> Impassable elevation 6
      7 ----------> Impassable elevation 7
      8 ----------> Impassable elevation 8
      9 ----------> Impassable elevation 9
      A ----------> Impassable elevation 10
      B ----------> Impassable elevation 11
      C ----------> Impassable elevation 12
      D ----------> Impassable elevation 13
      E ----------> Impassable elevation 14
      F ----------> Impassable elevation 15

      Con esto, ya podríamos entender el significado de cada byte. Unos ejemplos para que quede más claro:

      Metatile con bytes 70 11: offset del metatile -> 0x170; permiso de la casilla -> surf (Primer caso de YY)
      Metatile con bytes 75 05: offset del metatile -> 0x175; permiso de la casilla -> Impassable elevation 0 (Red X) (Segundo caso de YY)
      Metatile con bytes 6B 04: offset del metatile -> 0x06B; permiso de la casilla -> Impassable elevation 0 (Red X) (Segundo caso de YY)

      IMPORTANTE: cada metatile pertenece a un tileset, el primario o el secundario, y se puede determinar según la primera cifra del offset. Si esta es 0 o 1, el metatile pertenece al tileset primario, y si es 2 o 3, al secundario.
Con esto, quedaría explicada la estructura del map.bin. Pero si queremos hacer una imagen de este, necesitaríamos la imagen de cada uno de los metatiles que usa el mapa, y para eso necesitamos entender el "metatiles.bin" de los tilesets.
El archivo metatiles.bin, es un archivo que se encuentra en cada tileset del repositorio, el cual contiene información sobre los metatiles que posee el tileset y que posteriormente se utilizan para conformar mapas.

Antes de explicar esto, hay que recordar los siguientes conceptos:
  • Tile: un tile es la unidad gráfica mínima del tileset y mide 8x8 pixeles. Los tiles que tiene un tileset, se encuentran en la imagen tiles.png de su carpeta.
  • Metatile: el metatile o bloque, es un conjunto de 8 tiles, divididos en dos capas: la inferior y la superior. Están formados por los tiles de la imagen tiles.png, a los cuales han sido aplicados una paleta, y es posible que invertidos de forma horizontal, vertical, o ambas. Los metatiles son los que se usan para construir los mapas.
  • Offset del metatile: en la explicación del map.bin, no paraba de mencionar "offset del metatile", pero ¿qué es el offset del metatile?, pues es la posición en la que está definido ese metatile en el metatiles.bin del tileset al que corresponde.
Una vez sabiendo esto, voy a explicar la estructura del archivo metatiles.bin:

En este archivo, cada metatile viene definido por grupos de 16 bytes, de los cuales los 8 primeros determinan la primera capa del metatile y los 8 ultimos la segunda capa del metatile.

AA AA AA AA AA AA AA AA BB BB BB BB BB BB BB BB

Grupo de bytes AA -> Primera capa
Grupo de bytes BB -> Segunda capa

Tanto la estructura de la primera capa (8 primeros bytes) como la de la segunda (8 ultimos bytes), es exactamente igual.

Dentro de cada capa, los 8 bytes que la definen se agrupan en parejas, cada una definiendo el tile que utiliza, la paleta que le aplica, y los flips que le aplica.
Estos tiles se definen desde la esquina superior izquierda a la esquina inferior derecha de la capa, horizontalmente siempre de izquierda a derecha.

Ahora explicaré como interpretar cada pareja de bytes:

Sabiendo que cada tile viene definido por una pareja de Bytes, tenemos XX YY (Byte XX, Byte YY)

  • El byte XX, indica las dos últimas cifras del offset o posición del tile en la imagen tiles.png. Si XX fuera por ejemplo 02, el offset sería 0x?02. Como pasaba anteriormente, aquí la primera cifra del offset viene dada por el byte YY.

  • El byte YY, indica la paleta que está utilizando el tile, y la primera cifra del offset del tile en la imagen tiles.png. Para entender este byte, separaremos sus dos cifras, llamemos a su primera cifra A, y a su segunda cifra B.
    • La cifra A, sencillamente indica la paleta que está utilizando el tile en cuestión.

    • La cifra B, es la primera cifra del offset del tile, y tiene un comportamiento especial, que depende del X flip y el Y flip que se le haya aplicado al tile en cuestión. Se puede interpretar según la siguiente tabla:

      Cifra B --------> Valor --------> Flips aplicados
      ----------------------------------------------------------
      0 ------------------> 0 -----------> No flip
      1 ------------------> 1 -----------> No flip
      2 ------------------> 2 -----------> No flip
      3 ------------------> 3 -----------> No flip
      4 ------------------> 0 -----------> X flip
      8 ------------------> 0 -----------> Y flip
      C ------------------> 0 -----------> XY flip
      5 ------------------> 1 -----------> X flip
      9 ------------------> 1 -----------> Y flip
      D ------------------> 1 -----------> XY flip
      6 ------------------> 2 -----------> X flip
      A ------------------> 2 -----------> Y flip
      E ------------------> 2 -----------> XY flip
      7 ------------------> 3 -----------> X flip
      B ------------------> 3 -----------> Y flip
      F ------------------> 3 -----------> XY flip
Con esta información, ya podríamos leer en metatiles.bin, con el código pertinente. Unos ejemplos para que quede más claro:
Tile con bytes 02 20: offset del tile -> 0x002; paleta del tile -> 2; Flips: ninguno
Tile con bytes 16 24: offset del tile -> 0x016; paleta del tile -> 2; Flips: X flip
Tile con bytes F3 45: offset del tile -> 0x1F3; paleta del tile -> 4; Flips: X flip

Finalmente, ¿qué indica exactamente el offset del tile? Indica la posición en la que el tile está en la imagen tiles.png, es decir, si por ejemplo el offset fuera 0x002, el tile en la imagen, sería el tercero, empezando a contar desde la esquina superior izquierda hasta la inferior derecha, de forma horizontal (siempre de izquierda a derecha).

Veamoslo de forma más gráfica:

Imaginad que el tileset es este (tiene 3 tiles de ancho y 4 de alto):




Esa sería la forma de enumerar los tiles que están en la imagen, en mi caso ahí los he enumerado en decimal, por lo que si el offset fuese por ejemplo 0x00A, tendría que pasarlo a decimal, que sería el tile 10.

Pues esto simplemente, hay que aplicarlo sobre el tiles.png del tileset en cuestión que obviamente, es mas grande.

Cabe aclarar, que los offsets cuya primera cifra sea 0 o 1, pertenecen a la imagen del tile set primario, y los offsets cuya primera cifra sea 2 o 3, pertenecen a la imagen del tileset secundario.

Con esto, estaría explicada la estructura del metatiles.bin

Y esto sería todo sobre el formato del map.bin de los mapas y el metatiles.bin de los tilesets. A partir de aquí ya cada uno debe saber cómo utilizar esta información para conseguir hacer lo que tenga en mente.

Se que es una información que probablemente no se vaya a utilizar mucho, pero bueno, siempre es bueno que esté ahi por si llega a necesitarse para algo.

Un saludo!!
 

Galoc

Pequeño saltamontes
Muchas gracias por la informacion. Usando pokemon emerald decomp, leyendo este post y leyendo el codigo de Porymap, pude extraer mucha data. Mi unico problema es que no se como generar los tiles con colores. Tal vez eso sea algo que podrias agregar a tu post ya que ayudaria a crear herramientas para mapas.

Edit:
Al igual que tu, tambien estoy creando una herramienta para crear el mapa completo. Lo unico que faltan son los colores y algunas cositas relacionadas al offset de un mapa y otro. Me interesaria saber mas de tu proyecto, tal vez me pueda ayudar con el mio. Saludos!
 
Arriba