Understanding RPC's with Client Server
Asked Answered
G

4

0

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.

Gregory answered 1/3, 2023 at 16:18 Comment(0)
I
0

Could you put all the RPCs in a single script, keeping the simple shared file structure, but instead of detailing the actions in the call there just pass on a call to another script in a more traditional space?

@rpc
func rpc_call_to_player_gd():
     player_func()
Impersonate answered 11/5, 2023 at 0:19 Comment(0)
T
0

Gregory I have been working on a multiplayer project, and have had similar questions. The approach that has worked best for me that doesn't quite fit into your situations is to just have a singleton for the client and server that has all of your networking communications. That way any script from the client and server can send rpcs if necessary. You could also organize this further by making children of the singleton for specific features similar to one of your approaches if you are worried about the main singleton getting too populated. I think this is most similar to situation 2 but instead of it being in the main script it is a singleton.

For me the most annoying part is having to have the same function header in both the client and server even though one of the functions doesn't do anything. From what I understand the reason for this is so the sender of an rpc knows hows to format the information so that it will fit the function call on the other side. From what I know this is different from godot 3 where your rpc would give that information in the specific rpc method you used, like rpc_unreliable().

Would love to hear others approaches.

Tiernan answered 2/7, 2023 at 18:14 Comment(0)
M
0

Situation 4 is the way to go, about every other way is, to be quite honest, rubbish.

You should implement many parts of situation 2 though, as in just making a "ChatService" node on both client and server, and that deals with chat. Sadly, the example shown in situation 4 is not ideal because the UI shouldn't be responsible for sending messages, and should send them to a manager/service to deal with.

Also, the main reason that Situation 4 is better, is that you can identify unique instances, and use multiplayer spawners and synchronisers with them.

An alternative example for situation 4 would be like a specific tree or rock in a world with some RPC's like "mine".

In an actual project, you will have situation 2 for manager/services (e.g. "PlayersManager"), and situation 4 for unique instances, (e.g. a "Player") .

Mojave answered 3/7, 2023 at 7:47 Comment(0)
T
0

Mojave I had not thought about this since my project is a turn based game, so I had no need for synchronization or multiplayer spawners. For a real time multiplayer game that definitely makes more sense.

Tiernan answered 6/7, 2023 at 16:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.