Voltar ao Blog

Speedrunning o Desenvolvimento de Addons do Godot no JetBrains Rider: GDExtensions Nativas em C++ e Editor Plugins

Publicado em 29 de maio de 2026
Speedrunning o Desenvolvimento de Addons do Godot no JetBrains Rider: GDExtensions Nativas em C++ e Editor Plugins

Em resumo

Esta análise técnica aborda o novo fluxo de trabalho para desenvolvimento de addons no Godot 4 utilizando o JetBrains Rider 2026.2, destacando o suporte a GDExtensions nativas em C++ e a integração automatizada com CMake. Apresentamos as vantagens do debugging multilíngue simultâneo (GDScript/C++) e as melhores práticas para evitar gargalos de performance, vazamentos de memória e conflitos de namespaces na Godot Asset Store. Por fim, demonstramos como a integração com o backend escalável do horizOn elimina a complexidade de infraestrutura para permitir foco total na criação de ferramentas premium de gameplay e live-ops.

Criar um editor plugin customizado no Godot ou uma GDExtension nativa em C++ geralmente começa com uma percepção dolorosa e repentina: você passou três horas configurando scripts de compilação do SCons, lutando contra flags de compilador headless e analisando erros ambíguos de compilação cruzada (cross-compilation) em vez de escrever a lógica real do seu plugin. Embora a arquitetura do Godot 4 tenha liberado um potencial incrível para extensões, a experiência de desenvolvimento historicamente parecia configurar um rack de servidores usando um palito de dente. Com o lançamento da nova Godot Asset Store, os provedores de IDE finalmente estão tratando o desenvolvimento de addons como um cidadão de primeira classe.

O JetBrains Rider 2026.2 entrou oficialmente na arena como um dos primeiros grandes provedores de ferramentas de IDE a oferecer templates dedicados, automação com CMake e debugging multilíngue para o Godot Asset Store. Para desenvolvedores indie e engenheiros de ferramentas de equipe, isso significa o fim do inferno das configurações de boilerplate e o início da prototipagem rápida de ferramentas. Ao reduzir os tempos de configuração a um assistente de um único clique (single-click wizard), a barreira para estender a interface do editor principal do Godot nunca esteve tão baixa.

O Gargalo da GDExtension: Por Que o Tooling do Godot Costumava Ser Doloroso

Por baixo do capô, o Godot 4 usa GDExtension para permitir que os desenvolvedores escrevam código de alta performance em C++ ou Rust que interage diretamente com as estruturas principais da engine sem precisar recompilar a engine inteira. Ele faz isso carregando bibliotecas dinâmicas — como .dll no Windows, .so no Linux e .dylib no macOS — e mapeando-as para interfaces GDScript. No entanto, configurar isso manualmente exige clonar o repositório de bindings godot-cpp, corresponder exatamente ao header da versão da engine, escrever scripts customizados de SCons ou CMake e configurar um arquivo de configuração .gdextension para mapear os caminhos das bibliotecas em cinco plataformas de destino diferentes.

Pior ainda, o debugging desses binários nativos sempre foi notoriamente propenso a crashes. Um fluxo de trabalho típico de troubleshooting envolve iniciar o editor do Godot sob um debugger separado (como GDB ou LLDB), definir breakpoints em um editor externo e cruzar os dedos para que um hot-reload não cause um panic na thread principal da engine e force um crash completo. Quando os desenvolvedores estão criando tooling customizado — especialmente sincronizadores de banco de dados complexos, interfaces de netcode de baixa latência ou pipelines de assets —, essa fricção destrói completamente a produtividade.

Rider 2026.2: Uma Análise do Novo Toolchain de Addons

Templates de Projeto Prontos para Uso (Out-of-the-Box)

O Rider 2026.2 fornece templates dedicados e baseados em assistentes (wizards) que cobrem toda a gama de formatos de extensão do Godot. Você não precisa mais clonar boilerplates de repositórios ou copiar e colar estruturas de pastas de projetos antigos. Em vez disso, a IDE cria um repositório limpo e estruturado para GDScript editor plugins, extensões em C# ou GDExtensions em C++, pré-configurado com tudo, desde o plugin.cfg até as pastas de build de destino. Isso economiza horas de configuração e elimina a causa mais comum de falhas nos estágios iniciais: caminhos de diretório incorretos nos arquivos de manifesto.

Integração Nativa com CMake para C++

Historicamente, as bindings de C++ do Godot favoreciam fortemente o SCons como sistema de build. O SCons é poderoso, mas seus arquivos de configuração baseados em Python são notoriamente opacos, carecem de autocomplete na IDE e complicam a integração de CI/CD. O Rider 2026.2 introduz uma integração nativa e robusta com CMake para projetos GDExtension. Quando você cria um addon de GDExtension, o Rider gera automaticamente um arquivo CMakeLists.txt limpo que vincula a biblioteca de bindings principal godot-cpp ao seu código-fonte customizado. Isso permite que você utilize a poderosa engine de C++ do Rider para navegação de código, refatoração e análise estática (static analysis) sem qualquer configuração extra.

Debugging Multilíngue em uma Única Sessão

Esta é a joia da coroa da atualização. Desenvolvedores que escrevem ferramentas de alta performance no Godot raramente se limitam a uma única linguagem. Uma arquitetura padrão usa C++ de alta performance para o trabalho pesado de dados ou matemática complexa, e um arquivo GDScript leve para o dock de GUI ou painel de UI do editor. Fazer o debug dessa arquitetura híbrida significava usar ferramentas separadas para C++ e GDScript. O Rider 2026.2 gera configurações unificadas de execução (run configurations) automaticamente. Você pode clicar em um único botão "Debug", e o Rider iniciará o editor do Godot, fará o attach ao processo dele e rastreará a execução simultaneamente no GDScript e no C++. Um breakpoint no GDScript da sua UI será acionado e, conforme você entra (step into) em uma função nativa de C++, o Rider fará a transição perfeita para o debugger de C++ sem derrubar a sessão.

Arquitetura de Pastas Pronta para Publicação

A nova Godot Asset Store possui estruturas de pastas e requisitos de empacotamento rigorosos para evitar que os addons entrem em conflito nos namespaces uns dos outros. Os templates do Rider impõem essas recomendações desde o primeiro dia. Ao separar os arquivos de runtime dos componentes de GUI exclusivos do editor, a IDE garante que, quando você gerar um build, ele estará imediatamente pronto para upload na store, reduzindo os erros de empacotamento de uma dor de cabeça frequente a um não-evento automatizado.

Por Dentro do Ciclo de Vida da GDExtension: Construindo o Backend em C++

Para entender o valor da automação do Rider, devemos olhar para o que um projeto GDExtension realmente exige no nível do código. Em uma GDExtension padrão, você deve definir um inicializador de biblioteca como ponto de entrada (entry point), registrar seus tipos de classe customizados no ClassDB do Godot e limpar cuidadosamente as alocações de memória quando o módulo for desinicializado. Os seguintes headers e arquivos de origem em C++ representam o boilerplate mínimo necessário para criar um nó customizado nativo — neste caso, um manipulador de telemetria de alta performance.

// 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 seguir, implementamos o comportamento principal. No arquivo de implementação, registramos nossos métodos dentro de _bind_methods() para garantir que a engine de reflexão em runtime (reflection engine) do Godot possa acessá-los.

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

Finalmente, devemos instruir o Godot sobre como carregar nosso módulo usando uma função de inicialização. Este arquivo register_types atua como o ponto de entrada (entry point) principal da biblioteca, conectado através do sistema de carregamento da 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();
}
}

Desenvolvendo Editor Plugins: O Pipeline em GDScript

Enquanto a GDExtension lida com o backend de alta performance em C++, a UI do seu addon do Godot — como adicionar um painel customizado no dock inferior ou criar nós de inspector customizados — é tipicamente escrita em GDScript usando a anotação @tool. A diretiva @tool informa ao Godot que este script deve ser executado diretamente dentro da instância ativa do editor, e não apenas quando o jogo está rodando.

Escrever scripts de ferramenta (tool scripts) exige um gerenciamento de ciclo de vida limpo. As funções _enter_tree() e _exit_tree() funcionam como os construtores e destrutores de suas integrações com o editor. Deixar de limpar os nós de UI customizados durante o descarregamento do editor resultará em nós de GUI órfãos e obsoletos poluindo o espaço de memória do editor, o que eventualmente causa problemas de 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.")

O Desafio da Conectividade: Integrando Backends Remotos

Ao criar editor plugins ou GDExtensions, sua ferramenta geralmente é tão poderosa quanto os serviços de backend com os quais ela se conecta. Por exemplo, se você estiver construindo um painel de administração para um jogo indie, um editor de níveis remoto ou um rastreador de telemetria in-engine, seu plugin precisa se comunicar com bancos de dados, gerenciar identidades de desenvolvedores ou jogadores e sincronizar estados remotos. Implementar isso por conta própria significa construir um serviço web seguro e personalizado. Você precisa configurar um servidor virtual privado (VPS), criar um API gateway, implantar um banco de dados, escrever modelos customizados de autenticação de usuário e implementar a rotação de certificados SSL/TLS. Esse é um overhead gigantesco de engenharia que pode facilmente consumir de 4 a 6 semanas de desenvolvimento dedicado antes mesmo que seu plugin consiga se comunicar com um banco de dados.

Em vez de canalizar a energia limitada da sua equipe para o gerenciamento de infraestrutura bruta de backend, você pode integrar o horizOn como o backend principal da sua game engine. O horizOn fornece um SDK nativo e de alta performance em C# e GDScript que se conecta diretamente aos seus addons de editor customizados. Em vez de passar semanas provisionando bancos de dados e escrevendo WebSockets handlers customizados, você pode simplesmente adicionar o cliente do horizOn ao seu projeto e obter instantaneamente autenticação segura, acesso a banco de dados em tempo real e gerenciamento de jogadores. Ao deixar o trabalho pesado de infraestrutura para o horizOn, você pode dedicar seu tempo a refinar a UX do seu addon e suas ferramentas de gameplay, sabendo que seu backend escalará perfeitamente quando você publicar na store.

5 Melhores Práticas Testadas em Batalha para o Desenvolvimento de Addons no Godot

1. Isolamento de Namespace via Estrutura de Pastas

Sempre adicione um prefixo de namespace único às pastas e scripts do seu addon sob res://addons/seu_nome_de_addon_unico/. O Godot compartilha um único namespace global e plano de caminhos para todas as classes customizadas registradas por meio das diretivas @icon ou class_name. Se você usar um nome de classe genérico como NetworkManager or ConfigHelper, seu addon entrará em conflito com o projeto principal do desenvolvedor ou com outras extensões de terceiros. Mantenha todos os seus scripts utilitários estritamente restritos ao diretório da sua pasta única.

2. Automatize a Compilação de Binários e Exclua-os do VCS

Mantenha os binários pesados e compilados da GDExtension (.dll, .so, .dylib) fora do histórico do seu repositório Git principal. O tamanho do repositório aumentará rapidamente à medida que você recompila as bibliotecas durante o desenvolvimento. Em vez disso, use um .gitignore para ignorar os diretórios de build e pastas de release, e configure uma pipeline de CI/CD (como GitHub Actions ou GitLab CI) usando scripts CMake automatizados para compilar os binários de destino para múltiplas plataformas, empacotando-os apenas nos arquivos zip de release.

3. Gerencie com Cuidado a Fronteira entre GDScript e C++

Fique atento a como a memória é tratada ao passar variáveis através da fronteira de linguagens. O GDScript gerencia automaticamente o ciclo de vida de classes derivadas de RefCounted (como Resource), mas usa gerenciamento de memória manual para objetos que herdam de Object (como objetos Node puros). No código C++ da sua GDExtension, sempre use o wrapper inteligente Ref<T> do Godot para classes de contagem de referência (reference-counted) a fim de evitar erros de liberação dupla (double-free) ou memory leaks. Para classes padrão, realize casting defensivo usando Object::cast_to<T>() e verifique ponteiros nulos antes de invocar métodos nativos.

4. Prefira WebSockets e Conexões Persistentes para Estado em Tempo Real

Evite usar o tradicional HTTP polling para plugins que exigem sincronização em tempo real, como sistemas de editores compartilhados ou ferramentas de matchmaking no backend. Fazer requisições HTTP repetidamente introduz um alto overhead de CPU e gera penalidades massivas de rate-limiting nos serviços de backend. Em vez disso, você deve abandonar o HTTP polling em favor de WebSockets para estabelecer uma conexão persistente e bidirecional. Isso reduz a latência de lentos 500ms para intervalos inferiores a 10ms e minimiza o overhead de dados.

5. Projete Sistemas de Fallback Robustos para Pipelines de Nuvem Remota

Se o seu addon se comunica com servidores remotos na nuvem, nunca permita que uma interrupção de rede congele a thread do editor do Godot. Requisições web síncronas podem bloquear o processo principal do Godot, fazendo com que o editor trave. Sempre use callbacks assíncronos ou pools de threads para manter as respostas da UI fluidas. Além disso, se você estiver projetando uma integração de live-ops, estude como estruturar pipelines robustos avaliando a campanha stop killing games vs fallbacks de servidores de live ops. Isso garante que sua ferramenta faça o downgrade de maneira suave para o modo offline e mantenha o editor funcional mesmo quando os endpoints na nuvem estiverem totalmente inacessíveis.

Conclusão: Otimizando seu Pipeline de Tooling no Godot

O JetBrains Rider 2026.2 transforma o desenvolvimento de addons do Godot de um exercício complexo em configuração de sistemas para um fluxo de trabalho de desenvolvimento simplificado e altamente produtivo. Ao automatizar a estruturação (scaffolding) de GDExtensions, fornecer uma integração robusta com o CMake e oferecer debugging simultâneo em GDScript e C++, o Rider elimina a fadiga de configuração e permite que você se concentre em programar ferramentas incríveis. Combinar os templates de desenvolvimento do Rider com uma arquitetura de backend escalável e totalmente gerenciada permite que você crie plugins conectados de alta performance sem o overhead da engenharia manual de servidores.

Pronto para escalar seu backend multiplayer? Experimente o horizOn gratuitamente ou confira a documentação da API.


Fonte: JetBrains Rider traz suporte para addons da Godot Asset Store