Skip to content

Scripting backends: Mono and IL2CPP

UnityRuntime and limitsApplies toSkateBIRDSleddingPEAKBig Walk

Unity runs a game’s C# code through one of two backends, and the data folder shows which. Observed

Game Backend Evidence Confidence
SkateBIRD Mono MonoBleedingEdge/EmbedRuntime/mono-2.0-bdwgc.dll, Managed/ with 104 assemblies including Assembly-CSharp.dll (1,245,696 bytes) and Assembly-CSharp-firstpass.dll; no GameAssembly.dll Observed · SkateBIRD
PEAK Mono MonoBleedingEdge/ and PEAK_Data/Managed/ (Assembly-CSharp.dll, Photon, Zorro, Sirenix, Unity packages) Observed · PEAK
Sledding Game IL2CPP GameAssembly.dll and Sledding Game_Data/il2cpp_data/Metadata/global-metadata.dat (version 39, 26,654,580 bytes) Observed · Sledding
Big Walk IL2CPP GameAssembly.dll and Big Walk_Data/il2cpp_data/Metadata/global-metadata.dat (version 39, 20,269,204 bytes) Observed · Big Walk

A Mono game’s code is ordinary .NET assemblies in Managed/, readable with a decompiler. SkateBIRD’s Assembly-CSharp.dll has 947 type definitions and is not obfuscated; its namespaces include Skatebirb.Gameplay, Skatebirb.Managers and ReflexCLI. Observed · SkateBIRD The list of assemblies is repeated in ScriptingAssemblies.json. Observed · PEAK

A MonoBehaviour’s script identity in a scene is a reference to a MonoScript object, which names the assembly, namespace and class; its field bytes follow the base fields (script fields). Observed

SkateBIRD’s Assembly-CSharp.dll never mentions AssetBundle, StreamingAssets or a mods folder, so the game has no code path that loads outside content. Observed · SkateBIRD

An IL2CPP game’s C# was translated to C++ and compiled into GameAssembly.dll. Class, method and field names survive in global-metadata.dat (header magic 0xFAB11BAF, then the metadata version). Observed · Sledding, Big Walk Both IL2CPP games here use metadata version 39. Proven · Sledding, Big Walk

Cpp2IL (2022.1.0-pre.21) reads version 39 metadata and writes dummy .NET assemblies with the game’s types and signatures, and a decompiler on those gives the class and method list. Observed · Big Walk For Big Walk the output was about 14,000 signature lines over 120 dummy assemblies. Inferred · Big Walk The dummy assemblies lack serialized fields that the metadata does not give them, so a type tree generated from them comes out 4 bytes short on types that serialize such fields: in Big Walk, PeckSwitch, TrackedPeckState, PropHome and PlayerPose (each has a serialized ticket field the dummies miss). Types from the Dissonance voice package do not dump. Observed · Big Walk

Cpp2IL’s dummy assemblies carry no custom attributes unless its attribute processors run (--use-processor attributeanalyzer,attributeinjector), so a private field marked [SerializeField] looks like an ordinary private field and a type tree generated from them leaves it out; every serialized value after it is then read from the wrong offset. With the processors the attributes are restored and the same objects decode to plausible values. Observed · two Unity 2022.3 and 6000.2 IL2CPP players outside these games, metadata version 31 Unity serializes a non-public field only when it carries [SerializeField], which is why the attribute decides it. Sourced · Unity Manual, Script serialization That Big Walk’s missing ticket fields are private [SerializeField] fields dropped this way fits the 4-byte gap but has not been checked by regenerating its assemblies with the processors. Inferred · Big Walk

The metadata alone is enough to confirm that a class exists: Big Walk’s contains HouseNetworkManager, NetworkMinder, PeckSwitch, TrackedPeckState, PeckManager, TicketOffice, ITicketed, PlayerGrease, CullingAgent, KcpTransport, HouseAuthenticator, WorldManager, DevSettings, PropHome and SaveManager. Observed · Big Walk Sledding Game’s contains SkiLift, PlayerSledController, SnowmanBall and the FishNet generated code (Sledding scripts). Observed · Sledding

Serialized MonoBehaviour fields under IL2CPP

Section titled “Serialized MonoBehaviour fields under IL2CPP”

A stripped IL2CPP player has no type tree for a script’s fields either, so the same raw-bytes rule applies. A layout has to come from the generated assemblies (with the 4-byte caveat above) or from measuring the data. Observed

A complete field recovery for IL2CPP scripts

Whether dummy assemblies generated with the attribute processors account for every serialized field (Big Walk’s ticket fields included), or whether some fields are still missed for another reason, is not established.

Sources

  • Unity Manual, Script serialization — which fields Unity serializes (public, or non-public with SerializeField)
  • Cpp2IL — generates dummy managed assemblies from GameAssembly.dll and global-metadata.dat
  • ILSpy — decompiler for the Mono games' managed assemblies