Library / SDK
K0lb3/UnityPy avatar
K0lb3/UnityPy

UnityPy for extracting and patching Unity assets in Python

UnityPy is python module that makes it possible to extract/unpack and edit Unity assets

1,505 stars198 forksPythonMIT

At a glance

What is it?
UnityPy loads Unity assets from files, folders, streams, byte data, and APK containers, then exposes their objects for selective extraction or patching. It fits developers and game data analysts who need direct Python access, but its breaking minor releases and native dependency risks require version control.
Who is it for?
Adopt UnityPy for Python scripts that must inspect or modify Unity asset data without operating the Unity Editor. Do not choose it when unmodified exports alone are sufficient or when an unversioned, failure-prone dependency chain is unacceptable.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 18 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

UnityPy asset extraction and patching scope

UnityPy addresses a specific gap between raw Unity asset files and application code. It gives Python developers access to objects stored inside Unity files, including textures and sprites, without requiring the workflow to pass through a visual asset editor. Its intended audience includes developers handling Unity game data, analysts working with game assets, and programmers building extraction or modification tools.

The library is based on AssetStudio, but it is not limited to converting files into exportable formats. The README describes extraction, unpacking, and editing through UnityPy's typetree structure. Objects can be edited in native parsed forms, then written back into a loaded environment. That makes UnityPy relevant when the desired output is a changed Unity asset rather than merely a PNG or another converted representation.

The project classifies itself as a production/stable library in `pyproject.toml`, but that packaging metadata does not eliminate compatibility work for the caller. The README warns that breaking changes usually occur in minor versions such as `x.y`, rather than patch versions such as `x.y.z`. A script that works with one release can therefore require changes after a normal minor-version upgrade. Pinning the installed version is especially relevant for archive processing, build pipelines, and repeated asset generation.

Inside UnityPy's container and object loading flow

The entry point is `UnityPy.load`, which accepts a file path, folder path, stream, or bytes object. The README also states that UnityPy can detect `WebFile`, `BundleFile`, `Asset`, and `APK` containers. A folder is loaded as a collection of files, although the documentation warns against using that mode with folders containing many files because it is a bad idea in that case.

After loading, the resulting `Environment` stores unpacked assets in `.files`, keyed by asset name. Its `.objects` property provides a recursive iterator over objects from the loaded assets. An `Asset`, represented by the `SerializedFile` class, keeps its objects in an ID-indexed `.objects` dictionary. Objects that have a Unity file path are also available through `.container`, indexed by that path.

Objects are represented by `ObjectReader` instances. They are not parsed immediately when enumerated, because parsing is deferred to reduce unnecessary work. Calling `parse_as_object()` or `parse_as_dict()` causes the relevant object to be decoded. The dictionary route returns a mutable raw dictionary, while the object route returns a parsed class-like representation. Both forms can be passed to `patch` after modification.

This design gives callers two useful levels of control. Iterating through `env.objects` supports type-based processing across loaded files. Iterating through `env.container` preserves original Unity paths, which is preferable when output should follow the source asset hierarchy. The choice affects both selection and naming, not just formatting.

Installing UnityPy on Python 3.8 and newer

The documented package installation requires Python 3.8 or higher. For ordinary use, the README directs users to PyPI with this command:

bash
pip install UnityPy

The resulting dependency set includes `lz4`, `brotli`, `Pillow`, `texture2ddecoder`, `etcpak`, `astc-encoder-py`, `fmod_toolkit`, `fsspec`, `attrs`, and `tpk_ar`. These packages correspond to concerns such as bundle and web compression, texture and sprite handling, audio extraction, filesystem access, and TPK handling. The repository also includes a `UnityPy` command entry point in `pyproject.toml`, but the README excerpt does not provide a first-use example for that CLI.

A source checkout can instead be cloned and installed through the standard Python package build path:

bash
git clone https://github.com/K0lb3/UnityPy.git
cd UnityPy
python -m pip install .

This source build is relevant on Windows because the project builds native extensions. The `setup.py` build logic selects C++20 for supported compiler families. The README specifically says that Visual C++ Redistributable is required for the `brotli` dependency. It also warns that native dependencies may not have precompiled artifacts for a newer Python release. If compilation is necessary, the documentation points to issue 223, or it suggests selecting an older Python version supported by the PyPI Python-version badge.

First UnityPy texture extraction workflow

A first script can load one source file and export selected `Texture2D` or `Sprite` objects. The following is the README's basic loop, with the output directory expected by the example:

python
env = UnityPy.load(file_path)

for obj in env.objects:
    if obj.type.name in ["Texture2D", "Sprite"]:
        data = obj.parse_as_object()
        dest = os.path.join(destination_folder, data.m_Name)
        dest, ext = os.path.splitext(dest)
        dest = dest + ".png"
        img = data.image
        img.save(dest)

Before running a complete extractor, the script also needs imports for file traversal and UnityPy, and the destination directory must already exist because this short fragment does not create it. The exported image comes from the parsed object's `.image` property, while `m_Name` supplies the base filename. The README warns that the extension treatment is mainly appropriate for images and textures.

When preserving Unity's internal paths matters, use `env.container` instead. It maps paths to objects and supports reconstruction of the original directory structure under the destination folder:

python
for path,obj in env.container.items():
    if obj.type.name in ["Texture2D", "Sprite"]:
        data = obj.parse_as_object()
        dest = os.path.join(destination_folder, *path.split("/"))
        os.makedirs(os.path.dirname(dest), exist_ok = True)
        dest, ext = os.path.splitext(dest)
        dest = dest + ".png"
        data.image.save(dest)

This version calls `os.makedirs`, so it creates the destination directories. For broader asset handling, the README points advanced Python users to `UnityPy/tools/extractor.py` as a template or importable tool.

Patching parsed objects and saving the Unity file

UnityPy's editing model operates on the parsed representation. A caller can obtain a dictionary, change its fields, and pass the same dictionary to `patch`. Alternatively, `parse_as_object()` returns a parsed class that can be modified before it is supplied to `patch`.

python
raw_dict = obj.parse_as_dict()
# modify raw dict
obj.patch(raw_dict)

instance = obj.parse_as_object()
# modify instance
obj.patch(instance)

After applying changes, saving requires both an object-level `data.save()` call and serialization of the environment's file. The README's sequence explicitly says not to forget `data.save()`, then writes `env.file.save()` to the destination:

python
with open(dst, "wb") as f:
    f.write(env.file.save())

The examples describe two routes because they serve different editing needs. A dictionary is direct when the caller knows the serialized fields and wants ordinary Python mapping operations. A parsed object offers named attributes, as shown by `data.m_Name` and `data.image` in the extraction example. Neither route should be treated as an automatic round-trip guarantee. The documentation says that the typetree structure can edit object types in native forms, but it does not provide field-by-field validation rules for every supported Unity type.

Callers should therefore preserve output paths and compare the resulting file against the intended modification. Empty containers, external references, and version-specific object structures are practical concerns in a binary asset format, although the excerpt does not define a formal validation procedure.

UnityPy native reader crashes and dependency limits

UnityPy has a documented failure mode that is unusually important for batch processing: the C implementation of the typetree reader can crash Python directly. The README says that this reader can be disabled through its configuration section. It does not present the crash as a catchable Python exception, so a surrounding `try` block would not necessarily help. This makes the native reader choice relevant to unattended jobs and hostile or malformed input handling.

The broader limitation is compatibility between Python releases, native dependencies, compilers, and Unity file variants. The Windows guidance acknowledges that a newer Python version may not have precompiled UnityPy dependencies. It identifies reporting the issue, compiling the dependency, or downgrading Python as the documented paths. Source builds also invoke a native extension build configured for C++20.

UnityPy is therefore not the right tool when the requirement is only a simple conversion and no parsing or patching is needed. A dedicated exporter may offer a smaller operational surface. UnityPy is also a poor fit for production automation that cannot tolerate a native-reader crash or uncontrolled minor-version changes. Disabling the C reader may reduce that specific exposure, but the README gives no performance measurement, so the cost of doing so cannot be quantified from the available documentation.

Another boundary is licensing and asset rights. The software is MIT licensed, but that license does not determine whether a user has permission to extract, modify, or redistribute assets from a particular Unity application. The project also states that commercial use is expected to result in a donation or sponsorship. That statement is not presented as a separate license restriction.

UnityPy maintenance, releases, and upgrade policy

The repository is not archived, and its last push was on 2026-10-05. The README describes UnityPy as still in active development. That maintenance signal does not mean upgrades are compatibility-neutral, because the same README warns that breaking changes can occur in minor versions and advises projects to record the UnityPy version they use.

The repository has no GitHub releases. Package consumers therefore cannot rely on the repository's release list as the complete version history on GitHub. `CHANGELOG.md` exists at the top level, but its contents are not included here, so its ability to explain breaking changes cannot be assessed. The version is also declared dynamically in `pyproject.toml` rather than pinned in the project metadata shown.

For scripts embedded in a game asset pipeline, the documented version check can turn an upgrade mismatch into an explicit import failure:

python
if UnityPy.__version__ != '1.9.6':
    raise ImportError("Invalid UnityPy version detected. Please use version 1.9.6")

The README presents `1.9.6` as an example rather than requiring that version for every project. Upgrade cost comes from native packages, possible changes to parsing or patching behavior, and the need to validate saved assets. The repository layout includes `tests/`, but the excerpt does not describe how to run them or whether they cover all object types.

Editorial conclusion

Adopt UnityPy for Python scripts that must inspect or modify Unity asset data without operating the Unity Editor. Do not choose it when unmodified exports alone are sufficient or when an unversioned, failure-prone dependency chain is unacceptable. Before production adoption, verify the exact UnityPy version against representative files and inspect every patched output. For reproducible pipelines, pinning UnityPy and validating patched assets is the safer project-specific decision.

Frequently asked questions

How do I install UnityPy?

UnityPy requires Python 3.8 or higher. The README documents `pip install UnityPy` for installation through PyPI and also provides a source checkout command using `python -m pip install .`.

Can UnityPy extract textures and sprites from Unity files?

Yes. The documented example checks for object types named `Texture2D` and `Sprite`, parses each object, accesses its `.image`, and saves that image as a PNG.

Can UnityPy edit assets and save the changes?

Yes. The README shows editing through either `parse_as_dict()` or `parse_as_object()`, applying changes with `patch`, calling `data.save()`, and writing `env.file.save()` to a destination file.

Official sources

  1. Issues
  2. K0lb3/UnityPy on GitHub
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/k0lb3-unitypy.svg)](https://hysenlabs.com/projects/k0lb3-unitypy)

Was this useful?