-
-
Notifications
You must be signed in to change notification settings - Fork 287
api discomfort: MultiplayerApi.set_multiplayer_peer() requires manual upcast #796
Description
It's confusing to alter Godot's MultiplayerAPI on the Rust side of things.
In GDScript, you can freely assign the MultiplayerAPI a MultiplayerPeer, which lets you change things like the port, communication type, and networking privacy (WAN/LAN). MultiplayerPeer is inherited by the specialized peer types, like ENetMultiplayerPeer and WebRTCMultiplayerPeer.
So, networking in Godot looks just like the documentation:
const PORT: int = 1234
const MAX_CLIENTS: int = 16
# grab the API
var multiplayer_api: MultiplayerAPI = get_tree().get_multiplayer()
# make a server
var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new()
peer.create_server(PORT, MAX_CLIENTS)
# hand it to the global MultiplayerAPI
multiplayer_api.multiplayer_peer = peer That works great in GDScript! However, Rust isn't happy when you try to do that.
use godot::{
engine::{ENetMultiplayerPeer, MultiplayerPeer},
prelude::*,
};
#[derive(GodotClass)]
#[class(base = Node, init)]
struct SomeNode {
base: Base<Node>,
}
#[godot_api]
impl INode for SomeNode {
fn ready(&mut self) {
const PORT: u16 = 1234;
const _MAX_CLIENTS: u8 = 16;
// grab the multiplayer api
let multiplayer_api = self
.base_mut()
.get_tree()
.unwrap()
.get_multiplayer()
.unwrap();
// make a server
let mut peer: Gd<ENetMultiplayerPeer> = ENetMultiplayerPeer::new_gd();
peer.create_server(PORT.into());
// unrelated, but two quick notes about `peer.create_server(...)`:
// - why does it always return a `crate::prelude::Error`? why isn't the error in a result, like `Result<(), Error>`?
// - does it not support specifying the `max_clients`/channels/bandwidth props?
// hand it to the global MultiplayerAPI
multiplayer_api.set_multiplayer_peer(peer); // COMPILE ERROR!
// the following also have compile errors:
multiplayer_api.set_multiplayer_peer(peer.into());
multiplayer_api.set_multiplayer_peer(peer.cast());
multiplayer_api.set_multiplayer_peer(peer.cast::<MultiplayerPeer>());
multiplayer_api.set_multiplayer_peer(MultiplayerPeer::from(peer));
// but this works!
multiplayer_api.set_multiplayer_peer(peer.upcast());
}MultiplayerApi.set_multiplayer_peer() expects a MultiplayerPeer instead of any inherited node.
In other words, set_multiplayer_peer() would preferably take some kind of "impl MultiplayerPeer" over a MultiplayerPeer, as without it, you're left doing an upcast(), which doesn't appear to be documented for the type.
error[E0308]: mismatched types
--> src/lib.rs:55:50
|
55 | multiplayer_api.set_multiplayer_peer(peer); // COMPILE ERROR!
| -------------------- ^^^^ expected `Gd<MultiplayerPeer>`, found `Gd<ENetMultiplayerPeer>`
| |
| arguments to this method are incorrect
|
= note: expected struct `godot::prelude::Gd<godot::classes::MultiplayerPeer>`
found struct `godot::prelude::Gd<godot::classes::ENetMultiplayerPeer>`Fixing this across the many types of this workspace might be incompatible with the current method of resolving Inherits<T>. I can understand the difficulty - there isn't a form of class inheritance in Rust, and it's awkward to generate a hacky stateful trait for each type that requires inheritance.
Nonetheless, I think taking an impl Inherits<MultiplayerPeer> would suffice in this method and many others. I'm happy to attempt fixing this if it's something accessible to a first-time contributor.
Otherwise, a small documentation example would help a lot for multiplayer features in general, as the inheritance + getter-setter patterns for these types are somewhat obfuscated. Thank you for the incredible crate! :)