K0lb3 / UnityPy

UnityPy is python module that makes it possible to extract/unpack and edit Unity assets
MIT License
810 stars 123 forks source link

RectTransforms Are Missing Their Unique Properties #259

Closed DavidESDR closed 3 weeks ago

DavidESDR commented 1 month ago

Code Example python code and bundle (Unity 2020.3.48.1) example.zip

import UnityPy
import json
import os

path = os.getcwd() + "/example.bundle"

enviornment = UnityPy.load(path)

def get_child_transform(data, origin = [0, 0]):
    # These properties don't exist
    pos = data.m_AnchoredPosition
    size = data.m_SizeDelta
    pivot = data.m_Pivot

    return {
        "position": [
            +pos.X - size.X * (0 + pivot.X) + origin[0],
            -pos.Y - size.Y * (1 - pivot.Y) + origin[1]
        ],
        "size": [size.X, size.Y],
        "center": [pivot.X, pivot.Y]
    }

for obj in enviornment.objects:
    if obj.type.name == "RectTransform":
        data = obj.read()
        print(json.dumps(get_child_transform(data), indent=4))

Error Anchors, size delta, and pivot properties are not currently being parsed. See here for a deep look into RectTransforms. The article is four years old at this point, so the way bundles are stored may have changed in newer versions of Unity.

Bug What I added to ...\UnityPy\classes\RectTransform.py to parse the desired properties:

from .Transform import Transform

class RectTransform(Transform):
    def __init__(self, reader):
        super().__init__(reader=reader)

        # Added these lines of code:
        self.m_AnchoredMin = reader.read_vector2()
        self.m_AnchoredMax = reader.read_vector2()
        self.m_AnchoredPosition = reader.read_vector2()
        self.m_SizeDelta = reader.read_vector2()
        self.m_Pivot = reader.read_vector2()

NOTE: The Unity spec includes phantom properties called offsetsMin and offsetMax which are not actually stored in bundles. I am unsure if the properties above are the only properties, but I'm sure you have better methods of determining that than I do.

To Reproduce UnityPy 1.10.14 Python 3.12.5 See example file above.

K0lb3 commented 3 weeks ago

RectTransform has indeed a fair bit of additional fields, as can be seen in the docs auto-generated for the stale rust port of UnityPy.

As I'm planning to move away from hard-coded parsers, to only using typetree parsing, this issue will be solved with that.

As this is still some time away, you can simply use read_typetree() for now to get all attributes safely. This works for all classes, but won't deliver a nice class, but instead only a hacky dict wrapper that behaves like a class, or alternatively, as dict.

DavidESDR commented 3 weeks ago

'object.read_typetree' works great (I was already using a bunch of JSON in my project, so another string indexed dict wouldn't hurt). Thanks!