godotengine/godot
Mono / C#
Purpose
modules/mono/ integrates the .NET runtime so projects can use C# (and any .NET language that compiles to .NET assemblies). Despite the directory name, modern Godot uses .NET 8 and the official hostfxr rather than the legacy Mono runtime; the module name has been retained for historical reasons.
Directory layout
modules/mono/
├── README.md Build instructions (read first)
├── config.py Build options + can_build (.NET SDK detection)
├── csharp_script.{cpp,h} CSharpScript / CSharpInstance — Script subclass (~87 KB cpp)
├── csharp_script_resource_format.{cpp,h} ResourceFormatLoader for .cs files
├── godotsharp_dirs.{cpp,h} Per-platform asset paths
├── godotsharp_defs.h Shared constants for native + managed
├── interop_types.h Layout of Godot's Variant equivalents on the managed side
├── managed_callable.{cpp,h} Callable backed by a managed delegate
├── mono_gc_handle.{cpp,h} Strong/weak GC handles for keeping managed refs alive
├── signal_awaiter_utils.{cpp,h} Awaitable wrappers for engine signals
├── class_db_api_json.{cpp,h} Dumps the C# binding API to JSON for tooling
├── mono_gd/ Native helpers used during marshalling + interop
├── glue/ C# glue: GodotSharp + GodotSharpEditor + tools (the managed side)
├── editor/ Editor plugins (build dialog, project export, .NET solution sync)
├── thirdparty/ Vendored bits used at build time (e.g., aotc helpers)
├── utils/ Misc helpers
├── icons/, doc_classes/ Standard module assets
└── build_scripts/ Python helpers invoked by SCons during the C# glue buildTwo-pass build
Building the Mono module requires two passes:
- First pass — build Godot with
module_mono_enabled=yes. This producesbin/godot.<platform>.editor.<arch>plus a small set of registration stubs. - Generate glue —
./bin/godot --headless --generate-mono-glue modules/mono/glueruns the engine, walksClassDB, and emits C# source undermodules/mono/glue/GodotSharp/GodotSharp/Generated/(one C# class per native class, with marshalling code). - Build managed assemblies —
scons module_mono_enabled=yes build_assemblies=yesinvokesdotnet buildon the GodotSharp solution to produceGodotSharp.dll+GodotSharpEditor.dll+ native interop assemblies underbin/GodotSharp/Api/. - Second pass — re-run
scons module_mono_enabled=yesto pick up the generated glue (the binary now references the C# bindings).
README.md in the module documents this loop in detail.
Runtime architecture
graph LR
Editor[Godot editor / runtime] -->|hostfxr| Runtime[.NET 8 runtime]
Runtime --> GodotSharp[GodotSharp.dll]
GodotSharp --> User[User C# script: MyScript.cs]
Runtime <-->|P/Invoke| Native[modules/mono native code]
Native --> Object[Object / Variant / ClassDB]
User -->|Calls / Properties| GodotSharp
GodotSharp -->|gd_native_*| Native
Native -->|dispatch| Objecthostfxr (from .NET) loads the runtime in-process. Once initialized:
GodotSharp.dllexposes types likeNode,Sprite2D,Variant,GodotObject,Callable,Signal,Vector3. They are thin wrappers that P/Invoke into the native engine.- The native side calls into managed user scripts when scripts are attached to nodes. The handshake passes
MonoGCHandle-tracked references so the .NET GC keeps script instances alive. Variantis marshalled viainterop_types.h— the layout is shared between native C++ and the C#Variantstruct so memcpy-style transfer is safe.- Method calls go through generated marshalling stubs that pack arguments into
Variants, call the engine method, and unpack the return value.
CSharpScript / CSharpInstance
csharp_script.cpp (~87 KB) is the C# Script integration:
CSharpScriptis theScriptsubclass per.csfile. It loads the type, finds its base class, and prepares property/signal/method metadata for the editor.CSharpInstanceis the per-Objectscript instance. It holds the managed object, marshals property gets/sets, dispatches notifications, and calls signal handlers.- Hot reload is supported but with restrictions (changing class layout requires editor restart of the running game).
Editor integration
modules/mono/editor/ contributes:
- Build dialog — runs
dotnet buildwith the right project file; surfaces compiler errors in the editor's bottom panel. - Solution sync — the editor maintains a
<project>.csprojand<project>.slnso users can open the project in Visual Studio, Rider, or VS Code. - Export plugin — the per-platform exporters know how to bundle .NET assemblies, AOT-compiled binaries (when applicable), and the .NET runtime.
- GodotSharpEditor glue — implements
EditorPlugin-style helpers in C# that the editor uses for generating bindings on the fly.
Signal / async integration
C# scripts can await engine signals because Signal exposes a GetAwaiter() extension that listens for the signal once and resumes the calling task:
await GetTree().CreateTimer(1.0).Timeout;signal_awaiter_utils.cpp connects the once-only listener and wakes the awaiter on emission.
Per-platform AOT and packaging
- Desktop targets ship the .NET runtime alongside the executable (resolved via
hostfxr). - iOS requires AOT compilation; the export pipeline uses
mono-aot-cross(or .NET 8dotnet publish -p:PublishAot=true) to pre-compile assemblies. - Android packages assemblies in the APK and bundles a runtime archive.
- WebAssembly via .NET 8 wasm support is partial / experimental in current versions.
godotsharp_dirs.cpp knows where on each platform to place runtime files.
Key abstractions
| Abstraction | File | Role |
|---|---|---|
CSharpScript / CSharpInstance |
modules/mono/csharp_script.cpp |
Script subclass + per-Object runtime state |
MonoGCHandle |
modules/mono/mono_gc_handle.h |
RAII GC handle wrapper |
ManagedCallable |
modules/mono/managed_callable.cpp |
Callable backed by a managed delegate |
GodotSharp |
modules/mono/glue/GodotSharp/ (C#) |
Public C# API |
GodotPlugins |
modules/mono/glue/ (C#) |
Native↔managed interop helpers |
Integration points
register_types.cppregistersCSharpScriptwithScriptServerand the language with the script editor.- The export plugin slots into
editor/export/so building+exporting C# projects is a one-click flow. EngineDebuggerintegration lets the editor's debugger receive C# stack traces with file/line info from PDBs.
Entry points for modification
- Updating the binding generator →
modules/mono/glue/runtime_interop.{cpp,h}plus the SCons hooks inbuild_scripts/. - Changing how managed objects are tracked →
mono_gc_handle.cpp+csharp_script.cpp::_GodotSharp_*callbacks. - Adding a new C# helper → put it in
glue/GodotSharp/GodotSharp/Core/and rebuild the solution. - Tweaking export packaging →
modules/mono/editor/godotsharp_export.cpp(assembly bundling, AOT) and the per-platform exporters inplatform/<os>/export/.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.