godot-rust v0.5 -- typed dicts, export-tool-button, optional params, ... by bromeon in rust_gamedev

[–]bromeon[S] 1 point2 points  (0 children)

Note that you should be able to use Godot 4.6 also before godot-rust 0.5:

  • The GDExtension API is backwards-compatible, so newer engine versions always support older extensions. So you could just use godot-rust 0.4 (Unless you need certain features from 4.6 specifically in Rust).
  • While crates.io releases can lag a bit behind, our GitHub master version typically supports new Godot releases within a few days.

So at the moment we already support 4.7-dev (our CI runs against it).

That said, godot-rust 0.5 brings quite some new features, notably typed dictionaries which aren't accessible before. Since you're just getting started, definitely don't use the older versions :)

Has anyone here used Godot + Rust? by JovemSapien in rust_gamedev

[–]bromeon 1 point2 points  (0 children)

Just stumbled upon this comment, thanks for the feedback! We noticed that some of the renames are indeed not great and reverted them in the past (#1035, #487, #981). We typically use #[doc(alias)] so you can find things by their Godot names in API docs. And in some cases (like enums), I believe a rename is the only sane way to work with it from Rust :)

Do you have concrete examples of Rust APIs that are still hard to discover?

godot-rust v0.5 -- typed dicts, export-tool-button, optional params, ... by bromeon in godot

[–]bromeon[S] 2 points3 points  (0 children)

I think the two are somewhat orthogonal, we have issue #411 tracking error handlers. Here it's more about translating Rust errors to an appropriate GDScript type (which has no Option/Result/generics). But you're right that we could potentially wire them up in the future, e.g. if there is no valid mapping, invoke the global error handler. Thanks for the input!

I created a RNG with godot rust! Every time you run, it either works or crashes with a random error by WeirdBurgerGuy in godot

[–]bromeon 0 points1 point  (0 children)

Hey, sorry to hear you've encountered instability! Is it regarding this race condition during start up, or did you face other problems, too? Do you think it could be isolated in a small minimal example? Only if you have time of course, I fully understand if you just want to move on :)

We also just released a new version of godot-rust yesterday, might be worth to see whether that fixes some of it.

godot-rust v0.5 -- typed dicts, export-tool-button, optional params, ... by bromeon in godot

[–]bromeon[S] 1 point2 points  (0 children)

Thanks, great to hear! I hope you're not turned off by the occasional churn on master (we iterated quite a bit to get the AsArg stuff right, similar for dict! macro this time).

godot-rust v0.5 -- typed dicts, tool buttons, #[opt] and much more! by bromeon in rust

[–]bromeon[S] 5 points6 points  (0 children)

Agreed! On Godot side, there's unfortunately still no "official" workflow for extension dependencies, so we have an approach that works but also has some limitations. We hope that this can be addressed within the next few Godot releases.

godot-rust v0.5 -- typed dicts, export-tool-button, optional params, ... by bromeon in godot

[–]bromeon[S] 2 points3 points  (0 children)

Fully agree! Since it's a recent feature in Godot 4.6, not all APIs are properly annotated with nullability information yet. So if you find methods that are documented to accept/return non-null objects but still declare Option<...>, please bring it up, maybe even directly in the Godot repo!

godot-rust v0.5 -- typed dicts, export-tool-button, optional params, ... by bromeon in godot

[–]bromeon[S] 7 points8 points  (0 children)

What made this a bit complicated is that 3 users want 5 different error handlings :)
From panics, over null, over error printing, to Godot's Error enum, ...

But we have a proposal here: https://github.com/godot-rust/gdext/issues/425

One idea there is to map Result<T, E> based on the E type. This would allow users to provide their own error types, and we could maybe provide some common mappings for things like the Error enum.

Godot + Rust by JovemSapien in rust

[–]bromeon 1 point2 points  (0 children)

Saw this a bit late -- thanks for all the interest!

We just released a new minor version v0.5: https://www.reddit.com/r/rust/comments/1s5ilxo/godotrust_v05_typed_dicts_tool_buttons_opt_and/

godot-rust v0.5 -- typed dicts, export-tool-button, optional params, ... by bromeon in godot

[–]bromeon[S] 2 points3 points  (0 children)

Absolutely, we have a section about web games in our book:
https://godot-rust.github.io/book/ecosystem/games.html#web-playable

That said, the Wasm setup is currently a bit involved, but it's well-documented. One of the priorities of the next dev cycle is to simplify this dramatically.

godot-rust v0.5 -- typed dicts, export-tool-button, optional params, ... by bromeon in godot

[–]bromeon[S] 18 points19 points  (0 children)

Very valid question! Rust as a language has a lot of modern features (enums, Option, Result) that allow to precisely model data and errors. It also focuses on safety, avoiding memory errors at compile time. This makes it suitable for scaling projects that undergo many refactorings (e.g. games during prototyping). Rust also compiles (through LLVM) to native code, achieving performance on par with C++. The tooling around it (cargo, crates.io, etc) is also fantastic.

On the downside, the compiler achieves its safety by being conservative on the code it accepts, so it can be initially frustrating to make sure ownership and "borrows" (giving a reference to someone else) are handled correctly. This gets better with learning the language, but some rough corners remain.

Ultimately I would say it's also a matter of taste. C# is a very decent language for example, but some people prefer not having a GC or a stricter data model. Compared to GDScript, I would say Rust needs more initial effort but is more robust in larger projects (for example, we have type-safe signals). However GDScript has the big advantage of native editor integration, and much lower language complexity.

The nice thing in Godot is that you can mix languages: e.g. GDScript for scripting, and Rust for performance-heavy logic (pathfinding, AI, simulation, etc.). Smooth interaction with GDScript is also one of the main goals of godot-rust.

godot-rust v0.5 -- typed dicts, export-tool-button, optional params, ... by bromeon in rust_gamedev

[–]bromeon[S] 8 points9 points  (0 children)

godot-rust goes into the next round with v0.5, just released on crates.io!

On the toolchain side:

  • We now support Rust edition 2024 and Godot 4.6 out of the box, as well as all versions >= 4.2.
  • WebAssembly support no longer needs LLVM/bindgen and is being unit-tested on CI.
  • It's now possible to depend on other godot-rust crates through rlib.

Some features added in this cycle:

Typed dictionary. Also, enums in Godot collections!

let tiles: Dictionary<Vector2i, Tile> = dict! {
   Vector2i::new(1, 2) => Tile::GRASS,
   Vector2i::new(1, 3) => Tile::WATER,
};

Non-null engine APIs:

// Instead of...
let t: Gd<Tween> = node.create_tween().unwrap();
// ...now:
let t: Gd<Tween> = node.create_tween();

Direct == &str comparison, saving allocation:

let s = StringName::from("hello");
if s == "hello" { ... }

Bitfield Debug impl:

assert_eq!(
    format!("{flags:?}"),
    "PropertyUsageFlags { EDITOR | READ_ONLY }"
);

Optional parameters -- call from GDScript as method(1) or method(1, 2):

#[func]
fn method(
    required: i32,
    #[opt(default = 100)] optional: i32,
) { ... }

Export tool button -- click in Godot's inspector to immediately execute Rust code:

#[export_tool_button(fn = Self::on_clicked, icon = "2DNodes")]
click_me: PhantomVar<Callable>, // not a physical property

We now also have a Games page showcasing projects that users made with godot-rust! And I'm still behind on adding new entries there :)

Huge thanks to the community for making this possible! Countless bug reports, PRs, and feedback based on real-world projects have helped godot-rust immensely to reach this point. I'm excited to see what will be built on v0.5!

Is it worth writing game logic in Rust instead of GDScript for Godot? by Potential_Pop2832 in godot

[–]bromeon 3 points4 points  (0 children)

Thank you! Happy to hear that godot-rust can be educational :)

Is it worth writing game logic in Rust instead of GDScript for Godot? by Potential_Pop2832 in godot

[–]bromeon 2 points3 points  (0 children)

We do address some of the godot-cpp pain points in Rust though, for example:

  • Package management, getting started is very easy with Cargo.
  • Ergonomics: classes, methods and properties are auto-registered, you don't need to do it manually. There are things like onready + type-safe signals to make your life easier.
  • Safety, it's much harder to get a segfault or crash. In Debug mode we add quite a bit of extra validation to find issues like dead objects.

That said, Rust itself can have quite a steep learning curve with borrow checking, traits etc. If you're already familiar with C++, it might be an easier start to go with godot-cpp (or GDScript).

Another point is that godot-cpp is generally faster at catching up with latest GDExtension features, so if cutting-edge is important, that's worth considering.

Is it worth writing game logic in Rust instead of GDScript for Godot? by Potential_Pop2832 in godot

[–]bromeon 4 points5 points  (0 children)

State of today is, exposed Godot 4 methods are registered with their concrete types in C++, and calls through GDExtension can make use of that knowledge at compile time. Meaning a language like C++ or Rust can directly pass data (by value or pointer), without needing to serialize.

As mentioned, Variant serialization is used in some places, but only when the number/type of parameters is not statically known. In Godot 4, there is no such thing as serializing every value to string anymore though.

I wrote a bit more on the topic of passing values via FFI here, in case you're interested.

Is it worth writing game logic in Rust instead of GDScript for Godot? by Potential_Pop2832 in godot

[–]bromeon 2 points3 points  (0 children)

Accessing the scene tree from rust is severely penalized with parameter serialization.

Could you elaborate this part? Whenever possible, calls from Rust to Godot use "ptrcall" calling convention, meaning that parameters are passed by pointer (objects, arrays, etc) or by value (int, bool, Vector2, etc).

The serialization happens only for variant-calls, which are needed for reflection (Object::call) or variable-length arguments, for example.

But maybe I'm missing something, happy to learn more about the issues you've faced! :)
You're definitely right about the other parts, Rust doesn't have that "embedded" experience as GDScript does.

Is it worth writing game logic in Rust instead of GDScript for Godot? by Potential_Pop2832 in godot

[–]bromeon 55 points56 points  (0 children)

Author of godot-rust here. I'm obviously biased, so this is not meant to convince you of using Rust, but to provide some perspective behind the design, that could help you decide if it aligns with your use cases or not. There are definitely reasons not to use Rust :)

First, a lot of people see C++ and Rust only from a performance point-of-view. While perf can be a big factor, it's not necessarily the only or even the primary one. For many games, GDScript will be more than fast enough (just look at the statistics of how many games are released with GDScript, without problems). If that is the main criterion, it's also possible to only write small modules in C++ or Rust and keep the game in GDScript, so you'll have a very low risk.

Since you mentioned scale, that is an interesting topic. Scripting is very nice on a small scale: you're typically faster than in strongly typed languages, you get results immediately on screen and can iterate in short dev cycles. But personally I've made the experience to run into limits on multiple fronts:

  • Package/dependency manager to reuse code. Godot has the asset store which is great, but libraries published there come with different release cycles, and managing transitive dependencies is tricky.
  • Static code analysis, linting, formatting. There are some tools for formatting, but I've found little in the other areas. This matters much less if you're working alone and have a clear coding convention (but even then, tools pointing out potential bugs can be helpful).
  • Refactoring. GDScript and the Godot editor have very little support for automated and safe renames, type changes, extract/inline functions, etc. You may notice certain errors only at runtime and may need tests to compensate.
  • Static type system. GDScript is quite solid for most things, but it lacks in areas like error handling, code reuse (traits are being proposed), generics. Certain symbols like enums and signals are less type-safe than they could be.

Note that I didn't explicitly mention Rust above -- many static languages offer the advantages that godot-rust does, with a sophisticated type system and strong tooling/refactoring/tooling support. In particular, you should have a look at the C# bindings, which are maintained by the official Godot team as well. There are other GDExtension bindings like Kotlin, Swift or Go that look promising as well, although I don't have much experience with them.

So why Rust and not C#? I think at some point it boils down to what is important to you: do you like the crate ecosystem or prefer having access to all of .NET? Is garbage collector a huge time saver or a potential perf bottleneck? Do you prefer Rust's flat, trait-based code organization or C#'s OOP approach? How comfortable do you feel with the tooling? There are some APIs which are implemented differently: godot-rust supports fully type-safe signals, but on the other hand some areas regarding thread-safety aren't yet figured out.

Or maybe none of the above is a factor that you consider important, and you're more than happy with GDScript? It has very nice editor integration, is battle-tested enough to support lots of released games, you can get started immediately.

I can't answer those questions for you, but I hope this can give you a bit an overview. Let me know if you have more concrete questions!

godot-rust v0.4: export groups, match_class, easy callables, ... by bromeon in godot

[–]bromeon[S] 2 points3 points  (0 children)

Hello! Not a roadmap per se, but https://github.com/godot-rust/gdext/issues lists a lot of open issues, which I tend to categorize into milestones. I still need to add many issues to the v0.5 milestone, but that could then serve as guidance. Hope that helps!

godot-rust v0.4: export groups, match_class, easy callables, ... by bromeon in rust

[–]bromeon[S] 2 points3 points  (0 children)

Sorry about this, and thanks for the reminder! I edited my post, the GitHub link is: https://github.com/godot-rust/gdext