Skip to content

Commit f40fa27

Browse files
authored
Merge pull request #949 from godot-rust/qol/rpc-docs
Add docs for `#[rpc]`
2 parents b3086b5 + 343eb47 commit f40fa27

File tree

9 files changed

+112
-16
lines changed

9 files changed

+112
-16
lines changed

godot-codegen/src/special_cases/special_cases.rs

+3
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,9 @@ pub fn maybe_rename_virtual_method(rust_method_name: &str) -> &str {
366366
}
367367
}
368368

369+
// TODO method-level extra docs, for:
370+
// - Node::rpc_config() -> link to RpcConfig.
371+
369372
pub fn get_class_extra_docs(class_name: &TyName) -> Option<&'static str> {
370373
match class_name.godot_ty.as_str() {
371374
"FileAccess" => {

godot-core/src/meta/mod.rs

-5
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ mod class_name;
4949
mod godot_convert;
5050
mod method_info;
5151
mod property_info;
52-
// RpcConfig uses MultiplayerPeer::TransferMode and MultiplayerApi::RpcMode, which are only enabled in `codegen-full` feature.
53-
#[cfg(feature = "codegen-full")]
54-
mod rpc_config;
5552
mod sealed;
5653
mod signature;
5754
mod traits;
@@ -61,8 +58,6 @@ pub mod error;
6158
pub use args::*;
6259
pub use class_name::ClassName;
6360
pub use godot_convert::{FromGodot, GodotConvert, ToGodot};
64-
#[cfg(feature = "codegen-full")]
65-
pub use rpc_config::RpcConfig;
6661
pub use traits::{ArrayElement, GodotType, PackedArrayElement};
6762

6863
pub(crate) use array_type_info::ArrayTypeInfo;

godot-core/src/obj/traits.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ pub trait IndexEnum: EngineEnum {
244244
#[diagnostic::on_unimplemented(
245245
message = "Class `{Self}` requires a `Base<T>` field",
246246
label = "missing field `_base: Base<...>`",
247-
note = "A base field is required to access the base from within `self`, or when using script virtual functions",
247+
note = "A base field is required to access the base from within `self`, for script-virtual functions or #[rpc] methods",
248248
note = "see also: https://godot-rust.github.io/book/register/classes.html#the-base-field"
249249
)]
250250
pub trait WithBaseField: GodotClass + Bounds<Declarer = bounds::DeclUser> {

godot-core/src/registry/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
77

8-
// Note: final re-exports from godot-core are in lib.rs, mod private_register.
8+
// Note: final re-exports from godot-core are in lib.rs, mod register::private.
99
// These are public here for simplicity, but many are not imported by the main crate.
1010

1111
pub mod callbacks;
@@ -15,5 +15,11 @@ pub mod method;
1515
pub mod plugin;
1616
pub mod property;
1717

18+
// RpcConfig uses MultiplayerPeer::TransferMode and MultiplayerApi::RpcMode, which are only enabled in `codegen-full` feature.
19+
#[cfg(feature = "codegen-full")]
20+
mod rpc_config;
21+
#[cfg(feature = "codegen-full")]
22+
pub use rpc_config::RpcConfig;
23+
1824
#[doc(hidden)]
1925
pub mod godot_register_wrappers;

godot-core/src/meta/rpc_config.rs renamed to godot-core/src/registry/rpc_config.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use crate::{arg_into_ref, dict};
1414

1515
/// Configuration for a remote procedure call, used with `#[rpc(config = ...)]`.
1616
///
17-
/// See [Godot documentation](https://docs.godotengine.org/en/stable/tutorials/networking/high_level_multiplayer.html#remote-procedure-calls).
17+
/// Check documentation of the [`#[rpc]` attribute](attr.godot_api.html#rpc-attributes) for usage.
18+
///
19+
/// See also [Godot `@rpc` keyword](https://docs.godotengine.org/en/stable/tutorials/networking/high_level_multiplayer.html#remote-procedure-calls).
1820
#[derive(Copy, Clone, Debug)]
1921
pub struct RpcConfig {
2022
pub rpc_mode: RpcMode,

godot-macros/src/class/data_models/rpc.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub enum RpcAttr {
1919
call_local: Option<bool>,
2020
channel: Option<u32>,
2121
},
22+
2223
// `args` key in the `rpc` attribute.
2324
// Example:
2425
// const RPC_CFG: RpcConfig = RpcConfig { mode: RpcMode::Authority, ..RpcConfig::default() };
@@ -73,19 +74,22 @@ pub fn make_rpc_registrations_fn(class_name: &Ident, funcs: &[FuncDefinition]) -
7374
}
7475

7576
quote! {
76-
#[allow(clippy::needless_update)] // clippy complains about using `..RpcConfig::default()` if all fields are overridden
77+
// Clippy complains about using `..RpcConfig::default()` if all fields are overridden.
78+
#[allow(clippy::needless_update)]
7779
fn __register_rpcs(object: &mut dyn ::std::any::Any) {
7880
use ::std::any::Any;
79-
use ::godot::meta::RpcConfig;
81+
use ::godot::register::RpcConfig;
8082
use ::godot::classes::multiplayer_api::RpcMode;
8183
use ::godot::classes::multiplayer_peer::TransferMode;
8284
use ::godot::classes::Node;
8385
use ::godot::obj::{WithBaseField, Gd};
8486

85-
let mut gd = object
86-
.downcast_mut::<#class_name>()
87-
.expect("bad type erasure when registering RPCs")
88-
.to_gd();
87+
let this = object
88+
.downcast_ref::<#class_name>()
89+
.expect("bad type erasure when registering RPCs");
90+
91+
// Use fully-qualified syntax, so that error message isn't just "no method named `to_gd` found".
92+
let mut gd = ::godot::obj::WithBaseField::to_gd(this);
8993

9094
let node = gd.upcast_mut::<Node>();
9195
#( #rpc_registrations )*

godot-macros/src/lib.rs

+70
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ pub fn derive_godot_class(input: TokenStream) -> TokenStream {
518518
/// - [User-defined functions](#user-defined-functions)
519519
/// - [Associated functions and methods](#associated-functions-and-methods)
520520
/// - [Virtual methods](#virtual-methods)
521+
/// - [RPC attributes](#rpc-attributes)
521522
/// - [Constants and signals](#signals)
522523
///
523524
/// # Constructors
@@ -676,6 +677,75 @@ pub fn derive_godot_class(input: TokenStream) -> TokenStream {
676677
///
677678
/// Make sure you understand the limitations in the [tutorial](https://godot-rust.github.io/book/register/virtual-functions.html).
678679
///
680+
/// ## RPC attributes
681+
///
682+
/// You can use the `#[rpc]` attribute to let your functions act as remote procedure calls (RPCs) in Godot. This is the Rust equivalent of
683+
/// GDScript's [`@rpc` annotation](https://docs.godotengine.org/en/stable/tutorials/networking/high_level_multiplayer.html#remote-procedure-calls).
684+
/// `#[rpc]` is only supported for classes inheriting `Node`, and they need to declare a `Base<T>` field.
685+
///
686+
/// The syntax follows GDScript'a `@rpc`. You can optionally specify up to four keys; omitted ones use their default value.
687+
/// Here's an overview:
688+
///
689+
/// | Setting | Type | Possible values (first is default) |
690+
/// |---------------|------------------|----------------------------------------------------|
691+
/// | RPC mode | [`RpcMode`] | **`authority`**, `any_peer` |
692+
/// | Sync | `bool` | **`call_remote`**, `call_local` |
693+
/// | Transfer mode | [`TransferMode`] | **`unreliable`**, `unreliable_ordered`, `reliable` |
694+
/// | Channel | `u32` | any |
695+
///
696+
/// You can also use `#[rpc(config = value)]`, with `value` being an expression of type [`RpcConfig`] in scope, for example a `const` or the
697+
/// call to a function. This can be useful to reuse configurations across multiple RPCs.
698+
///
699+
/// `#[rpc]` implies `#[func]`. You can use both attributes together, if you need to configure other `#[func]`-specific keys.
700+
///
701+
/// For example, the following method declarations are all equivalent:
702+
/// ```
703+
/// use godot::classes::multiplayer_api::RpcMode;
704+
/// use godot::classes::multiplayer_peer::TransferMode;
705+
/// use godot::prelude::*;
706+
/// use godot::register::RpcConfig;
707+
///
708+
/// # #[derive(GodotClass)]
709+
/// # #[class(no_init, base=Node)]
710+
/// # struct MyStruct {
711+
/// # base: Base<Node>,
712+
/// # }
713+
/// #[godot_api]
714+
/// impl MyStruct {
715+
/// #[rpc(unreliable_ordered, channel = 2)]
716+
/// fn with_defaults(&mut self) {}
717+
///
718+
/// #[rpc(authority, unreliable_ordered, call_remote, channel = 2)]
719+
/// fn explicit(&mut self) {}
720+
///
721+
/// #[rpc(config = MY_RPC_CONFIG)]
722+
/// fn external_config_const(&mut self) {}
723+
///
724+
/// #[rpc(config = my_rpc_provider())]
725+
/// fn external_config_fn(&mut self) {}
726+
/// }
727+
///
728+
/// const MY_RPC_CONFIG: RpcConfig = RpcConfig {
729+
/// rpc_mode: RpcMode::AUTHORITY,
730+
/// transfer_mode: TransferMode::UNRELIABLE_ORDERED,
731+
/// call_local: false,
732+
/// channel: 2,
733+
/// };
734+
///
735+
/// fn my_rpc_provider() -> RpcConfig {
736+
/// RpcConfig {
737+
/// transfer_mode: TransferMode::UNRELIABLE_ORDERED,
738+
/// channel: 2,
739+
/// ..Default::default() // only possible in fn, not in const.
740+
/// }
741+
/// }
742+
/// ```
743+
///
744+
// Note: for some reason, the intra-doc links don't work here, despite dev-dependency on godot.
745+
/// [`RpcMode`]: ../classes/multiplayer_api/struct.RpcMode.html
746+
/// [`TransferMode`]: ../classes/multiplayer_peer/struct.TransferMode.html
747+
/// [`RpcConfig`]: ../register/struct.RpcConfig.html
748+
///
679749
/// # Constants and signals
680750
///
681751
/// Please refer to [the book](https://godot-rust.github.io/book/register/constants.html).

godot/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,15 @@ pub mod register {
177177
pub use godot_core::registry::property;
178178
pub use godot_macros::{godot_api, Export, GodotClass, GodotConvert, Var};
179179

180+
#[cfg(feature = "__codegen-full")]
181+
pub use godot_core::registry::RpcConfig;
182+
180183
/// Re-exports used by proc-macro API.
181184
#[doc(hidden)]
182185
pub mod private {
183186
#[cfg(feature = "__codegen-full")]
184187
pub use godot_core::registry::class::auto_register_rpcs;
188+
185189
pub use godot_core::registry::godot_register_wrappers::*;
186190
pub use godot_core::registry::{constant, method};
187191
}

itest/rust/src/register_tests/rpc_test.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
* License, v. 2.0. If a copy of the MPL was not distributed with this
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
7+
78
use godot::classes::multiplayer_api::RpcMode;
89
use godot::classes::multiplayer_peer::TransferMode;
910
use godot::classes::{Engine, MultiplayerApi};
10-
use godot::meta::RpcConfig;
1111
use godot::prelude::*;
12+
use godot::register::RpcConfig;
1213
use godot::test::itest;
1314

1415
#[derive(GodotClass)]
@@ -24,6 +25,14 @@ const CACHED_CFG: RpcConfig = RpcConfig {
2425
channel: 1,
2526
};
2627

28+
fn provide_cfg() -> RpcConfig {
29+
RpcConfig {
30+
transfer_mode: TransferMode::RELIABLE,
31+
channel: 1,
32+
..Default::default()
33+
}
34+
}
35+
2736
#[godot_api]
2837
impl RpcTest {
2938
#[rpc]
@@ -65,7 +74,10 @@ impl RpcTest {
6574
pub fn args_func_gd_self(_this: Gd<Self>) {}
6675

6776
#[rpc(config = CACHED_CFG)]
68-
pub fn arg_config(&mut self) {}
77+
pub fn arg_config_const(&mut self) {}
78+
79+
#[rpc(config = provide_cfg())]
80+
pub fn arg_config_fn(&mut self) {}
6981
}
7082

7183
// ----------------------------------------------------------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)