Kembali ke Blog

Speedrunning JetBrains Rider Godot Addon Development: Native C++ GDExtensions dan Editor Plugins

Diterbitkan pada 29 Mei 2026
Speedrunning JetBrains Rider Godot Addon Development: Native C++ GDExtensions dan Editor Plugins

Ringkasnya

Artikel ini mengulas bagaimana JetBrains Rider 2026.2 menyederhanakan pengembangan addon Godot melalui integrasi CMake native, template bawaan, dan fitur simultaneous debugging untuk GDScript dan C++. Pembaruan ini mengatasi hambatan konfigurasi manual GDExtension C++ yang rumit dan rentan error. Selain itu, artikel ini membahas praktik terbaik pengembangan addon seperti manajemen memori lintas bahasa, isolasi namespace, serta integrasi backend game menggunakan SDK horizOn untuk mempercepat prototyping.

Membangun custom Godot editor plugin atau native C++ GDExtension biasanya dimulai dengan sebuah kesadaran yang tiba-tiba dan menyakitkan: Anda telah menghabiskan waktu tiga jam untuk mengonfigurasi SCons compile scripts, berjuang melawan headless compiler flags, dan melakukan parsing terhadap error cross-compilation yang ambigu, alih-alih menulis logika aktual dari plugin Anda. Meskipun arsitektur Godot 4 telah membuka potensi luar biasa untuk extension, developer experience secara historis terasa seperti mengonfigurasi server rack dengan tusuk gigi. Dengan peluncuran Godot Asset Store yang baru, penyedia IDE akhirnya memperlakukan addon development sebagai first-class citizen.

JetBrains Rider 2026.2 telah resmi memasuki arena sebagai salah satu penyedia tool IDE utama pertama yang menawarkan template khusus, otomatisasi CMake, dan multi-language debugging untuk Godot Asset Store. Bagi developer indie dan tools engineer dalam tim, ini berarti berakhirnya boilerplate configuration hell dan dimulainya rapid tool prototyping. Dengan memangkas waktu konfigurasi hingga menjadi single-click wizard saja, batasan untuk memperluas core editor interface milik Godot kini menjadi sangat rendah.

GDExtension Bottleneck: Mengapa Godot Tooling Dulu Terasa Menyiksa

Di balik layar, Godot 4 menggunakan GDExtension agar developer dapat menulis kode C++ atau Rust berkinerja tinggi yang terhubung langsung ke struktur inti engine tanpa harus melakukan recompilation terhadap keseluruhan engine. Ini dilakukan dengan me-load dynamic libraries—seperti .dll pada Windows, .so pada Linux, dan .dylib pada macOS—lalu memetakannya ke GDScript interfaces. Namun, melakukan setup ini secara manual mengharuskan Anda melakukan pull pada repository bindings godot-cpp, mencocokkan header versi engine yang tepat, menulis custom SCons or CMake scripts, dan mengonfigurasi file konfigurasi .gdextension untuk memetakan library paths di lima target platform berbeda.

Lebih buruk lagi, debugging pada native binaries ini terkenal sangat rentan crash. Workflow troubleshooting yang biasa dilakukan melibatkan peluncuran Godot editor di bawah debugger terpisah (seperti GDB atau LLDB), menyetel breakpoints di eksternal editor, dan berharap agar hot-reload tidak membuat panik main thread engine dan memaksa terjadinya hard crash. Ketika developer membangun custom tooling—terutama database synchronizer yang kompleks, low-latency netcode interfaces, atau asset pipelines—hambatan ini benar-benar merusak produktivitas.

Rider 2026.2: Bedah Addon Toolchain Baru

Out-of-the-Box Project Templates

Rider 2026.2 menyediakan template khusus berbasis wizard yang mencakup seluruh spektrum format Godot extension. Anda tidak perlu lagi melakukan clone pada repository boilerplates atau melakukan copy-paste struktur folder dari project lama. Sebagai gantinya, IDE akan membangun repository terstruktur yang bersih untuk GDScript editor plugins, C# extensions, maupun C++ GDExtensions, lengkap dengan pra-konfigurasi mulai dari plugin.cfg hingga target build folders. Ini menghemat waktu konfigurasi berjam-jam dan mengeliminasi penyebab paling umum dari kegagalan di tahap awal: directory paths yang tidak cocok pada manifest files.

Integrasi Native CMake untuk C++

Secara historis, C++ bindings milik Godot sangat condong ke SCons sebagai build system. SCons memang powerful, tetapi file konfigurasi berbasis Python-nya terkenal kurang transparan, tidak memiliki autocompletion pada IDE, dan menyulitkan integrasi CI/CD. Rider 2026.2 menghadirkan integrasi native CMake yang tangguh untuk project GDExtension. Saat Anda membuat sebuah GDExtension addon, Rider secara otomatis menghasilkan file CMakeLists.txt bersih yang menghubungkan core godot-cpp bindings library ke custom source code Anda. Ini memungkinkan Anda memanfaatkan engine C++ milik Rider yang powerful untuk navigasi kode, refactoring, dan static analysis tanpa memerlukan konfigurasi tambahan.

Dual-Language Debugging dalam Satu Sesi

Ini adalah fitur unggulan utama (crown jewel) dari update kali ini. Developer yang menulis Godot tools berkinerja tinggi jarang hanya terpaku pada satu bahasa pemrograman saja. Arsitektur standar biasanya menggunakan C++ berkinerja tinggi untuk pemrosesan data berat atau matematika kompleks, dan file GDScript ringan untuk GUI dock atau editor UI panel. Melakukan debugging pada arsitektur hybrid seperti ini dulunya mengharuskan penggunaan tool terpisah untuk C++ dan GDScript. Rider 2026.2 menghasilkan unified run configurations secara otomatis. Anda cukup menekan satu tombol "Debug", dan Rider akan meluncurkan Godot editor, melakukan attach ke prosesnya, serta menelusuri eksekusi kode secara bersamaan di GDScript dan C++. Breakpoint pada GDScript di UI Anda akan terpicu, dan saat Anda melakukan step into ke fungsi native C++, Rider akan bertransisi dengan mulus ke C++ debugger tanpa memutus sesi debugging.

Arsitektur Folder yang Siap Rilis (Publish-Ready)

Godot Asset Store yang baru memiliki persyaratan struktur folder dan packaging yang ketat untuk mencegah addon saling menimpa namespace satu sama lain. Template dari Rider menerapkan rekomendasi ini sejak hari pertama. Dengan memisahkan runtime files dari editor-only GUI components, IDE memastikan bahwa saat Anda menghasilkan build, file tersebut langsung siap untuk diunggah ke store, memangkas error packaging dari masalah yang sering membuat pusing kepala menjadi proses otomatis yang berjalan mulus tanpa kendala.

Memahami GDExtension Lifecycle: Membangun Backend C++

Untuk memahami nilai dari otomatisasi yang ditawarkan Rider, kita harus melihat apa saja yang sebenarnya dibutuhkan oleh project GDExtension pada level kode. Pada GDExtension standar, Anda harus mendefinisikan sebuah entry point library initializer, mendaftarkan tipe custom class Anda ke ClassDB milik Godot, dan membersihkan alokasi memori secara hati-hati saat modul di-uninitialize. Header dan source file C++ berikut merepresentasikan boilerplate minimum yang dibutuhkan untuk membuat sebuah native custom node—dalam kasus ini, sebuah telemetry handler berkinerja tinggi.

// 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

Selanjutnya, kita akan mengimplementasikan core behavior. Dalam file implementasi, kita mendaftarkan method kita di dalam _bind_methods() untuk memastikan runtime reflection engine milik Godot dapat mengaksesnya.

// 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;
}

Terakhir, kita harus memberi tahu Godot cara memuat modul kita menggunakan fungsi inisialisasi. File register_types ini bertindak sebagai main entry point dari library, yang dihubungkan melalui loading system milik 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();
}
}

Mengembangkan Editor Plugins: GDScript Pipeline

Sementara GDExtension menangani backend C++ yang berkinerja tinggi, UI dari Godot addon Anda—seperti menambahkan custom panel di bottom dock atau membuat custom inspector nodes—biasanya ditulis dalam GDScript menggunakan anotasi @tool. Direktif @tool memberi tahu Godot bahwa script ini harus dieksekusi secara langsung di dalam editor instance yang sedang berjalan, tidak hanya ketika game sedang dimainkan.

Mennyusun tool scripts membutuhkan manajemen lifecycle yang bersih. Fungsi _enter_tree() dan _exit_tree() bertindak sebagai constructor dan destructor dari integrasi editor Anda. Kegagalan dalam membersihkan custom UI nodes saat proses unload editor akan menyebabkan GUI nodes menjadi usang dan terabaikan (orphaned) mengotori memory space milik editor, yang pada akhirnya memicu masalah crash-on-exit.

# 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.")

Tantangan Konektivitas: Mengintegrasikan Remote Backends

Saat membangun editor plugins atau GDExtensions, kekuatan tool Anda sering kali bergantung pada backend services yang dihubunginya. Sebagai contoh, jika Anda sedang membuat admin panel untuk game indie, remote level editor, atau in-engine telemetry tracker, plugin Anda perlu berkomunikasi dengan database, mengelola identitas developer atau player, serta melakukan sinkronisasi remote states. Mengimplementasikan hal ini sendiri berarti Anda harus membangun web service kustom yang aman. Anda harus menjalankan virtual private server, menyiapkan API gateway, men-deploy database, menulis model autentikasi user kustom, dan menerapkan rotasi sertifikat SSL/TLS. Ini adalah engineering overhead yang sangat besar yang dapat dengan mudah menghabiskan 4 hingga 6 minggu waktu pengembangan khusus sebelum plugin Anda bahkan bisa berkomunikasi dengan database.

Alih-alih menghabiskan energi tim Anda yang terbatas untuk mengelola infrastruktur backend mentah, Anda dapat mengintegrasikan horizOn sebagai core game engine backend Anda. horizOn menyediakan native C# dan GDScript SDK berkinerja tinggi yang dapat langsung dihubungkan ke custom editor addons Anda. Alih-alih menghabiskan waktu berminggu-minggu untuk menyiapkan database dan menulis custom WebSockets handlers, Anda cukup memasukkan client horizOn ke dalam project Anda dan langsung mendapatkan autentikasi yang aman, akses database real-time, serta player management. Dengan menyerahkan beban berat infrastruktur kepada horizOn, Anda dapat mendedikasikan waktu Anda untuk menyempurnakan UX addon dan gameplay tools Anda, dengan keyakinan bahwa backend Anda akan melakukan scaling secara seamless saat Anda memublikasikannya di store.

5 Battle-Tested Best Practices untuk Pengembangan Godot Addon

1. Namespace Isolation melalui Struktur Folder

Selalu berikan prefiks pada addon folders dan script Anda dengan namespace unik di bawah res://addons/nama_addon_unik_anda/. Godot berbagi satu namespace global path yang datar untuk semua custom classes yang didaftarkan melalui direktif @icon atau class_name directives. Jika Anda menggunakan nama class yang generik seperti NetworkManager atau ConfigHelper, addon Anda akan mengalami konflik dengan core project milik developer atau extension pihak ketiga lainnya. Jaga agar semua utility scripts Anda berada di bawah scope direktori folder unik Anda.

2. Otomatisasi Kompilasi Biner dan Pengecualian dari VCS

Jaga agar file GDExtension binaries hasil kompilasi yang berat (.dll, .so, .dylib) tetap berada di luar riwayat Git repository utama Anda. Ukuran repository akan membengkak dengan cepat seiring Anda melakukan rekompilasi library selama proses pengembangan. Sebagai gantinya, gunakan .gitignore untuk mengabaikan build directories dan folder rilis, lalu siapkan CI/CD pipeline (seperti GitHub Actions atau GitLab CI) menggunakan script CMake otomatis untuk mem-build target binaries untuk berbagai platform, dan mengemasnya hanya di dalam file zip rilis.

3. Kelola Batasan GDScript-ke-C++ dengan Hati-Hati

Perhatikan bagaimana memori dikelola saat melewatkan variabel melintasi batas bahasa pemrograman. GDScript secara otomatis mengelola lifecycle kelas yang diturunkan dari RefCounted (seperti Resource), tetapi menggunakan manajemen memori manual untuk objek yang mewarisi Object (seperti objek Node mentah). Dalam kode C++ GDExtension Anda, selalu gunakan smart wrapper Ref<T> milik Godot untuk kelas reference-counted guna menghindari error double-free atau memory leaks. Untuk kelas standar, lakukan defensive casting menggunakan Object::cast_to<T>() dan periksa pointer null sebelum memanggil native methods.

4. Prioritaskan WebSockets dan Koneksi Persisten untuk Real-Time State

Hindari penggunaan HTTP polling tradisional untuk plugin yang membutuhkan sinkronisasi real-time, seperti shared editor systems atau backend matchmaking tools. Mengirimkan HTTP requests secara berulang-ulang menyebabkan CPU overhead yang tinggi dan memicu penalti rate-limiting yang besar pada backend services. Sebagai gantinya, Anda harus meninggalkan HTTP polling dan beralih ke WebSockets untuk membangun koneksi persisten yang dua arah (bidirectional). Langkah ini memangkas latency dari yang awalnya lambat sekitar 500ms menjadi di bawah 10ms, serta meminimalkan data overhead.

5. Desain Sistem Fallback yang Anggun untuk Remote Cloud Pipelines

Jika addon Anda berkomunikasi dengan remote cloud servers, jangan biarkan gangguan jaringan membekukan thread editor Godot. Web requests yang sinkron dapat memblokir proses utama Godot, menyebabkan editor menjadi hang. Selalu gunakan asynchronous callbacks atau thread pools untuk menjaga respons UI tetap lancar. Selain itu, jika Anda merancang integrasi live-ops, pelajari cara mendesain pipeline yang kokoh dengan mengevaluasi kampanye stop killing games vs live ops server fallbacks. Ini memastikan tool Anda dapat melakukan downgrade secara mulus ke mode offline dan menjaga editor tetap berfungsi bahkan ketika cloud endpoints sama sekali tidak dapat dihubungi.

Kesimpulan: Menyederhanakan Pipeline Godot Tooling Anda

JetBrains Rider 2026.2 mentransformasi pengembangan Godot addon dari yang semula merupakan latihan konfigurasi sistem yang rumit menjadi workflow developer yang ramping dan produktif. Dengan mengotomatiskan pembuatan scaffolding GDExtension, menyediakan integrasi CMake yang kokoh, dan menawarkan simultaneous debugging untuk GDScript dan C++, Rider menghilangkan kejenuhan konfigurasi dan membiarkan Anda fokus menulis kode untuk membuat tool yang menakjubkan. Mengombinasikan template pengembangan Rider dengan arsitektur backend yang scalable dan dikelola penuh (fully managed) memungkinkan Anda menciptakan plugin berkinerja tinggi yang saling terhubung tanpa dibebani overhead dari server engineering manual.

Ready to scale your multiplayer backend? Try horizOn for free or check out the API docs.


Sumber: JetBrains Rider menghadirkan dukungan untuk addon Godot Asset Store