-
-
Notifications
You must be signed in to change notification settings - Fork 159
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 = 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.
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)
TODO