Releases: ExpHP/truth
0.5.2
Added
- Support for TH18.5 100th Black Market.
- Debug info. The
--output-debug-info JSONFILE
flag has been added to allcompile
subcommands. This file can be used by debuggers to relate source-level concepts (e.g. function names and variable names) to runtime concepts (e.g. registers and const values).
Perfect name resolution of locals in a debugger might not be possible yet as truth currently does not explicitly construct the tree used for name resolution (it is only implicitly constructed), so scope information is not yet available. - Bitwise negation. The unary
~
(bitwise not) operator has been added. No language natively provides it, but even when unavailable, it can be used (and will compile as-1 - x
). --no-builtin-mapfiles
option for both compilation and decompilation. This will disable the core mapfiles which provide the builtin signatures and intrinsic mappings for all games, which can be useful if you are trying to design a comprehensive mapfile from scratch.
Other changes
- The ternary operator
a ? b : c
can now be used in any expression, not just const expressions. - Relative time labels and interrupts now accept expressions, so you can use consts. Technically this also makes negative relative time labels possible; whether you choose to write them as
+(-15):
or (gasp)+-15:
is up to you... - Unary
-
now can be directly provided by an intrinsic, and will otherwise fall back to-1 * x
. (formerly, it would always produce0 - x
, which is not correct for all floats)
v0.5.0
Version 0.5.0 is a major release of the compiler containing many of the language additions that were found useful in alpha implementations of truecl. While truecl
is still not officially released, these additions and improvements are available in all languages.
Added
Commands
- Multiple
-m
args can now be provided. - Decompile commands now support
-o
/--output
, just like compilation. This is extremely useful on Windows where redirection on STDOUT may produce a file in a different encoding from UTF-8 depending on the system configuration. - truanm had some unhelpful behavior when using multiple image sources that provide the same image, or when using
has_data: "dummy"
together with an image source. Image sources have been redesigned to better support common use cases.
Language features
INF
,NAN
,PI
constants.break
keyword. This exits the nearest surrounding loop.- New type-cast syntax. The old
_S
and_f
functions have been split into two types of operations:int(expr)
andfloat(expr)
for type-casts, and$(expr)
and%(expr)
to read a temporary as some type. (the two are the same in most languages, except EoSD ECL which does not auto-cast) offsetof(label)
andtimeof(label)
expressions. You can use these if you want to write a jump usingins_
syntax or the instruction alias. (these were a necessary addition for decompilation of EoSD ECL files that use conditional jumps in a funny way).- User-defined enums. A mapfile can define an enum:
which defines constants
!enum(name="TestEnum") 20 Red 40 Blue
TestEnum.Red
andTestEnum.Blue
. An instruction can then specify that it takes an argument of this type, via a modifiedS
argument:In this example, when calling!ins_signatures 100 S(enum="TestEnum")
ins_100
you will be able to useins_100(Red)
as a shorthand forins_100(TestEnum.Red)
, and during decompilation it will try to decompile the values from this enum. Enums are open, in that the same enum can be defined multiple times or even across multiple mapfiles, and the list of consts will be merged. - Built-in enums:
bool
.true
andfalse
are no longer keywords but rather members of a builtinenum bool
. Use it like any other enum.BitmapColorFormat
. This now houses the constantsFORMAT_ARGB_8888
,FORMAT_RGB_565
,FORMAT_ARGB_4444
, andFORMAT_GRAY_8
used byimg_format
andrt_format
in ANM files.AnmSprite
,AnmScript
,MsgScript
,EclSub
. These get automatically generated from the names defined in a source script, allowing you to write e.g.S(enum="AnmSprite")
andS(enum="AnmScript")
instead ofn
andN
. This makes them more flexible, allowing these types to be used in word-sized arguments and, in the future, timeline arg0.
- Intrinsic mappings. (
!ins_intrinsics
) For instance, a patch which adds jump intrinsics to MSG could also provide a mapfile which tells trumsg about this intrinsic:and then you would be able to write!msgmap !ins_instrinsics 100 Jmp() !ins_signatures 100 ot
loop { }
s in MSG!
Improvements to decompilation
- Can now detect of
if/elseif
chains that have noelse
block. - Many improvements to detection of nested
if/else
s and loops. - Decompiling intrinsics will fall back to instruction syntax if the intrinsic cannot be decompiled. (e.g. PCB stage 7 ECL has a
set_int
instruction that tries to assign to an immediate) - Decompiling sub/script/sprite names will fall back to raw integers if the corresponding items don't exist.
Compatibility notes
- Using registers (e.g.
$REG[8]
) in a format without registers such as STD is now detected as an error. - If e.g.
X
is an alias for$REG[3]
, then using bothX
andREG[3]
in the same function body will now generate a warning. Similarly, using two different aliases (e.g.X
andY
) for the same register will also warn.- This is partly so that, in future versions of truth that provide
truecl
, the compiler can call attention to accidental usage of EoSD'sI0
or PCB's "param" registers in subs where these registers are already implicitly in use by function parameters.
- This is partly so that, in future versions of truth that provide
- Previously, using
-m mapfile.eclm
during decompilation would disable lookup fromTRUTH_MAP_PATH
. Now that multiple-m
are supported, this behavior now seems surprising, soTRUTH_MAP_PATH
is now always searched during decompilation.
Internal changes
- The order and encoding of arguments to intrinsics is no longer hardcoded by game/format, but rather inferred from the mapfile signature, meaning it can be defined by the user. So for instance, a
CondJmp(op="=="; type="float")
could have any of the signaturesotff
,toff
,ffto
, orffot
, and these would all be encoded correctly by the compiler. - Time labels are now internally stored as statements. This drastically simplifies parsing and some aspects of loop compilation/decompilation.
0.5.0-pre3
This prerelease contains a highly experimental and extremely early version of truecl with support for TH06-TH095. (N.B. Th095 is missing signatures)
Instructions on how to run truecl can be found here: https://github.com/ExpHP/truth/releases/tag/0.5.0-pre1
Changes from 0.5.0-pre2:
- The old
_S
and_f
functions have been split into two types of operations:int(expr)
andfloat(expr)
for type-casts, and$(expr)
and%(expr)
to read a temporary as some type. (the two are the same in most languages, except EoSD ECL which does not auto-cast)- A patch can define intrinsics for these casts in EoSD ECL as
UnOp(int,float)
(cast to int) andUnOp(float,int)
(cast to float). Suggested signatures areSf
andSS
in line with other EoSD ops, butfS
should also work forfloat(...)
.
- A patch can define intrinsics for these casts in EoSD ECL as
- People strongly disliked the
.Name
syntax for unqualified enum consts so it is now simplyName
. - This unifies the concepts of automatic consts and enums, finally destroying the concept of automatic consts once and for all. The previously existing automatic const kinds are now builtin enums; e.g.
N
in a signature can now be equivalently written asS(enum="AnmScript")
. (this means you can now express e.g. a word-sized sprite)- The builtin enums are:
AnmScript
,AnmSprite
,MsgScript
,EclSub
,BitmapColorFormat
- The builtin enums are:
- An unqualified enum is now able to be used in a place without an enum type (e.g.
int x = Name
) provided that only one enum defines a const with that name. (this was necessary to continue supporting existing color format syntax in anm files, and just generally somehow felt appropriate given the change from.Name
toName
)
0.5.0-pre2
This prerelease contains a highly experimental and extremely early version of truecl with support for TH06-TH095. (N.B. Th095 is missing signatures)
Instructions on how to run truecl can be found here: https://github.com/ExpHP/truth/releases/tag/0.5.0-pre1
The only differences from 0.5.0-pre1 are that this adds enum consts.
v0.5.0-pre1
This prerelease contains a highly experimental and extremely early version of truecl with support for TH06-TH095. (N.B. Th095 is missing signatures)
Disclaimer:
There are many things that may yet still change about the syntax, so it is not advised to use this for developing your own patches yet.
There is no binary for truecl
yet!! To use it, you must call truth-core truecl
instead of truecl
.
# decompile
truth-core truecl d -mmap/any.eclm th06/ecldata1.ecl > ecldata1.ecl.spec
# recompile
truth-core truecl c -mmap/any.eclm ecldata1.ecl.spec -o ecldata1.ecl
A list of known issues with truecl can be found here: #36
Here is the current working copy of the release notes:
Release notes (working copy)
Added
Commands
truecl
(!!!!) is available in prototype status, but the way to invoke it isa well guarded secrettruth-core truecl
. TH06-TH095 are supported.- Multiple
-m
args can now be provided.
New language features in support of ECL
- Function definition syntax for exported subs.
void Sub0(int x) {}
- Natural call syntax for exported subs.
Sub0(10, 20.4);
- Difficulty switches.
I0 = A + (3:4:4:5);
- Difficulty flags.
{"ENH"}: ins_10();
INF
,NAN
,PI
constants.break
keyword. This exits the nearest surrounding loop.offsetof(label)
andtimeof(label)
expressions. You can use these if you want to write a jump usingins_
syntax or the instruction alias. They'll also show up in contrived cases when decompiling an EoSD ECL file that uses conditional jumps in a funny way.@arg0
pseudo-arg. This will be used together with@blob
when decompiling timelines with unknown signatures in TH06 and TH07.
Improvements to decompilation
- Allow detection of
if/elseif
chains that have noelse
block. - Many improvements to detection of
if/else
s and loops in general. - Decompiling intrinsics will fall back to instruction syntax if the intrinsic cannot be decompiled. (e.g. PCB stage 7 ECL has a
set_int
instruction that tries to assign to an immediate) - Decompiling sub/script/sprite names will fall back to raw integers if the corresponding items don't exist.
Additions to mapfiles
Mapfiles can now define the following additional sections:
- Difficulty flag names. (
!difficulty_flags
) The prepackaged maps do this. - Intrinsic mappings. (
!ins_intrinsics
) For instance, a patch which adds a jump intrinsic to MSG could also provide a mapfile which tells trumsg about this intrinsic:and then you would be able to write!msgmap !ins_instrinsics 100 Jmp() !ins_signatures 100 ot
loop { }
s in MSG!
Internal changes
- The order of arguments to intrinsics is no longer hardcoded by game/format, but rather inferred from the mapfile signature (meaning it can be defined by the user).
- Time labels are now internally stored as statements. This drastically simplifies parsing and some aspects of loop compilation/decompilation.
Compatibility notes
- Using registers (e.g.
$REG[8]
) in a format without registers such as STD is now detected as an error. - If e.g.
X
is an alias for$REG[3]
, then using bothX
andREG[3]
in the same function body will now generate a warning. Similarly, using two different aliases (e.g.X
andY
) for the same register will also warn.- This is done in order to call attention to accidental usage of EoSD's
I0
or PCB's "param" registers in subs where these registers are already implicitly in use by function parameters.
- This is done in order to call attention to accidental usage of EoSD's
- Previously, using
-m mapfile.eclm
during decompilation would disable lookup fromTRUTH_MAP_PATH
. Now that multiple-m
are supported, this behavior now seems surprising, soTRUTH_MAP_PATH
is now always searched during decompilation.
v0.4.3
0.4.3 is a minor update that adds some information from Dai:
- The
unknown
field in STD objects has been renamed tolayer
; it behaves like thelayer(_)
command, and is used to control the layering of 3D objects relative to 2D sprites. The old name is still accepted, but may be deprecated and eventually removed in the distant future. - Small update to mapfiles.
v0.4.2
v0.4.2
-
Adds
truanm extract
(truanm x
) to extract images. See the readme for more details. -
Adds additional flags to tweak decompilation:
--no-blocks
: Disables conditional and loop decompilation, leaving behind allgoto
s and labels in their natural state.--no-intrinsics
: Forces every instruction to decompile intoname(arg1, arg2)
etc. (e.g.addf(F1, 0.3)
instead ofF1 += 0.3;
).--no-arguments
: Forces all instructions to decompile into raw form using pseudo-arguments. (e.g.addi(@mask=0b1, @blob="10270000 24000000")
).
These can help work with unusual files.
-
Bugfix: Floating point comparisons actually work now instead of causing a panic. So that's cool.
v0.4.1
Added
- Support for TH18: 東方虹龍洞 ~ Unconnected Marketeers has been added.
truanm
can now import image files (PNG, BMP, GIF). Simply supply a directory instead of an ANM file to--image-source
or#pragma image_source
.truanm
can generate dummy image data to be hotswapped by thcrap; tryhas_data: "generate"
.truanm
now has named constants for color formats:FORMAT_ARGB_8888, FORMAT_ARGB_4444, FORMAT_RGB_565, FORMAT_GRAY_8
.truanm
now provides sane defaults for the majority of fields on anentry
.
Changed
- Renamed some ANM entry fields to place greater focus on the things you should probably care more about:
width
,height
, andformat
have been renamed tort_width, rt_height, rt_format
to indicate that these are values for the runtime buffer. Generally speaking, you should almost never need to worry about these.thtx_width, thtx_height, thtx_format
have been renamed toimg_width, img_height, img_format
to make them less "scary." These describe the actual dimensions and format of an embedded image.- The old names still work, but will generate a deprecation warning.
0.4.0
v0.4.0
The biggest addition to 0.4.0 is that trumsg is now usable.
Compatibility Note
Text source files are now always UTF-8, never Shift-JIS. If you were previously using truth
with Shift-JIS files, you may need to change their encoding and re-save them in your text editor.
Changes
- trumsg now produces reasonable output, and can roundtrip-decode all (stage) MSG files in all games up to and including TH17.
- Added pseudo-arguments. When decompiling, instructions with unknown signatures will now be decoded to a form like
ins_1011(@mask=0b100, @blob="00501c46 00000040 00541c46");
- Added
const
variables. These are typed compile-time constants. Please see the truth syntax primer for more information. - More warnings! Diagnostics were heavily reworked, allowing warnings to be emitted for many more things (and allowing some things that used to be errors to become warnings instead).
- Default output line width changed from 100 to 80.
0.4.0-pre3
This release supports stage MSG files in all games up to TH17. Only TH06-TH08 and TH10-TH12 have been thoroughly tested; other games may be missing a few instruction names or signatures.