Godot v4.x - Mono C#
There are shorter version of questions at the end.
But figures provide some context to those questions.
Figure 1 - Question
At least before compilation, Godot Node provides virtual methods to override, like:
public override void _Process(double delta)
{
base._Process(delta);
}
And there are a lot of them.
How does Godot handle those empty virtual methods?
Are they still called, adding overhead, or stripped away?
(via Godot means, or C# JIT compiler)
Also, consider following:
Figure 2 - JIT dead code elimination
public partial class Entity : Node2D
{
public override void _Ready()
{
base._Ready();
}
}
public sealed class Tank : Entity
{
public override void _Ready()
{
base._Ready();
}
}
In regular C#, if you use (for whatever reason):
Tank tank = ...;
tank._Ready();
JIT might simply remove calls to _Ready() in a process of Dead Code Elimination.
However, I assume Godot calls C# methods from C++ environment?
If it’s true - does JIT optimizations still apply (dead code elimination, devirtualization, etc.), or does Godot uses a mechanism, bypassing JIT optimizations, thus C# code will have a performance as if compiled in a DEBUG mode? (with some asterisks)
Figure 3 - JIT in with dynamically loaded DLLs
Right now, I’ve stated 3 possibilities:
- Godot uses custom way of calling C# code, bypassing JIT - no optimizations.
- Godot harmonizes with C# JIT, allowing it to provide dead code elimination for empty C# methods.
- Godot reimplements JIT, potentially stripping away unused methods.
If 3rd option is the case - what happens if a mod (.pak/.zip) loads-in a C# DLL? Consider following:
// Game.DLL
public partial class Tracker : Node
{
public override void _Process(double delta) {}
}
Here, we have “Tracker” with empty _Process method - potential candidate method to be completely removed/not called.
But then, the mod adds functionality to it:
public sealed partial class PlayerTracker : Tracker
{
const EntityTags Any = EntityTags.Enemy | EntityTags.Ally | ...;
public override void _Process(double delta)
{
// Some player tracking logic:
using var list = EntitySystem.LocateAll<Player>(tags: Any);
foreach (Player p in list)
{
GD.Print($"Located player #{p.ID}: {p.DislayName}");
}
}
}
Now “PlayerTracker._Process(double)” has some code.
While Godot might have saw that “Tracker._Process(double)” has none.
So depending on how it is implemented, all calls from Godot C++ to “Tracker._Process(double)” might haave been elimintated, meaning that “PlayerTracker._Process(double)” will never be called as well.
Conclusion
Considering that Godot devs are smart - I doubt they will ever allow Godot C++ engine to eliminate calls to methods, which can be extended/inherited in mod libraries.
So I assume Godot might avoid calling _Process(delta) method if class does not override it.
But as soon as you override it, engine will call it, even if method is empty:
// Also, don't know if sealed keyword will do anything here.
// or in the method, like `sealed override`.
public partial class MyNode : Node
{
// Assuming: enough to force Godot to start calling this method.
public override void _Process(double delta) {}
}
And whether method should be called is associated with System.Type of the node.
But in short
Does Godot call:
_Process(double), _PhysicsProcess(double), _Notification(int), _EnterTree(), _ExitTree(), _Input(InputEvent), _ShortcutInput(InputEvent), etc.
If nothing explicitly overrides them? Like:
public partial class MyNode : Node
{
public override void _Process(double delta) {}
public override void _PhysicsProcess(double delta) {}
public override void _Notification(int what) {}
public override void _Input(InputEvent @event) {}
}
And how much performance impacts does it have?
Considering that Godot has to support dynamic DLL loading from .pak/.zip (i.e. Assembly.Load).