Skip to content

MonoBehaviours

Rudolf Kolbe edited this page Jul 23, 2022 · 3 revisions

Background

The MonoBehaviour object type in Unity assets can be interpreted as a serialized instance of a script class, which can be pretty much everything, going from scene definitions to localisations or game settings.

By definition, "[the] MonoBehaviour class is the base class from which every Unity script derives, by default"¹. So nearly all game developer-made script classes are children of the MonoBehaviour class, which allows a straightforward serialization of all of them via the MonoBehaviour class.

The MonoBehaviour class serves as a springboard, as seen by its signature.

class MonoBehaviour(Behaviour):
    m_GameObject: PPtr[GameObject] = None
    m_Enabled: int = None
    m_Script: PPtr[MonoScript] = None
    m_Name: str = None

m_GameObject points to the GameObject that uses the script. m_Enabled tells the engine if the script is enabled/turned on by default. m_Name is the name of the instance. m_Script points to a MonoScript object.

What is this MonoScript?

class MonoScript(TextAsset):
    m_Name: str = None
    m_ClassName: str = None
    m_Namespace: str = None
    m_AssemblyName: str = None
    m_IsEditorScript: Optional[bool] = None
    m_ExecutionOrder: Optional[int] = None
    m_PropertiesHash: Optional[Union[int, Hash128]] = None

As can be guessed by just reading the property names of the MonoScript class, it simply points to a specific class within an Assembly and is; therefore, used to find the class used by a MonoBehaviour object.

m_AssemblyName is the name of the assembly, e.g., Assembly-CSharp.dll. m_Namespace is the name of the namespace the target class resides in. m_ClassName is the name of the target class.

And that's already everything about the MonoBehaviour object type.

You may now ask, but what about the derived classes I want to parse? Let's talk about that next.

Reading

As explained in Background, all MonoBehaviour objects refer to a MonoScript object, which in turn refers to a class within an assembly. This class is the class type of the object stored with the MonoBehaviour object.

TODO

As Python can't directly interact with C#/Mono libraries, it's necessary to get the type tree nodes in another way than done by Unity itself.

One way for this is using TypeTreeGenerator](https://github.com/K0lb3/TypeTreeGenerator) to dump all type tree nodes to a .json, which UnityPy can then use.

# 0. load the .json holding the type tree nodes
ASSEMBLY = json.load(open("assembly-csharp.json", "rt", encoding="utf8"))

# 1. read the MonoBehaviour object
monobehaviour = obj.read()

# 2. get the nodes
nodes = None

# 2.1 check if they might be stored in the asset
nodes = obj.serialized_type.nodes

# 2.2 if they aren't stored, fetch them from the json
if not nodes:
    # 2.2.1 get the script
    script = monobehaviour.m_Script
    if not script:
        raise Exception("Couldn't find script")
    script = script.read()

    # 2.2.2 get the type tree nodes via the script
    key = f"{script.m_Namespace}.{script.m_ClassName}" if script.m_Namespace else script.m_ClassName
    nodes = ASSEMBLY.get(key, None)
    if not nodes:
        raise Exception(f"Couldn't find {key}")

# 3. read instance via found nodes
data: dict = obj.read_typetree(nodes)

Editing

TODO

Clone this wiki locally