Adhoc is a scripting language and bytecode that was introduced in Gran Turismo 4. It is an in-house developed custom scripting language by Polyphony Digital.
Scripting languages are typically implemented so that non-engine developers can work on new features without necessitating the compilation of a new game executable, which - especially in the early 2000s - can take a long time to build to test changes. In GT's case, Adhoc is responsible for almost all of the non-race logic.
In general, the game's main executable is really just the game engine, framework, car/graphics handler, etc. It only executes what the adhoc scripts are asking it to do.
It is important to understand that Adhoc is two different components, the programming language itself named Adhoc, and the bytecode - script interpreter also named and part of Adhoc.
Gran Turismo 7 still uses and supports adhoc bytecode, but no longer uses Adhoc as its input source code. It has moved to Swift with their own custom compiler compiling to adhoc bytecode.
Before explaining what each file format is, it is important to understand certain folders related to it.
||This is where each "menu" is stored, within its corresponding sub-folder. For instance, GT5's main menu is
||Stores function utilities for the projects to use in general. Most importantly, it contains a
||This is the least important one. It just defines some UI widgets.|
For the formats, there are four to keep in mind.
||See Specific Section||Adhoc Compiled - This is the game code itself. It is in a compiled form, so it cannot be edited out of the bat.|
||Yes||UI Projects/Widgets - These are essentially the UI layout definition, and sets properties for each widget. Adhoc Scripts are directly linked to them and manipulates them as a real UI framework.|
||Yes||UI Assets - Containers for each project that contains images|
||Yes||GT6 Only. These contain bundles of
Advanced Glossary (click to expand)
||Adhoc Compiled Script|
||Proprietary scripting language for Gran Turismo. Can also refer to bytecode when compiled from pure Adhoc or Swift (GT7). Not to be confused with PSP Ad hoc|
||Represents an object or module property.|
||Build type of the game. For GT6 it normally is
||An image/resource container for all the assets a project or root uses.|
||Similar to a namespace.|
||Represents any node within an MWidget. Any node is also a module on their own.|
||UI Layout definition for a project, generally many MWidgets combined into one MProject.|
||UI Layout definition for a root.|
||A compressed container for splitted adc and mproject/mwidget files.|
||A group of menus.|
||A game menu.|
||Name of the debug menu.|
||See Tiny Web. Web Server that GT6 and beyond can host which can be used to host pages for external access, or for executing Web Modules.|
||See Tiny Web. An adhoc script which returns a web response.|
As explained in the introduction, Adhoc scripts are responsible for roughly 99% of the gameplay logic. An ongoing effort to translate compiled scripts into compilable versions is available at OpenAdhoc.
Scripts that have not been reverse-engineered can be edited, but it is a difficult process as you will have to deal with hex-editing instructions.
Most of the operations are done through the GTAdhocToolchain. Compiled builds can be acquired from the Actions page, clicking on the latest build, and scrolling to the bottom for a build's executable. It is recommended to always check for updates.
That said, adhoc in general is quite similar to popular programming languages, a few differences and features be seen at the language spec.
Editing and recompiling scripts¶
Using the toolchain directly, scripts can be compiled using the .yaml file.
The version should match the version the game supports, you can check the Build List for each's game supported version. You can also check the by dissasembling the scripts.
Note that the toolchain supports compiling Version 7 through 12.
Or if you also have installed the VS Code extension provided:
- Run Build Task (Ctrl+Shift+B) with the VS Code Adhoc Extension on any source file or project file.
Catching exceptions/debugging error may be troublesome, here are some tips that can help debugging:
Unfortunately error handling is completely stripped in GT4. Throws do not do anything, meaning any adhoc exceptions will immediately crash the game. The best way to debug this is to spam around a bunch of
openConfirmDialog calls in various parts of code to keep track of the code that's being run.
GT5 and above¶
Fortunately catching exceptions is a lot easier from GT5 onwards. There are multiple ways to debug a script:
Method 1 - Try/Catch¶
try/catch clauses are available and can be used to intercept any error that happens.
Method 2 - Using the toolchain¶
The toolchain allows wrapping any function and subroutine into a try/catch that will print any exception to a file. The
--write-exceptions-to-file argument is used:
When an exception is caught, exceptions will be written to
/APP_DATA_RAW/exceptions.txt - this translates to USRDIR/exceptions.txt (at least for PS3 GTs).
Method 3 - Memory addresses¶
Here are some memory addresses you can put a breakpoint to see exception messages (using ProDG, or RPCS3)
0xA1FEE8(GT6 EU 1.22) -
0x9C2FF8(GT5 EU 2.11) -
Method 4 - Grim¶
If you have a Grim setup, adhoc errors are automatically reported to the console.
Editing scripts from compiled binaries (advanced)¶
To begin viewing them, drag any
.adc file onto the toolchain executable. This should output a
.strings file next to the source file.
.ad file can be viewed in any text editor, preferably Notepad++. In it, you will find the source code in an Assembly form. Adhoc Scripts are generally high level, but still contains stack handling, scopes, etc.
All instructions will start with three different numbers seperated by
|s. Lets take the following instruction as an example and lets tear it down.
209FD| 23| 21| STATIC_DEFINE: REPLAY_MINIMUM_HDD_SPACE
209FDis the offset of the instruction within the
.adcfile. It will point to the instruction type, which its enum is documented here.
23is the Line Number within the non-compiled source file (used for debugging purposes)
21is the instruction number within the current scope (i.e function, method, top-level code).
- The rest of the line is the instruction itself.
The process itself is easy but it is mainly the scope of what you can do that is a problem. Generally, this is how it goes:
- Dissasemble the source adhoc script
- Locate a code part and instruction that you want to edit
- Copy the instruction offset.
- Open the source
.adcfile in a hex editor.
- Go to the copied offset. You will be pointed to the instruction's type, the 4 bytes before it being the instruction's line number, and the next bytes after it being the instruction data (if applicable).
- Edit the instruction data (if applicable).
With that in mind, here is a basic example for editing a constant value.
209DA| 21| 17| INT_CONST: 1024 (0x400)
Let's say you wanted to edit 1024 to 500000. You would open the
.adc file, go to
209DA. The number itself is located at the next four bytes (int32), where 1024 would be
00 04 00 00. You can use the data inspector that most hex editors have (HxD, 010) to edit the value easily. In this example, setting the value to 500000 would change the bytes to
20 A1 07 00. Then you can save.
To verify that the change was made correctly, simply disassemble the edited file. If no errors are thrown, the script should work fine.
Obviously there are more complex instructions and used incorrectly, can break the game loop. Depending on where it happens, the game may still continue to run. For instance, if the game crashed while in the middle of a menu, chances are the adhoc will crash and simply restart the project. However it crashes during its loading, this is essentially a softlock.
One thing to look for in Adhoc when editing:
- Any object that is not defined (aka null
nilin adhoc) and then used is null derefencing.
- Invalid operators between object types is essentially null derefencing aswell.
- The stack. Adhoc uses it. Editing instructions that plays with the stack will certainly break unless you know what you are doing.
- Jump Instructions. You can essentially jump anywhere you want by editing the instruction target, so you can essentially also skip checks, but beware of jumping past variable declarations, as this may break the code further down the line at runtime.
Created: September 22, 2023