Final Fantasy XII: The Zodiac Age
0 of 0

File information

Last updated

Original upload

Created by

ffgriever

Uploaded by

ffgriever

Virus scan

Safe to use

About this mod

This tool can decompile FF12 VM binary scripts into c-like high level language and compile them back. Additional tools are included in the package.

Requirements
Permissions and credits
Changelogs
Final Fantasy XII Virtual Machine Script Decompiler and Compiler



ABOUT THIS TOOL


Here is something I've been working on for past few months. Tool that is able to properly disassemble, assemble, decompile and compile Final Fantasy XII Virtual Machine scripts.

These scripts are used in all event and map files and are responsible for most of the things that happen on screen (except menus), including positioning NPCs, playing animations, displaying text, etc. In other words - the logic of the game.

The tool is already in a very advanced state of development, but bear in mind, that it's still a Work in Progress. Also, while I'm doing everything I can to keep it bug free, I can't guarantee it will work without a hitch in all cases.
If you find any bugs, please report them with as much details as possible (including steps, code that causes issues, etc.).

REQUIREMENTS AND SUPPORTED GAME VERSIONS


The tool is compiled for x64 Windows system and that's pretty much only hard requirement. Obviously, the better the CPU, the better it will work. CPU is not an issue in case of decompilation, but compiling large scripts does take some time.

Supported game versions:
  • Final Fantasy XII (all PS2 versions)
  • Final Fantasy XII International Zodiac Job System (PS2)
  • Final Fantasy XII The Zodiac Age (PC/Steam)

Technically the tool supports also PS4/XB/Switch versions of FFXII:TZA, but it requires an update to call target map, to support new calls (if there is any need for that and switch modding is a case, just let me know).

USAGE


Scripts are contained within EBP files. They're always in the very first section of EBP files. Before decompiling a script, you have to unpack EBP file into sections. Tools able to do that are available within bin folder.

ff12-ebpunpack.exe file.ebp (to unpack into file.ebp_unc directory)
ff12-ebppack.exe file.ebp (to pack file.ebp_unc directory into file.ebp file)

ALL SUPPLIED EXECUTABLES ARE COMMAND LINE TOOLS. IF YOU DOUBLE CLICK IT AND A BLACK WINDOW POPS UP FOR A SPLIT SECOND AND THEN DISAPPEARS, EVERYTHING WORKS AS INTENDED. FOR USERS NOT FAMILIAR WITH COMMAND LINE I SUPPLIED A FEW *.BAT FILES, THAT ARE ABLE TO PERFORM BOTH UNPACK/DECOMPILATION and COMPILATION/REPACK. I WOULD SUGGEST LEARNING COMMAND LINE USAGE ANYWAY - IT'S MUCH FASTER, EASIER AND HASSLE FREE THAN ANY OF THE GUI TOOLS!

ebp_unpack_dir.bat

Drop a directory with ebp files onto this bat and all will be unpacked, decompiled and text sections will be unpacked. (works recursively for all subdirectories, too)

ebp_unpack_single.bat
Drop a single ebp file onto this bat and it will be unpacked, decompiled and text sections will be unpacked.

ebp_repack_dir.bat
Drop a directory with ebp files onto this bat and all will be compiled, text sections will be packed and then new ebp files will be created. Always keeps a copy of the last file and always keeps the original file. (works recursively for all subdirectories, too)

ebp_repack_signle.bat
Drop a single ebp file onto this bat and it will be compiled, text sections will be packed and then new ebp files will be created. Always keeps a copy of the last file and always keeps the original file.


And the decompiler/compiler itself:



-d     - disassembles script into VM's assembler (now used mostly to analyze
         binary if issues arrise)
-dc    - decompiles script into high level c-like language
-c     - assembles VM assembly into binary file (use if you need to do something
         not available in the high level language)
-cc    - compiles c-like high level language into script binary
-v     - enables verbose output (the amount of text is huge, so I advise
                 redirecting it into a file)

-Dname       - define a macro for preprocessor (so it will pass #ifdef and fail
               #ifndef check)
-Dname=value - define a macro name to have a value "value" (useful for
               conditional compilation)
-Ipath       - add include search path for #include preprocessor directive (by
               default, "include" path is added)


BASIC LANGUAGE FEATURES


VM's Assembler consists of 100 instructions, 11 registers and ~2000 predefined call targets. More informations are available on the wiki:

https://wiki.ff12.pl

Please note, though, that documentation is very incomplete, but there are still very useful things, like call target list with argument count, ACT usage and return values. A few dozens have even proper descriptions. I'll update the wiki whenever I can, but it will take a while.

As for the high level language, I chose to make it as similar to c/c++ as it was possible, given many limitations of the Virtual Machine. Proper documentation of the language isn't ready, so I'll just describe the most important differences and basic structure.

I would recommend reading this article first (especially regarding variables and variable scopes):

https://wiki.ff12.pl/index.php/General_Vritual_Machine_architecture

Script files are expected to be utf8, but internally only characters available in Shift-JIS Japanese character set are supported by the VM, so bear this in mind - proper check will be done during compilation.

Each file can contain multiple scripts. Each script has a specific level/type.
Basic structure is as follows

script name(LEVEL)
{
    function init()
    {
        return;
    }
    
    function other()
    {
        return;
    }
    
    function talk(2)
    {
        return;
    }
}


Internally scripts are accessed by their numbers not their names. Which means it is a good idea to add new scripts at the end (or as the last script of a given type we're trying to add). I made the decompiler use names whenever possible and convert them to numbers during compilation, but this isn't always possible. Sometimes scripts to call are calculated or even returned by calls. Luckily, it is very rare (and the most frequent case is getmyid(), which will not cause issues, because it will return proper number regardless of position).

Numbers in function's parentheses describe when a function should be called automatically (or not at all if not specified).
  • 1 - main (called after init is done)
  • 2 - talk (called when talked to NPC controlled by a script
  • 12 - mapjump (called when mapjump area is entered)
  • 17 - talkterm (called when conversation ends)
  • etc.
Names do not matter. A function foo(1) is still main, just as bar(2) is still talk.

Return statements have to be explicit. If there is no return statement, VM will simply proceed to a next function. It cannot be done otherwise, as the original scripts do sometimes take advantage of this behavior.

Functions defined in scripts cannot be called directly, only through one of the Remote Execution Queue instructions (sysReq, sysReqew, sysReqsw, etc). It's the VM's limitation. You CAN technically use goto instruction to jump to any function within a script (e.g. goto other;) or even to any label within a script, but return will act as if it was called from the script the execution began in. There is no jump to register or jump to address instruction at all and all jumps are done by specifying (internally, compiler takes care of that) an index of jump entry within script's jump table that has to be known at compile time and is unchangeable.

Supported variable types:
int (32bit, signed)
short (16bit, signed)
u_short (16bit, unsigned)
char (8bit, signed)
u_char (8bit, unsigned)
float (32bit, single precision)


While there is a possibility to get a variable's address (pointer/reference) it cannot be used in any other way than a normal integer value. It is used solely in cases of call targets that require multiple output variables. e.g:

getpos(&posX, &posY, &posZ);

VM doesn't simply have any instruction that would allow to dereference or use a pointer in any meaningful way.

Local variables are not supported by the VM, but they're emulated, so you can declare them in each block scope and they'll work more or less as expected. One VERY IMPORTANT thing to note, is that all variables should be treated as static. This means that values are retained between function calls and that initialization is done only during initial script load. This means that usually assigning values rather initializing them is more suitable.

If an array is initialized during declaration, the size can be omitted and will be properly set based on initializer values. VM supports only one and two dimensional arrays. Only one dimensional arrays can be initialized at declaration time.

While sizeof(variable) operator does act as in c/c++, returning size in bytes. There is also available countof(array), which returns count of elements in an array.

Some call targets (specified on the list by ACT = true) can be called in a context of another script. For example:

other.setkutipakustatus(1);

will make an NPC controlled by script "other" start moving lips instead of the script it's been called from.

Preprocessor is very basic for now.
#ifdef, #ifndef, #include, #define, #undef directives are supported.
#include <path> - search in compiler's directory
#include "path" - search in script's directory (current file's path is checked first, then the parent's, etc., up to the top)
"Function like" macros are now supported (see readme for details). Macros are evaluated at the time of usage, even if it is within another macro's definition (which is different that c/c++, which evaluates macros at first usage in code)

Until a proper documentation is ready, this will have to suffice. I recommend reading original scripts as well as some samples I have available on my gitlab (all released by me mods are open source).

https://gitlab.com/ff12-mods


EDITOR RECOMMENDATION


I'm doing all my work on the scripts in Visual Studio Code. It supports both syntax highlighting and statement autocompletion out of the box, without installing any plugins (actually installing e.g. c plugin will kill that functionality, as these are not c files, only similar to some degree).

IMPORTANT NOTICE


Please, please, for the love of everything that is dear to you, do keep your sources and do not rely on decompiler getting a recompiled source back from a binary. Decompiling this complex binaries and then compiling them back is never 1:1. The behavior should be the same, but a lot of information is lost.
Compiler uses some optimizations and it is even possible that some bugs in the code will be introduced at some point.

You wouldn't delete your c++ sources and then rely on decompilers to get them back, would you?

EVEN MORE IMPORTANT NOTICE


Please, do not redistribute these tools anywhere else. They're still in active development and having it all in one place does make things easier for me.

As always, have fun.

~~ffgriever 2019.09.25~~


VERSION HISTORY

v2.83
  • tag system in text tool completely revamped by Xeeavin
  • fixed order of operations for boolean expressions that led to unintended behavior (list of affected files: https://pastebin.com/KB1W9KQp)
  • throw exception on critical parser errors that were just printing errors before
  • added spawn group support (this will fix mimics/pandoras)
  • added "-cs" switch to compile to assembly instead of binary
  • added "-g" switch that will save variable names and actor types in binary
  • a lot of formatting fixed or standardized
  • disabled removing of repeated logical not operator (which basically casts non bool into bool value). List of affected files: https://pastebin.com/DXha74ww
  • to avoid confusion with script files themselves, script entries are now renamed to actor by default; script and class keywords are supported as well, so you can use them if they seem to fit a given case better
  • exitStruct now uses u8, u8, u16 instead of one u32 (backwards compatible)
  • function like macro support (with #macro(list) and #endmacro directives)
  • added decompiler support for detecting switches with only default present
  • added error when script type out of order is detected
  • switch value expressions can now contain boolean expressions (lus_b02 and lus_d01)

v2.62
  • added external function name definition support


v2.61
  • added external variable name definition support


v2.60

  • now faster by 70-130%

v2.52
  • split position flags into scriptId and teleportIndex
  • renamed unknownScale to weatherProbability
  • split unknownFlags2 into saveIndex and anchorIndex
  • added unknownNavIcon and unknownLocation
  • split unknownFlags1 into unknownScript2 and mooglingIndex

v2.51
  • trapOffset added
  • fixed local stack size calculation
  • added unknownFlags2
  • added sysAttach wrapper

v2.4g
  • name replace array added for scratch1

v2.4f
  • compatibility with new calls

v2.4e

  • removed optimization from v2.4b until grammar is fixed to work with it properly

v2.4d
  • fixed variables handling by system wrappers

v2.4c
  • sysReqwaitall "req array out of range" fix
  • added some characters used in scripts that were not recognized by lexer
  • fixed nal_c0101 (special case: function name is the same as an assembler keyword "RET")
  • fixed error reporting in some cases
  • added experimental "multithreaded" batch for packing

v2.4b
  • faster compile times (~3-4 times)

v2.4a
  • array initialization fix
  • text tools updated to support PS2 hdat files

v2.4
  • added support for initializing multidimensional arrays
  • decompiler support for initializing multidimensional arrays
  • fixed an issue with initializing arrays only partially
  • constant expressions can now be used for array size declarations instead of immediates only
  • updated text tools to support gmap and hdat files

v2.3d
  • fixed scripts with spaces in author name not compiling (added proper support for string literals)

v2.3c-update2
  • updated EBP unpack tool to support removing/adding sections
  • simple tool to export and import model id section (12)
  • simple tool to export and import position section (16)
  • bat files updated for the two new tools

v2.3c-fix1
  • text tool fix for very small ebp text files

v2.3c
  • first public release