Godot Version
4.2.2
Question
I’m currently trying to create a lobby that works that I can later implement into my game. I feel like I’m on the cusp of it working. When the game loads there’s a menu with two buttons, Host and Join. When a player presses the Host button, it creates a lobby, and in that lobby is a list of players in the lobby with their ready state, and a Ready Button. By default, players are not ready, and when they press ready it should change their ready state to ready, then if they press the button again it should make them not ready.
What is happening is that when a player presses the Ready button, it shows that they are ready on the other players screen, but not on their own! This means I never fulfill the conditions of having all of the players ready to start the game. Here is the related code.
Menu script:
extends Control
@onready var host_button = $HostButton
@onready var join_button = $JoinButton
func _ready():
host_button.pressed.connect(_on_host_button_pressed)
join_button.pressed.connect(_on_join_button_pressed)
func _on_host_button_pressed():
NetworkManager.host_game()
var lobby = preload("res://scenes/Lobby.tscn").instantiate()
get_tree().root.add_child(lobby)
queue_free()
func _on_join_button_pressed():
NetworkManager.join_game("127.0.0.1") # Use localhost for testing
var lobby = preload("res://scenes/Lobby.tscn").instantiate()
get_tree().root.add_child(lobby)
queue_free()
NetworkManager Script:
extends Node
const PORT = 7000
const MAX_PLAYERS = 2
signal player_connected(peer_id)
signal player_disconnected(peer_id)
signal serverFull()
signal connection_failed()
signal connection_succeeded()
signal player_ready_changed(peer_id, is_ready)
var peer = ENetMultiplayerPeer.new()
@export var players_ready = {}
func host_game():
var error = peer.create_server(PORT, MAX_PLAYERS)
if error == OK:
multiplayer.multiplayer_peer = peer
print("Server started")
else:
print("Failed to create server")
func join_game(ip_address):
var error = peer.create_client(ip_address, PORT)
if error == OK:
multiplayer.multiplayer_peer = peer
print("Attempting to connect to server")
else:
print("Failed to create client")
connection_failed.emit()
func _ready():
multiplayer.peer_connected.connect(_on_peer_connected)
multiplayer.peer_disconnected.connect(_on_peer_disconnected)
multiplayer.connected_to_server.connect(_on_connected_to_server)
multiplayer.connection_failed.connect(_on_connection_failed)
multiplayer.server_disconnected.connect(_on_server_disconnected)
func _on_peer_connected(id):
print("Peer connected: " + str(id))
if multiplayer.is_server() and multiplayer.get_peers().size() > MAX_PLAYERS - 1:
# Server is full, disconnect the peer
peer.disconnect_peer(id)
else:
player_connected.emit(id)
players_ready[id] = false
func _on_peer_disconnected(id):
print("Peer disconnected: " + str(id))
player_disconnected.emit(id)
players_ready.erase(id)
func _on_connected_to_server():
print("Successfully connected to server")
connection_succeeded.emit()
func _on_connection_failed():
print("Failed to connect to server")
connection_failed.emit()
func _on_server_disconnected():
print("Server disconnected")
# Handle server disconnection (e.g., return to main menu)
@rpc("any_peer", "reliable")
func player_ready(is_ready):
var id = multiplayer.get_remote_sender_id()
players_ready[id] = is_ready
player_ready_changed.emit(id, is_ready)
if multiplayer.is_server() and all_players_ready():
start_game.rpc()
func get_player_ready(peer_id):
return players_ready.get(peer_id, false)
func all_players_ready():
return players_ready.size() == MAX_PLAYERS and players_ready.values().all(func(x): return x)
@rpc("authority", "reliable")
func start_game():
get_tree().change_scene_to_file("res://scenes/Game.tscn")
@rpc("authority", "reliable")
func server_full():
serverFull.emit()
Lobby Script:
extends Control
@onready var player_list = $PlayerList
@onready var ready_button = $ReadyButton
var players = {}
func _ready():
NetworkManager.player_connected.connect(_on_player_connected)
NetworkManager.player_disconnected.connect(_on_player_disconnected)
NetworkManager.player_ready_changed.connect(_on_player_ready_changed)
ready_button.pressed.connect(_on_ready_button_pressed)
# Add local player
var local_id = multiplayer.get_unique_id()
_on_player_connected(local_id)
func _on_player_connected(peer_id):
players[peer_id] = {
"name": "Player " + str(peer_id),
"ready": false
}
update_player_list()
func _on_player_disconnected(peer_id):
players.erase(peer_id)
update_player_list()
func update_player_list():
player_list.clear()
for peer_id in players:
var player = players[peer_id]
var status = " (Ready)" if NetworkManager.get_player_ready(peer_id) else " (Not Ready)"
player_list.add_item(player["name"] + status)
# Update local ready button
var local_id = multiplayer.get_unique_id()
if local_id in players:
if players[local_id]["ready"]:
ready_button.text = "Not Ready"
else:
ready_button.text = "Ready"
func _on_ready_button_pressed():
var local_id = multiplayer.get_unique_id()
var new_ready_state = !players[local_id]["ready"]
NetworkManager.player_ready.rpc(new_ready_state)
func _on_player_ready_changed(peer_id, is_ready):
if peer_id in players:
players[peer_id]["ready"] = is_ready
update_player_list()
# If it's the local player, update the button text immediately
if peer_id == multiplayer.get_unique_id():
ready_button.text = "Not Ready" if is_ready else "Ready"
Oh, and the NetworkManager script is autoloaded in the project.
I feel like I’m missing something simple here. What am I missing?