Select random player in an online game?

Godot Version

4.2

Question

In my online game I am trying to select a random player and call a function on them. No matter what I do it always gets called on the host of the game.
Here is my current script.

extends Node2D

var player_scene = preload("res://Scenes/Character/player.tscn")

var players = 0

@onready var host_manage = $LOBBY/HostManagement
@onready var game = $GameManager

var players_in_game = []

func _ready():
	Network.game = self
	create_player(Network.unique_id)

func create_player(id):
	var p = player_scene.instantiate()
	p.name = str(id)
	p.global_position = Vector2(0, 0)
	p.set_multiplayer_authority(id)
	add_child(p)
	players_in_game.append(p)
	players += 1
	
func _physics_process(delta):
	if Network.unique_id == 1:
		host_manage.visible = true
		host_manage.MOUSE_FILTER_STOP
	else:
		host_manage.visible = false
		host_manage.MOUSE_FILTER_IGNORE
		


func _on_start_pressed():
	print("Start")
	rpc("start_game")
	start_game()

	print(players_in_game.size())
	players_in_game.pick_random().new_roll()

@rpc("any_peer", "reliable")	
func start_game():
	$StartTimer.start()
	host_manage.visible = false
	host_manage.MOUSE_FILTER_IGNORE
	$LOBBY.visible = false
	game.starting_game()
	ItemGained.game_started()
	


func _on_start_timer_timeout():
	ItemGained.attacking()
	game.attacking_enabled = true

Anyone have any ideas? (I am trying call the function on a player in the start game function)

The code is pretty much unreadable.
Please use the code tag button (it looks like this </>) to enclose your code.

1 Like

Does this print out > 1?

Yes. It is more than one.

Are you using seed() somewhere in the code?
Giving seed() a fixed value will repeat the random numbers drawn.

Also: separate the line out and check if you are getting a random number selected:

var p = players_in_game.pick_random()
print(p)
p.new_roll()

There is no seed in the code and prints say p is always the player.

Then if the array has more than 1 element and it always picks the same player it must be that the array is filled with the same player.
Try printing out the array:

print(players_in_game) 
players_in_game.pick_random().new_roll()    

Each item for players_in_game are different instances and players. Also, thanks for the help so far!

We are going to see actual output then.

for n in players_in_game:   
    print(n)

Copy the actual output and paste it here.

1:<CharacterBody2D#40282096847>
1300165634:<CharacterBody2D#42463134988>
1
1

Is what the console printed out, however, around 1/4th of the time I get something similar to this:

1:<CharacterBody2D#40449869007>
97170470:<CharacterBody2D#42379249054>
97170470
97170470

How do you know that it is the same player selected always?
Try:

for n in 10: 
    print(players_in_game.pick_random())
1 Like

I got this:

411371853:<CharacterBody2D#43922752784>
411371853:<CharacterBody2D#43922752784>
1:<CharacterBody2D#41926264015>
1:<CharacterBody2D#41926264015>
1:<CharacterBody2D#41926264015>
1:<CharacterBody2D#41926264015>
411371853:<CharacterBody2D#43922752784>
411371853:<CharacterBody2D#43922752784>
1:<CharacterBody2D#41926264015>
411371853:<CharacterBody2D#43922752784>
1
1

and this another time:

768698054:<CharacterBody2D#42261808403>
1:<CharacterBody2D#39845889231>
1:<CharacterBody2D#39845889231>
1:<CharacterBody2D#39845889231>
1:<CharacterBody2D#39845889231>
1:<CharacterBody2D#39845889231>
768698054:<CharacterBody2D#42261808403>
768698054:<CharacterBody2D#42261808403>
768698054:<CharacterBody2D#42261808403>
1:<CharacterBody2D#39845889231>
768698054
768698054

Well that is random.
So how do you come to the conclusion that it is the same player selected everytime?
When there is a small set of items the odds of selecting repeats increases.

When you are testing something using random use seed() with a known value.
This will repeat the same random set every time you run it.

Start at 1.

seed(1) 
for n in 10: 
    print(players_in_game.pick_random())

Change it to 2, 3, 4 until you find a seed that will give you a different player on the first pick.
Then use this seed in your original code and go from there. This guarantees that the pick_random() returns a different player and makes it much easier to test/debug.

After trying until ten and then trying random numbers everytime I got the same result of player 1. Do you think that the error could be coming from the game being online?

No I don’t think it has anything to do with it being online.
(Although I have no experience with multiplayer code)
My best guess is that you are misreading what is and isn’t player 1.
(Please don’t take offence to that and I may well be wrong)

When you print out the player what do the numbers on the left mean exactly?
Why is there a number ‘1’ and then a larger integer ‘1200165634’?
What are those numbers?

We are going to need to see your player script and the script where you call create_player()

create_player() is in the script. The numbers are the ID’s of the players in the online game. 1 is the host and any other is a new client joining the game, and is set as their name.

I am asking for the script that calls create_player()
Also will for sure need to see the player script.

As to the numbers; they are what I thought they were.
You can see in one of your posts above that the pick_random() is working.
In one example this player comes first.

768698054:<CharacterBody2D#42261808403>

So if player 1 keeps coming up then something else is wrong.
Maybe there is something in new_roll() that is doing it. Maybe it is elsewhere.
But for sure pick_random() is working.

In fact, if you want to brute force test it, print out players_in_game again and then select a player index you know for sure isn’t player 1 (using seed() with a known value).
Then send that player to new_roll().
players_in_game[x].new_roll()
where x is the index of a player who isn’t player 1.

Create_player() is called in the ready function in the script above. All new_roll() does is set a variable in the player to true and changes it’s color. I am pretty sure it could be something with pick_random(), but it also never worked when I tried to shuffle the list and pick one.

That accounts for 1 member of players_in_game.
Now about the rest…

The big problem here is that the reader of your code has no idea what makes you think that only player 1 is selected. I asked, but you have yet to tell me.

The posts above prove that pick_random() is working. There is no question about that.
The problem that you see comes after that.

I can understand reluctance to show code; most of us load our code with nonsense and then clean it up afterwards.
Unfortunately it is impossible to debug code that isn’t shown, going only by code that does work.
I can only recommend that you create a project and dump only the minimum code necessary to select the random player (and ostensibly, demonstrate the problem).
Doing this will very likely clue you in to what the problem is.

Sorry I made it unclear. Because it is an online game, there is a menu scene where the players can all click a button to go to the world scene (after someone has started hosting a game). Every time one of these players is joined the ready function is called and creates a new player. There is no other script that will create players. When each player is instantiated they all get a unique id (Network.unique_id) and that is set as their name, and then they are added to the players_in_game list. The only code for the player and new_roll() is this:

		
func new_roll():
	new_deceiver = true
	ItemGained.new_deceiver()
	print(name)
	
	print("Deceiver")
		

Item gained is a preloaded scene that just displays a message on a canvas layer.