How do I allow for multiple multiplayer rooms?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By bubbybumble

The Problem

I want to create a multiplayer game where you can have a bunch of multiplayer game rooms, similar to games like Among Us where there is a list of rooms you can join or create.

Possible Solution?

I have done some research on this topic, and found that one way to go about this is changing the port number on each room. For instance, room 1 would be on port 6970 and room 2 on 6971, and both games could run parallel to each other.

Problems I Have With This

Does an approach like this work for a single server file, and how do I allow players to see these rooms and join them? I assume I can keep one port aside just to show the server list, but then I would have to get the player to connect to a different port, and show available ports on the server-list.

I can’t seem to find any resources on how to achieve this goal, so I may be suggesting really bad ideas.

would each room be a different server and thus have different players playing on it, or are there supposed to be multiple rooms in one game server? (I haven’t played among us)

Millard | 2020-11-20 19:11

From what I know Among Us uses IDs or codes(as they are known by the players). The client sends and receives this IDs from the server. And the server creates a room for each ID. I think they use containers for each room, but that might be very complicated. You could try like creating the room as a class in an array and the server could loop through the array and send information to the clients, but as you may imagine that is very resource-heavy. I am not an expert in networking so you should take what I said as a general idea and search for more networking pages.

ra45 | 2020-11-21 09:30

They are like, multiple servers, but I doubt they have each room handled by a single, physical server. Most FPS games achieve this somehow, with different games happening at the same time.

bubbybumble | 2020-11-21 16:11

What do you mean containers for each room? I’ve never heard that term in networking. I’ll look into that though, and see if this is what I’m looking for.

bubbybumble | 2020-11-21 16:13

I’m just trying to understand, is there a more than one room in a game, and is it isolated until you move into another room?

Millard | 2020-11-21 16:20

@bubbybumble

What do you mean containers for each room?

I mean you create a program that represents one room(talking to clients, etc…), and for every room, you run another instance of it. You also need a program that manages them and assigns IDs or ports.

@Millard He’s talking about a multiplayer room (a lobby).

would each room be a different server and thus have different players playing on it

something like that

ra45 | 2020-11-21 19:03

:bust_in_silhouette: Reply From: tx350z

The answer to your question is “it depends”. You can implement this in several ways. The best solution depends upon the nature of the games in the “rooms” and how many simultaneous players will be in connected. For example, a single Godot server app can probably handle a few hundred poker players, but maybe only a dozen or less PVP real-time battle players.

First, you need to become very familiar with Godot’s built-in RPC networking support. Godot’s RPC support is great, but it was built-in primarily for P2P games where one player acts as the server. This means that the “server” and the “clients” are all running exactly the same code. HOWEVER, the built-in networking works very well for dedicated server apps also.

The key knowledge point is that RPC calls between “peers” (which includes the server) relies completely on the node_path and function name on both ends of the connection. There is no requirement for the code in the server and clients to be the same. Only the node-paths need to be the same.

The best way I’ve found to do this is to place all RPC “remote” functions in one or more auto loaded singletons. So the paths for these nodes is simply “/root/singleton-name”.

For example, an auto-loaded node named “rpc_functions” will have a node-path of “/root/rpc_functions”. Let’s say you have a function that is called for user login. In the client’s version of rpc_functions this might be

signal user_validation(results);

# called from client login scene to check user name and password
func user_login(username:String, password:String)->void:
	rpc(1, "authenticate_user", {"username":username, "password":password});

# called remotely from server to return authentication results
remote user_login_callback(results:Dictionary)->void:
	# Use a signal to send the results to whatever logic needs it
	emit_signal("user_validation", results);

In the server version of rpc_functions you will need a method like this.

remote func authenticate_user(params:Dictionary)->void:
	var results:Dictionary = {};
	
	# Do user validation and populate results
	
	# send authentication results back to the calling client
	rpc(get_tree().get_rpc_sender_id(), results);

If your game will be truly massive-multiplayer, you’ll likely need a much more scalable server-side solution. For example, look at Nakama server which is very scalable but does not support Godot’s built-in RPC networking and is challenging to set up don’t have a lot of experience with server administration.

Hope this helps.

Correction: The server-size code should be as follows (method name is missing from the RPC callback)

remote func authenticate_user(params:Dictionary)->void:
	var results:Dictionary = {};
	
	# Do user validation and populate results
	
	# send authentication results back to the calling client
	rpc(get_tree().get_rpc_sender_id(), "user_login_callback", results);

tx350z | 2020-12-15 12:21

since v3.3, for single id rpc call, i think its rpc_id(get_tree().get_rpc_sender_id(), "user_login_callback", results); ? anyway, very insightful answer, thanks. this stuff should be in the official documentation IMO

cs341 | 2021-08-30 23:10

My approach is to have a separate node3D node for each room on the server side, uniquely named and attached under scene_tree.root. The client-side follows the same structure, but each client only connects to their respective room. The server controls the process and physics_process. It works. However, I have encountered another issue: since the server has multiple node3D rooms, I need to plan their positions to avoid mutual interference, such as collisions, fired bullets, and raycasts.

I find the solve

var newwindow = Window.new()
newwindow.set_world_3d(World3D.new())
newwindow.set_use_own_world_3d(true)
newwindow.set_name(nodeName)
node.set_name(nodeName)
get_tree().get_root().add_child(newwindow)
newwindow.add_child(node)