Skip to main content

GVAS<->JSON De/Serializer in Python

This Python library implements GVAS and JSON file format conversions.

  1. Deserialization of UE4/5 GVAS binary files into Python classes.
  2. Serialization of Python classed into JSON
  3. Deserialization of JSON into Python classes.
  4. Serialization of Python classes into binary GVAS format.
  5. Matches all capabilities existing in https://github.com/localcc/gvas at the time of writing

The internet says that GVAS stands for Game Variable and Attribute System.

Conversions to JSON are LOSSLESS but there is a caveat. Python only has 64-bit floating point values, so 32-bit values can have additional digits when written to JSON. However, once converted back there should be no data changes.

One strategy to avoid potential ambiguity is storing 32-bit floats as strings in JSON. I've got some commented out code for this process but I'll only enable that if it becomes an issue because seeing something like ["x": 2497.000000000003] is as confusing ast seeing ["x": "2497"] in the JSON file.

License

This library is distributed under the terms of the Creative Commons CC BY-NC-SA 4.0. Also known as Attribution-NonCommercial-ShareAlike 4.0 International. See the LICENSE file for details.

Contributing

Please see the CONTRIBUTING document for guidelines on how to contribute to this project.

Credits

This library was inspired by two other projects I found when working to modify GVAS files of an offline game, Islands of Insight. After minor success and major failure using a HEX editor, I went looking for tools. I found a few that could convert GVAS to JSON but none were exactly what I wished for.

The most complete one (which this library followed as a template) was written in Rust, but the command line tools were binary executables.

I don't really like running arbitrary code on my machine, and I got tired of using virtual environments to isolate them.

The Rust project titled "gvas" (also see the sibling project gvas2json) that I used as a template is here:

Although I've delivered production code in a number of languages (Prolog, K&R C, ANSI C, C++, PHP, C#, XSLT/XML/JavaScript, Unreal Engine C++), I knew very little about Rust syntax when I started.

And I didn't really want to.

Looking harder led me to the project titled "Python-GVAS-JSON-Converter", which provided a great roadmap to understand the Rust code -- it implemented
the necessary bones, but in Python.

The full journey is described below, but first, a comparison summary.

Key Differences from Rust Version

  1. Deserialization Hints Content

    • There are cases where insufficient context exists in the GVAS binary to define the type of the next portion of the byte stream.
    • This implementation detects the most common hints for you: custom StructProperty and GUID.
    • Example JSON hints files are in the resources/test directory.
    • When GUID guesses are made they are printed in the console.
    • You can save those detected hints to a specified file for future use.
  2. Error Handling

    • Uses Python's exception system instead of Rust's Result types
    • Simplified error hierarchy with custom exception classes
  3. Type System

    • Uses Python's type hints and dataclasses
    • Replaces Rust enums with Python Enum classes
    • Uses Python's built-in types where appropriate, such as uuid
  4. Memory Management

    • Relies on Python's garbage collection instead of Rust's ownership system
    • Simplified memory handling patterns
  5. Performance Considerations

    • May be slower than Rust version due to Python's interpreted nature and the use of Pydantic for JSON serialization
    • Uses Python's struct module for binary data handling
    • Maintains similar algorithmic complexity
  6. JSON Format

    • The JSON file format is not identical to the RUST output
    • A layer of wrapping is removed so the depth is shallower
    • There are no type-specific JSON property names (e.g., "ints", "bools", " structs" in ArrayProperty), erring on the side of uniformity.
    • Data types are indicated by a sibling "type" property rather than the name of the property. This also makes Pydantic deserialization work well.

The Journey

I had originally used the GVAS rust code to generate JSON that I was then able to modify for my goals (visually mark puzzles in the game world as "completed", forcibly complete puzzles, and give myself unlimited amounts of currency).

I will share that work (TBD) but I didn't want to require installing the Rust CLI tools, etc. I wanted a one-stop shop. I also wanted code that cybersecurity-aware people could easily inspect. Python is a natural choice.

Choosing Python lead me to Python-GVAS-JSON-Converter.

My first attempt was to modify Python-GVAS-JSON-Converter to make the JSON output closer to that of the Rust project. However, there were puzzling areas in the Python deserialization code that just begged to be understood.

That made the next step looking at the Rust code, and boy was I intimidated. In an attempt to avoid learning Rust, I installed the Cursor IDE and asked Sonnet to translate Rust to Python.

That wasn't an abject failure, but after several days I gave that up and started reading both the Python and Rust code side-by-side. And then refactored all the Cursor-generated code.

I failed in my mission to not learn much about Rust syntax.

On the other hand, here is a pure Python library for working with Unreal Engine 4 and 5 GVAS files.

Note

This document was created in part with a generative AI prompt in the Cursor IDE.

Metadata

Release files for pygvas 0.9.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pygvas 0.9.7
File Size Uploaded
pygvas-0.9.7.tar.gz 14.6 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for pygvas 0.9.7
File Interpreter ABI Platform
pygvas-0.9.7-py3-none-any.whl Python 3 none any Details

Total release size: 14.7 MB

Release files / pygvas-0.9.7.tar.gz

Download URL pygvas-0.9.7.tar.gz
Size 14.6 MB
Tags Source
SHA-256 checksum
How to use checksums
0576b5c431b102395fea1b9e909668263d1815e543da0121a488b7a204a86e40
BLAKE2b-256 checksum
How to use checksums
4ad668d9ee00ffdb8e770690de9dd9c9be600ebbe8b3e3b37cfc543f828a10fc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release files / pygvas-0.9.7-py3-none-any.whl

Download URL pygvas-0.9.7-py3-none-any.whl
Size 50.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fd21bd49d09170c296a82138026961f08b39e0c2fcf8eb34674a335901d85adc
BLAKE2b-256 checksum
How to use checksums
c7a3186394aba6beae867dc66d48d2c05e2482432b834fe7fdf8d3c4ad090284
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release history Release notifications | RSS feed

This release

0.9.7 This release

2 release files

0.9.6

2 release files

0.9.5

2 release files

0.9.4

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page