CLI / API Usage¶
In addition to the ExplorerScript specification, this repository also contains a compiler and decompiler for Explorers of Sky’s binary SSB scripts.
The (de)compiler works with structured components of the SSB scripts. You will have to (dis)-assemble the SSB script using these components.
A reference implementation of the assembly process can be found in
skytemple-files (script_compiler
to create the model, writer
to convert it
to binary).
This document mostly focuses on the CLI interface.
SSB Data Structure¶
The compiler and decompiler work with a JSON-encoded structure to represent the SSB data and settings. The decompiler takes it as input and the compiler generates it as output.
General structure¶
{
"settings": "<<SETTINGS>>",
"routines": [{
"type": "COROUTINE",
"name": "NAME",
"ops": ["<<OPERATION>>"]
}, {
"type": "GENERIC",
"ops": ["<<OPERATION>>"]
}, {
"type": "ACTOR",
"target_id": "<<ARG_INT or ARG_CONSTANT>>",
"ops": ["<<OPERATION>>"]
}]
}
“routines” contains the routine specification. All routine types have the “ops” field, which contains a list of SSB operations. The ID of routines is the index in the list of routines.
Routine types¶
COROUTINE: A coroutine, the name is in the “name” field.
GENERIC: A simple generic routine.
ACTOR: A routine for an actor, the target actor ID is in the “target_id” field and is either a string or integer argument data type.
OBJECT: A routine for an object, see notes for ACTOR.
PERFORMER: A routine for a performer, see notes for ACTOR.
Structure of settings¶
Contains an object with the following fields:
“performance_progress_list_var_name”: The constant used for the variable PERFORMANCE_PROGRESS_LIST.
“dungeon_mode_constants”: The constants that should be used for the dungeon mode states. This is an object:
{"open": "DMODE_OPEN", "closed": "DMODE_CLOSED", "request": "DMODE_REQUEST", "open_request": "OPEN_AND_REQUEST"}
Structure of operations¶
An operation is an object with the following structure:
“opcode”: Name of the opcode to use (string).
“params”: A list of arguments, as described by “Argument types”.
The index of the operations in the operation list is the opcode offset plus the length of all previous routines. An assembler might need to convert those offsets to proper binary offsets!
The indices start at 1!
Argument types¶
Integer¶
Is encoded as an integer.
Fixed point number¶
Is encoded as a JSON object with “type” being “FIXED_POINT” and the “value” field being the value.
{
"type": "FIXED_POINT",
"value": "123.456"
}
Constant¶
Is encoded as a JSON object with “type” being “CONSTANT” and the “value” field being the constant name.
{
"type": "CONSTANT",
"value": "LEVEL_XYZ"
}
(Const) String¶
Is encoded as a JSON object with “type” being “CONST_STRING” and the “value” field being the string.
{
"type": "CONST_STRING",
"value": "Hello World"
}
Language String¶
Is encoded as a JSON object with “type” being “LANG_STRING” and the keys of the object under “value” being the language names and the values the string values.
{
"type": "LANG_STRING",
"value": {
"english": "Hello World!",
"german": "Hallo Welt!"
}
}
Position Mark¶
Is encoded as a JSON object with “type” being “POSITION_MARK” and the keys of the object under “value” being the data of the mark.
{
"type": "POSITION_MARK",
"value": {
"name": "Name of the mark",
"x": 10,
"y": 20
}
}
Best practices for constants¶
If you are using the compiler for Explorers of Sky, you should use the same prefixes SkyTemple uses for constants:
Type |
Prefix |
Notes |
---|---|---|
Direction |
DIRECTION_ |
Uppercased, camel case replaced with _. |
Special Process |
PROCESS_SPECIAL_ |
Uppercased. |
Menu |
MENU_ |
Uppercased. |
Level |
LEVEL_ |
Uppercased. |
Face Position |
FACE_POS_ |
Uppercased. |
Face ID |
FACE |
Uppercased. |
Object |
OBJECT_ |
The object name is uppercased and the ID is suffixed: OBJECT_D01P11B2_12 |
Actor |
ACTOR_ |
|
Coroutine |
CORO_ |
|
Game Variable |
$ |
|
Dungeon Mode |
DMODE_ |
OPEN / CLOSED / REQUEST / OPEN_AND_REQUEST |
This guarantees maximum compatibility between different tools.
Decompiling¶
To decompile run the CLI module like so:
python3 -m explorerscript.cli.decompile ssb_model.json
Where ssb_model
is the path to the JSON SSB model, including settings,
as described above.
You can specify the --source-map filename.exps.sm
parameter to
output a source map at the given location.
The ExplorerScript source code is printed on stdout. Errors are printed on stderr. If the process exits with exit code 0, it’s successful.
Compiling¶
To compile run the CLI module like so:
python3 -m explorerscript.cli.compile source_file.exps --settings settings.json
Where source_file.exps
is the path to the ExplorerScript source
file and settings.json
is the path to a JSON file, that contains
at least the settings block as described above.
You can specify the --source-map filename.exps.sm
parameter to
output a source map at the given location.
You can specify the --lookup PATH
parameter to specify lookup paths.
It can be added multiple times, for multiple lookup paths.
The SSB JSON is printed on stdout. Errors are printed on stderr. If the process exits with exit code 0, it’s successful.
Compiling an example¶
Compiling the source code in the example
directory:
python -m explorerscript.cli.compile example/SCRIPT/base.exps --settings /tmp/settings.json --lookup example/macros
With /tmp/settings.json
having the following content:
{
"settings": {
"performance_progress_list_var_name": "$PERFORMANCE_PROGRESS_LIST",
"dungeon_mode_constants": {
"open": "DMODE_OPEN",
"closed": "DMODE_CLOSED",
"request": "DMODE_REQUEST",
"open_request": "OPEN_AND_REQUEST"
}
}
}
Output:
{
"settings": {
"performance_progress_list_var_name": "$PERFORMANCE_PROGRESS_LIST",
"dungeon_mode_constants": {
"open": "DMODE_OPEN",
"closed": "DMODE_CLOSED",
"request": "DMODE_REQUEST",
"open_request": "OPEN_AND_REQUEST"
}
},
"routines": [
{
"type": "GENERIC",
"ops": [
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "Before Macro"
}
]
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "Begin LocalMacro"
}
]
},
{
"opcode": "vars",
"params": [
{
"type": "POSITION_MARK",
"value": {
"name": "PositionName",
"x": "10",
"y": "10.5"
}
},
2,
3,
{
"type": "CONST_STRING",
"value": "String"
}
]
},
{
"opcode": "vars_in_remote_macro",
"params": [
2,
{
"type": "CONST_STRING",
"value": "String"
},
{
"type": "CONSTANT",
"value": "$notAvailable"
}
]
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "BELOW IS A TEST RETURN"
}
]
},
{
"opcode": "BranchValue",
"params": [
{
"type": "CONSTANT",
"value": "$TEST_VAR"
},
4,
3,
8
]
},
{
"opcode": "Jump",
"params": [
10
]
},
{
"opcode": "print",
"params": [
{
"type": "CONST_STRING",
"value": "The variable is smaller"
}
]
},
{
"opcode": "Jump",
"params": [
11
]
},
{
"opcode": "vars_in_remote_macro2",
"params": [
{
"type": "CONST_STRING",
"value": "from remote_macro"
},
{
"type": "CONST_STRING",
"value": "String"
},
{
"type": "CONSTANT",
"value": "$notAvailable"
}
]
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "REMOTE2 SHOULD END HERE"
}
]
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "macro_in_macros_2"
}
]
},
{
"opcode": "NUMBER_TWO_im_in_macros_2",
"params": []
},
{
"opcode": "NUMBER_ONE_im_in_macros_2",
"params": []
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "End LocalMacro"
}
]
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "Begin LocalMacro"
}
]
},
{
"opcode": "vars",
"params": [
10,
9,
8,
{
"type": "CONST_STRING",
"value": "Another one"
}
]
},
{
"opcode": "vars_in_remote_macro",
"params": [
9,
{
"type": "CONST_STRING",
"value": "Another one"
},
{
"type": "CONSTANT",
"value": "$notAvailable"
}
]
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "BELOW IS A TEST RETURN"
}
]
},
{
"opcode": "BranchValue",
"params": [
{
"type": "CONSTANT",
"value": "$TEST_VAR"
},
4,
3,
22
]
},
{
"opcode": "Jump",
"params": [
24
]
},
{
"opcode": "print",
"params": [
{
"type": "CONST_STRING",
"value": "The variable is smaller"
}
]
},
{
"opcode": "Jump",
"params": [
25
]
},
{
"opcode": "vars_in_remote_macro2",
"params": [
{
"type": "CONST_STRING",
"value": "from remote_macro"
},
{
"type": "CONST_STRING",
"value": "Another one"
},
{
"type": "CONSTANT",
"value": "$notAvailable"
}
]
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "REMOTE2 SHOULD END HERE"
}
]
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "macro_in_macros_2"
}
]
},
{
"opcode": "NUMBER_TWO_im_in_macros_2",
"params": []
},
{
"opcode": "NUMBER_ONE_im_in_macros_2",
"params": []
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "End LocalMacro"
}
]
},
{
"opcode": "debug_Print",
"params": [
{
"type": "CONST_STRING",
"value": "After Macro"
}
]
}
]
},
{
"type": "ACTOR",
"target_id": "TEST",
"ops": [
{
"opcode": "test_actor",
"params": []
}
]
},
{
"type": "ACTOR",
"target_id": 2,
"ops": [
{
"opcode": "test_actor_id",
"params": []
}
]
}
]
}
Python API¶
The Python API mostly works the same way as the CLI interface.
However the settings are provided as arguments to the compiling/decompiling classes and the routine data is split into three separate lists:
Named coroutines: The names of the coroutines on the indexed position, None for all regular routines.
Routine Info:
SsbRoutineInfo
objects describing the type and target of the routine.Routine Ops: A list of
SsbOperation
. Each operation has a named opcode with it’s ID field being ignored (-1 generated by compiler). The parameter list contains objects of the types described bySsbOpParam
, they correspond to the JSON types described above.
The indices of the lists are the routine IDs.
The compiler is at explorerscript.ssb_converting.ssb_compiler.ExplorerScriptSsbCompiler
and the decompiler at explorerscript.ssb_converting.ssb_decompiler.ExplorerScriptSsbDecompiler
.