Zurück zum Blog

Speedrunning JetBrains Rider Godot Addon-Entwicklung: Native C++ GDExtensions und Editor-Plugins

Veröffentlicht am 29. Mai 2026
Speedrunning JetBrains Rider Godot Addon-Entwicklung: Native C++ GDExtensions und Editor-Plugins

Kurz und knapp

JetBrains Rider 2026.2 führt native CMake-Integration, Projekt-Templates und simultanes Dual-Language-Debugging für Godot-Erweiterungen ein. Diese neuen Features beseitigen den historisch hohen Konfigurationsaufwand bei der Entwicklung von C++ GDExtensions und GDScript-Editor-Plugins. Für die nahtlose Anbindung skalierbarer Live-Services in solchen Addons bietet das Backend-as-a-Service horizOn ein fertiges SDK zur Vermeidung von manuellem Infrastrukturaufwand.

Die Entwicklung eines benutzerdefinierten Godot-Editor-Plugins oder einer nativen C++ GDExtension beginnt meist mit einer plötzlichen, schmerzhaften Erkenntnis: Man hat drei Stunden damit verbracht, SCons-Kompilierskripte zu konfigurieren, mit Headless-Compiler-Flags zu kämpfen und kryptische Cross-Compilation-Fehler zu analysieren, anstatt die eigentliche Logik des Plugins zu schreiben. Obwohl die Architektur von Godot 4 ein enormes Potenzial für Erweiterungen freigesetzt hat, fühlte sich die Developer Experience in der Vergangenheit oft so an, als würde man ein Server-Rack mit einem Zahnstocher konfigurieren. Mit dem Start des neuen Godot Asset Stores behandeln IDE-Anbieter die Addon-Entwicklung nun endlich als First-Class Citizen.

JetBrains Rider 2026.2 hat offiziell die Arena betreten – als einer der ersten großen IDE-Anbieter, der dedizierte Templates, CMake-Automatisierung und Multi-Language-Debugging für den Godot Asset Store bereitstellt. Für Indie-Entwickler und Tools-Engineers in Teams bedeutet dies das Ende der Boilerplate-Konfigurationshölle und den Start von schnellem Tool-Prototyping. Da die Konfigurationszeit auf einen Single-Click-Wizard reduziert wird, war die Hürde für die Erweiterung des Godot Core-Editor-Interface noch nie so niedrig.

Der GDExtension-Bottleneck: Warum Godot-Tooling früher wehtat

Unter der Haube nutzt Godot 4 GDExtension, um Entwicklern das Schreiben von hochperformantem C++- oder Rust-Code zu ermöglichen, der direkt mit den Core-Strukturen der Engine interagiert, ohne dass die gesamte Engine neu kompiliert werden muss. Dies geschieht durch das Laden dynamischer Bibliotheken – wie .dll unter Windows, .so unter Linux und .dylib unter macOS – und deren Mapping auf GDScript-Interfaces. Die manuelle Einrichtung erfordert jedoch das Klonen des godot-cpp-Bindings-Repositorys, das Abgleichen der exakten Header der Engine-Version, das Schreiben benutzerdefinierter SCons- oder CMake-Skripte und das Konfigurieren einer .gdextension-Konfigurationsdatei, um die Pfade der Bibliotheken über fünf verschiedene Zielplattformen hinweg zuzuordnen.

Schlimmer noch: Das Debugging dieser nativen Binaries war bisher notorisch absturzanfällig. Ein typischer Troubleshooting-Workflow besteht darin, den Godot-Editor unter einem separaten Debugger (wie GDB oder LLDB) zu starten, Breakpoints in einem externen Editor zu setzen und die Daumen zu drücken, dass ein Hot-Reload nicht den Main-Thread der Engine in den Panic-Modus versetzt und einen harten Crash erzwingt. Wenn Entwickler maßgeschneiderte Tools bauen – insbesondere komplexe Datenbanksynchronisierer, Low-Latency-Netcode-Interfaces oder Asset-Pipelines –, zerstört diese Reibung die Produktivität komplett.

Rider 2026.2: Ein Überblick über die neue Addon-Toolchain

Out-of-the-Box Projekt-Templates

Rider 2026.2 bietet dedizierte, Wizard-gestützte Templates, die das gesamte Spektrum der Godot-Erweiterungsformate abdecken. Sie müssen keine Repository-Boilerplates mehr klonen oder Ordnerstrukturen aus alten Projekten kopieren. Stattdessen erstellt die IDE ein sauberes, strukturiertes Repository für GDScript-Editor-Plugins, C#-Erweiterungen oder C++ GDExtensions – vorkonfiguriert mit allem von der plugin.cfg bis hin zu den Ziel-Build-Ordnern. Dies spart stundenlange Konfigurationsarbeit und eliminiert die häufigste Ursache für Fehler in der Anfangsphase: falsche Verzeichnispfade in den Manifest-Dateien.

Native CMake-Integration für C++

Historisch gesehen bevorzugten die C++-Bindings von Godot SCons als Build-System. SCons ist zwar mächtig, aber seine Python-basierten Konfigurationsdateien sind notorisch intransparent, bieten keine IDE-Autovervollständigung und erschweren die CI/CD-Integration. Rider 2026.2 führt eine robuste, native CMake-Integration für GDExtension-Projekte ein. Wenn Sie ein GDExtension-Addon erstellen, generiert Rider automatisch eine saubere CMakeLists.txt, welche die Core godot-cpp-Bindings-Bibliothek mit Ihrem benutzerdefinierten Quellcode verknüpft. Dadurch können Sie die leistungsstarke C++-Engine von Rider für Code-Navigation, Refactoring und statische Analysen ohne zusätzlichen Konfigurationsaufwand nutzen.

Dual-Language Debugging in einer einzigen Session

Das ist das Kronjuwel dieses Updates. Entwickler, die hochperformante Godot-Tools schreiben, beschränken sich selten auf eine einzige Sprache. Eine Standardarchitektur verwendet hochperformantes C++ für rechenintensive Aufgaben oder komplexe Mathematik und ein leichtgewichtiges GDScript für das GUI-Dock oder das Editor-UI-Panel. Das Debuggen dieser hybriden Architektur bedeutete bisher, separate Tools für C++ und GDScript zu verwenden. Rider 2026.2 generiert automatisch vereinheitlichte Run Configurations. Sie können auf einen einzigen „Debug“-Button klicken, woraufhin Rider den Godot-Editor startet, sich an dessen Prozess anhängt (attach) und die Ausführung gleichzeitig in GDScript und C++ verfolgt. Ein Breakpoint im GDScript Ihrer Benutzeroberfläche wird ausgelöst, und sobald Sie in eine native C++-Funktion springen (step into), wechselt Rider nahtlos zum C++-Debugger, ohne die laufende Session zu unterbrechen.

Publish-Ready Ordnerarchitektur

Der neue Godot Asset Store stellt strenge Anforderungen an die Ordnerstruktur und das Packaging, um zu verhindern, dass Addons die Namespaces der jeweils anderen überschreiben. Die Templates von Rider setzen diese Empfehlungen vom ersten Tag an um. Durch die Trennung der Runtime-Dateien von den Editor-only GUI-Komponenten stellt die IDE sicher, dass der ausgegebene Build sofort für den Upload in den Store bereit ist. Dadurch werden Packaging-Fehler von einem ständigen Ärgernis zu einem automatisierten Non-Event.

Der GDExtension-Lifecycle im Detail: Aufbau des C++-Backends

Um den Wert der Automatisierung von Rider zu verstehen, müssen wir uns ansehen, was ein GDExtension-Projekt auf Code-Ebene tatsächlich erfordert. In einer standardmäßigen GDExtension müssen Sie einen Einstiegspunkt (Library Initializer) definieren, Ihre benutzerdefinierten Klassentypen bei Godots ClassDB registrieren und Zuweisungen sorgfältig bereinigen, wenn das Modul deinitialisiert wird. Die folgenden C++-Header und Quelldateien stellen den minimalen Boilerplate-Code dar, der benötigt wird, um einen nativen, benutzerdefinierten Node zu erstellen – in diesem Fall einen hochperformanten Telemetrie-Handler.

// horizon_telemetry_node.h
#ifndef HORIZON_TELEMETRY_NODE_H
#define HORIZON_TELEMETRY_NODE_H

#include <godot_cpp/classes/node.hpp>
#include <godot_cpp/core/class_db.hpp>

namespace godot {

class HorizonTelemetryNode : public Node {
    GDCLASS(HorizonTelemetryNode, Node);

private:
    String session_id;
    int event_count;

protected:
    static void _bind_methods();

public:
    HorizonTelemetryNode();
    ~HorizonTelemetryNode();

    void initialize_telemetry(const String &p_session_id);
    void track_event(const String &p_event_name);
    String get_session_id() const;
};

}

#endif // HORIZON_TELEMETRY_NODE_H

Als Nächstes implementieren wir das Core-Verhalten. In der Implementierungsdatei registrieren wir unsere Methoden innerhalb von _bind_methods(), um sicherzustellen, dass die Runtime-Reflection-Engine von Godot darauf zugreifen kann.

// horizon_telemetry_node.cpp
#include "horizon_telemetry_node.h"
#include <godot_cpp/variant/utility_functions.hpp>

using namespace godot;

void HorizonTelemetryNode::_bind_methods() {
    ClassDB::bind_method(D_METHOD("initialize_telemetry", "session_id"), &HorizonTelemetryNode::initialize_telemetry);
    ClassDB::bind_method(D_METHOD("track_event", "event_name"), &HorizonTelemetryNode::track_event);
    ClassDB::bind_method(D_METHOD("get_session_id"), &HorizonTelemetryNode::get_session_id);

    ADD_PROPERTY(PropertyInfo(Variant::STRING, "session_id"), "", "get_session_id");
}

HorizonTelemetryNode::HorizonTelemetryNode() {
    event_count = 0;
    session_id = "";
}

HorizonTelemetryNode::~HorizonTelemetryNode() {
    // Clean up memory safely here
}

void HorizonTelemetryNode::initialize_telemetry(const String &p_session_id) {
    session_id = p_session_id;
    UtilityFunctions::print("Telemetry initialized for session: ", session_id);
}

void HorizonTelemetryNode::track_event(const String &p_event_name) {
    event_count++;
    UtilityFunctions::print("Event tracked: ", p_event_name, " (Total: ", event_count, ")");
}

String HorizonTelemetryNode::get_session_id() const {
    return session_id;
}

Schließlich müssen wir Godot über eine Initialisierungsfunktion mitteilen, wie unser Modul geladen werden soll. Diese register_types-Datei fungiert als Haupteinstiegspunkt der Bibliothek, angebunden über das Ladesystem von GDExtension.

// register_types.cpp
#include "register_types.h"
#include "horizon_telemetry_node.h"
#include <gdextension_interface.h>
#include <godot_cpp/core/defs.hpp>
#include <godot_cpp/godot.hpp>

using namespace godot;

void initialize_horizon_plugin_module(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
        return;
    }
    ClassDB::register_class<HorizonTelemetryNode>();
}

void uninitialize_horizon_plugin_module(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
        return;
    }
}

extern "C" {
// Initialization entry point called by Godot.
GDExtensionBool GDE_EXPORT horizon_plugin_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, const GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
    godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);

    init_obj.register_initializer(initialize_horizon_plugin_module);
    init_obj.register_terminator(uninitialize_horizon_plugin_module);
    init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);

    return init_obj.init();
}
}

Editor-Plugins entwickeln: Die GDScript-Pipeline

Während GDExtension das hochperformante C++-Backend übernimmt, wird die Benutzeroberfläche Ihres Godot-Addons – wie das Hinzufügen eines benutzerdefinierten Panels im unteren Dock oder das Erstellen eigener Inspector-Nodes – typischerweise in GDScript unter Verwendung der @tool-Annotation geschrieben. Die @tool-Direktive teilt Godot mit, dass dieses Skript direkt in der laufenden Editor-Instanz ausgeführt werden soll, und nicht erst, wenn das Spiel läuft.

Das Schreiben von Tool-Skripten erfordert ein sauberes Lifecycle-Management. Die Funktionen _enter_tree() und _exit_tree() fungieren als Konstruktoren und Destruktoren Ihrer Editor-Integrationen. Wird die Bereinigung benutzerdefinierter UI-Nodes beim Entladen des Editors versäumt, führt dies zu verwaisten (orphaned) GUI-Nodes, die den Speicherplatz des Editors belasten und schließlich Crash-on-Exit-Probleme auslösen.

# horizon_editor_plugin.gd
@tool
extends EditorPlugin

const PLUGIN_NAME = "HorizonBackendHelper"
var dock: Control

func _enter_tree() -> void {
    # Initialize the dock UI from our pre-packed scene
    dock = preload("res://addons/horizon_plugin/dock.tscn").instantiate()
    
    # Add the main panel to the editor dock on the upper-right slot
    add_control_to_dock(DOCK_SLOT_LEFT_UR, dock)
    
    # Register our custom backend node so developers can add it in the scene tree
    add_custom_type(
        "HorizonClientNode",
        "Node",
        preload("res://addons/horizon_plugin/horizon_client_node.gd"),
        preload("res://addons/horizon_plugin/icon.png")
    )
    print("Plugin ", PLUGIN_NAME, " successfully initialized in editor.")

func _exit_tree() -> void {
    # Clean up dock and custom types to prevent editor memory leaks
    if dock:
        remove_control_from_docks(dock)
        dock.queue_free()
    
    remove_custom_type("HorizonClientNode")
    print("Plugin ", PLUGIN_NAME, " cleaned up.")

Die Konnektivitäts-Herausforderung: Integration von Remote-Backends

Beim Bau von Editor-Plugins oder GDExtensions ist Ihr Tool oft nur so mächtig wie die Backend-Dienste, mit denen es interagiert. Wenn Sie beispielsweise ein Admin-Panel für ein Indie-Game, einen Remote-Level-Editor oder einen in-engine Telemetrie-Tracker erstellen, muss Ihr Plugin mit Datenbanken kommunizieren, Entwickler- oder Spieler-Identitäten verwalten und Remote-Zustände synchronisieren. Dies selbst zu implementieren bedeutet, einen maßgeschneiderten, sicheren Webdienst aufzubauen. Sie müssen einen Virtual Private Server einrichten, ein API-Gateway aufsetzen, eine Datenbank bereitstellen, benutzerdefinierte Benutzerauthentifizierungs-Modelle schreiben und eine SSL/TLS-Zertifikatsrotation implementieren. Dies ist ein enormer technischer Overhead, der leicht 4 bis 6 Wochen reine Entwicklungszeit in Anspruch nehmen kann, noch bevor Ihr Plugin überhaupt mit einer Datenbank kommunizieren kann.

Anstatt die begrenzte Energie Ihres Teams in die Verwaltung roher Backend-Infrastruktur zu stecken, können Sie horizOn als Ihr Core-Game-Engine-Backend integrieren. horizOn bietet ein natives, hochperformantes C#- und GDScript-SDK, das direkt in Ihre benutzerdefinierten Editor-Addons integriert werden kann. Anstatt Wochen mit der Bereitstellung von Datenbanken und dem Schreiben benutzerdefinierter WebSocket-Handler zu verbringen, können Sie den Client von horizOn einfach in Ihr Projekt einbinden und erhalten sofort sichere Authentifizierung, Echtzeit-Datenbankzugriff und Spielerverwaltung. Indem Sie das schwere Heben der Infrastruktur horizOn überlassen, können Sie sich voll und ganz auf die Optimierung der UX Ihres Addons und Ihrer Gameplay-Tools konzentrieren – im sicheren Wissen, dass Ihr Backend nahtlos skaliert, wenn Sie es im Store veröffentlichen.

5 praxiserprobte Best Practices für die Godot Addon-Entwicklung

1. Namespace-Isolierung über die Ordnerstruktur

Versehen Sie Ihre Addon-Ordner und -Skripte immer mit einem eindeutigen Namespace-Präfix unter res://addons/ihr_eindeutiger_addon_name/. Godot teilt sich einen einzigen, flachen globalen Pfad-Namespace für alle benutzerdefinierten Klassen, die über die @icon- oder class_name-Direktiven registriert werden. Wenn Sie einen generischen Klassennamen wie NetworkManager or ConfigHelper verwenden, kollidiert Ihr Addon mit dem Core-Projekt des Entwicklers oder anderen Erweiterungen von Drittanbietern. Stellen Sie sicher, dass alle Ihre Hilfsskripte (Utility Scripts) streng auf Ihr eindeutiges Ordnerverzeichnis beschränkt bleiben.

2. Binärkompilierung automatisieren und von VCS ausschließen

Halten Sie große, kompilierte GDExtension-Binaries (.dll, .so, .dylib) aus der History Ihres Haupt-Git-Repositorys heraus. Die Größe des Repositorys bläht sich andernfalls schnell auf, wenn Sie Bibliotheken während der Entwicklung neu kompilieren. Verwenden Sie stattdessen eine .gitignore-Datei, um Build-Verzeichnisse und Release-Ordner zu ignorieren, und richten Sie eine CI/CD-Pipeline (wie GitHub Actions oder GitLab CI) mit automatisierten CMake-Skripten ein, um Ziel-Binaries für mehrere Plattformen zu erstellen und diese nur in Release-Zip-Dateien zu packen.

3. Vorsicht an der Grenze zwischen GDScript und C++

Seien Sie vorsichtig, wie der Speicher beim Übertragen von Variablen über die Sprachgrenze hinweg verwaltet wird. GDScript verwaltet den Lifecycle von Klassen, die von RefCounted abgeleitet sind (wie Resource), automatisch, nutzt jedoch manuelle Speicherverwaltung für Objekte, die von Object erben (wie reine Node-Objekte). Verwenden Sie in Ihrem C++ GDExtension-Code für referenzgezählte Klassen immer den Ref<T> Smart-Wrapper von Godot, um Double-Free-Fehler oder Memory Leaks zu vermeiden. Führen Sie bei Standardklassen ein defensives Casting mit Object::cast_to<T>() durch und prüfen Sie auf Nullpointer, bevor Sie native Methoden aufrufen.

4. Bevorzugen Sie WebSockets und persistente Verbindungen für Echtzeit-Zustände

Vermeiden Sie klassisches HTTP-Polling für Plugins, die eine Echtzeitsynchronisierung erfordern, wie etwa kollaborative Editorsysteme oder Backend-Matchmaking-Tools. Das wiederholte Senden von HTTP-Anfragen führt zu einem hohen CPU-Overhead und löst massive Rate-Limiting-Sperren bei Backend-Diensten aus. Stattdessen sollten Sie HTTP-Polling zugunsten von WebSockets aufgeben, um eine dauerhafte, bidirektionale Verbindung aufzubauen. Dies reduziert die Latenz von trägen 500 ms auf Intervalle unter 10 ms und minimiert den Daten-Overhead.

5. Designen Sie fehlertolerante Fallback-Systeme für Remote-Cloud-Pipelines

Wenn Ihr Addon mit Remote-Cloud-Servern kommuniziert, darf eine Netzwerkunterbrechung niemals den Thread des Godot-Editors einfrieren. Synchronisierte Web-Anfragen können den Hauptprozess von Godot blockieren, was zum Aufhängen des Editors führt. Verwenden Sie immer asynchrone Callbacks oder Thread-Pools, um die UI-Reaktionen flüssig zu halten. Wenn Sie darüber hinaus eine Live-Ops-Integration entwerfen, sollten Sie untersuchen, wie man robuste Pipelines designt, indem Sie die „Stop Killing Games“-Kampagne im Vergleich zu Live-Ops-Server-Fallbacks analysieren. Dies stellt sicher, dass Ihr Tool elegant in den Offline-Modus wechselt und der Editor funktionstüchtig bleibt, selbst wenn Cloud-Endpunkte völlig unerreichbar sind.

Fazit: Optimierung Ihrer Godot Tooling-Pipeline

JetBrains Rider 2026.2 verwandelt die Godot Addon-Entwicklung von einer komplexen Übung in der Systemkonfiguration in einen rationalisierten, produktiven Developer-Workflow. Durch die Automatisierung des GDExtension-Scaffoldings, die Bereitstellung einer robusten CMake-Integration und das simultane Debuggen von GDScript und C++ beseitigt Rider Konfigurationsmüdigkeit und ermöglicht es Ihnen, sich ganz auf das Schreiben großartiger Tools zu konzentrieren. Die Kombination der Entwicklungs-Templates von Rider mit einer skalierbaren, voll verwalteten Backend-Architektur ermöglicht es Ihnen, hochperformante, vernetzte Plugins ohne den Overhead manueller Serverentwicklung zu erstellen.

Bereit, Ihr Multiplayer-Backend zu skalieren? Testen Sie horizOn kostenlos oder werfen Sie einen Blick in die API-Dokumentation.


Quelle: JetBrains Rider bringt Support für Addons aus dem Godot Asset Store