GDExtension — нативные плагины на C++ и Rust
godot-cpp, gdext (Rust), когда нужны нативные расширения, как они работают.
GDScript хорош для большинства gameplay-логики, но иногда нужно опуститься ниже:
- Воксельный движок с миллионами блоков
- Custom shading в реальном времени с сложной CPU-математикой
- Интеграция со существующей C/C++ библиотекой (физика, NN inference, audio DSP)
- Performance hot path, где даже static-typed GDScript не справляется
GDExtension — современный способ расширять Godot на нативном уровне. Заменил GDNative с Godot 4.0.
Главные идеи
- Вы пишете код в C++ (через
godot-cpp) или Rust (черезgdext). - Компилируете в dynamic library (
.so/.dll/.dylib). - Создаёте манифест
.gdextension, который Godot загружает при старте. - В редакторе ваши классы появляются как обычные узлы — добавляются в сцену, имеют свойства в Inspector, можно подключать сигналы.
Главное преимущество GDExtension над модулями (которые в monorepo Godot): не нужно пересобирать сам редактор. Меняете плагин → reload Godot → новая версия работает.
Node native modules (.node файлы через node-gyp). Или WASM-модули, скомпилированные из
Rust/C++ для браузера.
Структура GDExtension-плагина
my_plugin/
├── my_plugin.gdextension ← манифест
├── src/
│ ├── register_types.cpp ← регистрация классов
│ ├── my_node.cpp
│ └── my_node.h
├── bin/ ← собранные .so/.dll
│ ├── libmyplugin.linux.x86_64.so
│ ├── libmyplugin.windows.x86_64.dll
│ └── libmyplugin.macos.universal.dylib
├── SConstruct ← сборка через SCons
└── godot-cpp/ ← submodule с биндингами
my_plugin.gdextension:
[configuration]
entry_symbol = "myplugin_library_init"
compatibility_minimum = "4.4"
[libraries]
linux.x86_64 = "bin/libmyplugin.linux.x86_64.so"
windows.x86_64 = "bin/libmyplugin.windows.x86_64.dll"
macos = "bin/libmyplugin.macos.universal.dylib"
Минимальный пример на C++
my_node.h:
#ifndef MY_NODE_H
#define MY_NODE_H
#include <godot_cpp/classes/node3d.hpp>
namespace godot {
class MyNode : public Node3D {
GDCLASS(MyNode, Node3D)
private:
double speed = 1.0;
protected:
static void _bind_methods();
public:
MyNode();
~MyNode();
void _process(double delta) override;
void set_speed(double p_speed);
double get_speed() const;
};
}
#endif
my_node.cpp:
#include "my_node.h"
#include <godot_cpp/core/class_db.hpp>
using namespace godot;
void MyNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_speed", "p_speed"), &MyNode::set_speed);
ClassDB::bind_method(D_METHOD("get_speed"), &MyNode::get_speed);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed"), "set_speed", "get_speed");
}
MyNode::MyNode() {}
MyNode::~MyNode() {}
void MyNode::_process(double delta) {
rotate_y(speed * delta);
}
void MyNode::set_speed(double p_speed) { speed = p_speed; }
double MyNode::get_speed() const { return speed; }
После компиляции (scons → бинарь в bin/) → перезапуск Godot → “MyNode” появится в Add Node
с полем speed в Inspector.
Rust — gdext
Сообщество разработало gdext — биндинги для Rust. Стиль более идиоматичный:
use godot::prelude::*;
struct MyExtension;
#[gdextension]
unsafe impl ExtensionLibrary for MyExtension {}
#[derive(GodotClass)]
#[class(base=Node3D)]
struct MyNode {
#[var]
speed: f64,
base: Base<Node3D>,
}
#[godot_api]
impl INode3D for MyNode {
fn init(base: Base<Node3D>) -> Self {
Self { speed: 1.0, base }
}
fn process(&mut self, delta: f64) {
let rotation_y = self.base().get_rotation().y + (self.speed * delta) as f32;
let mut rot = self.base().get_rotation();
rot.y = rotation_y;
self.base_mut().set_rotation(rot);
}
}
Rust-преимущества:
- Memory safety без overhead — нет malloc/free ошибок, нет UB.
- Cargo — экосистема пакетов проще, чем CMake/SCons для C++.
- Performance на уровне C++.
Минусы:
- Чуть медленнее компиляция первого раза.
- Меньше community-плагинов с примерами (чем C++).
gdext активно развивается и считается production-ready на 2026 год.
Когда стоит писать GDExtension
✅ Стоит:
- Voxel-engine, terrain LOD, marching cubes.
- Custom physics constraints или soft-body симуляция.
- Real-time DSP / audio synthesis.
- Интеграция со существующей C++ библиотекой (Open3D, OpenCV, библиотеки ML inference).
- Workflows, где даже Burst/SIMD-уровень GDScript недостаточен.
❌ НЕ стоит:
- Стандартная gameplay-логика (используйте GDScript).
- Single-shot операции (один раз сгенерировать карту — пишите в WorkerThreadPool из GDScript).
- Когда не уверены, что узкое место именно в CPU вычислениях. Профайлите сначала.
Производительность
Бенчмарки для простого numerical workload (миллион итераций):
| Язык | Время |
|---|---|
| GDScript (untyped) | 850 мс |
| GDScript (typed) | 400 мс |
| C# | 80 мс |
| C++ (GDExtension) | 12 мс |
| Rust (gdext) | 12 мс |
C++ и Rust — в десятки раз быстрее typed GDScript. Но overhead начинается при пересечении GDExtension boundary (вызов C++ метода из GDScript). Поэтому пишут большие куски в C++, вызывая редко.
GDExtension — это нативные бинарники. Linux x86_64 не работает на Windows. Нужно собирать под каждую target-платформу, что усложняет CI/CD. Для одной платформы — просто; для shipping в Windows + Linux + macOS + Android + iOS — нужны 5 разных CI-job’ов.
Расширения, которые часто пишут на GDExtension
- godot-rapier-3d — Rapier physics на Rust (альтернатива встроенной физике).
- Voxelity — voxel engine для Godot.
- godot-luau-script — Luau (Roblox-style) скриптинг.
- NAVigator — продвинутая навигация.
В Asset Library есть категория “Native plugins” — там готовые GDExtension-плагины.
Альтернатива — C# в Godot
Если у вас .NET-команда и не хочется лезть в C++, C# через Godot.NET даёт ~10× ускорение
над GDScript (untyped). См. следующую главу.
Сравнение с Unity
Unity-аналог:
- Native Plugin (
.dll/.dylib/.so) загружается через[DllImport]. - Менее интегрированно — нативные плагины не появляются как Node-классы в иерархии.
- Альтернатива в Unity для тяжёлых вычислений — Job System + Burst (см. главу про Jobs+Burst), всё внутри C# и без выхода в нативный мир.
GDExtension в Godot — более глубокая интеграция с движком; Burst в Unity — оптимизация без выхода из C#. Оба подхода правомерны.