Skip to content

Commit 836fa99

Browse files
Merge #593
593: Implement RPC Modes r=toasteater a=TylerMartinez Users can specify RPC modes on exported functions as follows `[export(rpc = "remotesync")]` The names of the RPC modes were updated to follow the Godot official documentaion: https://docs.godotengine.org/en/stable/classes/class_multiplayerapi.html#enumerations Co-authored-by: DESKTOP-GUJB72J\Tyler <[email protected]>
2 parents e19b207 + 2b48a9a commit 836fa99

File tree

2 files changed

+114
-15
lines changed

2 files changed

+114
-15
lines changed

gdnative-core/src/nativescript/init.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,11 @@ pub type ScriptMethodFn = unsafe extern "C" fn(
220220
pub enum RpcMode {
221221
Disabled,
222222
Remote,
223-
Sync,
224-
Mater,
225-
Slave,
223+
RemoteSync,
224+
Master,
225+
Puppet,
226+
MasterSync,
227+
PuppetSync,
226228
}
227229

228230
pub struct ScriptMethodAttributes {
@@ -249,10 +251,19 @@ impl<C: NativeClass> ClassBuilder<C> {
249251
#[inline]
250252
pub fn add_method_advanced(&self, method: ScriptMethod) {
251253
let method_name = CString::new(method.name).unwrap();
252-
let attr = sys::godot_method_attributes {
253-
rpc_type: sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_DISABLED,
254+
255+
let rpc = match method.attributes.rpc_mode {
256+
RpcMode::Master => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_MASTER,
257+
RpcMode::Remote => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_REMOTE,
258+
RpcMode::Puppet => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_PUPPET,
259+
RpcMode::RemoteSync => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_REMOTESYNC,
260+
RpcMode::Disabled => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_DISABLED,
261+
RpcMode::MasterSync => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_MASTERSYNC,
262+
RpcMode::PuppetSync => sys::godot_method_rpc_mode_GODOT_METHOD_RPC_MODE_PUPPETSYNC,
254263
};
255264

265+
let attr = sys::godot_method_attributes { rpc_type: rpc };
266+
256267
let method_desc = sys::godot_instance_method {
257268
method: method.method_ptr,
258269
method_data: method.method_data,
@@ -271,18 +282,21 @@ impl<C: NativeClass> ClassBuilder<C> {
271282
}
272283

273284
#[inline]
274-
pub fn add_method(&self, name: &str, method: ScriptMethodFn) {
285+
pub fn add_method_with_rpc_mode(&self, name: &str, method: ScriptMethodFn, rpc_mode: RpcMode) {
275286
self.add_method_advanced(ScriptMethod {
276287
name,
277288
method_ptr: Some(method),
278-
attributes: ScriptMethodAttributes {
279-
rpc_mode: RpcMode::Disabled,
280-
},
289+
attributes: ScriptMethodAttributes { rpc_mode },
281290
method_data: ptr::null_mut(),
282291
free_func: None,
283292
});
284293
}
285294

295+
#[inline]
296+
pub fn add_method(&self, name: &str, method: ScriptMethodFn) {
297+
self.add_method_with_rpc_mode(name, method, RpcMode::Disabled);
298+
}
299+
286300
/// Returns a `PropertyBuilder` which can be used to add a property to the class being
287301
/// registered.
288302
///

gdnative-derive/src/methods.rs

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,55 @@
11
use syn::{spanned::Spanned, FnArg, ImplItem, ItemImpl, Pat, PatIdent, Signature, Type};
22

33
use proc_macro::TokenStream;
4+
use quote::{quote, ToTokens};
45
use std::boxed::Box;
56

7+
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
8+
pub enum RpcMode {
9+
Disabled,
10+
Remote,
11+
RemoteSync,
12+
Master,
13+
Puppet,
14+
MasterSync,
15+
PuppetSync,
16+
}
17+
18+
impl RpcMode {
19+
fn parse(s: &str) -> Option<Self> {
20+
match s {
21+
"remote" => Some(RpcMode::Remote),
22+
"remote_sync" => Some(RpcMode::RemoteSync),
23+
"master" => Some(RpcMode::Master),
24+
"puppet" => Some(RpcMode::Puppet),
25+
"disabled" => Some(RpcMode::Disabled),
26+
"master_sync" => Some(RpcMode::MasterSync),
27+
"puppet_sync" => Some(RpcMode::PuppetSync),
28+
_ => None,
29+
}
30+
}
31+
}
32+
33+
impl Default for RpcMode {
34+
fn default() -> Self {
35+
RpcMode::Disabled
36+
}
37+
}
38+
39+
impl ToTokens for RpcMode {
40+
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
41+
match self {
42+
RpcMode::Disabled => tokens.extend(quote!(RpcMode::Disabled)),
43+
RpcMode::Remote => tokens.extend(quote!(RpcMode::Remote)),
44+
RpcMode::RemoteSync => tokens.extend(quote!(RpcMode::RemoteSync)),
45+
RpcMode::Master => tokens.extend(quote!(RpcMode::Master)),
46+
RpcMode::Puppet => tokens.extend(quote!(RpcMode::Puppet)),
47+
RpcMode::MasterSync => tokens.extend(quote!(RpcMode::MasterSync)),
48+
RpcMode::PuppetSync => tokens.extend(quote!(RpcMode::PuppetSync)),
49+
}
50+
}
51+
}
52+
653
pub(crate) struct ClassMethodExport {
754
pub(crate) class_ty: Box<Type>,
855
pub(crate) methods: Vec<ExportMethod>,
@@ -17,6 +64,7 @@ pub(crate) struct ExportMethod {
1764
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
1865
pub(crate) struct ExportArgs {
1966
pub(crate) optional_args: Option<usize>,
67+
pub(crate) rpc_mode: RpcMode,
2068
}
2169

2270
pub(crate) fn derive_methods(meta: TokenStream, input: TokenStream) -> TokenStream {
@@ -69,6 +117,8 @@ pub(crate) fn derive_methods(meta: TokenStream, input: TokenStream) -> TokenStre
69117
None => 0,
70118
};
71119

120+
let rpc = args.rpc_mode;
121+
72122
let args = sig.inputs.iter().enumerate().map(|(n, arg)| {
73123
let span = arg.span();
74124
if n < arg_count - optional_args {
@@ -85,7 +135,7 @@ pub(crate) fn derive_methods(meta: TokenStream, input: TokenStream) -> TokenStre
85135
fn #name ( #( #args )* ) -> #ret_ty
86136
);
87137

88-
#builder.add_method(#name_string, method);
138+
#builder.add_method_with_rpc_mode(#name_string, method, #rpc);
89139
}
90140
)
91141
})
@@ -153,6 +203,7 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
153203
let items = match func {
154204
ImplItem::Method(mut method) => {
155205
let mut export_args = None;
206+
let mut rpc = None;
156207

157208
let mut errors = vec![];
158209

@@ -174,7 +225,6 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
174225
if let Some("export") = last_seg.as_deref() {
175226
let _export_args = export_args.get_or_insert_with(ExportArgs::default);
176227
if !attr.tokens.is_empty() {
177-
use quote::ToTokens;
178228
use syn::{Meta, MetaNameValue, NestedMeta};
179229

180230
let meta = match attr.parse_meta() {
@@ -218,7 +268,7 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
218268
}
219269
};
220270

221-
for MetaNameValue { path, .. } in pairs {
271+
for MetaNameValue { path, lit, .. } in pairs {
222272
let last = match path.segments.last() {
223273
Some(val) => val,
224274
None => {
@@ -229,9 +279,43 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
229279
return false;
230280
}
231281
};
232-
let unexpected = last.ident.to_string();
233-
let msg =
234-
format!("unknown option for export: `{}`", unexpected);
282+
let path = last.ident.to_string();
283+
284+
// Match rpc mode
285+
match path.as_str() {
286+
"rpc" => {
287+
let value = if let syn::Lit::Str(lit_str) = lit {
288+
lit_str.value()
289+
} else {
290+
errors.push(syn::Error::new(
291+
last.span(),
292+
"unexpected type for rpc value, expected Str",
293+
));
294+
return false;
295+
};
296+
297+
if let Some(mode) = RpcMode::parse(value.as_str()) {
298+
if rpc.replace(mode).is_some() {
299+
errors.push(syn::Error::new(
300+
last.span(),
301+
"rpc mode was set more than once",
302+
));
303+
return false;
304+
}
305+
} else {
306+
errors.push(syn::Error::new(
307+
last.span(),
308+
format!("unexpected value for rpc: {}", value),
309+
));
310+
return false;
311+
}
312+
313+
return false;
314+
}
315+
_ => (),
316+
}
317+
318+
let msg = format!("unknown option for export: `{}`", path);
235319
errors.push(syn::Error::new(last.span(), msg));
236320
}
237321
}
@@ -283,6 +367,7 @@ fn impl_gdnative_expose(ast: ItemImpl) -> (ItemImpl, ClassMethodExport) {
283367
}
284368

285369
export_args.optional_args = optional_args;
370+
export_args.rpc_mode = rpc.unwrap_or(RpcMode::Disabled);
286371

287372
methods_to_export.push(ExportMethod {
288373
sig: method.sig.clone(),

0 commit comments

Comments
 (0)