|
| 1 | +# Migrating from godot-rust 0.9.x to 0.10.x |
| 2 | + |
| 3 | +Version 0.10 implements many improvements to ergonomics, naming consistency and bugfixes. Tooling and CI has been majorly overhauled, providing fast |
| 4 | +feedback cycles, higher confidence and easier-to-read documentation. |
| 5 | + |
| 6 | +This guide outlines what actions users of godot-rust need to take to update their code. |
| 7 | + |
| 8 | + |
| 9 | +## Minimum supported Rust version |
| 10 | + |
| 11 | +The MSRV has been increased to 1.56. When migrating, you will need to ensure that you are using **at least** Rust 1.56 or later or your projects may fail to build. |
| 12 | + |
| 13 | +We use the Rust 2021 edition; in your own code you may use any edition. |
| 14 | + |
| 15 | + |
| 16 | +## Breaking API changes |
| 17 | + |
| 18 | +This is a brief overview of the smaller breaking changes in the library API. Please refer to the [changelog](https://github.com/godot-rust/godot-rust/blob/master/CHANGELOG.md) for a comprehensive list. |
| 19 | + |
| 20 | +More sophisticated breaking changes are explained further down in section [_Migrations_](#Migrations). |
| 21 | + |
| 22 | +### Changes to modules |
| 23 | + |
| 24 | +The module structure has been simplified to ensure there is only one module per symbol: |
| 25 | +- Module `nativescript` has been renamed to `export`. |
| 26 | +- Types `nativescript::{Instance, RefInstance}` have been moved to `object`. |
| 27 | +- Less often used macros `godot_gdnative_init`, `godot_gdnative_terminate`, `godot_nativescript_init`, `godot_site` have been removed from the prelude. |
| 28 | +- Unnecessarily nested modules have also been removed. If you were depending upon the exact path, you will need to use the new path. |
| 29 | + |
| 30 | +### Changes to core types |
| 31 | + |
| 32 | +- The euclid vector library has been removed and replaced with [glam](https://docs.rs/glam/latest/glam/). |
| 33 | + |
| 34 | +- `Variant` has a redesigned conversion API. |
| 35 | + |
| 36 | +- Matrix types -- `Transform2D`, `Transform` and `Basis` -- have had their basis vectors renamed from `x/y/z` to `a/b/c`, to avoid confusion with the `x/y/z` vector components. |
| 37 | + |
| 38 | +- The following deprecated symbols have been removed: |
| 39 | + - `Reference::init_ref`(unsound) |
| 40 | + - `ClassBuilder::add_method`, `add_method_advanced`, `add_method_with_rpc_mode` |
| 41 | + - `ScriptMethod` |
| 42 | + - `ScriptMethodFn` |
| 43 | + - `ScriptMethodAttributes` |
| 44 | + |
| 45 | +- The following methods were removed due to being redundant: |
| 46 | + - unsafe access methods for `VariantArray<Shared>` (available in `VariantArray<Unique>`) |
| 47 | + - `Basis::invert` |
| 48 | + - `Basis::orthonormalize` |
| 49 | + - `Basis::rotate` |
| 50 | + - `Basis::tdotx` |
| 51 | + - `Basis::tdoty` |
| 52 | + - `Basis::tdotz` |
| 53 | + - `Rid::operator_less` |
| 54 | + - `StringName::operator_less` |
| 55 | + |
| 56 | + |
| 57 | +Various type names have been changed to improve clarity and consistency: |
| 58 | + |
| 59 | +| Old Type Name | New Type Name | |
| 60 | +|------------------|---------------| |
| 61 | +| `RefInstance` | `TInstance` | |
| 62 | +| `RefKind` | `Memory` | |
| 63 | +| `ThreadAccess` | `Ownership` | |
| 64 | +| `TypedArray` | `PoolArray` | |
| 65 | +| `Element` | `PoolElement` | |
| 66 | +| `SignalArgument` | `SignalParam` | |
| 67 | +| `Point2` | `Vector2` | |
| 68 | +| `Size2` | `Vector2` | |
| 69 | + |
| 70 | +The following methods have been renamed: |
| 71 | + |
| 72 | +| Old Method | New Method | |
| 73 | +|---------------------------------|------------------------| |
| 74 | +| `{String,Variant}::forget` | `leak` | |
| 75 | +| `Color::{rgb,rgba}` | `{from_rgb,from_rgba}` | |
| 76 | +| `Rid::is_valid` | `is_occupied` | |
| 77 | +| `Basis::to_scale` | `scale` | |
| 78 | +| `Basis::from_elements` | `from_rows` | |
| 79 | +| `Transform2D::from_axis_origin` | `from_basis_origin` | |
| 80 | +| `StringName::get_name` | `to_godot_string` | |
| 81 | + |
| 82 | + |
| 83 | +### Changes to procedural macros |
| 84 | + |
| 85 | +- `#[inherit]` is now optional and defaults to `Reference` instead of `Node`. |
| 86 | +- `#[property(before_set)]` and its siblings are replaced with `#[property(set)]` etc.; see below. |
| 87 | + |
| 88 | +### Ownership Changes |
| 89 | + |
| 90 | +- `Instance` and `TInstance` now use `Own=Shared` by default. Some adjustments to your assumptions should be re-evaluated as needed. |
| 91 | + |
| 92 | + |
| 93 | +## New features |
| 94 | + |
| 95 | +In addition to new functionality outlined here, it can be interesting to check the _Added_ section in the changelog. |
| 96 | + |
| 97 | +### Cargo features |
| 98 | + |
| 99 | +While these are not breaking changes, the following may be useful to consider when migrating, particularly if you were previously using a custom solution for either of the following: |
| 100 | + |
| 101 | +- [serde](https://serde.rs/) is now supported for `VariantDispatch` and types in the `core_types` module. |
| 102 | +- Async Foundations have been completed, so you can now make use of Rust `async` runtimes with Godot more easily. We have a recipe for using [async with the tokio runtime](../recipes/async-tokio.md). |
| 103 | +- Custom Godot builds are now supported. The advanced guide for [Custom Godot](./custom-godot.md) has been updated accordingly. |
| 104 | + |
| 105 | +### Custom property exports |
| 106 | + |
| 107 | +In godot-rust 0.9, it was necessary to manually register properties using the class builder such as the following: |
| 108 | + |
| 109 | +```rust |
| 110 | +#[derive(NativeClass)] |
| 111 | +#[inherit(Reference)] |
| 112 | +struct Foo { |
| 113 | + #[property] |
| 114 | + bar: i64, |
| 115 | +} |
| 116 | + |
| 117 | +#[methods] |
| 118 | +impl Foo { |
| 119 | + fn register_properties(builder: &ClassBuilder<Foo>) { |
| 120 | + builder |
| 121 | + .add_property::<String>("bar") |
| 122 | + .with_getter(get_bar) |
| 123 | + .with_setter(set_bar) |
| 124 | + .with_default(0) |
| 125 | + .done(); |
| 126 | + } |
| 127 | + #[export] |
| 128 | + fn set_bar(&mut self, _owner: &Reference, value: i64) { |
| 129 | + self.bar = value; |
| 130 | + } |
| 131 | + |
| 132 | + #[export] |
| 133 | + fn get_bar(&mut self, _owner: &Reference) -> i64 { |
| 134 | + self.bar |
| 135 | + } |
| 136 | +} |
| 137 | +``` |
| 138 | + |
| 139 | +In 0.10, this can be automated with the `#[property]` procedural macro, such as the following: |
| 140 | +```rust |
| 141 | +#[derive(NativeClass)] |
| 142 | +#[inherit(Reference)] |
| 143 | +struct Foo { |
| 144 | + #[property(name = "bar", set = "set_bar", get = "get_bar", default = 0)] |
| 145 | + bar: i64, |
| 146 | +} |
| 147 | + |
| 148 | +#[methods] |
| 149 | +impl Foo { |
| 150 | + #[export] |
| 151 | + fn set_bar(&mut self, _owner: &Reference, value: i64) { |
| 152 | + self.bar = value; |
| 153 | + } |
| 154 | + |
| 155 | + #[export] |
| 156 | + fn get_bar(&mut self, _owner: &Reference) -> i64 { |
| 157 | + self.bar |
| 158 | + } |
| 159 | +} |
| 160 | +``` |
| 161 | + |
| 162 | +### `VariantDispatch` |
| 163 | + |
| 164 | +`VariantDispatch` is an newly introduced type in godot-rust 0.10. This enum lets you treat `Variant` in a more rust-idiomatic way, e.g. by pattern-matching its contents: |
| 165 | + |
| 166 | +```rust |
| 167 | +let variant = 42.to_variant(); |
| 168 | + |
| 169 | +let number_as_float = match variant.dispatch() { |
| 170 | + VariantDispatch::I64(i) => i as f64, |
| 171 | + VariantDispatch::F64(f) => f, |
| 172 | + _ => panic!("not a number"), |
| 173 | +}; |
| 174 | + |
| 175 | +approx::assert_relative_eq!(42.0, number_as_float); |
| 176 | +``` |
| 177 | + |
| 178 | + |
| 179 | +## Migrations |
| 180 | + |
| 181 | +This section elaborates on APIs with non-trivial changes and guides you through the process of updating your code. |
| 182 | + |
| 183 | +### `Variant` |
| 184 | + |
| 185 | +If you were using the `Variant::from_*` methods, those no longer exist. |
| 186 | + |
| 187 | +In 0.9.x you would need to use the specific constructor, such as the following: |
| 188 | + |
| 189 | +```rust |
| 190 | +let variant = Variant::from_i64(42); |
| 191 | +let variant = Variant::from_f64(42.0); |
| 192 | +let variant2 = Variant::from_object(object); |
| 193 | +``` |
| 194 | + |
| 195 | +In 0.10.x, `new()` is sufficient for any type that implements `ToVariant`, such as the following: |
| 196 | + |
| 197 | +```rust |
| 198 | +let variant = Variant::new(42); |
| 199 | +let variant = Variant::new(42.0); |
| 200 | +let variant2 = Variant::new(object); |
| 201 | +``` |
| 202 | + |
| 203 | +When converting from a variant to a Rust type, it previously was necessary to do the following: |
| 204 | + |
| 205 | +```rust |
| 206 | +let integer64 = i64::from_variant(&variant_i64).unwrap(); |
| 207 | +let float64 = f64::from_variant(&variant_f64).unwrap(); |
| 208 | +let object = ObjectType::from_variant(&variant_object).unwrap(); |
| 209 | +``` |
| 210 | + |
| 211 | +In 0.10.x, you can now cast your variants by using the `to()` function on `FromVariant`-enabled types, such as the following: |
| 212 | + |
| 213 | +```rust |
| 214 | +// Note: If the compiler can infer your type, the turbofish `::<T>` is optional |
| 215 | +let integer64 = variant.to::<i64>().unwrap(); |
| 216 | +let float64 = variant.to::<f64>().unwrap(); |
| 217 | +let object = variant.to_object::<ObjectType>().unwrap(); // returns Ref<ObjectType> |
| 218 | +``` |
| 219 | + |
| 220 | + |
| 221 | +### Transforms |
| 222 | + |
| 223 | +Previously, transforms were defined by the matrix identities such as `m11`, `m12`; now, they are referred by the vector name for consistency. |
| 224 | + |
| 225 | +For example: When creating an identity `Transform2D` in 0.9.x, you would create it using the following code: |
| 226 | + |
| 227 | +```rust |
| 228 | +let tform = Transform2D::new(1.0, 0.0, 0.0, 1.0, 1.0, 1.0); |
| 229 | +``` |
| 230 | + |
| 231 | +In 0.10.x you now need to create it using `from_basis_origin` and use `a`, `b`, and `origin` vectors, such as the following: |
| 232 | + |
| 233 | +```rust |
| 234 | +let tform = Transform2D::from_basis_origin( |
| 235 | + Vector2::new(1.0, 0.0), |
| 236 | + Vector2::new(0.0, 1.0), |
| 237 | + Vector2::new(1.0, 1.0), |
| 238 | +); |
| 239 | +``` |
| 240 | + |
| 241 | +### Vector types |
| 242 | + |
| 243 | +The underlying vector library as well as the implementation have been fundamentally replaced. In 0.9.x, many of the goemetric types were thinly wrapping a separate library. This led to several wrapping classes such as `Point2`, `Size2` being removed now. In addition, other geometric types -- for example `Rect2`, `Quat`, `Transform`, `Plane` -- have all been changed, and certain convenience functions may not be available anymore, depending upon the struct. |
| 244 | + |
| 245 | +For example: `Rect2` no longer has `width()` or `height()`, but lets you directly access its `size.x` or `size.y` fields. |
| 246 | + |
| 247 | +### `ClassBuilder` |
| 248 | + |
| 249 | +The [`ClassBuilder`](https://docs.rs/gdnative/latest/gdnative/prelude/struct.ClassBuilder.html) type has been extended to use the builder pattern when registering signals and properties. |
| 250 | + |
| 251 | +In 0.9, registering a signal would look like the following: |
| 252 | + |
| 253 | +```rust |
| 254 | +fn register_signals(builder: &ClassBuilder<Self>) { |
| 255 | + builder.add_signal( |
| 256 | + Signal { |
| 257 | + name: "signal1", |
| 258 | + args: &[], |
| 259 | + } |
| 260 | + ); |
| 261 | + builder.add_signal( |
| 262 | + Signal { |
| 263 | + name: "signal2", |
| 264 | + args: &[SignalArgument { |
| 265 | + name: "myArg", |
| 266 | + default: 42.0.to_variant(), |
| 267 | + export_info: ExportInfo::new(VariantType::F64), |
| 268 | + usage: PropertyUsage::DEFAULT, |
| 269 | + }], |
| 270 | + }); |
| 271 | +} |
| 272 | +``` |
| 273 | + |
| 274 | +In 0.10, this changes to: |
| 275 | + |
| 276 | +```rust |
| 277 | +fn register_signals(builder: &ClassBuilder<Self>) { |
| 278 | + builder.signal("signal1").done(); |
| 279 | + |
| 280 | + builder.signal("signal2") |
| 281 | + .with_param_custom( |
| 282 | + SignalParam { |
| 283 | + name: "myArg", |
| 284 | + default: 42.0.to_variant(), |
| 285 | + export_info: ExportInfo::new(VariantType::F64), |
| 286 | + usage: PropertyUsage::DEFAULT, |
| 287 | + }, |
| 288 | + ).done(); |
| 289 | + |
| 290 | + // If you only need a default value, you can also register a signal like this: |
| 291 | + builder.signal("signal3") |
| 292 | + .with_param_default("myArg", 42.0.to_variant()) |
| 293 | + .done() |
| 294 | +} |
| 295 | +``` |
| 296 | + |
| 297 | + |
| 298 | +### Server singletons |
| 299 | + |
| 300 | +Godot's server singletons have received a safety overhaul. As a result, all functions that take one or more parameters of type `Rid` are now marked `unsafe` and thus require being used inside an `unsafe` block or `unsafe` function. |
| 301 | + |
| 302 | +In 0.9.x, creating a canvas_item and attaching it to a parent would be done as follows: |
| 303 | +```rust |
| 304 | +let vs = unsafe { VisualServer::godot_singleton() }; |
| 305 | +let canvas = vs.canvas_create(); |
| 306 | +let ci = vs.canvas_item_create(); |
| 307 | +vs.canvas_item_set_parent(ci, canvas); |
| 308 | +``` |
| 309 | + |
| 310 | +In 0.10.x, you now must wrap the `canvas_item_set_parent` function in an `unsafe` block, such as follows: |
| 311 | + |
| 312 | +```rust |
| 313 | +let vs = unsafe { VisualServer::godot_singleton() }; |
| 314 | +let canvas = vs.canvas_create(); |
| 315 | +let ci = vs.canvas_item_create(); |
| 316 | +unsafe { |
| 317 | + vs.canvas_item_set_parent(ci, canvas); |
| 318 | +} |
| 319 | +``` |
| 320 | + |
| 321 | +#### Additional UB notes |
| 322 | + |
| 323 | +The reason for this change was due to [issue #836](https://github.com/godot-rust/godot-rust/issues/836) being raised. Developers were able to demonstrate that you could easily cause undefined behavior when using any function that accepted `Rid` as a parameter, such as the following: |
| 324 | + |
| 325 | +```rust |
| 326 | +let vs = unsafe { VisualServer::godot_singleton() }; |
| 327 | +let canvas = vs.canvas_create(); |
| 328 | +let vp = vs.viewport_create(); |
| 329 | +vs.canvas_item_set_parent(vp, canvas); // crashes immediately |
| 330 | +vs.canvas_item_set_parent(canvas, canvas); // crashes at shutdown |
| 331 | +``` |
0 commit comments