[Projekt] Extracting Ace Combat

Hier könnt ihr euch selbst, eure Homepage, euren Entwicklerstammtisch, Termine oder eure Projekte vorstellen.
Forumsregeln
Bitte Präfixe benutzen. Das Präfix "[Projekt]" bewirkt die Aufnahme von Bildern aus den Beiträgen des Themenerstellers in den Showroom. Alle Bilder aus dem Thema Showroom erscheinen ebenfalls im Showroom auf der Frontpage. Es werden nur Bilder berücksichtigt, die entweder mit dem attachement- oder dem img-BBCode im Beitrag angezeigt werden.

Die Bildersammelfunktion muss manuell ausgeführt werden, die URL dazu und weitere Details zum Showroom sind hier zu finden.

This forum is primarily intended for German-language video game developers. Please don't post promotional information targeted at end users.

[Projekt] Extracting Ace Combat

Beitragvon Krishty » 24.09.2016, 13:14

In nostalgischer Verstimmung extrahiere ich manchmal Assets aus alten PlayStation-Spielen. Ich schrieb hier bereits über meine Experimente mit Driver und Driver 2; nun kommt was zur Ace Combat-Reihe.

Ace Combat begann in den 90ern als PlayStation-Portierung eines Arcade-Flugsimulators nach Top Gun-Manier. Kein Realitätsanspruch, hauchdünne Story, technisch dilettantisch. Hat aber mächtig Spaß gemacht, nicht zuletzt dank des großartigen Rock-Soundtracks. Teil 2 wurde flux nachgeschoben – umfangreicher, technisch ausgereift, spielerisch wunderbar abwechslungsreich … und der Soundtrack war sogar noch besser!

Mit Ace Combat 3: Electrosphere haben sie Neuland betreten: Cyberpunk. Dystopie der Konzerne, Gedankenkontrolle, Nano-Viren. Total futuristischer Look und Elektronik statt Rock. Namco investierte Millionen in eine epische Storyline mit hunderten Anime-Sequenzen. Bei der Übersetzung für den US- und EU-Markt wurde all das weggelassen; zurück blieben völlig zusammenhanglose Missionen ohne Sinn und Zweck. Damals enttäuschte das Spiel; rückwirkend nennen es aber viele als das Beste der Reihe.

Ich nun die CDs von Ace Combat 1–3 in verschiedenen Regionalcodes vor mir liegen und will mal sehen, was ich tun kann.
Ace Combat 3 EU disk content.png


Previous Work

Rad neu erfinden ist scheiße. Also gucken wir doch einfach mal, was bisher so getan wurde.

Die PlayStation-Spiele sind fast 20 Jahre alt und nie für den PC erschienen, es gibt also keine Modding Community. Es scheint überhaupt keine Community zu geben.

Aber dann ist da USEA Today – ein kleines Grüppchen (scheinbar Italiener und Portugisen), das sich vorgenommen hat, der japanischen Originalversion von Ace Combat 3 – ich erwähnte, dass die US- und EU-Version stark beschnitten war – übersetzte Untertitel zu verpassen. Und sie haben’s – wie standen die Chancen? – fast geschafft!

Möglich war das übrigens nur, weil die Texte als Bitmaps vorliegen (also als Texturen statt in Textform).

Ich stehe nicht in Kontakt mit der Gruppe (unsere Ziele mögen auch unterschiedlich sein), aber vieles hier baut auf ihrer Arbeit auf. Insbesondere muss ich Gipphe danken, dem ehemaligen Coder der Gruppe. Leider ist seine Webseite offline, und damit auch alle seine Beiträge über die Datenstrukturen. Was verblieben ist, muss ich mir mühsam von ROMhacking zusammensuchen.

Außerdem hat jemand Texturen aus Ace Combat 2 extrahiert – auf die Old-School-Art: Emulator starten, Spiel laden, und den VRAM nach Texturen durchsuchen. Wie das besser geht, erzähle ich nächstes Mal. Der Link ist mittlerweile tot, aber hier hat jemand eine Kopie.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
 
Beiträge: 6007
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [Projekt] Extracting Ace Combat

Beitragvon Schrompf » 24.09.2016, 13:24

Cool. Du hast immer so whacky Hobbies. Viel Erfolg.
Häuptling von Dreamworlds. Baut an was Neuem. Hilft nebenbei nur höchst selten an der Open Asset Import Library mit.
Benutzeravatar
Schrompf
Thomas Ziegenhagen
Moderator
 
Beiträge: 3608
Registriert: 26.02.2009, 00:44
Wohnort: Dresden
Benutzertext: Lernt nur selten dazu

Re: [Projekt] Extracting Ace Combat

Beitragvon joggel » 24.09.2016, 13:35

Keine Ahnung was Du machst, aber wird schon cool sein.
Respekt und so... :)
...
Benutzeravatar
joggel
 
Beiträge: 1172
Registriert: 06.11.2007, 19:06
Wohnort: Dresden

Re: [Projekt] Extracting Ace Combat

Beitragvon Krishty » 25.09.2016, 11:11

Danke!


Hier ist der Inhalt der Ace Combat 2-CD:
Ace Combat 2 EU disk content.png

Er ähnelt sehr den AC3-Daten im ersten Beitrag: zwei große Dateien, und ein paar kleine.
  • SCES_009.02 ist die EXE, die das Spiel bootet.
  • SYSTEM.CNF enthält Einstellungen zu Stack-Größe usw., die das BIOS nutzt, um das Spiel zu starten.
  • ACES2.STH enthält eine Handvoll unbekannter Binärdaten.
  • Natürlich sind wir an den beiden großen Dateien – ACE2.DAT und ACE2.STP – interessiert. Die enthalten eigentliche Spieldaten.

Kurze technische Exkursion: Warum liegen die Spieldaten eigentlich in dicken Archiven?

Weil CDs langsam sind und es äußerst wichtig ist, die Daten auf der CD derart zu organisieren, dass der Lesekopf wenig bewegt werden muss. Das gilt natürlich für alle statischen Daten, um die Ladezeiten vor jedem Level kurz zu halten. Das gilt aber noch mehr für Streaming-Daten, die im laufenden Betrieb gelesen werden müssen, während das CD-Laufwerk bereits Hintergrundmusik liest und die CPU mit Spielmechanik ausgelastet ist. Man findet deshalb oft große Archive vor, die Daten nach Spielsituation sortiert bündeln und an Adressen ablegen, die direkt durch den Lesekopf angesprungen werden können. Im Fall von Ace Combat (2 wie auch 3) enthält ein Archiv die Streaming-Daten (Levelgeometrie, Soundeffekte) und ein anderes statische Daten (Schrift-Texturen, Videosequenzen, Musik).


Ich sagte zuvor, dass man nicht zwingend das Spiel in einen Emulator laden und den VRAM durchforsten muss, um an Texturen zu kommen. Wir schaffen das auch offline.

Das Standardtexturformat der PSX ist TIM. Die meisten Tools des PSX-SDKs arbeiten mit diesem Format, und es ist direkt auf die PSX zugeschnitten. Nicht jedes Spiel nutzt dieses Format, aber die Wahrscheinlichkeit ist recht hoch.

Also durchforsten wir einfach alle Archive nach der Magic Number 10 00 00 00. Das bewirkt natürlich viele False Positives, weil die Zahl in beliebigen Binärdaten nicht gerade selten auftaucht. Zum Glück habe ich aber meinen TIM-Loader zur Hand. Wenn 10 00 00 00 auftaucht, versucht der, die folgenden Bytes auf gut Glück als TIM zu lesen. Sobald ein Problem auftaucht, bricht er ab. Sonst kopiert er die Datei. Nach einigen Sekunden erhalten wir 13.141 Texturen:
Ace Combat 2 TIMs.png


(Wer kein eigenes Programm schreiben will: Tim2View kann beliebige Dateien nach TIMs scannen. Allerdings hat es bei mir große Probleme mit den Paletten.)

Sieht vielversprechend aus. Um die auswerten zu können, muss man aber eine PSX-Eigenheit kennen: das ewige Wechseln der Paletten.

Früher war Speicher knapp usw. Die PSX arbeitet optimal mit palettierten Texturen (16 oder 256 Farben). Um die Grafik weiter zu verbessern, und den Platz effizienter auszunutzen, hat man Bildern erlaubt, mehr als eine Palette zu nutzen. TIMs speichern einfach mehrere Paletten und das Programm wählt je nach Situation die beste Palette aus.

Die Textur links oben ist in der Vorschau schwarz. Gleichzeitig ist sie aber die wichtigste Textur des Spiels, weil sie alle Schriftarten des Hauptmenüs enthält. Schalten wir alle ihre Paletten durch:
Bild

Die 6. Textur enthält alle HUD-Symbole in allen möglichen Farben und Helligkeiten, sowie Animationen der Symbole (über 40 Paletten!):
Bild

Flugzeuge werden üblicherweise mit einer Handvoll Texturen versehen:
Bild
Hier sehen wir (doppelte Größe) vier Paletten:
  1. normale Tarnfarben (damit wird der Großteil des Flugzeugs gerendert)
  2. eine Feuertextur für den Triebwerksinnenraum, die Bordkanone, und den Nachbrenner
  3. eine Specular/Reflection Map
  4. eine unfertige Palette, die mal eine zweite Tarnfarbe werden sollte?
Die Information, welcher Bereich zu welcher Palette gehört, ist übrigens nicht in der Datei enthalten. Man kann also nicht automatisiert eine „richtige“ Textur erzeugen. Diese Daten liegen entweder im Modell oder sind fest im Programm verdrahtet, wir werden’s sehen.


Eine noch:

Bild

Dies ist die fünfte Textur im Spiel, und sie wird scheinbar zusammen mit den Menüs geladen. Das könnte das Überbleibsel eines Editors sein, aber für mich sieht es eher nach einem Labyrinth-Mini-Game aus. (Ace Combat 1 enthielt ein Mini-Game, das sich während des Ladebildschirms freischalten lies.) Jedenfalls habe ich in keinen Cheat-Sammlungen Hinweise darauf gefunden, und abgesehen von den Entwicklern sind wir vielleicht die ersten, die auf dieses Easter Egg blicken :)


Leider lassen sich keine unentdeckten Levels oder Flugzeuge finden. Keine großen Überraschungen. Schade!


Das war ein nettes, einfaches Aufwärmen. Nächstes Mal geht’s mit AC3 weiter.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
 
Beiträge: 6007
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [Projekt] Extracting Ace Combat

Beitragvon Chromanoid » 25.09.2016, 13:42

Sehr unterhaltsam aufgebaut, dein Videospiel-Archäologie-Bericht :) Ich bin schon gespannt auf die nächsten Einträge :ugeek: :D
Benutzeravatar
Chromanoid
Christian Kulenkampff
Moderator
 
Beiträge: 3610
Registriert: 16.10.2002, 19:39
Wohnort: Lüneburg
Alter Benutzername: atr_23

Re: [Projekt] Extracting Ace Combat

Beitragvon GameDevR » 25.09.2016, 18:47

Obwohl ich die Reihe nur vom Hörensagen her kenne und selbst nie aktiv gezockt habe, finde ich deine Beiträge dazu verdammt interessant zu lesen! :)
Auch zu finden auf: Pewn.de | itch.to | Game Jolt | Twitter | YouTube
Benutzeravatar
GameDevR
 
Beiträge: 60
Registriert: 27.06.2014, 10:16
Wohnort: Wien

Re: [Projekt] Extracting Ace Combat

Beitragvon Krishty » 26.09.2016, 01:08

Freut mich, dass es euch unterhält. Für mich ist das wie ein Puzzle, aber eben mit 1,4 Milliarden Bytes :) Außerdem kann ich schön was über Hardware und Optimierung lernen.


Ace Combat 2s Texturen konnten wir durch einfache Header-Suche in den Spieldateien extrahieren. Bei Ace Combat 3 ist das schwieriger.


Ace Combat 3 wurde 1999 veröffentlicht – fünf Jahre nach Entwicklungsbeginn von Ace Combat und kurz vor Veröffentlichung der PlayStation 2. Spiele, die so spät erschienen, sind naturgemäß besser optimiert (weil bei Entwicklung mehr über die Besonderheiten der Konsole bekannt war). Auf USEA Today kann man einen Eindruck von der Grafik gewinnen, mit Specular Reflections, Wolken, Nebel – in 34 MHz.
Bild
(Alles geklaut von DragonSpikeXIIIs Picasa)

Das hat einige Konsequenzen. Beispielsweise schreibt AC3 bewusst über Textur-Caches hinaus, was Emulatoren Kopfzerbrechen bereitet. Vor allem aber ist die Datenmenge nur in Echtzeit von der CD auf den Bildschirm zu kriegen, indem man Kompression anwendet.


Die Kompression haben glücklicherweise schon andere geknackt. Zunächst hat CUE unpac geschrieben, das die allgemeine Archivstruktur von .BPB und .SPB aufschlüsselt. Ich finde meine Quelle nicht mehr, also poste ich den Quelltext in Gänze.
Code: Ansicht erweitern :: Alles auswählen
/*----------------------------------------------------------------------------*/
/*-- unpac.c                                                                --*/
/*-- Unpacker for 'Ace Combat 3' - Play Station                             --*/
/*-- Copyright (C) 2012 CUE                                                 --*/
/*--                                                                        --*/
/*-- This program is free software: you can redistribute it and/or modify   --*/
/*-- it under the terms of the GNU General Public License as published by   --*/
/*-- the Free Software Foundation, either version 3 of the License, or      --*/
/*-- (at your option) any later version.                                    --*/
/*--                                                                        --*/
/*-- This program is distributed in the hope that it will be useful,        --*/
/*-- but WITHOUT ANY WARRANTY; without even the implied warranty of         --*/
/*-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the           --*/
/*-- GNU General Public License for more details.                           --*/
/*--                                                                        --*/
/*-- You should have received a copy of the GNU General Public License      --*/
/*-- along with this program. If not, see <http://www.gnu.org/licenses/>.   --*/
/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>

/*----------------------------------------------------------------------------*/
#define FILE_HDR "ACE.BPH"
#define FILE_BIN "ACE.BPB"
#define FOLDER   "BPB"

#define MIN_FILESIZE   0x0000001C
#define MAX_FILESIZE   0x08000000

/*----------------------------------------------------------------------------*/
#define EXIT(text) { printf(text); exit(EXIT_FAILURE); }

/*----------------------------------------------------------------------------*/
void  Title(void);
int   FileSize(char *filename);
char *FileLoad(char *filename);
void  FileSave(char *filename, char *buffer, int length);
char *Memory(int length, int size);
void  Folder(char *path);
void  UnPac(char *path, int count, char *buffer, int size);

/*----------------------------------------------------------------------------*/
int main(void) {
  char *buffer_hdr, *buffer_bin;
  int   num_entries, offset, length;
  int   i;

  Title();

  buffer_hdr = FileLoad(FILE_HDR);
  buffer_bin = FileLoad(FILE_BIN);

  num_entries = *(int *)(buffer_hdr + 16);
  for (i = 0; i < num_entries; i++) {
    offset = *(int *)(buffer_hdr + 20 + i * 8 + 4) * 0x800;
    if (i < num_entries - 1)
      length = *(int *)(buffer_hdr + 20 + i * 8 + 12) * 0x800 - offset;
    else
      length = FileSize(FILE_BIN) - offset;

    UnPac(FOLDER, i, buffer_bin + offset, length);
  }    

  free(buffer_bin);
  free(buffer_hdr);

  printf("\nDone\n");

  exit(EXIT_SUCCESS);
}

/*----------------------------------------------------------------------------*/
void Title(void) {
  printf(
    "\n"
    "UNPAC - Copyright (C) 2012 CUE\n"
    "Unpacker for &#39;Ace Combat 3&#39; - Play Station\n"
    "\n"
  );
}

/*----------------------------------------------------------------------------*/
int FileSize(char *filename) {
  FILE *fp;
  int   fs;

  if ((fp = fopen(filename, "rb")) == NULL) EXIT("File open error\n");
  fs = filelength(fileno(fp));
  if (fclose(fp) == EOF) EXIT("File close error\n");

  return(fs);
}

/*----------------------------------------------------------------------------*/
char *FileLoad(char *filename) {
  FILE *fp;
  int   fs;
  char *fb;

  if ((fp = fopen(filename, "rb")) == NULL) EXIT("File open error\n");
  fs = filelength(fileno(fp));
  if (fs < MIN_FILESIZE) EXIT("File too short\n");
  if (fs > MAX_FILESIZE) EXIT("File too big\n");
  fb = Memory(fs, sizeof(char));
  if (fread(fb, 1, fs, fp) != fs) EXIT("File read error\n");
  if (fclose(fp) == EOF) EXIT("File close error\n");

  return(fb);
}

/*----------------------------------------------------------------------------*/
void FileSave(char *filename, char *buffer, int length) {
  FILE *fp;

  Folder(filename);

  if ((fp = fopen(filename, "wb")) == NULL) EXIT("File create error\n");
  if (fwrite(buffer, 1, length, fp) != length) EXIT("File write error\n");
  if (fclose(fp) == EOF) EXIT("File close error\n");
}

/*----------------------------------------------------------------------------*/
char *Memory(int length, int size) {
  char *fb;

  fb = (char *)calloc(length, size);
  if (fb == NULL) EXIT("Memory error\n");

  return(fb);
}

/*----------------------------------------------------------------------------*/
void Folder(char *path) {
  int i;

  for (i = 0; path<span style="font-style: italic">; i++) {
    if ((path[i] == &#39;/&#39;) || (path[i] == &#39;\\&#39;)) {
      path[i] = 0;
      if (mkdir(path) > 0) EXIT("Create folder error\n");
      path[i] = &#39;/&#39;;
    }
  }
}

/*----------------------------------------------------------------------------*/
void UnPac(char *path, int count, char *buffer, int size) {
  char name[256];
  int  header0, header1;
  int  num_entries, offset, length;
  int  i;

  header0 = *(int *)(buffer + 0);
  header1 = *(int *)(buffer + 4);

  if ((header0 + 1) << 2 == header1) {
    num_entries = header0;
    for (i = 0; i < num_entries; i++) {
      offset = *(int *)(buffer + (i + 1) * 4);
      if (i < num_entries - 1)
        length = *(int *)(buffer + (i + 2) * 4) - offset;
      else
        length = size - offset;  

      sprintf(name, "%s/%04d", path, count);
      UnPac(name, i, buffer + offset, length);
    }
  } else {
    switch (header0) {
      case 0x00000010: sprintf(name, "%s/%04d.tim", path, count); break;
      case 0x1A7A6C55: sprintf(name, "%s/%04d.ulz", path, count); break;
      default:         sprintf(name, "%s/%04d.dat", path, count); break;
    }
    printf("- &#39;%s&#39;\n", name);
    FileSave(name, buffer, size);
  }
}

/*----------------------------------------------------------------------------*/
/*--  EOF                                           Copyright (C) 2012 CUE  --*/
/*----------------------------------------------------------------------------*/
Die .BPH- und .SPH-Dateien sind also eine Liste von Offsets in die .BPBs und .SPBs, an denen Daten liegen. Diese kann man grob in TIM-Texturen, ULZ-Archive, und unbekannte Daten unterteilen.

ULZ-Dateien sind komprimierte Archive. Weil die PSX-CPU schwach mit variablen Shifts war und Patente eine Rolle spielten, waren heute übliche Kompressionsmethoden damals keine Option. Es lief im Grunde immer auf etwas RLE-artiges oder auf LZ ohne Entropiekodierung hinaus.

[i]Gipphe hatte recht früh die erste Kompressionsmethode als LZSS (Lempel-Ziv-Storer-Szymanski) identifiziert, aber das reichte noch nicht aus, um alle Daten zu extrahieren. esperknight hat später eine zweite Kompressionsmethode identifiziert und Code zum Extrahieren gepostet.

Im Grunde handelt es sich um drei separate Datenströme:
  1. Literals
  2. Referenzen zu bereits geschriebenen Daten
  3. ein Array von Bits, wovon jedes entscheidet, ob die nächsten Daten aus 1. oder 2. kommen
Auf die Daten angewandt erkennt man nun auch in ULZ-Dateien Ordner und Unterordner. Man bekommt eine Liste von fast 50.000 Dateien, darunter über 11.000 TIMs:
3 Ace Combat 3 TIMs.png


In diesen Texturen wird der Trick mit Palettierung auf die Spitze getrieben: Viele Texturen enthalten überlagerte Texte, die nur mit bestimmter Palette sichtbar werden.
Bild
Wie das geht? Um zwei Texte zu überlagern, sammelt man die Palettenindizes in Gruppen:
  • in beiden Texten Hintergrundfarbe
  • in Text A Hintergrundfarbe; in Text B Textfarbe
  • in Text A Textfarbe; in Text B Hintergrundfarbe
  • in beiden Texten Textfarbe
  • … das gleiche für alle Helligkeitsabstufungen
Je nachdem, welchen Indizes man nun eine helle Farbe zuweist, erscheint Text A oder Text B. Ihr könnt in der Animation die Farbpalette am linken unteren Rand beobachten.
(Das wäre ebenso mit zwei 2-Bit-Texturen möglich gewesen, aber die PSX unterstützt mindestens 4-Bit-Texturen.)

Auch die Flugzeugtexturen nutzen wieder mehrere Paletten:
Bild
Richtig ausgewählt ergeben die Abschnitte:
Bild

Aus irgend einem Grund (Werbung?) findet sich auch das Logo des Vorgängers in den Dateien wieder (in anderem Layout als wir es in den Originaldateien im letzten Beitrag gesehen haben):
3 Ace Combat 2 logo.png
3 Ace Combat 2 logo.png (19.14 KiB) 6367-mal betrachtet


Auch hier sind leider keine unbekannten Flugzeuge oder Levels zu finden :( Dafür ein kleines Schmankerl ganz am Anfang der Daten:
3 tittle.png
3 tittle.png (321 Bytes) 6367-mal betrachtet
Immer diese Tittenspiele!


Abgesehen von den TIM-Texturen kommen keine bekannten Dateitypen vor, jedenfalls entdecke ich auf Anhieb keine Magic Numbers. Die Ordnerstruktur und andere Daten knöpfen wir uns nächstes Mal vor.
Zuletzt geändert von Krishty am 29.06.2017, 18:06, insgesamt 1-mal geändert.
Grund: fixed ROMhacking link
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
 
Beiträge: 6007
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [Projekt] Extracting Ace Combat

Beitragvon Krishty » 26.09.2016, 22:50

Also gut, die Ordnerstruktur von Ace Combat 3. Aua, das ist trocken. Dafür wird nächstes Mal interessanter, versprochen!

Es gibt zwei Hauptarchive:
  • ACE.BPB – 90,5 MiB, indiziert durch ACE.BPH
  • ACE.SPB – 502 MiB, indiziert durch ACE.SPH
Rein intuitiv verspricht uns hier die große Datei mehr. Allerdings haben wir starke Gründe für die kleinere Datei:
  • die Decoding-Tools funktionieren bisher nur mit der kleineren Datei
  • in den entpackten Dateien haben wir so ziemlich jede Textur gefunden, die im Gameplay vorkommt, plus fast 40.000 unbekannte Dateien – unwahrscheinlich, dass die große Datei Gameplay-relevante Daten enthält
  • die Profis sind der Ansicht, dass in der großen Datei nur Anime-Sequenzen und Musik stecken
Ich teile die Intuition der Profis und mache hier mit der kleineren Datei weiter.

Sie entpackt zu 570 Unterordnern und vier Dateien, die sich allerdings einfach gruppieren lassen:
  • Ein Ordner mit Dingen, die während des gesamten Gameplays in Nutzung sind:
    • Texturen mit Menütext
    • Texturen für HUD
    • Texturen für Explosionen
    • Buchstabentabellen
    • eine große unbekannte Datei (nächster Beitrag!)
  • 61 Ordner identischer Struktur enthalten mit an Sicherheit grenzender Wahrscheinlichkeit je ein Level. Diskussion weiter unten.
    (AC3 hat 52 Missionen, aber was die neun zusätzlichen Ordner bedeuten, kann ich erst später sagen.)
  • 37 Ordner identischer Struktur scheinen Flugzeuge zu enthalten, die der Spieler steuern kann (bemerkt man an den deutlich höheren Texturauflösungen gegenüber KI-Flugzeugen).
  • 9 Ordner haben identische, unbekannte Struktur (ohne Texturen).
  • Ein Ordner (0112) enthält das Logo des Vorgängers und so ziemlich jede Textur des Spielmenüs.
  • 14 Ordner mit scheinbaren Menütexturen. (Jedes Menü in einem Ordner? Klar, VRAM ist eben knapp!)
  • 60 Ordner identischer Struktur (0126–0185) enthalten Level-Briefings samt Name und Thumbnail.
  • 62 Ordner identischer Struktur enthalten japanische Walls of Text.
  • 152 Ordner identischer Struktur (0248–0399) mit erneuten Walls of Text (tja, die haben viel in die Story investiert).
  • Ein paar unterschiedliche Ordner.
  • 158 Ordner identischer Struktur (–0573) ohne Texturen.
  • Vier Binärdateien mit Levelnamen, Flugzeugnamen, Pilotennamen, Debug-Ausgaben, und viel unverstandenem Binärkram.

Für Gameplay-Assets sind erstmal am interessantesten: Die Level-Ordner und die Flugzeugordner.

Ein Level-Ordner sieht so aus:
  1. kleine Binärdatei
  2. große Binärdatei
  3. Ordner mit hunderten kleinen Binärdateien
  4. Ordner mit rund hundert winzigen Binärdateien (viele leer – Fehler beim Extrahieren?)
  5. Ordner mit kleinen Binärdateien
  6. Ordner mit Handvoll kleiner Binärdateien
  7. mittlere Binärdatei
  8. Ordner mit Handvoll kleiner Binärdateien
  9. kleine Binärdatei
  10. kleine Binärdatei
  11. kleine Binärdatei
  12. Ordner mit hunderten Texturen von Terrain & Gebäuden
  13. Ordner mit Texturen von KI-Flugzeugen, die im Level auftauchen
  14. Ordner mit Texturen von Raketen, die im Level auftauchen
  15. Ordner mit Wolkentexturen und Sprites für Sonne/Mond und Sterne (Laterne, Laterne)
  16. Ordner mit Textur für Übersichtskarte und japanischen Text
  17. mittlere Binärdatei
Daten mit offensichtlicher Bedeutung habe ich fett markiert. Den Rest müssen wir uns zusammenreimen.

Wo fangen wir da an? Bei 2., der größten Datei. Je größer die Datei, desto höher die Chance, dass wir Muster erkennen :)
4 filesize.png
4 filesize.png (11.01 KiB) 6291-mal betrachtet

Hmmm. 128 KiB. Schöne runde Zahl. Visualisieren wir sie doch mal, indem wir es als 256×512-Pixel Monochrom-Bitmap lesen (ergibt genau 128 KiB):
4 256×512.png
4 256×512.png (5.6 KiB) 6291-mal betrachtet

Da ist ja tatsächlich was Grafisches drin! Nur stören die vertikalen schwarzen Balken. Das geschulte Auge erkennt hier 256×256 16-Bit-Zahlen, wobei die schwarzen Balken die höchstwertigsten Bytes sind (fast immer Null):
4 256×256.png
4 256×256.png (4.47 KiB) 6291-mal betrachtet

Vergleichen wir das mal mit der Übersichtskarte aus Ordner 16:
4 level overview.png
4 level overview.png (4.32 KiB) 6291-mal betrachtet

Perfekt! Wir haben eine Art Karte des Levels gefunden. Eine Heightmap kann’s nicht sein, dafür sind die Konturen zu scharf. Hm.

Ich habe mal schnell ein Programm hingehackt, das die Datei als Array von 16-Bit-Zahlen liest und zählt, wie viele einzigartige Werte darin vorkommen. Das sind … 334. Und der Ordner 3. enthält … *Trommelwirbel* … 332 kleine Binärdateien. Bingo! (Um die kleine Abweichung kümmern wir uns später.)

Wir wissen also nun, dass Datei 2. eine Tile Map des Levels ist, und dass Ordner 3. ungefähr eine kleine Binärdatei pro Kachel enthält. Wie die Daten pro Kachel aussehen, dazu kommen wir später.

Eine Ergänzung von Außerhalb:
DragonSpikeXIII (http://www.romhacking.net/forum/index.p ... #msg263081) hat geschrieben:0000 : the 0004.dat contained narrator sounds like engage, bingo, bulls eye, MA, MF, MO, etc

0005 - 0065 : every 0016.dat is sound archive, and no, not all sounds yet.
Die Dateinamen in dem Thread sind etwas anders als hier, aber mit dem ersten Kommentar meint er den Haupt-Ordner. Mit dem zweiten meint er Datei 16. in unserer Liste. Wir aktualisieren also zu:

  1. kleine Binärdatei
  2. Tile Map des Levels
  3. Ordner mit einer Datei pro Level-Kachel
  4. Ordner mit rund hundert winzigen Binärdateien Modellen beweglicher Einheiten (Flugzeuge, Fallschirme) … viele leer – Fehler beim Extrahieren?
  5. Ordner mit kleinen Binärdateien Waffenmodellen (Raketen, Bomben, …)
  6. Ordner mit Handvoll kleiner Binärdateien statischen Modellen (Sky Boxes, Schiffe, große Gebäude)
  7. mittlere Binärdatei
  8. Ordner mit Handvoll kleiner Binärdateien
  9. kleine Binärdatei
  10. kleine Binärdatei
  11. kleine Binärdatei
  12. Ordner mit hunderten Texturen von Terrain & Gebäuden
  13. Ordner mit Texturen von KI-Flugzeugen, die im Level auftauchen
  14. Ordner mit Texturen von Raketen, die im Level auftauchen
  15. Ordner mit Wolkentexturen und Sprites für Sonne/Mond und Sterne (Laterne, Laterne)
  16. Ordner mit Textur für Übersichtskarte und japanischen Text
  17. alle Sounds, die im Level vorkommen
Nicht schlecht für zehn Minuten Arbeit.

Wie DragonSpikeXIII darauf kommt, dass die Dateien Sounds enthalten, wissen wir an dieser Stelle nicht. Aber im nächsten Beitrag schmeißen wir den Hex-Editor an und extrahieren die besagten Klänge in gute alte WAV-Dateien :)
Zuletzt geändert von Krishty am 02.05.2017, 19:24, insgesamt 2-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
 
Beiträge: 6007
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [Projekt] Extracting Ace Combat

Beitragvon MasterQ32 » 27.09.2016, 12:48

Das ist echt spannend, hier mitzulesen. Gute Arbeit!
Duct tape is like the force. It has a light side, a dark side, and it holds the world together.
Benutzeravatar
MasterQ32
Felix Queißner
 
Beiträge: 937
Registriert: 07.10.2012, 14:56

Re: [Projekt] Extracting Ace Combat

Beitragvon Krishty » 27.09.2016, 22:21

Danke! Wird leider bald versiegen – ich habe das alles schon Anfang des Jahres gemacht und mir am Wochenende Zeit genommen, die Arbeitsschritte in Text- und GIF-Form zu pressen. Nach diesem Beitrag kommt vielleicht noch einer, dann ist aber erstmal Schluss bis das Real Life wieder Zeit zur Verfügung stellt :(



Also SFX. Schauen wir uns eine der besagten Dateien an: 292 KiB, viel binäres drin.
raw file.png
Der Header enthält nichts markantes. Die ersten Bytes sind bei jeder Datei, die angeblich Sounds enthält, unterschiedlich. Sehen wir uns die Mitte der Datei an.

Stop! Ich erkenne ein Muster! Meine primitive, aber wirkungsvolle Methode, um Wiederholungen in Binärdaten zu finden:
  • einen Hex-Blob aus der Mitte kopieren (Mitte, damit man keine Header erwischt, denn die sind ungleich schwerer zu verstehen)
  • im Notepad++ einfügen
  • automatische Zeilenumbrüche einschalten
  • einen häufig auftretenden Wert (meist die Null) markieren, Notepad++ markiert dann automatisch alle Vorkommen
  • das Fenster so lange vergrößern, bis man die Wiederholrate erkennt
Bild
Wir sehen, dass jedes 16. Byte Null ist. Wir sehen außerdem, dass das Byte davor immer recht kleine Zahlenwerte annimmt (15, 16, manchmal 45).

Stöbern wir weiter, vielleicht finden wir ja was Markantes …
Bild
Da ist eine ganze Zeile voll kleiner Ws (Zahlenwert 0x77). Wenn das nicht markant ist!

Das Schöne an unserer modernen Zeit ist, dass man jederzeit Zugriff auf das gesammelte Wissen der Menschheit hat. Nutzen wir das doch …
Bild
http://forums.qhimm.com/index.php?topic=8326.msg100499#msg100499 hat geschrieben:It's very easy to detect playstation audio as the actual data is split in block of 16 bytes whereas the last 14 bytes are 28 packed samples, first byte is predictor/shiftfactor and the 2nd byte is flag. The flag byte is usually 0x00 or 0x02, so every 16th byte is either a zero or a two. Also the flag for sample end is 0x07, and often the last block looks like this:

00 07 77 77 77 77 77 77 77 77 77 77 77 77 77 77
Das passt wie gespuckt auf die Hex-Daten, die wir gefunden haben. Es handelt sich also um Audio-Daten im PlayStation-üblichen XA-Format.

XA ist durch die PSX-Community längst dekodiert, aber wie immer ist die Dokumentation
  • schlicht falsch, oder
  • brilliant geschrieben, aber mit Google nicht auffindbar.
Dieser Thread auf PSXDEV war mir eine große Hilfe: Zum einen verlinkt er auf die sehr ausführliche Dokumentation auf problemkaputt.de, zum anderen stellt er C#-Quelltext bereit (der aber kaputt ist [sogar in der korrigierten Version], Anmerkung am Ende dieses Beitrags).

Mit der Dokumentation fügt sich nun das Puzzle zusammen:
  • Die PSX speichert ihre Audio-Daten in Blöcken von 28 Werten. Diese krumme Zahl ergibt sich aus den Eigenschaften des CD-Laufwerks, lest bei Interesse die Dokumentation.
  • Die Daten sind als ADPCM (Adaptive Differential Pulse Code Modulation) kodiert. Das sind im Grunde rohe Zahlenwerte der Klangwelle, jedoch um einen Vorfaktor skaliert und als Delta zu den vorherigen Werten gespeichert. Keine Kosinustransformation oder Wavelets oder schwieriges Zeug. PCM kennt ihr aus WAV-Dateien, das ist die einfachste Art, Klang zu speichern.
  • Wenn man die 28 Samples eines Blocks in 4 Bits kodiert und Zusatzdaten für Vorfaktor und Flags voranstellt, erhält man die 16-Byte-Blöcke, die wir in der Datei identifiziert haben.
  • Die Klänge werden aus dem RAM ohne Längenangabe wiedergegeben. Das setzt voraus, dass das letzte Sample speziell markiert ist. Diese Markierung ist 07 77 77 ….
Die Daten passen perfekt auf die Dokumentation, und die Dokumentation sagt, dass das Datenformat sehr einfach ist (zehn Zeilen Code reichen zum Dekomprimieren!). Also los!
  • Im Hex-Editor den Müll vor und nach den 16-B-Blöcken löschen
  • darauf achten, dass die Datei exakt mit einem Block beginnt
  • ein 30-Zeilen-Programm schreiben, das die Datei liest und alle PSX-XA-ADPCM-XYZ-FUBAR-Daten dekomprimiert und als Array von 16-Bit-Zahlen speichert
Und wie geben wir das jetzt wieder?

Audacity hat die fantastische Funktion, Rohdaten zu importieren. Einfach ein Array von Zahlen reinschmeißen (Größe und Endianness der Werte wird automatisch erkannt), anhören:
Bild
Sieht aus wie Klang. Klingt auch irgendwie so. Nur viel zu schnell!

Die großen Bereiche am Anfang sind Explosionen und Triebwerksgeräusche. Die sind mit einer Frequenz von rund 8 KHz gespeichert (nicht viel) und werden deshalb bei 44 KHz viel zu schnell abgespielt. Die Bereiche weiter rechts sind Sprache (die HUD-Fragmente der Bitching Betty). Ihre Frequenz ist sogar noch niedriger, 6 KHz (verdammt wenig für Sprache).

Okay. Schmeißen wir das Ganze in ein einfacher lesbares Format. Schonmal eine WAV-Datei geschrieben? Falls nicht, nimmt euch Wikipedia an die Hand. Hier ein paar Zeilen, die ein Array von 16-Bit-shorts als WAV speichert:
Code: Ansicht erweitern :: Alles auswählen
void writeWAV_mono_16bit(
        char const *   outName,
        SInt2B const * samples,
        int            num_samples,
        int            sampleRate
) {
        auto const dataSize       = 2 * num_samples;
        auto const dataSizePadded = (dataSize + 3) / 4 * 4;
        auto const dataChunkSize  = 4 + 4 + dataSizePadded;
        auto const sixteen        = 16;
        auto const fmtChunkSize   = 4 + 4 + sixteen;
        auto const riffSize       = 4 + fmtChunkSize + dataChunkSize;

        auto resFile = fopen(outName, "wb");
        fwrite("RIFF", 1, 4, resFile);
        fwrite(&riffSize, 4, 1, resFile);
        fwrite("WAVE", 1, 4, resFile);

        auto const one            = UInt2B(1);
        auto const frameSize      = UInt2B(one * sizeof *samples);
        auto const bytesPerSecond = sampleRate * frameSize;
        auto const bitDepth       = UInt2B(16);
        fwrite("fmt ", 1, 4, resFile);
        fwrite(&sixteen, 4, 1, resFile);
        fwrite(&one, 2, 1, resFile); // format: PCM
        fwrite(&one, 2, 1, resFile); // mono
        fwrite(&sampleRate, 4, 1, resFile);
        fwrite(&bytesPerSecond, 4, 1, resFile);
        fwrite(&frameSize, 2, 1, resFile);
        fwrite(&bitDepth, 2, 1, resFile);

        fwrite("data", 1, 4, resFile);
        fwrite(&dataSize, 4, 1, resFile);
        fwrite(samples, num_samples, 2, resFile);
        fclose(resFile);
}
Kurz, schmutzig, erledigt die Arbeit. Resultat:

0004.wav [ 1015.54 KiB | 6214-mal betrachtet ]


Jetzt fehlt noch Code, um die Audio-Daten automatisch aus den Dateien zu extrahieren. Den lasse ich aber als Hausaufgabe stehen, denn für heute war’s wirklich genug :)


Lasst mal Revue passieren, wie wenig wir tatsächlich selber programmiert haben. Schultern von Giganten und so :)


Anmerkung zum C#-Quelltext auf PSXDEV:
Error:
sbyte filter = (sbyte)(parameters[4+block*2+nibble] & 0x30 >> 4);

Correction:
sbyte filter = (sbyte)((parameters[4+block*2+nibble] & 0x30) >> 4);
Immernoch falsch. Korrektur:

  sbyte filter = (sbyte)((parameters[4+block*2+nibble] & 0x70) >> 4);

Sonst werden die hochfrequenten Filter weggeschmissen und man bekommt sehr subtiles Rauschen. (Ich hab’s drei Stunden lang gesucht. LOL!)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
 
Beiträge: 6007
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [Projekt] Extracting Ace Combat

Beitragvon marcgfx » 07.10.2016, 11:26

hab mir das ganze schon vor einiger zeit durchgelesen und fands richtig interessant was du hier machst. dachte nur ich sollte auch mal bescheid sagen, dass so sachen zumindest bei mir gut ankommen :)
Benutzeravatar
marcgfx
 
Beiträge: 1031
Registriert: 18.10.2010, 23:26

Re: [Projekt] Extracting Ace Combat

Beitragvon Infrid » 04.11.2016, 23:51

Hello,
thanks for allow me to join your community. I came across to this page thanks to my friend, we are trying to translate this game in Italian too from the English script (thanks team nemo). I read (sort of) this page thanks to google translator, alas I don't speak German, so I cannot really understand everything.

Translate the game is not impossible, we need better tools and better documentation. There are various team that try the same challenge (I know a Spanish team and mine of course), so why not join the efforts? Could we write some documentation about our discoveries and open a github repository for the tools.

This page looks incredibly complete and can help other people to translate the game, I was already put my knowledge to hack the game in a wiki, write and compile some tools from the available source code and make the process easier. It would be great to have those information in English for everyone, would you like to join my wiki?

I am a developer and its not hard for me to create new tools from the available code, I tried to hack this game when I was a boy, alas I didn't implemented nothing useful and personal commitments were more important. I always like to see this game translated.

I have also another idea, many translation project are tied to the hacker that changes the game, I'd like to make a small web application for make easier to non tech-savvy translate the text and rise the quality bar for the future projects. Some kind of CMS for game translations. But this projects comes when we have decent tools for the game.

Kind Regards
Infrid
 
Beiträge: 7
Registriert: 04.11.2016, 15:20

Re: [Projekt] Extracting Ace Combat

Beitragvon Krishty » 06.11.2016, 23:43

Infrid hat geschrieben:This page looks incredibly complete and can help other people to translate the game, I was already put my knowledge to hack the game in a wiki, write and compile some tools from the available source code and make the process easier. It would be great to have those information in English for everyone, would you like to join my wiki?
Thanks! I definitely want to, but with spare time being the limiting factor for me, I cannot guarantee for progress in a specific timeframe.

Where is your wiki? I was doing some research on the game before I started reversing, but I didn’t find anything better than the discussions on romhacking.net. I'm glad to find any little piece of information to speed up my reversing :)

Infrid hat geschrieben:I have also another idea, many translation project are tied to the hacker that changes the game, I'd like to make a small web application for make easier to non tech-savvy translate the text and rise the quality bar for the future projects. Some kind of CMS for game translations. But this projects comes when we have decent tools for the game.
I'm not much of a web programmer, so this would be left to you. My next plans involved 1. decoding some 3D models (planes etc.) and 2. decoding the levels to an open mesh format in order to use them in other games …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
 
Beiträge: 6007
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Re: [Projekt] Extracting Ace Combat

Beitragvon Infrid » 09.11.2016, 15:51

thanks so much, everybody has real file commitments, I don't want to pressure anyone :D

Sorry for this late reply but I wanted to tidy up the wiki in the spare time, I have cloned some repositories and now I am editing a download section for retrieve the tools.

The wiki anyway is here: http://ac3es.infrid.com/ and I'll send your email/password by email, anyone can ask me for an account by the way!

My next plans involved 1. decoding some 3D models (planes etc.) and 2. decoding the levels to an open mesh format in order to use them in other games …


for who wants to hack the and and maybe create some sort of editor, this would be a great input.

Kind Regards!
Infrid
 
Beiträge: 7
Registriert: 04.11.2016, 15:20

Re: [Projekt] Extracting Ace Combat

Beitragvon Krishty » 19.11.2016, 02:51

I just cracked one of the mesh formats, so I might as well write about it before losing focus again.

Mission subfolder #6 is almost empty for all the “boring” missions, so my initial guess was it containing meshes. Quickly looking at the files, it turned out I was right. Take BPB\0009\0005.ulz\53544\0024.dat, for example:
Code: Ansicht erweitern :: Alles auswählen
00 00 0D 02 24 00 00 00 00 00 00 00 64 00 00 00 D4 00 00 00 00 00 00 00 50 00 AD FF FA FF F3 FD 62 00 9A FF 08 00 00 00 26 00 F3 FD 50 00 D1 FF F3 FF F3 FD 00 00 00 00 CD FF 00 00 F3 FF FA FF AD FF FA FF F3 FF F3 FD 9A FF E6 FF 33 00 00 00 B0 FF E3 FF F3 FF D1 FF 00 00 00 00 1B 00 62 00 00 00 00 00 03 00 00 00 03 02 00 00 E8 5A F0 5A 14 20 04 0E 18 22 28 34 03 01 04 06 F6 A9 D4 43 FE A1 27 00 F0 A3 F0 9F 11 11 11 2C 03 01 00 00 F8 5A F8 5A 2C 36 28 34 04 0E 04 0E 07 06 01 01 F6 99 D4 43 F0 9F 27 00 FE A1 FE A1 11 11 11 2C 03 01 00 00 40 00 40 00 08 10 1C 24 00 0C 00 0C 02 05 00 00 FF AF D4 43 F0 9F 27 00 F0 AF F0 AF 80 80 80 2C 05 00 00 00 03 01 00 00 E0 5A E0 5A 08 10 14 20 18 22 18 22 02 03 04 04 F5 80 D4 43 F2 9F 27 00 FA 9F FA 9F 88 88 88 3C 22 22 22 3C 22 22 22 3C 22 22 22 3C 03 01 00 00 C8 5A C8 5A 1C 24 28 34 2C 36 2C 36 05 06 07 07 F5 80 D4 43 F9 9E 27 00 F2 9D F2 9D 36 36 36 3C 22 22 22 3C 22 22 22 3C 22 22 22 3C 03 02 00 00 B8 5A C0 5A 08 10 18 22 1C 24 28 34 02 04 05 06 F0 80 D4 43 F7 BF 27 00 FF 80 FF 80 88 88 88 3C 22 22 22 3C 36 36 36 3C 22 22 22 3C 03 02 00 00 A8 5A B0 5A 00 0C 04 0E 08 10 14 20 00 01 02 03 FA 80 D4 43 FC 9D 27 00 F5 80 F2 9F AA AA AA 3C 22 22 22 3C 91 8C 87 3C 22 22 22 3C 03 02 00 00 D0 5A D8 5A 1C 24 2C 36 00 0C 04 0E 05 07 00 01 F5 80 D4 43 F2 9D 27 00 FA 80 FC 9D 36 36 36 3C 22 22 22 3C 36 36 36 3C 22 22 22 3C

The first numbers are 32-bit offsets into the file, obviously. This allows us to group the file into the header and three blocks (it’s five in other files, but let’s keep things simple here):
Code: Ansicht erweitern :: Alles auswählen
00 00 0D 02
24 00 00 00 ← offset A
00 00 00 00 ← offset B (unused)
64 00 00 00 ← offset C
D4 00 00 00 ← offset D
00 00 00 00 ← offset E (?)

50 00 AD FF FA FF F3 FD 62 00 9A FF ← not sure about that, might be bounding box

block A:
08 00 00 00 26 00 F3 FD 50 00 D1 FF F3 FF F3 FD 00 00 00 00 CD FF 00 00 F3 FF FA FF AD FF FA FF F3 FF F3 FD 9A FF E6 FF 33 00 00 00 B0 FF E3 FF F3 FF D1 FF 00 00 00 00 1B 00 62 00 00 00 00 00

block C:
03 00 00 00 03 02 00 00 E8 5A F0 5A 14 20 04 0E 18 22 28 34 03 01 04 06 F6 A9 D4 43 FE A1 27 00 F0 A3 F0 9F 11 11 11 2C 03 01 00 00 F8 5A F8 5A 2C 36 28 34 04 0E 04 0E 07 06 01 01 F6 99 D4 43 F0 9F 27 00 FE A1 FE A1 11 11 11 2C 03 01 00 00 40 00 40 00 08 10 1C 24 00 0C 00 0C 02 05 00 00 FF AF D4 43 F0 9F 27 00 F0 AF F0 AF 80 80 80 2C

block D:
05 00 00 00 03 01 00 00 E0 5A E0 5A 08 10 14 20 18 22 18 22 02 03 04 04 F5 80 D4 43 F2 9F 27 00 FA 9F FA 9F 88 88 88 3C 22 22 22 3C 22 22 22 3C 22 22 22 3C 03 01 00 00 C8 5A C8 5A 1C 24 28 34 2C 36 2C 36 05 06 07 07 F5 80 D4 43 F9 9E 27 00 F2 9D F2 9D 36 36 36 3C 22 22 22 3C 22 22 22 3C 22 22 22 3C 03 02 00 00 B8 5A C0 5A 08 10 18 22 1C 24 28 34 02 04 05 06 F0 80 D4 43 F7 BF 27 00 FF 80 FF 80 88 88 88 3C 22 22 22 3C 36 36 36 3C 22 22 22 3C 03 02 00 00 A8 5A B0 5A 00 0C 04 0E 08 10 14 20 00 01 02 03 FA 80 D4 43 FC 9D 27 00 F5 80 F2 9F AA AA AA 3C 22 22 22 3C 91 8C 87 3C 22 22 22 3C 03 02 00 00 D0 5A D8 5A 1C 24 2C 36 00 0C 04 0E 05 07 00 01 F5 80 D4 43 F2 9D 27 00 FA 80 FC 9D 36 36 36 3C 22 22 22 3C 36 36 36 3C 22 22 22 3C

Using my usual approach, I quickly grouped blocks C & D into lists of entries. Block A was harder, but the zero words pretty much convinced me it’s a 10-word structure:
Code: Ansicht erweitern :: Alles auswählen
00000D02
24000000 ← offset A
00000000 ← offset B (unused)
64000000 ← offset C
D4000000 ← offset D
00000000 ← offset E (?)

50 00 AD FF FA FF F3 FD 62 00 9A FF ← not sure about that, might be bounding box

block A:
08000000 ← 8 entries
2600 F3FD 5000 D1FF F3FF F3FD 0000 0000 CDFF 0000 ← always 9 words + terminating zero
F3FF FAFF ADFF FAFF F3FF F3FD 9AFF E6FF 3300 0000
B0FF E3FF F3FF D1FF 0000 0000 1B00 6200 0000 0000

block C:
03000000 ← 3 entries
0302 0000 E8 5A F0 5A 14 20 04 0E 18 22 28 34 03 01 04 06 F6 A9 D4 43 FE A1 27 00 F0 A3 F0 9F 1111112C
0301 0000 F8 5A F8 5A 2C 36 28 34 04 0E 04 0E 07 06 01 01 F6 99 D4 43 F0 9F 27 00 FE A1 FE A1 1111112C
0301 0000 40 00 40 00 08 10 1C 24 00 0C 00 0C 02 05 00 00 FF AF D4 43 F0 9F 27 00 F0 AF F0 AF 8080802C

block D:
0500 0000 ← 5 entries
0301 0000 E0 5A E0 5A 08 10 14 20 18 22 18 22 02 03 04 04 F5 80 D4 43 F2 9F 27 00 FA 9F FA 9F 8888883C 2222223C 2222223C 2222223C
0301 0000 C8 5A C8 5A 1C 24 28 34 2C 36 2C 36 05 06 07 07 F5 80 D4 43 F9 9E 27 00 F2 9D F2 9D 3636363C 2222223C 2222223C 2222223C
0302 0000 B8 5A C0 5A 08 10 18 22 1C 24 28 34 02 04 05 06 F0 80 D4 43 F7 BF 27 00 FF 80 FF 80 8888883C 2222223C 3636363C 2222223C
0302 0000 A8 5A B0 5A 00 0C 04 0E 08 10 14 20 00 01 02 03 FA 80 D4 43 FC 9D 27 00 F5 80 F2 9F AAAAAA3C 2222223C 918C873C 2222223C
0302 0000 D0 5A D8 5A 1C 24 2C 36 00 0C 04 0E 05 07 00 01 F5 80 D4 43 F2 9D 27 00 FA 80 FC 9D 3636363C 2222223C 3636363C 2222223C
Let’s start with block C, which is the most obvious one:

  0302 0000 E8 5A F0 5A 14 20 04 0E 18 22 28 34 03 01 04 06 F6 A9 D4 43 FE A1 27 00 F0 A3 F0 9F 1111112C

The red numbers are vertex indices:
  • all numbers from 0 to 7 (hint: block A contains 8 entries!)
  • you can easily identify shared edges
The green numbers seem to be triangle colors.

The same logic applies to block D, just with more colors (per-vertex instead of per-triangle):

  0301 0000 E0 5A E0 5A 08 10 14 20 18 22 18 22 02 03 04 04 F5 80 D4 43 F2 9F 27 00 FA 9F FA 9F 8888883C 2222223C 2222223C 2222223C

Notice how there are just three distinct vertex indices in that polygon. From my observation, triangles are always represented as degenerated quads (the last index is always collapsed).

One closer look at the color. These are nice even numbers, but the 3C and 2C constants don’t quite make sense. They can’t be alpha values, as the PSX does not support interpolated alpha blending. Again, Nocash’s PSX Specifications to the rescue:
GPU Render Polygon Commands

[…]

GP0(24h) - Textured three-point polygon, opaque, texture-blending
GP0(25h) - Textured three-point polygon, opaque, raw-texture
GP0(26h) - Textured three-point polygon, semi-transparent, texture-blending
GP0(27h) - Textured three-point polygon, semi-transparent, raw-texture
GP0(2Ch) - Textured four-point polygon, opaque, texture-blending
GP0(2Dh) - Textured four-point polygon, opaque, raw-texture
GP0(2Eh) - Textured four-point polygon, semi-transparent, texture-blending
GP0(2Fh) - Textured four-point polygon, semi-transparent, raw-texture
1st Color+Command (CcBbGgRrh) (color is ignored for raw-textures)
2nd Vertex1 (YyyyXxxxh)
3rd Texcoord1+Palette (ClutYyXxh)
4th Vertex2 (YyyyXxxxh)
5th Texcoord2+Texpage (PageYyXxh)
6th Vertex3 (YyyyXxxxh)
7th Texcoord3 (0000YyXxh)
(8th) Vertex4 (YyyyXxxxh) (if any)
(9th) Texcoord4 (0000YyXxh) (if any)


[…]

GP0(34h) - Shaded Textured three-point polygon, opaque, texture-blending
GP0(36h) - Shaded Textured three-point polygon, semi-transparent, tex-blend
GP0(3Ch) - Shaded Textured four-point polygon, opaque, texture-blending
GP0(3Eh) - Shaded Textured four-point polygon, semi-transparent, tex-blend
1st Color1+Command (CcBbGgRrh)
2nd Vertex1 (YyyyXxxxh)
3rd Texcoord1+Palette (ClutYyXxh)
4th Color2 (00BbGgRrh)
5th Vertex2 (YyyyXxxxh)
6th Texcoord2+Texpage (PageYyXxh)
7th Color3 (00BbGgRrh)
8th Vertex3 (YyyyXxxxh)
9th Texcoord3 (0000YyXxh)
(10th) Color4 (00BbGgRrh) (if any)
(11th) Vertex4 (YyyyXxxxh) (if any)
(12th) Texcoord4 (0000YyXxh) (if any)


[…]

Notes
Polygons are displayed up to <excluding> their lower-right coordinates.
Four-point polygons are internally processed as two Three-point polygons, the first consisting of Vertices 1,2,3, and the second of Vertices 2,3,4.[…]

Caution: For untextured graphics, 8bit RGB values of FFh are brightest. However, for texture blending, 8bit values of 80h are brightest (values 81h..FFh are "brighter than bright" allowing to make textures about twice as bright as than they were originially stored in memory; of course the results can't exceed the maximum brightness, ie. the 5bit values written to the framebuffer are saturated to max 1Fh).
Important insights from the text:
  1. the 1st vertex color passed to the GPU contains the draw command in the most significant bits (i.e. in the last byte)
  2. 2C is the command for a “Textured four-point polygon, opaque, texture-blending”
  3. 3C is the command for a “Shaded Textured four-point polygon, opaque, texture-blending” (matches the color data pretty well, doesn’t it?)
  4. the 808080 isn’t a gray polygon, but rather a white one
  5. the bytes from the file are passed to the GPU without much modification
  6. so texture coordinates and palette indices must be present there, too
At this point I was 99 % sure I had found the models. However, block A (the vertices) are very problematic.
Code: Ansicht erweitern :: Alles auswählen
08000000 ← 8 entries
2600 F3FD 5000 D1FF F3FF F3FD 0000 0000 CDFF 0000 ← always 9 words + terminating zero
F3FF FAFF ADFF FAFF F3FF F3FD 9AFF E6FF 3300 0000
B0FF E3FF F3FF D1FF 0000 0000 1B00 6200 0000 0000
It’s vertex data, obviously. It’s signed 16-bit numbers (we can tell from the FF bytes). However, it’s stored in some non-linear fashion (zero bytes interleaved after three vertices?). Just reading X-Y-Z, X-Y-Z, X-Y-Z, (skip zero) left me clueless:
2.png

On the other hand, comparing the number of vertices in the block to the number of words (enumerated from all available files) tells us that there *must* be a strict 7-to-1 mapping. With zeroes intermixed, there is no other place for the vertex positions to go.
2016-11-18 bytes per vertex.png
2016-11-18 bytes per vertex.png (4.65 KiB) 5740-mal betrachtet

Now this took me some weeks to figure out. I would have been a nice programming challenge to use a list of individual coordinate components and a list of connections to find a consistent mapping that produces a non-overlapping topology, but this is my hobby and I’m short on time, so screw that.

Came to mind: Like many PSX games, Ace Combat 3 uses a tile-based renderer. Maybe they just decoupled the height information? Turns out, they did. Reading the numbers as X-Y, X-Y, X-Y, Z, Z, Z:
5.png

I have yet to apply vertex colors, textures, winding order etc., but for now it’s a satisfying result:
  • 600 files
  • only static models (buildings etc.), no planes yet … but some four-legged Antlion tanks :)
  • the selected file is a satellite from the space mission
  • the one in the lower right is a ship with wakes
Here’s a ZIP containing the models in STL format, in case anyone bothers:
extracted Ace Combat 3 models.zip
(288.08 KiB) 83-mal heruntergeladen


Infrid, I’ll add all that stuff to your Wiki at some point … just not today; Real Life is calling.
Zuletzt geändert von Krishty am 19.11.2016, 21:56, insgesamt 2-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
 
Beiträge: 6007
Registriert: 26.02.2009, 12:18
Benutzertext: state is the enemy

Nächste

Zurück zu Vorstellungsbereich

Wer ist online?

Mitglieder in diesem Forum: Yahoo [Bot] und 3 Gäste