-
-
Notifications
You must be signed in to change notification settings - Fork 131
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 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