This page covers the C++ side of Godot's C# scripting integration: how the CSharpLanguage singleton registers as a script language, how GDMono loads and initializes the .NET runtime, how CSharpScript and CSharpInstance manage the per-script and per-object lifecycle, how hot-reloading works in editor builds, and how native Godot objects acquire managed C# bindings.
For the C#-side interop bridge and function-pointer mechanism that allows C++ to invoke managed code, see 13.3. C++/C# Interop Bridge For the BindingsGenerator that produces the Godot.* C# API wrappers, see 13.2. C# Bindings Generation
The C# scripting module lives entirely under modules/mono/. It is disabled by default and must be enabled with module_mono_enabled=yes at build time.
| Subdirectory | Role |
|---|---|
modules/mono/ | Root: CSharpLanguage, CSharpScript, CSharpInstance |
modules/mono/mono_gd/ | GDMono runtime init, GDMonoCache callback table |
modules/mono/glue/ | C++ interop glue; also contains the GodotSharp C# assembly source |
modules/mono/editor/ | BindingsGenerator, editor tooling (tools-only) |
GD_MONO_HOT_RELOAD is defined only in editor builds to enable assembly unloading and state preservation.
Sources: modules/mono/csharp_script.cpp31-76 modules/mono/mono_gd/gd_mono.h1-30
Diagram: Major C++ Classes and Their Relationships
Sources: modules/mono/csharp_script.h56-124 modules/mono/csharp_script.h307-335 modules/mono/mono_gd/gd_mono.h66-153
CSharpLanguage is the singleton that Godot's ScriptServer queries for anything related to .cs files. It owns the GDMono instance and coordinates the full script lifecycle.
CSharpLanguage::init() is called during engine startup modules/mono/csharp_script.cpp102-134:
dotnet/project/assembly_name, reload attempt count) modules/mono/csharp_script.cpp118-122EditorNode modules/mono/csharp_script.cpp125GDMono instance via memnew(GDMono) modules/mono/csharp_script.cpp128gdmono->initialize() only if should_initialize() returns true (checks for the existence of C# project files or runtime features) modules/mono/csharp_script.cpp131-133CSharpLanguage::finalize() modules/mono/csharp_script.cpp140-190:
DisposablesTracker_OnGodotShuttingDown so managed disposables can clean up modules/mono/csharp_script.cpp145-147 This invokes GDMonoCache::managed_callbacks.DisposablesTracker_OnGodotShuttingDown() modules/mono/mono_gd/gd_mono_cache.h107CSharpScriptBinding GC handles and detaches them from their owner objects modules/mono/csharp_script.cpp152-163GDMono instance modules/mono/csharp_script.cpp165-168unsafe_object_references modules/mono/csharp_script.cpp173-184Sources: modules/mono/csharp_script.cpp102-190 modules/mono/mono_gd/gd_mono.cpp66-151 modules/mono/mono_gd/gd_mono_cache.h107
GDMono owns the interaction with the native .NET host (hostfxr and coreclr). Its initialize() method tries several loading strategies in order.
Diagram: GDMono Runtime Loading Decision Tree
Sources: modules/mono/mono_gd/gd_mono.cpp166-250 modules/mono/mono_gd/gd_mono.cpp636-760
GDMono uses hostfxr to locate and load the .NET runtime. In editor builds, it uses hostfxr_resolver to find the SDK or runtime path modules/mono/mono_gd/gd_mono.cpp166-181 If hostfxr is not found via standard paths, it attempts to query the dotnet executable via the command line modules/mono/mono_gd/gd_mono.cpp113-164
Sources: modules/mono/mono_gd/gd_mono.cpp113-181
GDMonoCache::ManagedCallbacks is a struct of function pointers that allows the C++ engine to invoke specific managed methods in the Godot.Bridge namespace. These function pointers are populated during GDMono initialization modules/mono/mono_gd/gd_mono.cpp700-701
Diagram: ManagedCallbacks — Key Callback Groups and Code Entities
Sources: modules/mono/mono_gd/gd_mono_cache.h70-164 modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs92-110 modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs113-170 modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs80-89
CSharpScript represents a .cs source file and its associated metadata. Its core state is stored in TypeInfo modules/mono/csharp_script.h63-124
class_name, native_base_name, and flags like is_tool, is_abstract, or is_generic modules/mono/csharp_script.h63-124_update_script_class_info() is called, which in turn invokes GDMonoCache::managed_callbacks.ScriptManagerBridge_UpdateScriptClassInfo() modules/mono/csharp_script.cpp212 This managed callback populates exported members, signals, and base class info.instance_create(Object* p_this) creates a CSharpInstance which maintains a GC handle to the managed object modules/mono/csharp_script.h59-60 This involves calling GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance() modules/mono/csharp_script.cpp1000-1001Sources: modules/mono/csharp_script.h63-124 modules/mono/csharp_script.cpp82-100 modules/mono/csharp_script.cpp212 modules/mono/csharp_script.cpp1000-1001
In editor builds (GD_MONO_HOT_RELOAD), C# supports hot-reloading when assemblies are recompiled.
CSharpInstance state is serialized into a StateBackup struct modules/mono/csharp_script.h153-159 This involves calling GDMonoCache::managed_callbacks.CSharpInstanceBridge_SerializeState() modules/mono/csharp_script.cpp106pending_reload_instances and pending_reload_state to restore values after the new assembly is loaded modules/mono/csharp_script.h161-162 After the new assembly is loaded, GDMonoCache::managed_callbacks.CSharpInstanceBridge_DeserializeState() is called to restore the state modules/mono/csharp_script.cpp107ScriptManagerBridge.OnAlcUnloading() C# method is registered as a callback for AssemblyLoadContext.Unloading events modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs27 This method handles the cleanup of script types and stores data for reloading modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs31-42Sources: modules/mono/csharp_script.h152-166 modules/mono/csharp_script.cpp41-44 modules/mono/csharp_script.cpp106-107 modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs27 modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs31-42
Godot objects (Object) and their managed C# counterparts are linked via GC handles.
CSharpLanguage creates a binding using _instance_binding_callbacks modules/mono/csharp_script.cpp84-89 The _instance_binding_create_callback function calls GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectBinding() to create the managed object modules/mono/csharp_script.cpp103CSharpScriptBinding struct stores a MonoGCHandleData to keep the managed wrapper alive as long as the native object exists modules/mono/csharp_script.cpp152-158_instance_binding_reference_callback handles the transition between strong and weak references for RefCounted objects to prevent cycles between the Godot reference counter and the .NET Garbage Collector modules/mono/csharp_script.cpp87Sources: modules/mono/csharp_script.cpp82-89 modules/mono/csharp_script.cpp151-163 modules/mono/mono_gc_handle.h1-30 modules/mono/csharp_script.cpp103
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.