Only Host is able to enter Lobby (not really)

Hey there again!

I’ve come so far and am able to create a Lobby as a Host, everything works basically, except for the Client who joins the lobby by accepting the invitation from host, but the UI doesnt Update whatsoever…
I’m not sure what I’m missing, its probably a small line of code, but I cant seem to find it…
Also, does the client start the game and sit on menu until accepting, or does he have to close the game completely and then accept the invitation?

here is my menu code:

using Mirror;
using Steamworks;
using UnityEngine;
using UnityEngine.SceneManagement;

public class Menu : MonoBehaviour
{

[SerializeField] private GameObject landingPagePanel = null;
[SerializeField] private GameObject lobbyPanel = null;
[SerializeField] private bool useSteam = false;

private const string HostAddressKey = "HostAddress";

protected Callback<LobbyCreated_t> LobbyCreated;
protected Callback<GameLobbyJoinRequested_t> GameLobbyJoinRequested;
protected Callback<LobbyEnter_t> LobbyEntered;

public static CSteamID LobbyId { get; private set; }


private void Start()
{
    if (!useSteam) return;

    LobbyCreated = Callback<LobbyCreated_t>.Create(OnLobbyCreated);
    GameLobbyJoinRequested = Callback<GameLobbyJoinRequested_t>.Create(OnGameLobbyJoinRequested);
    LobbyEntered = Callback<LobbyEnter_t>.Create(OnLobbyEntered);
}

public void HostLobby()
{
    landingPagePanel.SetActive(false);

    if (useSteam)
    {
        lobbyPanel.SetActive(true);
        SteamMatchmaking.CreateLobby(ELobbyType.k_ELobbyTypeFriendsOnly, 4);
        return;
    }
    
    NetworkManager.singleton.StartHost();
}

public void PlayGame()
{
SceneManager.LoadScene("gameScene");

}

public void QuitGame()
{
Debug.Log("Quit");
Application.Quit();

}

private void OnLobbyCreated(LobbyCreated_t callback)
{
    if (callback.m_eResult != EResult.k_EResultOK)
    {
        lobbyPanel.SetActive(false);
        landingPagePanel.SetActive(true);
        return;
    }
    
    
    NetworkManager.singleton.StartHost();
    
    LobbyId = new CSteamID(callback.m_ulSteamIDLobby);

    SteamMatchmaking.SetLobbyData(
        LobbyId,
        HostAddressKey,
        SteamUser.GetSteamID().ToString());
}
private void OnGameLobbyJoinRequested(GameLobbyJoinRequested_t callback)
{
    SteamMatchmaking.JoinLobby(callback.m_steamIDLobby);
}
private void OnLobbyEntered(LobbyEnter_t callback)
{
    if (NetworkServer.active) return;
    
    string hostAddress = SteamMatchmaking.GetLobbyData(
        new CSteamID(callback.m_ulSteamIDLobby),
        HostAddressKey);

    NetworkManager.singleton.networkAddress = hostAddress;
    NetworkManager.singleton.StartClient();
    
    landingPagePanel.SetActive(false);
    lobbyPanel.SetActive(true);
}

}

If you need any more code to figure out what wrong, please let me know.

Cheers

I believe the client needs to have the game open for the invitation to work correctly. What version of fizzy steam works and Unity are you using?

both are the latest versions…
The clients can still connect and I can start the game just fine, its just they never see or join the lobby, except for the host.
Can I check in what scene the player is, and if he joins a lobby, it automatically joins the lobby scene?

I also just realized, except for the host, all the clients who join have their steam name show up normally in the lobby, however, once I start the game, everyone gets assigned the name of someone else.
Example:
Lobby:
Player 1 (host)
Player 2
Player 3
Player 4

and once I start the game, it gets randomly assigned (except the host)
Player 1 (stays always the same)
Player 2 is now called Player 4
Player 4 is now called Player 3
Player 3 is now called Player 2
It’s completely random, I tried it couple a times, sometimes everyone gets their name correct.

I’m almost certain it has to do with this part of the code:

public override void OnServerAddPlayer(NetworkConnectionToClient conn)
{
base.OnServerAddPlayer(conn);

MyNetworkPlayer player = conn.identity.GetComponent<MyNetworkPlayer>();
Players.Add(player);

CSteamID steamId = SteamMatchmaking.GetLobbyMemberByIndex(
  Menu.LobbyId, 
  numPlayers - 1);

var playerInfoDisplay = conn.identity.GetComponent<MyNetworkPlayer>();

playerInfoDisplay.SetSteamId(steamId.m_SteamID);

player.SetPartyOwner(Players.Count == 1);

}

I tried stuff out, like this for example:

public override void OnServerAddPlayer(NetworkConnectionToClient conn)
{
base.OnServerAddPlayer(conn);

MyNetworkPlayer player = conn.identity.GetComponent<MyNetworkPlayer>();
Players.Add(player);

CSteamID steamId = SteamMatchmaking.GetLobbyMemberByIndex(
  Menu.LobbyId, 
  numPlayers - 1);

if (player.isLocalPlayer)
{
  var playerInfoDisplay = conn.identity.GetComponent<MyNetworkPlayer>();
  playerInfoDisplay.SetSteamId(steamId.m_SteamID);
}

player.SetPartyOwner(Players.Count == 1);

}

but it doesnt work properly

What are the client’s seeing after they join?
Have you done the lecture updating everything to the latest Steam/Mirror/Unity?

I just fixed the lobby thing, the bigger problem seems to be the names though… can you help me with that?

So whenever everyone joins the lobby (let’s say 4 ppl)
and I, as the host, start the game, everyone except the host gets their name wrong

just like I stated in the previous post, it looks like this:
Player 1 (stays always the same) (host)
Player 2 is now called Player 4
Player 4 is now called Player 3
Player 3 is now called Player 2
It’s completely random, I tried it couple a times, sometimes everyone gets their name correct.

Can you help me with this please?

I have tried lots of things, like:

public override void OnServerAddPlayer(NetworkConnectionToClient conn)
{
base.OnServerAddPlayer(conn);

MyNetworkPlayer player = conn.identity.GetComponent<MyNetworkPlayer>();
Players.Add(player);

CSteamID steamId = SteamMatchmaking.GetLobbyMemberByIndex(
  Menu.LobbyId, 
  numPlayers - 1);

  var playerInfoDisplay = conn.identity.GetComponent<MyNetworkPlayer>();
  playerInfoDisplay.SetSteamId(steamId.m_SteamID);

  for (int i = 0; i < Players.Count; i++)
  {
    player.SetPlayerName(SteamFriends.GetFriendPersonaName(steamId));
  }

player.SetPartyOwner(Players.Count == 1);

}

I’ll provide you with all my code I have so far, might be easier to understand

this is my NetworkPlayer script:

using System;
using UnityEngine;
using Mirror;
using Steamworks;
using TMPro;

public class MyNetworkPlayer : NetworkBehaviour
{

[SyncVar(hook = nameof(AuthorityHandlePartyOwnerStateUpdated))]
private bool isPartyOwner = false;


[SyncVar(hook = nameof(HandleSteamIdUpdated))] 
private ulong steamID;

[SerializeField] private TMP_Text playerNameText;


public static event Action<bool> AuthorityOnPartyOwnerStateUpdated;
public static event Action ClientOnInfoUpdated;



public string GetDisplayName()
{
    return playerNameText.text;
    
}


public void SetPlayerName(string nickName)
{
    playerNameText.text = nickName;
}


public bool GetIsPartyOwner()
{
    return isPartyOwner;
}



#region Server

public void SetSteamId(ulong steamIdNum)
{
    steamID = steamIdNum;
}

[Server]
public void SetPartyOwner(bool state)
{
    isPartyOwner = state;
}

#endregion

#region Client

public override void OnStartClient()
{
    if (NetworkServer.active) return;
    ClientOnInfoUpdated?.Invoke();
    ((MyNetworkManager)NetworkManager.singleton).Players.Add(this);
}

public override void OnStopClient()
{
    ClientOnInfoUpdated?.Invoke();
    
    if (isClientOnly) return;
    ((MyNetworkManager)NetworkManager.singleton).Players.Remove(this);

    if (!hasAuthority) return;
}



private void HandleSteamIdUpdated(ulong oldSteamId, ulong newSteamId)
{
    ClientOnInfoUpdated?.Invoke();
    var cSteamId = new CSteamID(newSteamId);
    playerNameText.text = SteamFriends.GetFriendPersonaName(cSteamId);
    ClientOnInfoUpdated?.Invoke();

}






public override void OnStartAuthority()
{
    if (NetworkServer.active) return;
}



[Command]
public void CmdStartGame()
{
    if (!isPartyOwner) return;
    ((MyNetworkManager)NetworkManager.singleton).StartGame();
}


#endregion

private void AuthorityHandlePartyOwnerStateUpdated(bool oldState, bool newState)
{
    if (!hasAuthority) return;

    AuthorityOnPartyOwnerStateUpdated?.Invoke(newState);
}

}

this is my NetworkManager script:

using System;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
using Steamworks;
using TMPro;

public class MyNetworkManager : NetworkManager
{

public static event Action ClientOnConnected;
public static event Action ClientOnDisconnected;

private bool isGameInProgress;
public List Players { get; } = new();

#region Server

public override void OnServerConnect(NetworkConnectionToClient conn)
{
if (!isGameInProgress) return;

conn.Disconnect();

}

public override void OnServerDisconnect(NetworkConnectionToClient conn)
{
MyNetworkPlayer player = conn.identity.GetComponent();

Players.Remove(player);

base.OnServerDisconnect(conn);

}

public override void OnStopServer()
{
Players.Clear();

isGameInProgress = false;

}

public void StartGame()
{
if (Players.Count < 1) return;

isGameInProgress = true;

ServerChangeScene("gameScene");

}

// ReSharper disable Unity.PerformanceAnalysis
public override void OnServerAddPlayer(NetworkConnectionToClient conn)
{
base.OnServerAddPlayer(conn);

MyNetworkPlayer player = conn.identity.GetComponent<MyNetworkPlayer>();
Players.Add(player);

CSteamID steamId = SteamMatchmaking.GetLobbyMemberByIndex(
  Menu.LobbyId, 
  numPlayers - 1);

  var playerInfoDisplay = conn.identity.GetComponent<MyNetworkPlayer>();
  playerInfoDisplay.SetSteamId(steamId.m_SteamID);

  
  player.SetPartyOwner(Players.Count == 1);

}

public override void OnServerSceneChanged(string sceneName)
{
foreach (MyNetworkPlayer player in Players)
{
GameObject baseInstance = Instantiate(playerPrefab, GetStartPosition().position, Quaternion.identity);
NetworkServer.Spawn(baseInstance, player.connectionToClient);
}
}

#endregion

#region Client
public override void OnClientConnect()
{
base.OnClientConnect();
ClientOnConnected?.Invoke();
}

public override void OnClientDisconnect()
{
base.OnClientDisconnect();
ClientOnDisconnected?.Invoke();
}

public override void OnStopClient()
{
Players.Clear();
}

#endregion

}

How did you fix the lobby issue?

For the player names, I could see them getting scrambled here if they are in order:

CSteamID steamId = SteamMatchmaking.GetLobbyMemberByIndex(
  Menu.LobbyId, 
  numPlayers - 1);

  var playerInfoDisplay = conn.identity.GetComponent<MyNetworkPlayer>();
  playerInfoDisplay.SetSteamId(steamId.m_SteamID);

  for (int i = 0; i < Players.Count; i++)
  {
    player.SetPlayerName(SteamFriends.GetFriendPersonaName(steamId));
  }

Can you add some debug statements here and see if player’s are being assigned the right name.

I had to add another serializefield in my steam script, connect it to my actual lobby UI + Parent and set it active whenever someone joins a lobby.
Nothing too crazy…

I have been trying a LOT of things in order to get the names right, asked for help on a couple of forums, but it looks like you are my only hope :D.

So, interestingly, after setting a breakpoint at this line of code:

public void SetPlayerName(string nickName)
{
(breakpoint) playerNameText.text = nickName;
}

I went through hosting → starting a game for like 100x and it went well every single time, which made me think about something. Coroutine.
Since whenever I use debugging, I prevent all the players from the Lobby to join the game at the same time.
And so I’ve tried to change this code:

public override void OnServerSceneChanged(string sceneName)
{
foreach (MyNetworkPlayer player in Players)
{
GameObject baseInstance = Instantiate(playerPrefab, GetStartPosition().position, Quaternion.identity);
NetworkServer.Spawn(baseInstance, player.connectionToClient);
}
}

to this:

IEnumerator WaitForPlayer()
{
yield return new WaitForSeconds(3f);
}

public override void OnServerSceneChanged(string sceneName)
{
foreach (MyNetworkPlayer player in Players)
{
GameObject baseInstance = Instantiate(playerPrefab, GetStartPosition().position, Quaternion.identity);
NetworkServer.Spawn(baseInstance, player.connectionToClient);
StartCoroutine(WaitForPlayer());

}

}

But unfortunately, this didnt change anything…

so TLDR:
Debugging prevented the players from joining the gamescene all at the same time, which made it work.
So I tried using the Coroutine code (see codeblock above) which didn’t work.

is my thinking direction correct, or does it have to do with something else?

Could you somehow use this to set the lobby display name as well as the player name in game? I assume right now the lobby names are being assigned in order of entry, and the then the names in game are assigned using the steam info.

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.

Privacy & Terms