I'm currently developing a multiplayer game in godot 4. We have two projects, one for the client and one for the server.
For the networking aspect of the game we are using rpc
calls, taking a look at the docs, we read:
Sends a remote procedure call request for the given method to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same NodePath, including the exact same node name. Behavior depends on the RPC configuration for the given method, see rpc_config() and @GDScript.@rpc. Methods are not exposed to RPCs by default. Returns null.
The area of interest for me is:
The call request will only be received by nodes with the same NodePath, including the exact same node name
Under this restriction a couple of different things could arise. To start let's make some assumptions.
We have a game which sends the following information
Client -> Server:
----user commands (sampled inputs from the client's input devices [mouse, keyboard])
----messages (text clients send through the chatbox)
----configuration (any configuration settings this client wants set)
Server -> Client:
----game snapshots (translation/position & rotation of all players, projectiles, number of kills they have, active weapon, alive/dead)
----messages (passing on messages sent from a client to the others and server messages)
Situation 1:
We store all @rpc functions in one file, attached to the Main node.
Benefits:
----The client and server tree structure aren't tied to eachother since both have a Main function
Cons:
----The Main file is polluted by many functions which may or may not be related in any way
Situation 2:
We have one Layer of abstraction so on the client and server, they both have this structure as part of their tree
Main
----UserCommands
----GameSnapshots
----Messages
----Configuration
Each of these nodes having an attached script which contains respective rpc calls.
Benefits:
----The code is more organized and the files are less polluted with random @rpc functions
Cons:
----The client and the server must always have this tree structure in their code somewhere. And you'll always have to import these
----scripts into whatever file you need to do networking code in
Situation 3:
We only have one @rpc function called send, but when we pass the data through, it contains enough information
so that it can be sorted and can then figure out which methods to call on the client/server
Benefits:
----We only have one function which sends data across the network
Cons:
----Seems like it's a re-implementation of what @rpc actually does.
Situation 4:
We put rpc calls directly in the code where we need them and don't move them elsewhere.
Benefits:
----rpc calls are stored exactly where they are used
Cons:
----the client and the server must share the exact same tree structure and naming
This is potentially annoying because if we have
Main (Client)
----Hud
--------Chatbox
------------@rpc func send_message():
then the server side would also need to have a Hud in their tree and a Chatbox, which doesn't
make sense as the server doesn't need a Hud.
End
After thinking about rpc calls, I don't seem to see any situation where rpc's are not forcing me to do something at least a little strange.
My main question here is about which method is most recommended/used by others in terms of making
multiplayer games like this. And maybe why the rpc has this restriction anyways.