How to show specific gui for only specific players. MultiplayerSynchronizer

Godot Version

Godot Engine 4.3

Question

Hello! I have been making a round system. Which uh remain in the development of the architecture.

I am developing a multiplayer game. There is usually a problem with the multiple players in a hosted game when player A moves and player B also moves exactly how the player A. The way to fix that is to add MultiplayerSynchronizer with specific parameters set to replicate (position, rotation and etc.). There also may be a problem with the players input. Which is again solved through MultiplayerSynchronizer with specific parameters set to replicate (in this case if it’s camera rotation then replicate camera parameters; if it’s keyboard input then replicate the variables from the script e.g. CTRL for crouching).

My round system have rounds. When the round have ended there is intermission screen for all players for 15-20 seconds during which everything is being setup for the next round. When the round starts the intermission screen gets hidden for the players who spawned into the map.

For rendering GUI and HUD there is Control node at the CharacterBody3D node scene (this scene is the player scene). The Control have everything: intermission screen, inventory UI and HUD. (I don’t know if it’s too much to have everything in one node. If it is then please let me know and help me to resolve this. The inventory is it’s own scene).


To be honest I haven’t came up with the architecture for the round system. But in any way I should somehow hide the intermission screen ONLY for the players who have spawned on the map. I also should somehow be able to show specific HUD for the specific team the player has.

What is team? I have script extends Resource which is class_name Team. This script has specific variables like team name, team description, team color and friendly_teams. The @export var friendly_teams : Arary[Team] is important and has teams that are friendly to the specific team. Let’s say: Researchers are friendly to the Security Guards.
This means that if the player is in Researchers team then his HUD will look in yellow colors (yellow healthbar, yellow colored inventory). For the security Guards it would be gray.

There is also tecnhically specific subroles for the teams that don’t matter much. It’s literally just rank at which the player spawned as. For example, the player’s team is Security Guards but the rank is Security Chief. For other players who have spawned as Security Guards the rank would be Security Officer. The only difference for the players is what items the players have. I geniunely don’t know how to put that in my OOP design to be honest.

There is also specific problem when there is… let’s say “Red Team” which basically have specific characters with absolutely different their own interfaces. Let’s say there is super computer role. When the player is assigned to this role he is technically in the “Red Team”. He can view cameras, open/close doors, and etc. just everything to control the facility. Of course his interface is absolutely different as he would have camera map and the ability to move the mouse to the sides of the screen and move the camera in different directions that are allowed to the specific camera placed in a room.

How to control all of that? What MultiplayerSynchronizers should I even use and how and for what? How to show/hide the intermission screen on the specific occasions for the specific players (if player was spawned hide the intermission screen if it was even enabled). How to show/hide the spectators screen for the specific players?

Tecnhically, round system… would send a signal to show the intermission screen to everyone but that would mean that all players’ script are connected to these signals. Which means that if I .emit() the signal to hide the intermission screen on the round system script side then all players will have intermission screen hidden which I do not want.

To be honest the overall logic of the multiplayer high-level API is really complicated in the Godot Engine.

Probably use more RPC functions and local functions too. If UI is only shown for one client then the UI should be edited on that client, no multiplayer synchronizing needed aside from determining their team/super computer-ability.

You could use the MultiplayerSynchronizer for server-wide statistics, like score and time, if both seldom update RPCs may be more performant. Then your clients can choose to hide certain nodes in the main server-wide statistics UI.

This should be similar to how you keep players from controlling each other,

# Assuming authority and team is assigned before ready
func _ready() -> void:
    var is_authority := is_mulitplayer_authority()
    set_process_input(is_authority)
    $Camera.current = is_authority
    $HUD.team_label.text = my_team
    if my_team == "Red Team":
        $HUD.red_score.show()

Individual RPCs can determine how a team mate should respond to signals

@rpc("call_local")
func intermission_emission() -> void:
    if my_team == "Security":
        pass # do nothing
    else:
        $HUD.hide()

Hello! I am sorry that I did not respond to you back then. I wasn’t able to do that because I couldn’t actually test it. I just asked that question for the future when I am gonna need this.

Now I have tested it and encountered an issue.

I have main_game scene type of Node. There is another Node that has script attached round_manager.gd. That script calls rpc call on all players which looks like this rpc(“intermission_message”, message).

Player (client peer) scene have a Control node which is made only for UI. The Control node is actually an additional scene added to the Player scene. The Control node have attached script to it that have that rpc call defined.

Both server and client have this rpc function defined.
round_manager.gd:

@rpc("reliable")
func intermission_message(message : String):
	pass;

player_hud.gd:

@rpc("reliable")
func intermission_message(message : String):
	intermission_message_ui.text = message;

Technically, this should work. But it doesn’t. No errors and no warnings.

(Well, there are warnings but it’s just The parameter “message” is never used in the function about the server implementation of the rpc call. I geniunely hate this. Should argument names and types be same as on the client one?)