Can the server know what information was in the packet it received?

Godot Version

4.3

Question

I’ve been refactoring my game’s netcode for about a week now, trying to get a dedicated server model working.

I’ve figured out how to send RPC packets directly to the server with:

@rpc("any_peer","call_remote","reliable",0)
func client_test(Client_ID) -> void:
	print("CLIENT CALL from ", Client_ID)

if Input.is_action_just_pressed("jump"):
	client_test.rpc_id(1, Client_ID)

This triggers a print event on the server and sends the client who sent it via their ID.

However, is there any way for the server that received this packet to convert it into a string or other variable? And is there any way to store this info? The reason is I’m trying to send actions to the server, then send it back to the client.

1 Like

Hi. If I understood correctly, you want to get client action string and store it on the server side.

Simply on the client side:

if Input.is_action_just_pressed("jump"):
    client_action.rpc_id(1, "jump")

And on the server side:

var client_actions = {}

@rpc("any_peer", "call_remote", "reliable", 0)
func client_action(Client_ID, action: String) -> void:
    client_actions[Client_ID] = action
    var client_id = multiplayer.get_remote_sender_id()
    print("Received action from Client_ID ", client_id, ": ", action)
    send_response(client_id, "Action registered: " + action)

@rpc("any_peer", "call_remote", "reliable", 1)
func send_response(client_id, message: String) -> void:
    send_response.rpc_id(client_id, message)

But, that is simple solution and you might need something more deep. Please give more details of the problem.

Updated by @pennyloafers note.

2 Likes

Thank you for this response. I don’t have a specific issue, I just need to wrap my head around client-server communication.

Just to vent, networking was never easy, but Godot’s API especially makes it so much worse. Networking logic is pretty straightforward and easy to understand, but the way you have to execute it in Godot can make code so dang convoluted.

@sarunas_ramonas Hey, I actually have a few follow up question. Do these 2 functions happen in the same script?

Just so you know you dont need to send the client id. You can retrieve the id from the packet like this.

@rpc("any_peer","call_remote","reliable",0)
func client_test() -> void:
	print("CLIENT CALL from ", multiplayer.get_remote_sender_id())

This will be a little more secure as anyone can put in someone elses id, and can save you some bandwidth

2 Likes

Yes, both functions client_action and send_response reside in the same script on server.

However, if your server logic become too complex, you can spit them into dedicated server script and action handles script.

1 Like

Could I get an example of that? That’s the system I’m going with, separate client and server manager scripts.

If you are still using the SceneMuliplayer:MultiplayerAPI you can achieve this with placing a node, on client and server, at the same node path with two different scripts depending on if it is a client or server. You could also potentially write an api class that both scripts inherent from, and contains rpc defines and stub implementations to reduce compatibility issues. The xlient and server will extend the api class and provide implementations.

But it isnt really necessary and may get convoluted to have class inheritance.

1 Like

You will also have to change your rpc call if the server has a function that the client does not. (At the same nodepath)

rpc_id(1,"target_function_name", <params>...)

I guess if you have a stub implementation on the client you could still use the old syntax.

1 Like

@pennyloafers
This is all pretty useful info, I have a specific issue though, but it’s so difficult to explain.

So basically, what I want to happen is as follows:

  1. Client and server script are in the same project, and are separated by an export preset. (This works)
  2. The server creates itself. (This works)
  3. The client joins the server when the client project is loaded. (This works)
  4. The server is the main authority over all nodes. (This works)
  5. The client receives their own player and unique ID. (This works)
  6. The client sends input to the server from their client script. The server then receives this input info on it’s server script, checks if it’s a valid action, then performs that action on the client’s player script. (This DOES NOT work)

Step 6 baffles me, because I have no idea what to do. I see the information and code examples, but I cannot wrap my head around it.

What I want to happen with step 6 is as follows:

  1. Client sends an any_peer RPC that sends the input to the server.
  2. Server receives that packet, can convert it into a string, and process it. (No idea how to do this)
  3. Server applies that input to the sending client’s player.

Edit: I could make this into a separate question, because this is a lot more specific than this one.

Sure i guess i would like to see, in detail, how you currently have point 6 implemented.

1 Like

Alright, I’ll draft it up when i get home.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.