Volver al Blog

Speedrunning el desarrollo de addons de Godot con JetBrains Rider: GDExtensions nativas en C++ y plugins para el editor

Publicado el 29 de mayo de 2026
Speedrunning el desarrollo de addons de Godot con JetBrains Rider: GDExtensions nativas en C++ y plugins para el editor

En resumen

Esta guía práctica explora el nuevo soporte oficial de JetBrains Rider 2026.2 para el desarrollo de addons en la Godot Asset Store, destacando la automatización con CMake para GDExtensions en C++ y la depuración dual simultánea con GDScript. Analizamos el ciclo de vida y la implementación a nivel de código de componentes nativos de alto rendimiento y scripts de herramientas del editor. Por último, abordamos las mejores prácticas de aislamiento de namespaces, optimización de memoria en la frontera de lenguajes y la integración de backends persistentes mediante WebSockets utilizando la plataforma horizOn.

El desarrollo de un plugin personalizado para el editor de Godot o una GDExtension nativa en C++ suele comenzar con una dolorosa y repentina revelación: has pasado tres horas configurando scripts de compilación de SCons, lidiando con flags de compiladores headless y depurando errores ambiguos de compilación cruzada en lugar de escribir la lógica real de tu plugin. Aunque la arquitectura de Godot 4 ha desbloqueado un potencial increíble para las extensiones, la experiencia de desarrollo históricamente se ha sentido como configurar un rack de servidores con un palillo de dientes. Con el lanzamiento de la nueva Godot Asset Store, los proveedores de IDE por fin están tratando al desarrollo de addons como un ciudadano de primera clase.

JetBrains Rider 2026.2 ha entrado oficialmente en escena como uno de los primeros grandes proveedores de herramientas IDE en ofrecer plantillas dedicadas, automatización con CMake y depuración multilenguaje para la Godot Asset Store. Para desarrolladores indie e ingenieros de herramientas de equipo (tools engineers), esto significa el fin del infierno de la configuración de boilerplate y el comienzo de un prototipado rápido de herramientas. Al reducir los tiempos de configuración a un asistente de un solo clic, la barrera para extender la interfaz central del editor de Godot nunca ha sido tan baja.

El cuello de botella de GDExtension: Por qué el tooling de Godot solía doler

Bajo el capó, Godot 4 utiliza GDExtension para permitir a los desarrolladores escribir código C++ o Rust de alto rendimiento que interactúa directamente con las estructuras centrales del engine sin tener que recompilarlo por completo. Esto lo logra cargando librerías dinámicas —como .dll en Windows, .so en Linux y .dylib en macOS— y mapeándolas a interfaces de GDScript. Sin embargo, configurar esto manualmente requiere clonar el repositorio de bindings de godot-cpp, hacer coincidir la cabecera exacta de la versión del engine, escribir scripts personalizados de SCons o CMake, y configurar un archivo .gdextension para mapear las rutas de las librerías a través de cinco plataformas de destino diferentes.

Peor aún, depurar estos binarios nativos ha sido históricamente propenso a fallos. El flujo de trabajo típico de resolución de problemas implica lanzar el editor de Godot bajo un depurador independiente (como GDB o LLDB), establecer breakpoints en un editor externo y cruzar los dedos para que un hot-reload no cause un pánico en el hilo principal del engine y provoque un cierre forzado. Cuando los desarrolladores crean herramientas personalizadas —especialmente sincronizadores de bases de datos complejos, interfaces de netcode de baja latencia o pipelines de assets—, esta fricción destruye por completo la productividad.

Rider 2026.2: Un desglose del nuevo toolchain para addons

Plantillas de proyecto listas para usar

Rider 2026.2 proporciona plantillas dedicadas basadas en asistentes que cubren toda la gama de formatos de extensión de Godot. Ya no tienes que clonar boilerplates de repositorios ni copiar y pegar estructuras de carpetas de proyectos antiguos. En su lugar, el IDE crea un repositorio limpio y estructurado tanto para plugins de editor en GDScript como para extensiones en C# o GDExtensions en C++, preconfigurado con todo lo necesario, desde el plugin.cfg hasta las carpetas de compilación de destino. Esto ahorra horas de configuración y elimina la causa más común de fallos en etapas tempranas: las rutas de directorio desalineadas en los archivos de manifiesto.

Integración nativa de CMake para C++

Históricamente, los bindings de C++ para Godot favorecían enormemente a SCons como sistema de compilación. SCons es potente, pero sus archivos de configuración basados en Python son notoriamente opacos, carecen de autocompletado en el IDE y complican la integración de CI/CD. Rider 2026.2 introduce una integración nativa y robusta de CMake para proyectos GDExtension. Al crear un addon de GDExtension, Rider genera automáticamente un archivo CMakeLists.txt limpio que enlaza la librería central de bindings de godot-cpp con tu código fuente personalizado. Esto te permite aprovechar el potente motor de C++ de Rider para la navegación de código, refactorización y análisis estático sin ninguna configuración adicional.

Depuración dual en una sola sesión

Esta es la joya de la corona de la actualización. Los desarrolladores que crean herramientas de alto rendimiento para Godot rara vez se limitan a un solo lenguaje. Una arquitectura estándar utiliza C++ de alto rendimiento para el procesamiento pesado de datos o matemáticas complejas, y un archivo GDScript ligero para el dock de la GUI o el panel de la interfaz del editor. Depurar esta arquitectura híbrida requería el uso de herramientas independientes para C++ y GDScript. Rider 2026.2 genera configuraciones de ejecución unificadas automáticamente. Puedes presionar un único botón de "Debug", y Rider iniciará el editor de Godot, se acoplará a su proceso y rastreará las ejecuciones simultáneamente tanto en GDScript como en C++. Se activará un breakpoint en el GDScript de tu interfaz y, a medida que entres en una función nativa de C++, Rider transicionará de forma fluida al depurador de C++ sin perder la sesión.

Arquitectura de carpetas lista para publicar

La nueva Godot Asset Store tiene requisitos de empaquetado y estructuras de carpetas estrictas para evitar que los addons interfieran con los namespaces de los demás. Las plantillas de Rider aplican estas recomendaciones desde el primer día. Al separar los archivos de runtime de los componentes de GUI exclusivos del editor, el IDE garantiza que, cuando generes una build, esta esté lista de inmediato para subirse a la tienda, transformando los errores de empaquetado de un dolor de cabeza frecuente a un no-evento automatizado.

Dentro del ciclo de vida de GDExtension: Construyendo el backend en C++

Para comprender el valor de la automatización de Rider, debemos observar lo que realmente requiere un proyecto GDExtension a nivel de código. En una GDExtension estándar, debes definir un inicializador de librería como punto de entrada, registrar tus tipos de clases personalizadas en la ClassDB de Godot y limpiar cuidadosamente las asignaciones de memoria cuando el módulo se desinicializa. Las siguientes cabeceras y archivos fuente de C++ representan el boilerplate mínimo necesario para crear un nodo personalizado nativo; en este caso, un gestor de telemetría de alto rendimiento.

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

A continuación, implementamos el comportamiento central. En el archivo de implementación, registramos nuestros métodos dentro de _bind_methods() para asegurar que el motor de reflexión en tiempo de ejecución de Godot pueda acceder a ellos.

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

Por último, debemos indicarle a Godot cómo cargar nuestro módulo mediante una función de inicialización. Este archivo register_types actúa como el punto de entrada principal de la librería, conectado a través del sistema de carga de 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();
}
}

Desarrollo de plugins para el editor: El pipeline de GDScript

Mientras que GDExtension gestiona el backend en C++ de alto rendimiento, la interfaz de usuario de tu addon de Godot —como añadir un panel personalizado en el dock inferior o crear nodos de inspector personalizados— se escribe típicamente en GDScript utilizando la anotación @tool. La directiva @tool le indica a Godot que este script debe ejecutarse directamente dentro de la instancia activa del editor, y no solo cuando el juego se está reproduciendo.

Escribir scripts de tipo tool requiere una gestión limpia del ciclo de vida. Las funciones _enter_tree() y _exit_tree() actúan como los constructores y destructores de tus integraciones con el editor. No limpiar los nodos de la interfaz de usuario personalizada al descargar el editor dará lugar a nodos de GUI huérfanos y obsoletos que abarrotarán el espacio de memoria del editor, lo que eventualmente provocará problemas de crash-on-exit (cierre inesperado al salir).

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

El desafío de la conectividad: Integrando backends remotos

Al crear plugins para el editor o GDExtensions, tu herramienta suele ser tan potente como los servicios de backend con los que se conecta. Por ejemplo, si estás desarrollando un panel de administración para un juego indie, un editor de niveles remoto o un rastreador de telemetría integrado en el engine, tu plugin necesita comunicarse con bases de datos, gestionar identidades de desarrolladores o jugadores y sincronizar estados remotos. Implementar esto por tu cuenta significa construir un servicio web personalizado y seguro. Tendrás que desplegar un servidor virtual privado, configurar un API gateway, desplegar una base de datos, escribir modelos personalizados de autenticación de usuarios e implementar la rotación de certificados SSL/TLS. Esto representa una enorme carga de ingeniería que fácilmente puede consumir de 4 a 6 semanas de desarrollo dedicado antes de que tu plugin pueda siquiera comunicarse con una base de datos.

En lugar de canalizar la energía limitada de tu equipo en la gestión de infraestructura de backend pura, puedes integrar horizOn como tu backend central para el motor de juego. horizOn ofrece un SDK nativo de alto rendimiento para C# y GDScript que se conecta directamente a tus addons personalizados del editor. En lugar de pasar semanas aprovisionando bases de datos y escribiendo gestores de WebSockets personalizados, puedes incorporar el cliente de horizOn en tu proyecto y obtener instantáneamente autenticación segura, acceso a bases de datos en tiempo real y gestión de jugadores. Al dejar el trabajo pesado de la infraestructura en manos de horizOn, puedes dedicar tu tiempo a perfeccionar la UX y las herramientas de gameplay de tu addon, con la tranquilidad de saber que tu backend escalará sin problemas cuando lo publiques en la tienda.

5 buenas prácticas probadas en batalla para el desarrollo de addons en Godot

1. Aislamiento de namespaces mediante la estructura de carpetas

Utiliza siempre un prefijo con un namespace único para las carpetas y scripts de tu addon bajo la ruta res://addons/tu_nombre_de_addon_unico/. Godot comparte un único namespace de rutas globales plano para todas las clases personalizadas registradas mediante las directivas @icon o class_name. Si utilizas un nombre de clase genérico como NetworkManager o ConfigHelper, tu addon entrará en conflicto con el proyecto principal del desarrollador o con otras extensiones de terceros. Mantén todos tus scripts de utilidad estrictamente limitados al directorio de tu carpeta única.

2. Automatiza la compilación de binarios y exclúyelos del VCS

Mantén los binarios compilados pesados de GDExtension (.dll, .so, .dylib) fuera del historial principal de tu repositorio Git. El tamaño del repositorio se inflará rápidamente a medida que recompiles las librerías durante el desarrollo. En su lugar, utiliza un .gitignore para ignorar los directorios de compilación (builds) y las carpetas de lanzamiento (release), y configura un pipeline de CI/CD (como GitHub Actions o GitLab CI) usando scripts automatizados de CMake para compilar los binarios de destino para múltiples plataformas, empaquetándolos únicamente dentro de archivos zip de lanzamiento.

3. Gestiona con cuidado el límite entre GDScript y C++

Ten en cuenta cómo se gestiona la memoria al pasar variables a través de la frontera entre lenguajes. GDScript gestiona automáticamente el ciclo de vida de las clases derivadas de RefCounted (como Resource), pero utiliza una gestión de memoria manual para los objetos que heredan de Object (como los objetos Node puros). En tu código C++ de GDExtension, utiliza siempre el wrapper inteligente Ref<T> de Godot para clases con conteo de referencias (reference-counted) para evitar errores de doble liberación (double-free) o fugas de memoria. Para clases estándar, realiza un casting defensivo utilizando Object::cast_to<T>() y verifica punteros nulos antes de invocar métodos nativos.

4. Prefiere WebSockets y conexiones persistentes para estados en tiempo real

Evita el uso de polling HTTP tradicional para plugins que requieran sincronización en tiempo real, como sistemas de edición compartidos o herramientas de matchmaking en el backend. Realizar peticiones HTTP de forma repetitiva introduce un alto consumo de CPU y provoca severas penalizaciones de rate-limiting en los servicios de backend. En su lugar, deberías abandonar el HTTP polling en favor de los WebSockets para establecer una conexión persistente y bidireccional. Esto reduce la latencia de unos lentos 500ms a intervalos inferiores a 10ms y minimiza la sobrecarga de datos.

5. Diseña sistemas de fallback robustos para pipelines en la nube remotos

Si tu addon se comunica con servidores remotos en la nube, nunca dejes que una interrupción de la red congele el hilo de ejecución del editor de Godot. Las peticiones web síncronas pueden bloquear el proceso principal de Godot, haciendo que el editor se cuelgue. Utiliza siempre callbacks asíncronos o pools de hilos para mantener la fluidez de las respuestas de la interfaz de usuario. Además, si estás diseñando una integración para live-ops, estudia cómo diseñar pipelines robustos evaluando la relación entre la campaña stop killing games y los fallbacks de servidores en live-ops. Esto garantizará que tu herramienta degrade con elegancia al modo offline y mantenga el editor funcional incluso cuando los endpoints de la nube sean completamente inaccesibles.

Conclusión: Optimizando tu pipeline de tooling en Godot

JetBrains Rider 2026.2 transforma el desarrollo de addons de Godot de un complejo ejercicio de configuración de sistemas a un flujo de trabajo optimizado y productivo para el desarrollador. Al automatizar el scaffolding de GDExtension, proporcionar una sólida integración con CMake y ofrecer depuración simultánea de GDScript y C++, Rider elimina la fatiga de configuración y te permite concentrarte en programar excelentes herramientas. Combinar las plantillas de desarrollo de Rider con una arquitectura de backend escalable y completamente gestionada te permite crear plugins conectados de alto rendimiento sin la sobrecarga de la ingeniería de servidores manual.

¿Listo para escalar tu backend multiplayer? Prueba horizOn de forma gratuita o consulta la documentación de la API.


Fuente: JetBrains Rider trae soporte para addons de la Godot Asset Store