Hi, I’ve been running into this issue where two players are spawned in from a lobby (One is hosting the other is a client who joins). The Host works perfectly fine and has the correct network object bools.
as shown here
But my main issue is that the Client player does not have these bools working
also as shown here
This has caused client players to obviously not work properly as they should, like how the host is.
I’ve tried looking through the code albiet not with a lot of luck I had Co-Pilot help me create this script so bear that in mind I’m terrible with networking
If anyone could give me any help or feedback I would really appriciate it!
Here is the code for the Menu, Lobby and player spawning.
Menu script
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Unity.Netcode;
using System.Collections;
public class MainMenu : NetworkBehaviour
{
[Header("UI References")]
[SerializeField] private TMP_InputField playerNameInputField;
[SerializeField] private TMP_InputField lobbyIdInputField;
[SerializeField] private Button hostButton;
[SerializeField] private Button joinButton;
[SerializeField] private GameObject mainMenuPanel;
[SerializeField] private GameObject lobbyPanel;
[SerializeField] private GameObject lobbyManager; // Drag your Lobby Manager here in the Inspector
public static class PlayerData
{
public static string PlayerName = "Player";
}
private void Start()
{
if (!ValidateUIReferences()) return;
hostButton.onClick.AddListener(OnHostButtonClicked);
joinButton.onClick.AddListener(OnJoinButtonClicked);
mainMenuPanel.SetActive(true);
lobbyPanel.SetActive(false);
if (playerNameInputField != null)
{
playerNameInputField.text = GameManager.Instance != null ? GameManager.Instance.PlayerName : PlayerData.PlayerName;
SavePlayerName(playerNameInputField.text);
playerNameInputField.onEndEdit.AddListener(SavePlayerName);
}
}
private void SavePlayerName(string name)
{
if (!string.IsNullOrWhiteSpace(name))
{
if (GameManager.Instance != null)
{
GameManager.Instance.PlayerName = name.Trim();
Debug.Log($"Player name saved: {GameManager.Instance.PlayerName}");
}
else
{
Debug.LogError("GameManager instance is missing. Cannot save player name.");
}
}
else
{
Debug.LogWarning("Player name is empty or invalid. Please enter a valid name.");
}
}
private bool ValidateUIReferences()
{
bool isValid = true;
if (!playerNameInputField)
{
Debug.LogError("Player Name Input Field is not assigned! Please assign it in the Inspector.");
isValid = false;
}
if (!lobbyIdInputField)
{
Debug.LogError("Lobby ID Input Field is not assigned! Please assign it in the Inspector.");
isValid = false;
}
if (!hostButton)
{
Debug.LogError("Host Button is not assigned! Please assign it in the Inspector.");
isValid = false;
}
if (!joinButton)
{
Debug.LogError("Join Button is not assigned! Please assign it in the Inspector.");
isValid = false;
}
if (!isValid)
{
Debug.LogError("UI references are not assigned to MainMenu! Check the Inspector.");
}
return isValid;
}
public void OnHostButtonClicked()
{
if (NetworkManager.Singleton.IsHost)
{
ShowLobbyPanel();
Debug.LogWarning("Host is already running. No need to start it again.");
return;
}
Debug.Log("Attempting to start host...");
if (NetworkManager.Singleton.StartHost())
{
ShowLobbyPanel();
Debug.Log("Host started successfully.");
}
else
{
StartCoroutine(RestartHost());
Debug.LogError("Failed to start host.");
}
}
private IEnumerator RestartHost()
{
var nm = NetworkManager.Singleton;
nm.Shutdown();
yield return new WaitWhile(() => nm.IsServer || nm.IsClient);
Debug.Log("Host shutdown complete. Restarting host...");
}
public void OnJoinButtonClicked()
{
string lobbyId = lobbyIdInputField.text.Trim();
if (string.IsNullOrEmpty(lobbyId))
{
Debug.LogError("Please enter a lobby ID.");
return;
}
Debug.Log($"Attempting to join lobby with ID: {lobbyId}...");
if (NetworkManager.Singleton.IsServer || NetworkManager.Singleton.IsHost)
{
Debug.LogWarning("NetworkManager is already running as a host or server. Shutting it down before starting client...");
NetworkManager.Singleton.Shutdown();
}
StartCoroutine(WaitForShutdownAndStartClient());
}
private IEnumerator WaitForShutdownAndStartClient()
{
yield return new WaitWhile(() => NetworkManager.Singleton.IsServer || NetworkManager.Singleton.IsClient);
if (NetworkManager.Singleton.StartClient())
{
Debug.Log("Client started successfully. Joining lobby...");
ShowLobbyPanel();
}
}
private void ShowLobbyPanel()
{
Debug.Log("Switching to Lobby Panel...");
mainMenuPanel.SetActive(false);
lobbyPanel.SetActive(true);
// Enable Lobby Manager directly
if (lobbyManager != null)
{
lobbyManager.SetActive(true);
Debug.Log("Lobby Manager activated.");
}
StartCoroutine(WaitForHostAndSetupLobby());
}
private IEnumerator WaitForHostAndSetupLobby()
{
// Wait until the host is fully started
while (!NetworkManager.Singleton.IsHost)
{
yield return null;
}
// Use the serialized reference, not FindFirstObjectByType
if (lobbyManager != null)
{
var lobbyMgrScript = lobbyManager.GetComponent<LobbyManager>();
if (lobbyMgrScript != null)
{
lobbyMgrScript.HostSetup();
}
else
{
Debug.LogError("LobbyManager script not found on lobbyManager GameObject!");
}
}
else
{
Debug.LogError("lobbyManager GameObject reference is not set in MainMenu!");
}
}
}
Lobby script
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Unity.Netcode;
using UnityEngine.SceneManagement;
using System.Collections;
using System.Collections.Generic;
public class LobbyManager : MonoBehaviour
{
[Header("UI References")]
[SerializeField] private TMP_Text playerListText;
[SerializeField] private Button startGameButton;
[SerializeField] private TMP_Text lobbyIdText;
[SerializeField] private Button readyButton;
private string lobbyId;
public static readonly Dictionary<string, List<ulong>> activeLobbies = new Dictionary<string, List<ulong>>();
// Ready system
private Dictionary<ulong, bool> playerReadyStates = new Dictionary<ulong, bool>();
private void Start()
{
StartCoroutine(WaitForNetworkManagerAndInitialize());
}
private IEnumerator WaitForNetworkManagerAndInitialize()
{
while (NetworkManager.Singleton == null)
{
yield return null;
}
if (!ValidateUIReferences()) yield break;
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
startGameButton.gameObject.SetActive(false); // Always hide here
readyButton.gameObject.SetActive(true);
readyButton.onClick.AddListener(OnReadyClicked);
UpdatePlayerList();
if (NetworkManager.Singleton.SceneManager != null)
{
NetworkManager.Singleton.SceneManager.OnSceneEvent += OnSceneEvent;
}
startGameButton.onClick.AddListener(StartGame);
}
private bool ValidateUIReferences()
{
if (playerListText && startGameButton && lobbyIdText && readyButton)
return true;
Debug.LogError("UI references are not assigned to LobbyManager!");
return false;
}
private void GenerateLobbyId()
{
if (!NetworkManager.Singleton.IsHost) return;
// Generate a unique lobby ID
lobbyId = System.Guid.NewGuid().ToString("N").Substring(0, 6);
LobbyManager.activeLobbies[lobbyId] = new List<ulong>();
lobbyIdText.text = $"Lobby ID: {lobbyId}";
Debug.Log($"Lobby created with ID: {lobbyId}");
}
private void AddPlayerToLobby(ulong playerId)
{
if (!NetworkManager.Singleton.IsHost || string.IsNullOrEmpty(lobbyId)) return;
// Ensure the lobby ID exists in the dictionary
if (!activeLobbies.ContainsKey(lobbyId))
{
Debug.LogWarning($"Lobby ID '{lobbyId}' does not exist in the dictionary. Creating a new entry.");
activeLobbies[lobbyId] = new List<ulong>();
}
if (!activeLobbies[lobbyId].Contains(playerId))
{
activeLobbies[lobbyId].Add(playerId);
playerReadyStates[playerId] = false; // Not ready by default
UpdatePlayerList();
}
}
private void UpdatePlayerList()
{
if (playerListText == null || string.IsNullOrEmpty(lobbyId)) return;
// Ensure the lobby ID exists in the dictionary
if (!activeLobbies.ContainsKey(lobbyId))
{
Debug.LogWarning($"Lobby ID '{lobbyId}' does not exist in the dictionary. Cannot update player list.");
return;
}
var playerList = activeLobbies[lobbyId];
playerListText.text = "Players in Lobby:\n";
foreach (var playerId in playerList)
{
string playerName = $"Player {playerId}";
string readyStatus = playerReadyStates.ContainsKey(playerId) && playerReadyStates[playerId] ? " (Ready)" : " (Not Ready)";
playerListText.text += $"{playerName}{readyStatus}\n";
}
}
public void UpdatePlayerListText(string playerList)
{
if (playerListText != null)
{
playerListText.text = playerList;
}
}
// Called when local player clicks ready
private void OnReadyClicked()
{
SetReadyServerRpc(NetworkManager.Singleton.LocalClientId);
readyButton.interactable = false; // Prevent spamming
}
[Rpc(SendTo.Server)]
private void SetReadyServerRpc(ulong playerId)
{
if (!playerReadyStates.ContainsKey(playerId))
playerReadyStates[playerId] = false;
playerReadyStates[playerId] = true;
UpdatePlayerListClientRpc();
// Only the host checks and starts the game
if (NetworkManager.Singleton.IsHost && AllPlayersReady())
{
StartGame();
}
}
[Rpc(SendTo.ClientsAndHost)]
private void UpdatePlayerListClientRpc()
{
UpdatePlayerList();
}
private bool AllPlayersReady()
{
if (string.IsNullOrEmpty(lobbyId) || !activeLobbies.ContainsKey(lobbyId))
return false;
var playerList = activeLobbies[lobbyId];
foreach (var playerId in playerList)
{
if (!playerReadyStates.ContainsKey(playerId) || !playerReadyStates[playerId])
return false;
}
return true;
}
public void StartGame()
{
if (!NetworkManager.Singleton.IsHost)
{
Debug.LogError("Only the host can start the game.");
return;
}
Debug.Log("All players ready! Loading Store Game scene...");
NetworkManager.Singleton.SceneManager.LoadScene("Store Game", LoadSceneMode.Single);
}
private void OnSceneEvent(SceneEvent sceneEvent)
{
if (sceneEvent.SceneEventType != SceneEventType.LoadComplete)
{
Debug.Log($"Scene loaded: {sceneEvent.SceneName}");
}
}
private void OnDestroy()
{
if (NetworkManager.Singleton != null && NetworkManager.Singleton.SceneManager != null)
{
NetworkManager.Singleton.SceneManager.OnSceneEvent -= OnSceneEvent;
}
if (NetworkManager.Singleton.IsHost && !string.IsNullOrEmpty(lobbyId))
{
activeLobbies.Remove(lobbyId);
}
}
public void HostSetup()
{
if (NetworkManager.Singleton.IsHost)
{
GenerateLobbyId();
AddPlayerToLobby(NetworkManager.Singleton.LocalClientId);
startGameButton.gameObject.SetActive(true); // Enable Start button for host
Debug.Log("HostSetup: Start button enabled for host.");
}
}
}
Spawning script
using UnityEngine;
using Unity.Netcode;
using UnityEngine.SceneManagement;
public class StoreGamePlayerSpawner : NetworkBehaviour
{
public GameObject playerPrefab;
private void OnEnable()
{
if (NetworkManager.Singleton.IsServer)
{
Debug.Log("PlayerSpawner: Subscribing to events");
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
NetworkManager.Singleton.SceneManager.OnSceneEvent += OnSceneEvent;
}
}
private void OnDisable()
{
if (NetworkManager.Singleton.IsServer)
{
NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected;
NetworkManager.Singleton.SceneManager.OnSceneEvent -= OnSceneEvent;
}
}
private void OnSceneEvent(SceneEvent sceneEvent)
{
Debug.Log($"PlayerSpawner: SceneEvent {sceneEvent.SceneEventType} for {sceneEvent.SceneName}, client {sceneEvent.ClientId}");
// Only spawn after the client has loaded the "Store Game" scene
if (sceneEvent.SceneEventType == SceneEventType.LoadComplete &&
sceneEvent.SceneName == "Store Game")
{
ulong clientId = sceneEvent.ClientId;
Debug.Log($"PlayerSpawner: Scene loaded for client {clientId}, trying to spawn player");
TrySpawnPlayer(clientId);
}
}
private void OnClientConnected(ulong clientId)
{
Debug.Log($"PlayerSpawner: Client connected {clientId}, current scene: {SceneManager.GetActiveScene().name}");
// If the client is already in the Store Game scene, spawn immediately
if (SceneManager.GetActiveScene().name == "Store Game")
{
Debug.Log($"PlayerSpawner: Store Game scene already loaded, trying to spawn player for {clientId}");
TrySpawnPlayer(clientId);
}
}
private void TrySpawnPlayer(ulong clientId)
{
Debug.Log($"PlayerSpawner: TrySpawnPlayer called for client {clientId}");
if (!NetworkManager.Singleton.ConnectedClients.ContainsKey(clientId))
{
Debug.LogWarning($"PlayerSpawner: Client {clientId} not in ConnectedClients!");
return;
}
var client = NetworkManager.Singleton.ConnectedClients[clientId];
if (client.PlayerObject != null)
{
Debug.LogWarning($"PlayerSpawner: Client {clientId} already has a PlayerObject!");
return;
}
var player = Instantiate(playerPrefab, GetSpawnPosition(), Quaternion.identity);
var networkObject = player.GetComponent<NetworkObject>();
if (networkObject == null)
{
Debug.LogError("PlayerSpawner: Player prefab does not have a NetworkObject component!");
return;
}
// Only use SpawnAsPlayerObject for player objects
networkObject.SpawnAsPlayerObject(clientId, true);
Debug.Log($"PlayerSpawner: Spawned player for client {clientId} at position {networkObject.transform.position}");
}
private Vector3 GetSpawnPosition()
{
return new Vector3(Random.Range(-5, 5), 0, Random.Range(-5, 5));
}
}
And for anyone who might want or need it. Here is the debug log
Player 1 (Host)
Player 2 (Client)



