Forest of Fun

Claire's Personal Ramblings & Experiments

Godot Modular Design

micro

There are many reasons I think that Godot is a great technical base and has a robust future, but chiefly among them is the modular way in which things are built and designed with the assumption that parts will be ripped out, replaced and improved. This is done through an easy to approach code base, modules system and robust support for addons and extensions through GDExtension (using godot-cpp) while encouraging most people to work at the scripting level.

Also importantly, you can work in this modular design without leaving scripting, using GDScript or C# through Addons.

Good reasons to move into C++ land:
* Performance
* Complex Systems with Unit Testing
* Existing Code

Then when moving into C++ you have several routes:
* GDExtension - Dynamic library style extensions that can work across multiple engine versions
* Modules - Engine modules compiled directly into specific engine versions
* Custom Engine Builds - Full engine modifications

For scripting-level extensions:
* Add-ons - Script-based extensions that integrate with the editor
* Custom Scripts - Project-specific scripting solutions
* @Tool Scripts - Single file editor extensions

Here is a graph to help visualize the various options:

My personal choice graph

Use Case: Commercial Extension

https://docs.godotengine.org/en/stable/tutorials/scripting/gdextension/what_is_gdextension.html

You have some kind of tool or service you want to bring into the Godot community but you have commercial IP which you want to protect and manage? Then GDExtension is likely the best approach as it allows you to provide a closed source binary which users can easily drop into their project with no C++ work to use your service or tech.

This approach can work across multiple versions through proper version handling in your GDExtension implementation.

It is also a great way to reduce the recompilation of the engine and keep code stable. Complex systems can be built in their own project and you can also use languages other than C++ as all you need to produce is a dll to link against. There is also a very minor performance overhead.

Pros Cons
Closed source distribution possible Additional build complexity
Cross-version compatibility Performance overhead
No engine recompilation needed Limited access to engine internals
Language flexibility beyond C++ Must maintain versioning carefully
Hot-reloading support More complex debugging
Easier distribution to users Initial setup learning curve
Independent development cycle Platform-specific considerations
Protects IP effectively Must handle ABI compatibility

Use Case: Gameplay Workflow Add-on

https://docs.godotengine.org/en/stable/tutorials/plugins/editor/making_plugins.html

You are a developer who is working on an RPG game with a variety of enemies. It turns out you need to customise a lot of enemies in the world. You decide to develop some @tool scripts to make some helper functions to provide a friendlier editing workflow for your enemies. Some custom gizmos, some editor-time logic to double check stats and reduce the busy work.

You make a 3D gizmo plugin and add some additional helpers to quickly setup enemy behaviours and visually see data in the viewport for enemies while setting up scenes.

You want to use this code across more than one game because you know your studio is working on another RPG title in the near future. Or maybe you're just a nice person who wants to share their tool with the community.

The huge benefit of this approach is it requires no C++ knowledge. Your logic which is likely already in GDScript is easy to isolate and move into an add-on. The challenges with this approach are that it's still a scripting solution which means you will have less performance, less robust debugging tools and writing unit tests requires additional setup. While there are unit testing tools available like GUT (Godot Unit Test), they are not yet in the core engine. See https://github.com/bitwes/Gut

Pros Cons
No C++ knowledge required Limited performance compared to C++
Quick to develop Less robust debugging tools
Easy to modify and iterate Unit testing requires external tools
Simple to share and distribute Can't access low-level engine features
Works directly with GDScript code May have scaling limitations
Hot-reload support No built-in testing framework
Native editor integration Script security limitations
Cross-project compatibility Resource-intensive for complex tools

Use Case: Game Specific Engine Modules

You have some game specific code which ties tightly into the engine. While you could make a GDExtension, the reality is this code is project specific - maybe some of it will be shared with other projects in your studio but it's fairly bespoke. It is in active development and you're not sure which parts of the engine you need to access but performance is critical. You want to avoid the abstraction of the godot-cpp extension API. In these cases, modules are often the best approach.

Modules allow you to build internal C++ changes to the Godot engine in a fashion which is isolated from the main engine code, reducing merge conflicts during engine upgrades. Sometimes an engine upgrade will break a function call because of a signature change. Modules are part of the engine so the functions you call make no promises of API stability, though in most cases this is not much of an issue.

Additionally, modules can be turned on and off easily during compilation, and adding bindings to the scripting layer is handled through a bind function and some simple macros which are fast and easy to implement. Working in this way allows us to write robust unit tests and leverage mature C++ tooling.

The major downside is you need to recompile the engine, cannot use official binaries, and any changes require rebuilding the engine. Additionally, you need to generate custom export templates. Though this is no different from working with any other C++ engine.

Pros Cons
Direct engine access Requires engine recompilation
Best possible performance Cannot use official binaries
Full C++ debugging support Need to maintain custom export templates
Mature unit testing tools Longer iteration times due to compilation
Easy integration with engine systems Can break with engine updates
Simple binding to scripting layer Higher technical barrier to entry
Module-specific version control More complex distribution
Can modify core engine behaviour Team needs C++ expertise

Use Case: Engine Glowup

Godot is an open source engine. You will find bugs, and you will want to fix them. After fixing the bug you are hopefully submitting a pull request back to the engine to help others. Though we all know how much time that PR will take to process and likely enter into discussions. Also your solution might not be preferred by others or they might not agree there is a problem. So maintaining your own engine fork for a commercial game is almost inevitable in some ways.

Likewise you will likely need to optimise the engine for your specific use cases or maybe you need to add support for consoles or systems which are not compatible with an MIT licence. Features that could never be in the core open source MIT lib. In these cases you can modify the engine. I would encourage you to examine the code structure and try to avoid merge conflicts down the line.

Some modifications I have made on my branch:
* Fixed some bugs (submitted PR when relevant)
* Changed XR input to present old value in signal (API change so PR turned down)
* Changed some Vulkan memory management and buffer code
* Added some rendering functionality specific to my title
* Changed some editor quality of life to my preferred workflow

Pros Cons
Complete control over engine code Requires maintaining a custom fork
Can implement proprietary features Most complex to maintain
Maximum performance optimization possible Harder to update to new engine versions
Direct fix for engine bugs Need strong C++ and engine expertise
Custom platform support Longest compilation times
Unlimited access to internals Most expensive in development time
Can make deep architectural changes Team needs deep engine understanding
Full debugging and profiling capability Requires careful merge management

Roundup

I hope this has provided a round trip into the various ways that Godot can be edited, taken apart and improved.

I wrote this article on the bus and then while sitting in some conference talks. Apologies for any oversights.