-
-
Notifications
You must be signed in to change notification settings - Fork 161
MonoBehaviours
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 = Nonem_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]] = NoneAs 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.
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 to dump all type tree nodes to a .json, which UnityPy can then use to get the nodes required for reading instance stored in a MonoBehaviour object.
# 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)TODO