Decompile, edit and compile the scenerio.gcx scripts of Metal Gear Solid 4, Metal Gear Online 2 and Metal Gear
Arcade — with highlighting, autocomplete, linting and a byte-exact round trip.
GCX files are the compiled form of GCL (Game Command Language), the TCL-like scripting language of the MGS4 engine. Every stage has one: it spawns the actors, sets up the HUD, weapons and loadouts, defines the game rules and wires up events. This extension turns a GCX file into readable GCL text, lets you edit it with full editor support, and compiles it back into a file the game loads.
An unedited project compiles back to the original file byte for byte. Edited projects get every size, offset and table rebuilt automatically.
- Marketplace: search for Metal Gear GCL in the Extensions view (
Ctrl+Shift+X), or runext install zoft123.metal-gear-gcl. - From a
.vsix: download it from the Releases page, then Extensions view → … → Install from VSIX….
No other software is needed: the decompiler, the compiler and the name lists for hashes are all part of the extension.
- Right-click a
scenerio.gcxin the Explorer and choose Decompile GCX to GCL project. A folderscenerio/is created next to it withscript.gcl(the procs and main script) andresources.gcl(strings and data tables), and the script opens. - Edit. Errors and warnings appear as you type; hover anything to see what it is.
- Press the Compile button in the editor title bar (or right-click the folder → Compile GCL project to GCX)
and choose where to write the
.gcx.
Encrypted files are decrypted automatically when you decompile them (the key is the stage/<name> folder in the
file's path) and re-encrypted when you compile. When the path contains a disc or PSN title ID, that decides it:
| Title IDs | USRDIR/mgs (MGS4) |
USRDIR/o (MGO2) |
|---|---|---|
| BLUS30109, BLES00246, BLJM67001, BLJM67002, BLJM67003, BLJM57001, BLUS30148, BLAS55004, BLAS55005, BLKS25002 | plain | encrypted |
| NPUB31633, NPEB02182, NPJB00698 (PSN releases) | encrypted | encrypted |
| BLJM60082 (standalone MGO disc) | — | encrypted |
The output folder counts too: compiling into a USRDIR/o folder always encrypts, compiling into a Blu-ray
USRDIR/mgs folder never does.
Diagnostics come from the real compiler, so a file with no errors compiles. On top of syntax errors, the extension checks for:
| Check | Example |
|---|---|
| Calls to procs that don't exist | @proc999, -init_hud p:proc999 |
Resources past the end of resources.gcl |
$res:99999 |
| Strings longer than the 254 bytes GCL allows | print "…300 characters…" |
| Names that look right but hash to something else | chara NewSky … — the word NewSky hashes to 8cda7b, but the NewSky handler is [ce2d24] (one-click fix) |
| Typos in new option or command names | -wp_di 3 when the script uses -wp_id everywhere else |
| Resource lines out of order or malformed | resources.gcl is checked line by line |
The guess-based checks only judge names a person typed. Decompiled code never trips them, and after a syntax error only the error and the definite problems before it are shown.
@procandp:proc— every proc in the script, with a preview of its body.-after a command — the options used with that command in this script, ranked by how often they appear.- Commands at the start of a statement — commands used in the script and every handler from
commands.txt(typingNewSkinserts[ce2d24/NewSky]). $res:— resources with their text;$—$status,$argN,$localNand the variables used in the script.- Snippets for
if,if / else,if / else if / else,switch,case,procand a rule check.
Proc bodies, resource contents, hashes (handler label, dictionary names, use count), option codes, how a number will
be stored, variable layout (type, region, offset, bit), and what each %(…) encoding annotation means.
Go to definition and find references for procs (@procN, p:procN) and resources ($res:N jumps into
resources.gcl); an outline of all procs with the first statement of each.
GCL refers to commands, actor types, options and many values by 24-bit hashes. The extension ships with two community name lists, so scripts read well from the first decompile:
data/dictionary.txt— about 48,000 known strings. A hash is shown as a word (chara,-wp_id,Rule_TDM) only when that word really hashes to the stored value.data/commands.txt— handler names for 287 command hashes, shown as labels:[f576c7/COM_svGetRule].
Bundled names take priority by default. A dictionary.txt / commands.txt beside the project (or up to four
folders above it) or in the workspace supplements names missing from the bundle, so old local copies cannot hide
new extension names. To deliberately override bundled names, set gcl.dictionaryPath / gcl.commandsPath
(or use CLI --dict / --labels); bundled fallback names remain available. The GCL output channel lists the
name-file sources used by Decompile. Names only change how hashes are displayed; compiled bytes do not depend on them.
| Command | Where |
|---|---|
| GCL: Decompile GCX to GCL project | Explorer context menu on .gcx files, command palette |
| GCL: Compile GCL project to GCX | editor title bar, Explorer context menu, command palette |
| GCL: Verify GCX round trip | Explorer context menu on .gcx files — decompiles and recompiles in memory and compares the bytes |
| GCL: Reload dictionary and command names | command palette |
gcx timestamp=0x49d307e4 seed=0x00000000
proc 22 {
command [5d0cc1] \
-wp_id 7 \
-num 80
}
proc 125 {
if (4 == {
command [f576c7/COM_svGetRule]
}) {
if ({
command [5e8ea5]
} & 2) {
@proc121
@proc22
} else {
@proc34
@proc22
}
} else {
@proc34
@proc22
}
}
main {
...
}
| Syntax | Meaning |
|---|---|
proc 3 7:1 { … } |
a proc; @proc3 calls it. Ids are 1-based and must run 1..N without gaps; 7:1 = id 7 with flags 1 |
name args… -option values… \ |
a command; a trailing \ continues it on the next line |
if (…) { } else if (…) { } else { } |
control flow, as the original MGS source wrote it |
switch (…) { case X { } default { } } |
switch |
@proc12 1 2 |
call proc 12 with arguments |
p:proc12 |
pass proc 12 by reference (for example -init_hud p:proc32) |
word / [c2c7a0] / [ce2d24/NewSky] |
a 24-bit hash: a dictionary word, a raw hash, or a hash with a display label (labels are ignored when compiling) |
80, 300:s32, 5:u16 |
numbers get the original compiler's encoding; a :type suffix keeps an explicit one |
"text", e"テキスト", b"\x00\x01" |
UTF-8 string, EUC-JP string, exact bytes |
$res:12 |
resource 12 from resources.gcl |
$status, $arg1, $local0 |
last result, proc argument, proc-local variable |
$s32@link:a9c, $bit@var:20.b3 |
a game variable: type, region (var, link, local), offset, bit |
(($arg1 + 2) * 70000) |
an expression, fully parenthesised |
%(short=1), %(w=1), %(noend) |
quirks of the original compiler, kept so files rebuild byte for byte — leave them in place |
resources.gcl holds one resource per line: index kind content, where kind is s (a string) or v (a list of
values). Add new resources at the end with the next index and refer to them as $res:N.
| Setting | Default | Description |
|---|---|---|
gcl.dictionaryPath |
(bundled) | your own dictionary.txt. Empty: one next to the project or up to four folders above it, then in the workspace folders, else the bundled list |
gcl.commandsPath |
(bundled) | your own commands.txt (0xHASH -> Name), searched the same way |
gcl.mgo2Key |
MGO2 key (e.g. stage/n001a) for encrypted files whose path has no stage/<name> folder |
|
gcl.lint.labelNames |
warning |
severity of the "name hashes to something else" check |
gcl.lint.unknownCommands |
information |
severity of the unknown typed command check |
gcl.lint.unknownOptions |
information |
severity of the unknown typed option check |
gcl.compile.output |
ask |
ask for a destination each time, or nextToProject to write <folder>.gcx |
The same engine runs in a terminal with Node.js 18 or later:
node bin/gcx.js scenerio.gcx # decompile next to the file -> scenerio/
node bin/gcx.js decompile scenerio.gcx out/
node bin/gcx.js compile scenerio/ [out.gcx]
node bin/gcx.js verify a.gcx b.gcx … # byte-exact round-trip checkOptions: --dict FILE, --labels FILE, --key stage/NAME, --no-encrypt. Without --dict / --labels the
tool uses a dictionary.txt / commands.txt near the input file, else the bundled lists in data/.
The GCX reader follows the game's own GCL interpreter: variable-length sizes, typed literals, variables, expressions
in stack form, options, commands, blocks and the proc table. The original compiler's choices are reproduced exactly
(number encodings, size-field widths, end markers), and the few places where it left unusual encodings carry a
%(…) annotation, so unedited text always compiles to the original bytes. MGO2 encryption is a 64-bit XOR chain
with an MD5-based checksum keyed by the stage folder.
extension.js VS Code integration (diagnostics, completion, hover, navigation, commands)
lib/gcx.js GCX container and bytecode: parse and rebuild
lib/gcltext.js GCL text: decompiler (emitter), parser and compiler
lib/project.js project folders, names, MGO2 decryption
lib/mgo2crypt.js MGO2 stage-file encryption
bin/gcx.js command-line tool
data/ bundled name lists: dictionary.txt, commands.txt
syntaxes/, snippets/ grammar and snippets
test/ provider tests against a mock of the VS Code API
build_vsix.py packages the extension as a .vsix
- Package:
python3 build_vsix.pywritesgcl-<version>.vsix(novsceornpm installneeded). - Round-trip test:
node bin/gcx.js verify path/to/*.gcx— every file must reportOK. - Provider tests: decompile a script, then
node test/test-extension.js path/to/projectruns diagnostics, quick fixes, hovers, navigation and completion against it. - Run from source: open this folder in VS Code and press
F5to start an Extension Development Host.
- Rename a proc id across the script (renumbering all
@procN/p:procNreferences). - Signature help for commands, learned from how each command is used.
- Semantic highlighting of hashes by kind (command, chara type, option).
- A built-in hex view of binary resources.
- Semantic checks for common commands (argument counts and types).
Issues and pull requests are welcome.
- Format knowledge from the games' own GCL interpreter and the MGS2
gclconvsources. dictionary.txtandcommands.txtare community name lists that started with Jayveer's Gcx decompiler (MIT) and have been extended since.- MGO2 decryption follows the method implemented by HavenStudio2 of the MGO2 revival community (shared with LA2 Studio).
This is an unofficial fan-made tool. It is not affiliated with, endorsed by or connected to Konami or Kojima Productions. Metal Gear, Metal Gear Solid, Metal Gear Online and Metal Gear Arcade are trademarks of their respective owners. The extension contains no game files: you need your own copies of the games' files. The bundled name lists only map hashes to readable names.