A tool for unpacking, decompiling and modding GameMaker games such as Undertale or Deltarune.
This is effectively a Rust port of UndertaleModTool (specifically UndertaleModLib).
-
Runtime for parsing and building is ~8x faster than UndertaleModLib.
- This can be further accelerated with the upcoming threaded chunk reading feature (opt-in).
-
Thorough documentation on docs.rs.
-
Clean and maintainable library code.
-
Helpful error messages:
-
No
NullReferenceException, ever -
No meaningless stack traces over 50 lines long
-
Still more information than just "Reading out of bounds"
-
Strict data integrity checks catch errors earlier, making debugging easier
-
Example trace printed out using
.chain():sprite::swf::item::shape::style_group::fill::gradient::Record count 1065353216 implies data size 8.5 GB which exceeds failsafe size 10.0 MB > while reading simple list > while deserializing element 1/2 of sprite::swf::item::shape::style_group::StyleGroup<sprite::swf::item::subshape::Data> simple list > while deserializing element 0/1 of sprite::swf::item::Item simple list > while deserializing element 3/60 of GMSprite pointer list > while deserializing chunk 'SPRT' > while parsing GameMaker data file ./gm48_datafiles/a-loop_detective.win
-
-
Configurable lenient options for trying to parse half-broken data files (see
ParsingOptions).
- Null pointers are not yet supported.
- GML Decompiler and Compiler not yet implemented (help would be greatly appreciated!)
- No GUI yet, only a Rust library.
Add this line in the [dependencies] section of your Cargo.toml file:
libgm = "0.4.1"Or if you want bleeding edge:
libgm = { git = "https://github.com/BioTomateDE/LibGM" }Now you can use these functions exposed by LibGM:
parse_file(data_file_path: impl AsRef<Path>) -> Result<GMData>parse_bytes(raw_data: impl AsRef<[u8]>) -> Result<GMData>build_data(gm_data: &GMData, path: impl AsRef<Path>) -> Result<()>build_bytes(gm_data: &GMData) -> Result<Vec<u8>>
If you need more control over how the data file should be read, you can also use
the ParsingOptions struct to modify parsing options:
// Create a parser with custom options
let parser = ParsingOptions::new()
.verify_alignment(false)
.allow_unread_chunks(true);
// Parse multiple files
for path in data_files {
let data: GMData = parser.parse_file(path)?;
// Process the parsed data...
}
// Parse from a byte vector
let raw_data: Vec<u8> = read_from_zip(zip_file, "Undertale/assets/game.unx")?;
let data: GMData = parser.parse_bytes(raw_data)?;| Feature | Default | Dependencies |
|---|---|---|
| catch-panic | enabled | |
| check-integrity | enabled | |
| game-creation-timestamp | disabled | chrono |
| bzip2-image | enabled | bzip2 |
| png-image | enabled | image/png |
catch-paniccatches panics in GameMaker (de)serialization functions and returns them as a LibGM error.check-integrityenables alignment and constant validation while parsing. These checks may still be demoted to a warning usingParsingOptions. Some checks regarding panic safety or memory allocation are always enabled.game-creation-timestampexposes thecreation-timestampfield inGMGeneralInfo. Otherwise, it will be stored as an i64 internally.bzip2-imageenables (de)serialization of BZip2+QOI encoded texture pages. If you try to change the format of aGMImagethat stores BZip2-QOI data with this feature disabled, an error will be returned.png-imageenables PNG (de)serialization. In games older than GM 2022.2, you will not be able to serializeGMImages storingDynamicImages with this feature disabled.
Huge thanks to the Underminers Team! Without UndertaleModTool, this project would've been impossible. I also want to thank the people in the Underminers Discord Guild who helped me along the way, especially @colinator27.
This project is licenced under the GNU Public License v3.0 (GPL-3.0).
All contributions are welcome! Whether that's a pull request, a feature you would like to see added, a bug you found; just create an Issue/PR in this repo.
- Everything related to GameMaker is located in
libgm/src/wad/. - A disassembler and assembler are available in
libgm/src/gml/assembly/. - There is a basic CLI to interact with LibGM in
libgm-cli/src/.