Git Product home page Git Product logo

unitypy's Introduction

UnityPy

Discord server invite PyPI supported Python versions Win/Mac/Linux MIT Test and Publish

A Unity asset extractor for Python based on AssetStudio.

Next to extraction, it also supports editing Unity assets. So far following obj types can be edited:

  • Texture2D
  • Sprite(indirectly via linked Texture2D)
  • TextAsset
  • MonoBehaviour (and all other types that you have the typetree of)

If you need advice or if you want to talk about (game) data-mining, feel free to join the UnityPy Discord.

If you're using UnityPy a commercial project, a donation to a charitable cause or a sponsorship of this project is expected.

As UnityPy is still in active development breaking changes can happen. Those changes are usually limited to minor versions (x.y) and not to patch versions (x.y.z). So in case that you don't want to actively maintain your project, make sure to make a note of the used UnityPy version in your README or add a check in your code. e.g.

if UnityPy.__version__ != '1.9.6':
    raise ImportError("Invalid UnityPy version detected. Please use version 1.9.6")
  1. Installation
  2. Example
  3. Important Classes
  4. Important Object Types
  5. Custom Fileystem
  6. Credits

Installation

Python 3.7.0 or higher is required

via pypi

pip install UnityPy

from source

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

Notes

Windows

Visual C++ Redistributable is required for the brotli dependency. In case a new(ish) Python version is used, it can happen that the C-dependencies of UnityPy might not be precompiled for this version. In such cases the user either has to report this as issue or follow the steps of this issue to compile it oneself. Another option for the user is downgrading Python to the latest version supported by UnityPy. For this see the python version badge at the top of the README.

Crash without warning/error

The C-implementation of the typetree reader can directly crash python. In case this happens, the usage of the C-typetree reader can be disabled by adding these two lines to your main file.

from UnityPy.helpers import TypeTreeHelper
TypeTreeHelper.read_typetree_c = False

Example

The following is a simple example.

import os
import UnityPy

def unpack_all_assets(source_folder : str, destination_folder : str):
    # iterate over all files in source folder
    for root, dirs, files in os.walk(source_folder):
        for file_name in files:
            # generate file_path
            file_path = os.path.join(root, file_name)
            # load that file via UnityPy.load
            env = UnityPy.load(file_path)

            # iterate over internal objects
            for obj in env.objects:
                # process specific object types
                if obj.type.name in ["Texture2D", "Sprite"]:
                    # parse the object data
                    data = obj.read()

                    # create destination path
                    dest = os.path.join(destination_folder, data.name)

                    # make sure that the extension is correct
                    # you probably only want to do so with images/textures
                    dest, ext = os.path.splitext(dest)
                    dest = dest + ".png"

                    img = data.image
                    img.save(dest)

            # alternative way which keeps the original path
            for path,obj in env.container.items():
                if obj.type.name in ["Texture2D", "Sprite"]:
                    data = obj.read()
                    # create dest based on original path
                    dest = os.path.join(destination_folder, *path.split("/"))
                    # make sure that the dir of that path exists
                    os.makedirs(os.path.dirname(dest), exist_ok = True)
                    # correct extension
                    dest, ext = os.path.splitext(dest)
                    dest = dest + ".png"
                    data.image.save(dest)

You probably have to read Important Classes and Important Object Types to understand how it works.

People with slightly advanced python skills should look at UnityPy/tools/extractor.py for a more advanced example. It can also be used as a general template or as an importable tool.

Setting the decryption key for Unity CN's AssetBundle encryption

The chinese version of Unity has its own inbuild option to encrypt AssetBundles/BundleFiles. As it's a feature of Unity itself, and not a game specific protection, it is included in UnityPy as well. To enable encryption simply use UnityPy.set_assetbundle_decrypt_key(key), with key being the value that the game that loads the budles passes to AssetBundle.SetAssetBundleDecryptKey.

Important Classes

Environment loads and parses the given files. It can be initialized via:

  • a file path - apk files can be loaded as well
  • a folder path - loads all files in that folder (bad idea for folders with a lot of files)
  • a stream - e.g., io.BytesIO, file stream,...
  • a bytes object - will be loaded into a stream

UnityPy can detect if the file is a WebFile, BundleFile, Asset, or APK.

The unpacked assets will be loaded into .files, a dict consisting of asset-name : asset.

All objects of the loaded assets can be easily accessed via .objects, which itself is a simple recursive iterator.

import io
import UnityPy

# all of the following would work
src = "file_path"
src = b"bytes"
src = io.BytesIO(b"Streamable")

env = UnityPy.load(src)

for obj in env.objects:
    ...

# saving an edited file
    # apply modifications to the objects
    # don't forget to use data.save()
    ...
with open(dst, "wb") as f:
    f.write(env.file.save())

Assets are a container that contains multiple objects. One of these objects can be an AssetBundle, which contains a file path for some of the objects in the same asset.

All objects can be found in the .objects dict - {ID : object}.

The objects with a file path can be found in the .container dict - {path : object}.

Objects contain the actual files, e.g., textures, text files, meshes, settings, ...

To acquire the actual data of an object it has to be read first. This happens via the .read() function. This isn't done automatically to save time because only a small part of the objects are of interest. Serialized objects can be set with raw data using .set_raw_data(data) or modified with .save() function, if supported.

Important Object Types

All object types can be found in UnityPy/classes.

  • .name
  • .image converts the texture into a PIL.Image
  • .m_Width - texture width (int)
  • .m_Height - texture height (int)

Export

from PIL import Image
for obj in env.objects:
    if obj.type.name == "Texture2D":
        # export texture
        data = obj.read()
        data.image.save(path)
        # edit texture
        fp = os.path.join(replace_dir, data.name)
        pil_img = Image.open(fp)
        data.image = pil_img
        data.save()

Sprites are part of a texture and can have a separate alpha-image as well. Unlike most other extractors (including AssetStudio), UnityPy merges those two images by itself.

  • .name
  • .image - converts the merged texture part into a PIL.Image
  • .m_Width - sprite width (int)
  • .m_Height - sprite height (int)

Export

for obj in env.objects:
    if obj.type.name == "Sprite":
        data = obj.read()
        data.image.save(path)

TextAssets are usually normal text files.

  • .name
  • .script - binary data (bytes)
  • .text - script decoded via UTF8 (str)

Some games save binary data as TextFile, so it's usually better to use .script.

Export

for obj in env.objects:
    if obj.type.name == "TextAsset":
        # export asset
        data = obj.read()
        with open(path, "wb") as f:
            f.write(bytes(data.script))
        # edit asset
        fp = os.path.join(replace_dir, data.name)
        with open(fp, "rb") as f:
            data.script = f.read()
        data.save()

MonoBehaviour assets are usually used to save the class instances with their values. If a type tree exists, it can be used to read the whole data, but if it doesn't exist, then it is usually necessary to investigate the class that loads the specific MonoBehaviour to extract the data. (example)

  • .name
  • .script
  • .raw_data - data after the basic initialisation

Export

import json

for obj in env.objects:
    if obj.type.name == "MonoBehaviour":
        # export
        if obj.serialized_type.nodes:
            # save decoded data
            tree = obj.read_typetree()
            fp = os.path.join(extract_dir, f"{tree['m_Name']}.json")
            with open(fp, "wt", encoding = "utf8") as f:
                json.dump(tree, f, ensure_ascii = False, indent = 4)
        else:
            # save raw relevant data (without Unity MonoBehaviour header)
            data = obj.read()
            fp = os.path.join(extract_dir, f"{data.name}.bin")
            with open(fp, "wb") as f:
                f.write(data.raw_data)

        # edit
        if obj.serialized_type.nodes:
            tree = obj.read_typetree()
            # apply modifications to the data within the tree
            obj.save_typetree(tree)
        else:
            data = obj.read()
            with open(os.path.join(replace_dir, data.name)) as f:
                data.save(raw_data = f.read())
  • .samples - {sample-name : sample-data}

The samples are converted into the .wav format. The sample data is a .wav file in bytes.

clip : AudioClip
for name, data in clip.samples.items():
    with open(name, "wb") as f:
        f.write(data)
if obj.type.name == "Font":
    font : Font = obj.read()
    if font.m_FontData:
        extension = ".ttf"
        if font.m_FontData[0:4] == b"OTTO":
            extension = ".otf"

    with open(os.path.join(path, font.name+extension), "wb") as f:
        f.write(font.m_FontData)
  • .export() - mesh exported as .obj (str)

The mesh will be converted to the Wavefront .obj file format.

mesh : Mesh
with open(f"{mesh.name}.obj", "wt", newline = "") as f:
    # newline = "" is important
    f.write(mesh.export())

Renderer, MeshRenderer, SkinnedMeshRenderer

ALPHA-VERSION

  • .export(export_dir) - exports the associated mesh, materials, and textures into the given directory

The mesh and materials will be in the Wavefront formats.

mesh_renderer : Renderer
export_dir: str

if mesh_renderer.m_GameObject:
    # get the name of the model
    game_object = mesh_renderer.m_GameObject.read()
    export_dir = os.path.join(export_dir, game_object.name)
mesh_renderer.export(export_dir)

WARNING - not well tested

  • .name
  • .image converts the texture2darray into a PIL.Image
  • .m_Width - texture width (int)
  • .m_Height - texture height (int)

Export

import os
from PIL import Image
for obj in env.objects:
    if obj.type.name == "Texture2DArray":
        # export texture
        data = obj.read()
        for i, image in enumerate(data.images):
            image.save(os.path.join(path, f"{data.m_Name}_{i}.png"))
        # editing isn't supported yet!

Custom-Filesystem

UnityPy uses fsspec under the hood to manage all filesystem interactions. This allows using various different types of filesystems without having to change UnityPy's code. It also means that you can use your own custom filesystem to e.g. handle indirection via catalog files, load assets on demand from a server, or decrypt files.

Following methods of the filesystem have to be implemented for using it in UnityPy.

  • sep (not a function, just the seperator as character)
  • isfile(self, path: str) -> bool
  • isdir(self, path: str) -> bool
  • exists(self, path: str, **kwargs) -> bool
  • walk(self, path: str, **kwargs) -> Iterable[List[str], List[str], List[str]]
  • open(self, path: str, mode: str = "rb", **kwargs) -> file ("rb" mode required, "wt" required for ModelExporter)
  • makedirs(self, path: str, exist_ok: bool = False) -> bool

Credits

First of all, thanks a lot to all contributors of UnityPy and all of its users.

Also, many thanks to:

unitypy's People

Contributors

01101sam avatar ablegao avatar aelurum avatar ahmedahmedeg avatar ai0796 avatar astiob avatar autumnsun1996 avatar bloodwiing avatar deibu avatar elioty avatar extacy avatar hydrargyrum avatar jerryhwq avatar jesliwang avatar k0lb3 avatar nattsu39 avatar parnassius avatar realsupremium avatar snowyegret23 avatar sparr avatar squaresmile avatar starhearthunt avatar t-wy avatar therhokar avatar userunknownfactor avatar wolfgangkurz avatar ysmu avatar yuanyan3060 avatar yvsdrop avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

unitypy's Issues

'memoryview' object has no attribute 'decode'

hi i'm using anaconda with python3.7 , and i'm trying to execute AssetBatchConverter.py, and i'm getting this error..

can anyone help me with it?

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-3a0252ea1ade> in <module>
    107 
    108 if __name__ == '__main__':
--> 109         main()

<ipython-input-3-3a0252ea1ade> in main()
     37                                         extract_assets(archive.open(zf))
     38                         else:
---> 39                                 extract_assets(src)
     40 
     41 

<ipython-input-3-3a0252ea1ade> in extract_assets(src)
     42 def extract_assets(src):
     43         # load source
---> 44         am = AssetsManager(src)
     45 
     46         # iterate over assets

~/opt/anaconda3/lib/python3.7/site-packages/UnityPy/environment.py in __init__(self, *args)
     30                         else:
     31                             self.path = os.path.dirname(arg)
---> 32                             self.load_file(arg)
     33                     elif os.path.isdir(arg):
     34                         self.path = arg

~/opt/anaconda3/lib/python3.7/site-packages/UnityPy/environment.py in load_file(self, full_name, data)
     77             self.files[full_name] = files.BundleFile(reader, self)
     78         elif typ == FileType.WebFile:
---> 79             self.files[full_name] = files.WebFile(reader, self)
     80         elif typ == FileType.ZIP:
     81             self.load_zip_file(reader.stream)

~/opt/anaconda3/lib/python3.7/site-packages/UnityPy/files/WebFile.py in __init__(self, reader, environment)
     53             length = reader.read_int()
     54             path_length = reader.read_int()
---> 55             name = reader.read_bytes(path_length).decode("utf8")
     56             files.append((name, offset, length))
     57 

AttributeError: 'memoryview' object has no attribute 'decode'

Extracting fails when .resource is not in current directory

When extracting data from foo/bar.asset, it will fail to load resources from foo/bar.resources if we execute the script from another dir than foo, it seems ResourceReader only looks in current directory not in the directory from which the asset is (i.e. dir of foo/bar.asset).

error happened when use the simple example code.

Code
A snippet of the code section that cases the bug or error.

            if obj.type in ["Texture2D", "Sprite"]:
                # parse the object data
                data = obj.read()

                # create destination path
                dest = os.path.join(destination_folder, data.name)

                # make sure that the extension is correct
                # you probably only want to do so with images/textures
                dest, ext = os.path.splitext(dest)
                dest = dest + ".png"

                img = data.image
                img.save(dest)

Error
The error message that is produced by python.

Traceback (most recent call last):
File "/Users/zhuangyou/opt/anaconda3/lib/python3.7/site-packages/PIL/ImageFile.py", line 496, in _save
fh = fp.fileno()
AttributeError: '_idat' object has no attribute 'fileno'

Bug
A description of what you expect to happen/see and what actually happens.

To Reproduce

  • a copy of the file that causes the problem
  • following data:
    • Python version 3.7
    • UnityPy version 1.6.7

Suggestion: object generator and more extensive loading/saving options

I think it would be better if you could re-implement #22 in a way you think would be more appropriate for the project.

What I basically thought is missing:

  • Example of dumping / restoring raw MonoBehaviours.
  • Example of iterating over objects without writing additional code for getting local asset path, asset file name etc each time.
  • Some kind of generator or iterator over objects in all files with progress function changing option that provides the aforementioned things.
  • Function (ex. am.save("lz4")) for auto-saving all changed files using the generator in the Environment class. It could be overridden if some project needs more but in most cases it should be enough by itself.

generated data.unity3d file is too big

unitypy version :1.7.7

for obj in env.objects:
if obj.type == "Texture2D":
data = obj.read()
if data.name == "xx":
path=os.path.join("tmp", f"123.png")
pil_img = Image.open(path)
data.img=pil_img
data.save()

with open("1.unity3d", "wb") as f:
f.write(env.file.save())

////
the product 1.unity3d file is 200M bigger than origin file

Support ogg and wav samples

Some games do not use FSB5 clips. I can work on a patch but I'm unsure about those:

  • RIFF/WAV has no metadata so no filename to return from extract_audioclip_samples
  • OGG would need another dependency to extract the file title metadata? (like mutagen, tagpy)
  • in an AudioClip, could there be multiple OGG (or WAV) samples/files?

Import issue with from TypeTreeHelper in Object.py

To make obj.dump() work properly, I had to change from ..helpers import TypeTreeHelper in classes/Object.py to from ..helpers.TypeTreeHelper import TypeTreeHelper. I am unsure why this is the case since helpers/__init__.py seems to be set up properly.

OS: Windows 10, Python 3.7

I have a question to ask you.

Ask, in your project.
Img = Image.frombytes (mode, (width, height), data [0:], codec, args).
You can turn the content into a picture. Is there any way to turn the picture into content?

parser mesh have error

File "/usr/local/lib/python3.7/site-packages/UnityPy/files/SerializedFile.py", line 701, in read
raise e
File "/usr/local/lib/python3.7/site-packages/UnityPy/files/SerializedFile.py", line 699, in read
return getattr(classes, self.type.name, classes.Object)(self)
File "/usr/local/lib/python3.7/site-packages/UnityPy/classes/Mesh.py", line 385, in init
self.m_SubMeshes = [SubMesh(reader) for _ in range(m_SubMeshesSize)]
File "/usr/local/lib/python3.7/site-packages/UnityPy/classes/Mesh.py", line 385, in
self.m_SubMeshes = [SubMesh(reader) for _ in range(m_SubMeshesSize)]
TypeError: init() missing 1 required positional argument: 'version'

AttributeError: module 'PIL._imaging' has no attribute 'etc2_decoder'

Traceback (most recent call last):
  File "<censored>/UnityPy/lib/python3.8/site-packages/PIL/Image.py", line 409, in _getdecoder
    decoder = getattr(core, decoder_name + "_decoder")
AttributeError: module 'PIL._imaging' has no attribute 'etc2_decoder'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<censored>/UnityPy/AssetBatchConverter.py", line 116, in <module>
    main()
  File "<censored>/UnityPy/AssetBatchConverter.py", line 42, in main
    extract_assets(src)
  File "<censored>/UnityPy/AssetBatchConverter.py", line 63, in extract_assets
    export_obj(obj, fp)
  File "<censored>/UnityPy/AssetBatchConverter.py", line 97, in export_obj
    data.image.save(f"{fp}{extension}")
  File "<censored>/UnityPy/UnityPy/classes/Sprite.py", line 13, in image
    return SpriteHelper.get_image_from_sprite(self)
  File "<censored>/UnityPy/UnityPy/export/SpriteHelper.py", line 45, in get_image_from_sprite
    original_image = get_image(m_Sprite, m_Texture2D, alpha_texture)
  File "<censored>/UnityPy/UnityPy/export/SpriteHelper.py", line 28, in get_image
    original_image = get_image_from_texture2d(texture.read(), False)
  File "<censored>/UnityPy/UnityPy/export/Texture2DConverter.py", line 258, in get_image_from_texture2d
    img = Image.frombytes(mode, (texture_2d.m_Width, texture_2d.m_Height), image_data, codec, args)
  File "<censored>/UnityPy/lib/python3.8/site-packages/PIL/Image.py", line 2581, in frombytes
    im.frombytes(data, decoder_name, args)
  File "<censored>/UnityPy/lib/python3.8/site-packages/PIL/Image.py", line 767, in frombytes
    d = _getdecoder(self.mode, decoder_name, args)
  File "<censored>/UnityPy/lib/python3.8/site-packages/PIL/Image.py", line 412, in _getdecoder
    raise OSError("decoder %s not available" % decoder_name)

I can as well provide the assets file if you wish.

'EndianBinaryReader_Streamable' object has no attribute 'save'

Code

    src = "D:\\ZTA\\MLBG Data\\#MLBGChanger-Python\\restore\\"+b
    src = b"bytes"
    src = io.BytesIO(b"Streamable")
    env = UnityPy.load(src)
    for obj in env.objects:
        if obj.type in ["Texture2D"]:
            # export texture
            data = obj.read()
            if data.name == a:
                # edit texture
                with Image.open(a+".png") as pil_img:
                    data.image = pil_img
                    data.save()
    with open(b, "wb") as f:
        f.write(env.file.save())

Error

    Traceback (most recent call last):
      File "D:\ZTA\MLBG Data\#MLBGChanger-Python\ImageConverter.py", line 78, in <module>
        f.write(env.file.save())
    AttributeError: 'EndianBinaryReader_Streamable' object has no attribute 'save'

Bug
I can't save it.

Replace Texture2D 2020.2.2f1 failed.

The code, repalce one image:

import os
import UnityPy
from PIL import Image

if __name__ == '__main__':
  path = r'./data.unity3d'    
  env = UnityPy.load(path);
  for obj in env.objects:
      if obj.type == "Texture2D":
        data = obj.read();
        target = 'sactx-4-2048x2048-Crunch-Opening-f2cb946e';
        if data.name == target:
            print('save');
            data.image = Image.open(r''+target+'.png')
            data.save();
  open(path + '_2', 'wb').write(env.file.save());
  print('done');

The log:

E/Unity: Could not open file /data/app/r****.t2-hvUp7W4EeakH85PlEo-8Xg==/base.apk/assets/bin/Data/archive:/CAB-UnityPy_Mod.resS for read

 E/Unity: async texture load: failed to load sactx-4-2048x2048-Crunch-Opening-f2cb946e from /data/app/r*****.t2-hvUp7W4EeakH85PlEo-8Xg==/base.apk/assets/bin/Data/archive:/CAB-UnityPy_Mod.resS

UnityPy version : 1.7.6

MonoBehaviour Raw-data Import

So,
I'm trying to export raw-data from MonoBehaviour, edit it and then reimport it

The export part was pretty easy, I've managed to export only the raw part that I need, but, for the import, part I don't know how to do it.
I've tried to follow the patch example but I've encountered some issue and at the end it doesn't work..

This is my code:

`

file_name = "resources.assets"
file_path = os.path.join(root, "asset/resources.assets")
e = UnityPy.load(file_path)

for obj in e.objects:

    if obj.type == "MonoBehaviour":

        data = obj.read()               
        namer=data.name

        if data.name=="GeneralLockitEnglish":

            with open(os.path.join(destination_folder, f"{file_name}-{namer}.txt"), "rb") as fr:
                data.raw_data=fr.read()

with open(os.path.join(root, "file_patched"), "wb") as f:
    f.write(e.file.save()) 

I've added a setter to the MonoBehaviour like this:
@raw_data.setter

def raw_data(self, val):

    self._raw_offset = val

The result is that the same file is saved without any changes
Probably the problem could be the setter since I'not so good with python, but I don't have found any example about restoring edited raw-data on MonoBehaviour

Please I kinda lost here 🤣

Sprite-Texture2D merging issue

Code

import UnityPy
env = UnityPy.load("live_note_default")
for path, obj in env.container.items():
    print(path, obj.type)

Error
N/A

Bug
Seems like the Sprite-Texture2D merging is performed in the wrong direction.
Four Sprite in the sample: notes_crtcl, notes_flick, notes_long and notes_normal, all based on the Texture2D notes. (let's ignore the rest of the items here)
I'm expecting all four Sprites in the output, but UnityPy only gives me one Sprite named notes.

Also a tiny bug, too lazy for a separate issue: 1.7.3 breaks str(obj.type), now all items are UnknownType.

To Reproduce

  • a copy of the file that causes the problem
    live_note_default.zip (unzip it and you should get an asset bundle file)
  • following data:
    • Python version 3.7.3
    • UnityPy version 1.7.2

Include FMOD libraries for all available architectures?

I'm using UnityPy on an ARM machine, and import UnityPy raises an OSError:

OSError: /usr/local/lib/python3.7/dist-packages/UnityPy/lib/FMOD/Linux/32bit/libfmod.so: cannot open shared object file: No such file or directory

Obviously the pointed file is for x86 only.
So:

  • Could you add an try...except block so it does not block importing?
  • Of course, including libraries for all architectures is also appreciated.

Should avoid changing `_value` in `Enum._missing_`

Code

from UnityPy.enums import ClassIDType

# two unkonw values
t1 = ClassIDType(-10)
t2 = ClassIDType(-20)

assert t1 == -10, (t1, t1.value)

Error

AssertionError: (<ClassIDType.UnknownType: -1>, -20)

New unkonw value will change the value of previous values.

Bug
The bug is caused by Enum._missing_

@classmethod
def _missing_(cls, value):
ret = ClassIDType.UnknownType
ret._value = value
return ret

ClassIDType.UnknownType is singlenton, so changes to _value should be avoided.

BuildTarget will suffer the same issue.

Didn't find a easy method to fix this. Maybe a custom Enum implemention is reqeuired.

Error occurred when downloading texture2ddecoder module.

Hi. I know it is not appropriate place to ask this question, but I can't find the place to ask this. The author seems to stop the support the package.. (at least, in Github)

When I tried to download texture2ddecoder, there is an error:

ERROR: Command errored out with exit status 1:
   command: /Library/Frameworks/Python.framework/Versions/3.7/bin/python3 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/fs/wc5llrws0b71vppjd83hz1b00000gn/T/pip-install-fvrj6xf6/texture2ddecoder_def16d0532a044a4b681c511176465ed/setup.py'"'"'; __file__='"'"'/private/var/folders/fs/wc5llrws0b71vppjd83hz1b00000gn/T/pip-install-fvrj6xf6/texture2ddecoder_def16d0532a044a4b681c511176465ed/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d /private/var/folders/fs/wc5llrws0b71vppjd83hz1b00000gn/T/pip-wheel-3m2jxqpv
       cwd: /private/var/folders/fs/wc5llrws0b71vppjd83hz1b00000gn/T/pip-install-fvrj6xf6/texture2ddecoder_def16d0532a044a4b681c511176465ed/
  Complete output (144 lines):
  running bdist_wheel
  running build
  running build_ext
  building 'texture2ddecoder' extension
  creating build
  creating build/temp.macosx-10.9-x86_64-3.7
  creating build/temp.macosx-10.9-x86_64-3.7/src
  creating build/temp.macosx-10.9-x86_64-3.7/src/Texture2DDecoder
  gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -Isrc/Texture2DDecoder -I/Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m -c src/pylink.cpp -o build/temp.macosx-10.9-x86_64-3.7/src/pylink.o -std=c++11
  src/pylink.cpp:2:9: warning: #pragma once in main file [-Wpragma-once-outside-header]
  #pragma once
          ^
  src/pylink.cpp:187:5: warning: cannot delete expression with pointer-to-'void' type 'void *' [-Wdelete-incomplete]
      delete ret;
      ^      ~~~
  src/pylink.cpp:208:5: warning: cannot delete expression with pointer-to-'void' type 'void *' [-Wdelete-incomplete]
      delete ret;
      ^      ~~~
  3 warnings generated.
  gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -Isrc/Texture2DDecoder -I/Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m -c src/Texture2DDecoder/astc.cpp -o build/temp.macosx-10.9-x86_64-3.7/src/Texture2DDecoder/astc.o -std=c++11
  gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -Isrc/Texture2DDecoder -I/Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m -c src/Texture2DDecoder/atc.cpp -o build/temp.macosx-10.9-x86_64-3.7/src/Texture2DDecoder/atc.o -std=c++11
  gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -Isrc/Texture2DDecoder -I/Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m -c src/Texture2DDecoder/bcn.cpp -o build/temp.macosx-10.9-x86_64-3.7/src/Texture2DDecoder/bcn.o -std=c++11
  gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -Isrc/Texture2DDecoder -I/Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m -c src/Texture2DDecoder/crunch.cpp -o build/temp.macosx-10.9-x86_64-3.7/src/Texture2DDecoder/crunch.o -std=c++11
  In file included from src/Texture2DDecoder/crunch.cpp:4:
  src/Texture2DDecoder/crunch/crn_decomp.h:666:10: warning: expression result unused [-Wunused-value]
           num_check;
           ^~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:2418:7: warning: expression result unused [-Wunused-value]
        p;
        ^
  src/Texture2DDecoder/crunch/crn_decomp.h:2433:7: warning: expression result unused [-Wunused-value]
        pUser_data;
        ^~~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:2492:7: warning: expression result unused [-Wunused-value]
        pUser_data;
        ^~~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:2700:7: warning: expression result unused [-Wunused-value]
        tmp_header;
        ^~~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:3720:10: warning: expression result unused [-Wunused-value]
           dst_size_in_bytes;
           ^~~~~~~~~~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:4155:10: warning: expression result unused [-Wunused-value]
           dst_size_in_bytes;
           ^~~~~~~~~~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:4341:10: warning: expression result unused [-Wunused-value]
           dst_size_in_bytes;
           ^~~~~~~~~~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:4484:10: warning: expression result unused [-Wunused-value]
           dst_size_in_bytes;
           ^~~~~~~~~~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:4626:10: warning: expression result unused [-Wunused-value]
           dst_size_in_bytes;
           ^~~~~~~~~~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:666:10: warning: expression result unused [-Wunused-value]
           num_check;
           ^~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:1929:16: note: in instantiation of function template specialization 'crnd::crnd_delete_array<unsigned int>' requested here
                 crnd_delete_array(m_lookup);
                 ^
  src/Texture2DDecoder/crunch/crn_decomp.h:666:10: warning: expression result unused [-Wunused-value]
           num_check;
           ^~~~~~~~~
  src/Texture2DDecoder/crunch/crn_decomp.h:1936:16: note: in instantiation of function template specialization 'crnd::crnd_delete_array<unsigned short>' requested here
                 crnd_delete_array(m_sorted_symbol_order);
                 ^
  src/Texture2DDecoder/crunch/crn_decomp.h:501:10: warning: expression result unused [-Wunused-value]
           p;
           ^
  src/Texture2DDecoder/crunch/crn_decomp.h:654:19: note: in instantiation of function template specialization 'crnd::helpers::destruct<crnd::prefix_coding::decoder_tables>' requested here
           helpers::destruct(p);
                    ^
  src/Texture2DDecoder/crunch/crn_decomp.h:2940:7: note: in instantiation of function template specialization 'crnd::crnd_delete<crnd::prefix_coding::decoder_tables>' requested here
        crnd_delete(m_pDecode_tables);
        ^
  src/Texture2DDecoder/crunch/crn_decomp.h:501:10: warning: expression result unused [-Wunused-value]
           p;
           ^
  src/Texture2DDecoder/crunch/crn_decomp.h:654:19: note: in instantiation of function template specialization 'crnd::helpers::destruct<crnd::crn_unpacker>' requested here
           helpers::destruct(p);
                    ^
  src/Texture2DDecoder/crunch/crn_decomp.h:4752:10: note: in instantiation of function template specialization 'crnd::crnd_delete<crnd::crn_unpacker>' requested here
           crnd_delete(p);
           ^
  14 warnings generated.
  gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -fno-common -dynamic -DNDEBUG -g -fwrapv -O3 -Wall -arch x86_64 -g -Isrc/Texture2DDecoder -I/Library/Frameworks/Python.framework/Versions/3.7/include/python3.7m -c src/Texture2DDecoder/etc.cpp -o build/temp.macosx-10.9-x86_64-3.7/src/Texture2DDecoder/etc.o -std=c++11
  src/Texture2DDecoder/etc.cpp:41:35: error: non-constant-expression cannot be narrowed from type 'int' to 'uint_fast8_t' (aka 'unsigned char') in initializer list [-Wc++11-narrowing]
      const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};  // Table codewords
                                    ^~~~~~~~~~~~
  src/Texture2DDecoder/etc.cpp:41:35: note: insert an explicit cast to silence this issue
      const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};  // Table codewords
                                    ^~~~~~~~~~~~
                                    static_cast<uint_fast8_t>( )
  src/Texture2DDecoder/etc.cpp:41:49: error: non-constant-expression cannot be narrowed from type 'int' to 'uint_fast8_t' (aka 'unsigned char') in initializer list [-Wc++11-narrowing]
      const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};  // Table codewords
                                                  ^~~~~~~~~~~~~~~~
  src/Texture2DDecoder/etc.cpp:41:49: note: insert an explicit cast to silence this issue
      const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};  // Table codewords
                                                  ^~~~~~~~~~~~~~~~
                                                  static_cast<uint_fast8_t>( )
  src/Texture2DDecoder/etc.cpp:148:43: error: non-constant-expression cannot be narrowed from type 'int' to 'uint_fast8_t' (aka 'unsigned char') in initializer list [-Wc++11-narrowing]
              const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                            ^~~~~~~~~~~~
  src/Texture2DDecoder/etc.cpp:148:43: note: insert an explicit cast to silence this issue
              const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                            ^~~~~~~~~~~~
                                            static_cast<uint_fast8_t>( )
  src/Texture2DDecoder/etc.cpp:148:57: error: non-constant-expression cannot be narrowed from type 'int' to 'uint_fast8_t' (aka 'unsigned char') in initializer list [-Wc++11-narrowing]
              const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                                          ^~~~~~~~~~~~~~~~
  src/Texture2DDecoder/etc.cpp:148:57: note: insert an explicit cast to silence this issue
              const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                                          ^~~~~~~~~~~~~~~~
                                                          static_cast<uint_fast8_t>( )
  src/Texture2DDecoder/etc.cpp:167:39: error: non-constant-expression cannot be narrowed from type 'int' to 'uint_fast8_t' (aka 'unsigned char') in initializer list [-Wc++11-narrowing]
          const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                        ^~~~~~~~~~~~
  src/Texture2DDecoder/etc.cpp:167:39: note: insert an explicit cast to silence this issue
          const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                        ^~~~~~~~~~~~
                                        static_cast<uint_fast8_t>( )
  src/Texture2DDecoder/etc.cpp:167:53: error: non-constant-expression cannot be narrowed from type 'int' to 'uint_fast8_t' (aka 'unsigned char') in initializer list [-Wc++11-narrowing]
          const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                                      ^~~~~~~~~~~~~~~~
  src/Texture2DDecoder/etc.cpp:167:53: note: insert an explicit cast to silence this issue
          const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                                      ^~~~~~~~~~~~~~~~
                                                      static_cast<uint_fast8_t>( )
  src/Texture2DDecoder/etc.cpp:263:39: error: non-constant-expression cannot be narrowed from type 'int' to 'uint_fast8_t' (aka 'unsigned char') in initializer list [-Wc++11-narrowing]
          const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                        ^~~~~~~~~~~~
  src/Texture2DDecoder/etc.cpp:263:39: note: insert an explicit cast to silence this issue
          const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                        ^~~~~~~~~~~~
                                        static_cast<uint_fast8_t>( )
  src/Texture2DDecoder/etc.cpp:263:53: error: non-constant-expression cannot be narrowed from type 'int' to 'uint_fast8_t' (aka 'unsigned char') in initializer list [-Wc++11-narrowing]
          const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                                      ^~~~~~~~~~~~~~~~
  src/Texture2DDecoder/etc.cpp:263:53: note: insert an explicit cast to silence this issue
          const uint_fast8_t code[2] = {data[3] >> 5, data[3] >> 2 & 7};
                                                      ^~~~~~~~~~~~~~~~
                                                      static_cast<uint_fast8_t>( )
  8 errors generated.
  error: command 'gcc' failed with exit status 1
  ----------------------------------------
  ERROR: Failed building wheel for texture2ddecoder

Hence, I need another way to handle this error to use Unitypy. Any idea? Thanks.

where is globalmanagers

my project is a il2cpp project .
there is bin/data/managed/global_metadata
where is globalmanagers file ?

  • Python version 3.8
  • UnityPy version 2019.4.15

AudioClip class passes a parameter into SerializedFile.read(), which does not accept parameters.

Attempting to read AudioClip objects results in a TypeError as follows:

>>> for asset in am.assets.values():
...     for obj in asset.objects.values():
...         if obj.type.name == 'AudioClip':
...             data = obj.read()
...             print(data)
...             break
... 
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
  File "/home/ian/.local/lib/python3.8/site-packages/UnityPy/files/SerializedFile.py", line 670, in read
    return getattr(classes, self.type.name, classes.Object)(self)
  File "/home/ian/.local/lib/python3.8/site-packages/UnityPy/classes/AudioClip.py", line 57, in __init__
    self.m_AudioData = reader.read(m_Size)
TypeError: read() takes 1 positional argument but 2 were given

Importing type trees not working

When using obj.save_typetree it outputs blank data and does not affect the edited files. I talked about this issue on the Discord but figured I'd put it here too (I need it fixed soon lmao)

Open, how to save again, the resource size has increased a lot

I used a resource file to test. I just opened it and saved it again. The resource file changed from 30M to 300M. How to solve this? Below is the code I tested。

root = os.path.dirname(os.path.realpath(file))
fp = os.path.join(root,"data.unity3d")

env = UnityPy.load(fp)
with open("data_patch.unity3d", "wb") as f:
f.write(env.file.save())

ValueError: This cab already exists and isn't an EndianBinaryWriter

Code
from PIL import Image
import io
import UnityPy

all of the following would work

src = "D:\ZTA\Test2\UI_FirstLoading.unity3d"

env = UnityPy.load(src)
print(env)

for obj in env.objects:
if obj.type in ["Texture2D"]:
# export texture
data = obj.read()
if data.name == "Atlas_Menu02":
data.image.save(data.name+"_bak.png")
# edit texture
with Image.open("Atlas_Menu02.png") as pi_img:
data.image = pi_img
data.save()

with open("UI_FirstLoading_REPLACE.unity3d", "wb") as f:
f.write(env.file.save())

Error
Traceback (most recent call last):
File "C:\Users\Thuya\AppData\Local\Programs\Python\Python36\lib\runpy.py", line 193, in _run_module_as_main
"main", mod_spec)
File "C:\Users\Thuya\AppData\Local\Programs\Python\Python36\lib\runpy.py", line 85, in run_code
exec(code, run_globals)
File "c:\Users\Thuya.vscode\extensions\ms-python.python-2021.2.633441544\pythonFiles\lib\python\debugpy_main
.py", line 45, in
cli.main()
File "c:\Users\Thuya.vscode\extensions\ms-python.python-2021.2.633441544\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 444, in main
run()
File "c:\Users\Thuya.vscode\extensions\ms-python.python-2021.2.633441544\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 285, in run_file
runpy.run_path(target_as_str, run_name=compat.force_str("main"))
File "C:\Users\Thuya\AppData\Local\Programs\Python\Python36\lib\runpy.py", line 263, in run_path
pkg_name=pkg_name, script_name=fname)
File "C:\Users\Thuya\AppData\Local\Programs\Python\Python36\lib\runpy.py", line 96, in _run_module_code
mod_name, mod_spec, pkg_name, script_name)
File "C:\Users\Thuya\AppData\Local\Programs\Python\Python36\lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "d:\ZTA\Test2\Edit.py", line 20, in
data.image = pi_img
File "C:\Users\Thuya\AppData\Local\Programs\Python\Python36\lib\site-packages\UnityPy\classes\Texture2D.py", line 21, in image
self.image_data = img_data
File "C:\Users\Thuya\AppData\Local\Programs\Python\Python36\lib\site-packages\UnityPy\classes\Texture2D.py", line 35, in image_data
cab = self.assets_file.get_writeable_cab()
File "C:\Users\Thuya\AppData\Local\Programs\Python\Python36\lib\site-packages\UnityPy\files\SerializedFile.py", line 378, in get_writeable_cab
cab = self.parent.get_writeable_cab(name)
File "C:\Users\Thuya\AppData\Local\Programs\Python\Python36\lib\site-packages\UnityPy\files\File.py", line 81, in get_writeable_cab
"This cab already exists and isn't an EndianBinaryWriter")
ValueError: This cab already exists and isn't an EndianBinaryWriter

Bug
First time it's ok!
But second time it come with that error.

PPtr objects never return true when getting bool value

In UnityPy/export/SpriteHelper.py L24 , the alpha_texture will always be False due to the __bool__ method in UnityPy/classes/PPtr.py L56.
That means alpha channel will never be automatically merged into original image, but it seems to be unexpected.
Also Unitypack has the same problem, Is it a mistake when copied from Unitypack?

mod assets question

*******************************************write files to bundle *****************
globalgamemanagers
Resources/unity_builtin_extra
globalgamemanagers.assets
sharedassets0.assets
sharedassets0.assets.resS
level0
sharedassets1.assets
sharedassets1.assets.resS
level1
resources.assets
resources.assets.resS
CAB-UnityPy_Mod.resS
********************************************write files to bundle over **************************
The above is log of the "save " function procedure, why there is no CAB-UnityPy_Mod.assets file written

  • UnityPy version 2019.4.15f1
  • python version 3.8

Error calling StreamedClip.ReadData(): list object has no attribute "seek"

Code

for obj in env.objects:
    if obj.type == 'AnimationClip':
        data = obj.read()
        print(data.m_MuscleClip.m_Clip.m_StreamedClip.ReadData())

Error

Traceback:
  File "classes/AnimationClip.py", line 370, in ReadData
    reader = EndianBinaryReader(buffer)
  File "streams/EndianBinaryReader.py", line 21, in __new__
    obj.__init__(item, endian)
  File "streams/EndianBinaryReader.py", line 217, in __init__
    self.Length = self.stream.seek(0, 2) - offset
AttributeError: 'list' object has no attribute 'seek'

Bug
StreamedClip initializes its data attribute by calling read_u_int_array(), which returns a list. ReadData() passes data to EndianBinaryReader as stream, whereupon EndianBinaryReader_Streamable tries to call seek(), which I guess is a method of IOBase.

To Reproduce

  • Problem encountered when working with some Live2D ab files from Android
  • following data:
    • Python version: 3.9.5
    • UnityPy version: 1.7.6

bug in class Mesh

File "UnityPy/classes/Mesh.py", line 423, in ProcessData
if hasattr(self, 'm_StreamData') and self.m_StreamData.get('path'):
AttributeError: 'StreamingInfo' object has no attribute 'get'

should be self.m_StreamData.path

android runtime error after mod

After mod , android app report this error at runtime
Could not open file /data/app/xxx/base.apk/assets/bin/Data/archive:/CAB-UnityPy_Mod.resS for read
06-18 15:13:23.357 15383 15527 E Unity : (Filename: Line: 61)
06-18 15:13:23.357 15383 15527 E Unity :
06-18 15:13:23.358 15383 15527 E Unity : async texture load: failed to load xxxx from /data/app/xxx/base.apk/assets/bin/Data/archive:/CAB-UnityPy_Mod.resS

  • Python version 3.8
  • UnityPy version 2019.4.15f1

Float number parsing & rounding issue

Not sure if this is a feature request or a question, but how do I get rid of numbers like 0.1000004?

I know that in a binary POV, it's impossible to represent 0.1 due to its nature. However, when I was using AssetStudio in C#, for some reason, the exported floats won't have this kind of thing. Python has decimal class for handling this.

I haven't looked deep into decimal, but my proposal will be to add something like UnityPy.load(decimal=True), so that the user won't run into trouble (or at least expect some) if the interface for decimal is different.

This fix would be greatly appreciated because I recently switched over from AssetStudio C# custom CLI to this for easier library access. I was doing exact number match in my test cases, but now I have to equip all of them with approx match. This rounding issue could also lead to some inaccurate results.

MonoBehaviour Treetype Edit

I‘m tring to edit MonoBehaviour by tree type, but it is no effect when I save it with 'save_typetree(tree)'.
I notice the other issue #43, but it can not help me.
Pls help me, this is a great project, best wishes for you.

Code
for obj in env.objects:

if obj.type == 'MonoBehaviour':

    # export
    if obj.serialized_type.nodes:
        tree = obj.read_typetree()

        if name is not None:
            text = tree.get('Text')

            if '学園付近' in text:

                tree['Text'] = """選抜レースを明日に控えた昼下がり、\n\n学園付近の公園を散歩していると――"""
                obj.save_typetree(tree)

Bug
It is no effect when I save it with 'save_typetree(tree)'. and I try to save it like:
with open(path + '.txt', 'wb') as f:
f.write(env.file.save('original'))
Pls notice that I only change '\t' to '\n' in tree['Text'].

I will get a ompletely different file.(the Original vs the changed)
image
image

To Reproduce

  • following data:
    • Python 3.6
    • UnityPy 1.7.2

How to edit FONT

I want to edit FONT, export, modify and reimport. But it do not work when I save() it:
Code

env = UnityPy.load(file_path)
    for obj in env.objects:
        if obj.type == 'Font':
           font.m_FontData = open(font_file_path, 'rb').read()
           font.save()
    with open(another_file_path, 'wb') as f:
        f.write(env.file.save())

Error
The Font do not change. How can I edit a Font file pls?

  • following data:
    • Python version: 3.6.0
    • UnityPy version: 1.7.6

Can't decompress font with 'KerningValues_size' > 0

Code
Font.py:24
for i in range(KerningValues_size):
reader.Position += 8

Error
FontData_size -1082130432 FLARESERIF-821-BT
FontData_size 85688 SukhumvitSet-Text
FontData_size -1082130432 FLARESERIF-821-BOLD-BT
FontData_size -1082130432 Arial

get wrong FontData_size

Bug
I TEST AND TRY. When it changes to 'reader.Position += 8' To 'reader.read_int() reader.read_int() ', EVERYTHING WILL BE OK!!!!

To Reproduce

  1. Get "State of Survival Survive the Zombie Apocalypse_v1.10.10_apkpure.com" from internet

Importing TypeTree breaks MonoBehaviour

This issue occurs in asset files for Yurucamp: Have a nice day. Unsure if it may affect other games using Unity 2020.x format.

Code

env = UnityPy.load("title.unity3d")
env.objects[1].save_typetree(json.load(open("1.json")))
env.save()

Bug
The resulting asset file works in the game, but MonoBehaviours modified using save_typetree() will be broken. (e.g. if it is a text asset, its text won't show up anymore)

To Reproduce

  • a copy of the file that causes the problem (original file is copyrighted and not mine, but can be retrieved following instructions here)
  • following data:
    • Python version 3.9.7
    • UnityPy version 1.7.24

Question: access object directly with file_id and path_id

Hi, sorry to use the issues system to ask a question.

I'm using UnityPy to automatically dump stuff, and I've added the ability to automatically dump files referenced by a pptr.
I face two issues however:

  • I don't know how to access an object directly based on its file_id/path_id, so I have to iterate over all objects every time to find it which is unbearably slow. I've browsed UnityPy's code and I'm not sure what I could use to directly access an object knowing its file_id/path_id.
  • There doesn't seem to be support for file_ids ? What I work on unfortunately has objects with same path_id in different asset files (differents file_id) and I don't know how to check for that with UnityPy. I have to currently check only for path_id and hope it's the right file.

Would appreciate any guidance, thanks!

Editing Texture2d is not working and It's just Black.

Bug

When I edit the Texture2d obj from .unity3d file format with UnityPy, Image was changed but When i use it, the image is just Black and it's not working like an original one.
But When i edit with UABE, it's working well.
I found the diffrent between their changes!

The one edited with UnityPy change the image in StreamingInfo m_StreamData But the one edited with UABE change in the TypelessData image data.
Is it relevant?

I provide the image for you.

UnityPy
UnityPy

UABE
UABE

Bundle folder structure

Some bundle files contain folder structures in them, would be nice if it was possible to see under which folder the files are stored on. Unity Studio does it but it does break sometimes and only display asset name.

`reader` not defined bug and unterminated string

On SerializedFile.py under read_serialized_type function, I got an exception saying reader is not defined.
After fixing that (by changing it in self.reader) actually, I found out that there's more. I found out that there's also an issue with the reading of the type Unterminated string: [b''].

I'm also providing the sample file for it (it's decrypted, so there shouldn't be any encryption/xor/anything else issue).

Unity version: 2019.4.1f1

bundle.zip

NodeHelper breaks on dictionaries with non-string keys

I'm trying to load an AssetBundleManifest using UnityPy (apologies for the spaghetti code, just trying to get it working and see what's possible):

import UnityPy
import requests
r = requests.get("<URL REDACTED, but literally any AssetBundleManifest would work>")
am = UnityPy.AssetsManager(r.content)
bundle = list(am.assets.values())[0]
abm = [i for i in bundle.objects.values() if i.class_id == UnityPy.enums.ClassIDType.AssetBundleManifest][0].read()

This all work, and I can see the resulting AssetBundleManifest:
image

However, when I try to access an attribute like abm.AssetBundleNames, I just get a NodeHelper object and tab complete won't work:
image

Using dir on it gives me an exception:
image

I can still see all the asset bundle names if I do abm.AssetBundleNames.__dict__:
image

I think the problem is AssetBundleNames is stored as a dict from int to str, and you're just assigning everything in this dictionary to the object's __dict__ when python expects every key in __dict__ to be a string.

I'm not sure what the best way to fix this is, but maybe a type check for the keys and falling back to something else if the keys aren't strings might be a good idea. For now, I'm just operating directly on abm.AssetBundleNames.__dict__, which isn't ideal but works.

Texture2DConverter.py Image.tobytes should be img.tobytes

Code
A snippet of the code section that cases the bug or error.
elif target_texture_format == TF.Alpha8:
enc_img = Image.tobytes("raw", "A")
tex_format = TF.Alpha8
# R
elif target_texture_format in [
TF.R8,
TF.R16,
TF.RHalf,
TF.RFloat,
TF.EAC_R,
TF.EAC_R_SIGNED,
]:
enc_img = Image.tobytes("raw", "R")
tex_format = TF.R8
# RGBA
elif target_texture_format in [
TF.RGB565,
TF.RGB24,
TF.RGB9e5Float,
TF.PVRTC_RGB2,
TF.PVRTC_RGB4,
TF.ATC_RGB4,
]:
enc_img = Image.tobytes("raw", "RGB")
tex_format = TF.RGB24

Error
The error message that is produced by python.
Image.tobytes("raw", "xxx") -> img.tobytes("raw", "xxx")

Bug
A description of what you expect to happen/see and what actually happens.

To Reproduce

  • a copy of the file that causes the problem
  • following data:
    • Python version
    • UnityPy version

NameError: name 'sp' is not defined in export/ShaderConverter.py

Code

sp.append(buff.decode("utf8"))

Error
NameError: name 'sp' is not defined

Bug
I suppose this is a typo.

sb.append(buff.decode("utf8"))

After fixing this typo, I encountered AttributeError: 'memoryview' object has no attribute 'decode'.

sb.append(buff.tobytes().decode("utf8"))

And this fixes.

To Reproduce

  • An ab file from IOS platform may cause this issue.
  • following data:
    • Python version 3.8
    • UnityPy version 1.7.6

`'FakeNode' object has no attribute 'type'`

Code

import UnityPy

def main():
    asset = UnityPy.load("assetbundle.manifest.decrypted")
    asset.objects[0].read()

if __name__ == '__main__':
    main()

Error

E:\Personal@SSD\Game\DL\dragalia-asset-downloader-2\venv\Scripts\python.exe E:/Personal@SSD/Game/DL/dragalia-asset-downloader-2/sandbox.py
Traceback (most recent call last):
  File "E:\Personal@SSD\Game\DL\dragalia-asset-downloader-2\sandbox.py", line 10, in <module>
    main()
  File "E:\Personal@SSD\Game\DL\dragalia-asset-downloader-2\sandbox.py", line 6, in main
    asset.objects[0].read()
  File "E:\Personal@SSD\Game\DL\dragalia-asset-downloader-2\venv\lib\site-packages\UnityPy\files\ObjectReader.py", line 155, in read
    raise e
  File "E:\Personal@SSD\Game\DL\dragalia-asset-downloader-2\venv\lib\site-packages\UnityPy\files\ObjectReader.py", line 153, in read
    obj = getattr(classes, self.type.name, classes.Object)(self)
  File "E:\Personal@SSD\Game\DL\dragalia-asset-downloader-2\venv\lib\site-packages\UnityPy\classes\MonoBehaviour.py", line 15, in __init__
    self.read_typetree()
  File "E:\Personal@SSD\Game\DL\dragalia-asset-downloader-2\venv\lib\site-packages\UnityPy\classes\Object.py", line 50, in read_typetree
    tree = self.reader.read_typetree(nodes)
  File "E:\Personal@SSD\Game\DL\dragalia-asset-downloader-2\venv\lib\site-packages\UnityPy\files\ObjectReader.py", line 207, in read_typetree
    tree = TypeTreeHelper.read_typetree(
  File "E:\Personal@SSD\Game\DL\dragalia-asset-downloader-2\venv\lib\site-packages\UnityPy\helpers\TypeTreeHelper.py", line 78, in read_typetree
    obj[node.name] = read_value(nodes, reader, i)
  File "E:\Personal@SSD\Game\DL\dragalia-asset-downloader-2\venv\lib\site-packages\UnityPy\helpers\TypeTreeHelper.py", line 91, in read_value
    typ = node.type
AttributeError: 'FakeNode' object has no attribute 'type'

Bug

Error shouldn't occur.

Reproduce

File that causes the error: assetbundle.manifest.zip

Python version: v3.9.5
UnityPy version: v1.7.14

Confirmed that the error only occurs after updating to v1.7.14. v1.7.11 - v1.7.13 doesn't have this issue.

EOFError: got only 0 bytes out of 4 requested

I'm trying to load Materials in the file using UnityPy, but all the Materials cannot be correctly loaded.(UnityPack can load them)

Unity Asset File:Download Here

My Code:

import os
from UnityPy import AssetsManager

def unpack_all_assets(source_folder : str):
    # iterate over all files in source folder
    for root, dirs, files in os.walk(source_folder):
        for file_name in files:
            # generate file_path
            file_path = os.path.join(root, file_name)
            # load that file via AssetsManager
            am = AssetsManager(file_path)

            # iterate over all assets and named objects
            for asset in am.assets.values():
                for obj in asset.objects.values():
                 #   if obj.type == "GameObject" and obj.read().name.startswith("illust"):
                      #  data = obj.read()
                        
                      #  print(data.name, data.read_type_tree())
                        
                    # only process specific object types
                    #if obj.type == "MonoBehaviour" and obj.path_id == 413749536710485738:
                        # parse the object data
                      #  data = obj.read()
                        
                        #print(obj.path_id, data.name, data.type_tree)
                    if obj.type == "Material":
                        print(obj.path_id)
                        data = obj.read()

unpack_all_assets('./')

Traceback:

Traceback (most recent call last):
  File "test.py", line 32, in <module>
    unpack_all_assets('./')
  File "test.py", line 29, in unpack_all_assets
    data = obj.read()
  File "/usr/local/python3/lib/python3.8/site-packages/UnityPy/files/SerializedFile.py", line 670, in read
    return getattr(classes, self.type.name, classes.Object)(self)
  File "/usr/local/python3/lib/python3.8/site-packages/UnityPy/classes/Material.py", line 34, in __init__
    self.disabledShaderPasses = reader.read_string_array()
  File "/usr/local/python3/lib/python3.8/site-packages/UnityPy/streams/EndianBinaryReader.py", line 193, in read_string_array
    return self.read_array(self.read_aligned_string, self.read_int())
  File "/usr/local/python3/lib/python3.8/site-packages/UnityPy/streams/EndianBinaryReader.py", line 175, in read_array
    return [command() for i in range(length)]
  File "/usr/local/python3/lib/python3.8/site-packages/UnityPy/streams/EndianBinaryReader.py", line 175, in <listcomp>
    return [command() for i in range(length)]
  File "/usr/local/python3/lib/python3.8/site-packages/UnityPy/streams/EndianBinaryReader.py", line 131, in read_aligned_string
    length = self.read_int()
  File "/usr/local/python3/lib/python3.8/site-packages/UnityPy/streams/EndianBinaryReader.py", line 85, in read_int
    return struct.unpack(self.endian + "i", self.read(4))[0]
  File "/usr/local/python3/lib/python3.8/site-packages/UnityPy/streams/EndianBinaryReader.py", line 68, in read
    raise EOFError("got only %d bytes out of %d requested" %
EOFError: got only 0 bytes out of 4 requested

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.