Ok, so I've managed to put together something that my brain can grasp better.
I have an autoload script which I'll call RelayPoint.gd
extends Node
signal data_received(data:Variant, req_id:String);
#functions go inside
var listener:Dictionary = {};
@rpc("any_peer")
func req(req_id:String, args:Array = []) -> void: #targets all clients
if multiplayer.get_remote_sender_id() == 0: return rpc("req", req_id, args);
if multiplayer.get_remote_sender_id() == multiplayer.get_unique_id(): return;
var data = listener[req_id].callv(args);
rpc_id(multiplayer.get_remote_sender_id(), "_emit_data", data, req_id);
@rpc("any_peer")
func req_to(target:int, req_id:String, args:Array = []) -> void: #targets specific client
if multiplayer.get_remote_sender_id() == 0: return rpc_id(target, "req_to", target, req_id, args);
var data = listener[req_id].callv(args);
rpc_id(multiplayer.get_remote_sender_id(), "_emit_data", data, req_id);
@rpc("any_peer")
func _emit_data(data:Variant, req_id:String = "") -> void: data_received.emit(data, req_id);
func on(listen_id:String, function:Callable) -> void:
listener[listen_id] = function;
Essentially, you can use Server.on(id:String, function:Callable)
from any script and it'll save it in a dictionary. Now from any script (even ones you didn't call Server.on()
in), you can call Server.req("id_you_chose", [required, args])
to call that function. (You can also use Server.req_to()
if you're requesting data from a specific peer).
To actually catch responses, you need to add Server.connect("data_received", process_data)
to the relevant script's _ready()
function, and add a function called process_data()
, which looks like this.
extends Node
func process_data(data:Variant, req_id:String) -> void:
match req_id:
"id_you_chose": pass; #do whatever to the 'data' you returned
Now any connected peer (or the host) can request data from everyone (or a specific peer) and get a response directly to them from any script.
Is this efficient? Idk. It just works. 🫤