| Crates.io | libgm |
| lib.rs | libgm |
| version | 0.3.2 |
| created_at | 2025-12-30 15:12:49.441884+00 |
| updated_at | 2026-01-25 13:14:15.816995+00 |
| description | A tool for modding, unpacking and decompiling GameMaker games |
| homepage | |
| repository | https://github.com/BioTomateDE/LibGM |
| max_upload_size | |
| id | 2012803 |
| size | 688,916 |
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.
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_pretty():
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.
Add this line in the [dependencies] section of your Cargo.toml file:
libgm = "0.3.2"
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 DataParserOptions struct to modify parsing options:
// Create a parser with custom options
let parser = DataParserOptions::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)?;
// Parse from a byte slice reference
let byte_slice: &[u8] = &[0x46, 0x4F, 0x52, 0x4D, /* ... */];
let data: GMData = parser.parse_bytes(byte_slice)?;
// You can also parse directly from borrowed data
let buffer: Vec<u8> = std::fs::read("./data.win")?;
let data: GMData = parser.parse_bytes(&buffer)?;
// buffer is still accessible here since we passed a reference
| Feature | Default | Dependencies |
|---|---|---|
| catch-panic | enabled | |
| check-integrity | enabled | |
| game-creation-timestamp | disabled | chrono |
| bzip2-image | enabled | bzip2 |
| png-image | enabled | image/png |
catch-panic catches panics in GameMaker (de)serialization functions
and returns them as a LibGM error.check-integrity enables alignment and constant validation while parsing.
These checks may still be demoted to a warning using ParsingOptions.
Some checks regarding panic safety or memory allocation are always enabled.game-creation-timestamp exposes the creation-timestamp field in GMGeneralInfo.
Otherwise, it will be stored as an i64 iternally.bzip2-image enables deserialization of BZip2+QOI encoded texture pages.
If *_dynamic_image is called on a GMImage that contains Bzip2-Qoi
data and this feature is disabled, an error will be returned.png-image enables PNG deserialization and all serialization of texture pages.
If you deserialize texture pages into DynamicImages with this feature disabled,
you will not be able to serialize the data.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 Server who helped me along the way, especially @colinator27.
This project is licenced under the GNU Public Licence v3.0 (GPL-3).
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.
libgm/src/gamemaker/.libgm-cli/src/.fn get_variable(&self) -> Option<&CodeVariable> that returns some for push, pushloc, pushglb, pushbltn or pop)