Search Unity

Feedback Steam/Netcode Players join steam lobby but Host tries to spawn client with same client id

Discussion in 'Netcode for GameObjects' started by pacificeve, Mar 11, 2024.

?

Am I the only one that can't find a good working steamworks.net / NGO example?

  1. Yes

    1 vote(s)
    100.0%
  2. No

    0 vote(s)
    0.0%
  1. pacificeve

    pacificeve

    Joined:
    Jan 6, 2018
    Posts:
    9
    With two seperate computers, ISP and steam accounts they can connect to the lobby I can see in the console and its instant when I put join code in to connect. However the host doesnt spawn the client and I can't figure out why.

    upload_2024-3-11_13-28-16.png

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic; // This line is required for Dictionary<,>
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using Steamworks;
    6. using Unity.Netcode;
    7. using TMPro;
    8. using System.Linq; // Include this if you're using LINQ queries
    9.  
    10. // The rest of your SteamNetworkManager class...
    11.  
    12.  
    13. public class SteamNetworkManager : NetworkBehaviour
    14. {
    15.     [SerializeField] private TextMeshProUGUI lobbyIDTextMeshPro;
    16.     [SerializeField] private GameObject yourCustomPlayerPrefab;
    17.  
    18.     public GameObject playerPrefab;
    19.     public Button hostButton;
    20.     public Button joinButton;
    21.     public TMP_InputField lobbyIDInputField;
    22.     public Canvas mainMenuCanvas;
    23.     private LobbyEnter_t? lastLobbyEntered;
    24.     private Callback<LobbyCreated_t> lobbyCreated;
    25.     private Callback<LobbyEnter_t> lobbyEntered;
    26.     private bool isAuthenticated = false;
    27.     private const int maxLobbyPlayers = 4;
    28.     private bool hostPlayerSpawned = false;
    29.     private bool isPlayerSpawned = false;
    30.  
    31.     private bool isHosting = false;
    32.     private ulong lobbyID;
    33.     private Dictionary<ulong, bool> playerSpawnedDict = new Dictionary<ulong, bool>();
    34.     private Dictionary<ulong, CSteamID> clientSteamIDMap = new Dictionary<ulong, CSteamID>();
    35.  
    36.     private void Awake()
    37.     {
    38.         if (!SteamManager.Initialized)
    39.         {
    40.             Debug.LogError("Steam Manager not initialized.");
    41.             return;
    42.         }
    43.         Debug.Log("Steam Manager initialized.");
    44.         lobbyCreated = Callback<LobbyCreated_t>.Create(OnLobbyCreated);
    45.         lobbyEntered = Callback<LobbyEnter_t>.Create(OnLobbyEntered);
    46.     }
    47.  
    48.     private void Start()
    49.     {
    50.         StartCoroutine(CheckAuthentication());
    51.  
    52.         hostButton.onClick.AddListener(() => StartCoroutine(HostGame()));
    53.  
    54.         joinButton.onClick.AddListener(() =>
    55.         {
    56.             if (isAuthenticated)
    57.             {
    58.                 StartCoroutine(JoinGame());
    59.             }
    60.             else
    61.             {
    62.                 Debug.LogWarning("User not authenticated. Please log in with Steam.");
    63.             }
    64.         });
    65.  
    66.         NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
    67.         NetworkManager.Singleton.OnServerStarted += () => hostPlayerSpawned = true;
    68.     }
    69.  
    70.     private IEnumerator CheckAuthentication()
    71.     {
    72.         yield return new WaitUntil(() => SteamManager.Initialized);
    73.  
    74.         isAuthenticated = SteamUser.BLoggedOn();
    75.  
    76.         if (isAuthenticated)
    77.         {
    78.             Debug.Log("Player authenticated. Username: " + SteamFriends.GetPersonaName());
    79.         }
    80.         else
    81.         {
    82.             Debug.LogWarning("User not authenticated. Please log in with Steam.");
    83.         }
    84.     }
    85.  
    86.     public void StartHosting()
    87.     {
    88.         if (isHosting || NetworkManager.Singleton.IsServer)
    89.         {
    90.             Debug.LogWarning("Already hosting or already a server.");
    91.             return;
    92.         }
    93.  
    94.         isHosting = true;
    95.         SteamMatchmaking.CreateLobby(ELobbyType.k_ELobbyTypeFriendsOnly, maxLobbyPlayers);
    96.         // Additional lobby setup here...
    97.  
    98.         NetworkManager.Singleton.StartHost();
    99.         mainMenuCanvas.gameObject.SetActive(false); // Optionally hide the main menu
    100.  
    101.         isHosting = false;
    102.     }
    103.  
    104.     private IEnumerator HostGame()
    105.     {
    106.         if (isHosting || NetworkManager.Singleton.IsServer)
    107.         {
    108.             Debug.LogWarning("Already hosting or already a server.");
    109.             yield break;
    110.         }
    111.  
    112.         if (!isAuthenticated)
    113.         {
    114.             Debug.LogWarning("User not authenticated. Please log in with Steam.");
    115.             yield break;
    116.         }
    117.  
    118.         isHosting = true;
    119.         SteamMatchmaking.CreateLobby(ELobbyType.k_ELobbyTypeFriendsOnly, maxLobbyPlayers);
    120.         yield return new WaitUntil(() => lobbyCreated != null);
    121.  
    122.         NetworkManager.Singleton.StartHost();
    123.         yield return new WaitUntil(() => NetworkManager.Singleton.IsListening && NetworkManager.Singleton.IsHost && NetworkManager.Singleton.IsServer);
    124.  
    125.         CSteamID hostSteamId = SteamUser.GetSteamID();
    126.         clientSteamIDMap[NetworkManager.Singleton.LocalClientId] = hostSteamId;
    127.         Debug.Log($"Mapped host SteamID {hostSteamId.m_SteamID} to client ID {NetworkManager.Singleton.LocalClientId}");
    128.  
    129.         if (!hostPlayerSpawned)
    130.         {
    131.             // Code to spawn the host player
    132.             hostPlayerSpawned = true;
    133.         }
    134.         mainMenuCanvas.gameObject.SetActive(false);
    135.         isHosting = false;
    136.     }
    137.  
    138.     private void OnLobbyCreated(LobbyCreated_t callback)
    139.     {
    140.         if (callback.m_eResult == EResult.k_EResultOK)
    141.         {
    142.             Debug.Log("[OnLobbyCreated] Lobby created successfully! Lobby ID: " + callback.m_ulSteamIDLobby);
    143.             lobbyID = callback.m_ulSteamIDLobby;
    144.             lobbyIDTextMeshPro.text = "Lobby ID: " + lobbyID.ToString();
    145.             SteamMatchmaking.SetLobbyJoinable(new CSteamID(lobbyID), true);
    146.         }
    147.         else
    148.         {
    149.             Debug.LogError("[OnLobbyCreated] Failed to create a lobby.");
    150.         }
    151.     }
    152.  
    153.     private IEnumerator JoinGame()
    154.     {
    155.         if (!isAuthenticated)
    156.         {
    157.             Debug.LogWarning("User not authenticated. Please log in with Steam.");
    158.             yield break;
    159.         }
    160.  
    161.         if (!ulong.TryParse(lobbyIDInputField.text, out ulong parsedLobbyID))
    162.         {
    163.             Debug.LogError("Invalid Lobby ID");
    164.             yield break;
    165.         }
    166.  
    167.         lobbyID = parsedLobbyID;
    168.         Debug.Log("Attempting to join lobby with ID: " + lobbyID);
    169.  
    170.         SteamMatchmaking.JoinLobby(new CSteamID(lobbyID));
    171.         yield return new WaitUntil(() => lastLobbyEntered.HasValue);
    172.  
    173.         LobbyEnter_t lobbyEnter = lastLobbyEntered.Value;
    174.         if (lobbyEnter.m_ulSteamIDLobby == lobbyID)
    175.         {
    176.             string lobbyInfo = $"Lobby ID: {lobbyIDTextMeshPro.text}, Username: {SteamFriends.GetPersonaName()}, Connected to: {lobbyEnter.m_ulSteamIDLobby}, Spawned from host: {isPlayerSpawned}";
    177.             Debug.Log(lobbyInfo);
    178.  
    179.             if (NetworkManager.Singleton.IsClient)
    180.             {
    181.                 Debug.Log("Successfully joined lobby.");
    182.             }
    183.             else
    184.             {
    185.                 Debug.LogError("Failed to join lobby.");
    186.                 yield break;
    187.             }
    188.  
    189.             if (!NetworkManager.Singleton.IsClient)
    190.             {
    191.                 NetworkManager.Singleton.StartClient();
    192.                 yield return new WaitUntil(() => NetworkManager.Singleton.IsClient);
    193.  
    194.                 if (NetworkManager.Singleton.IsClient)
    195.                 {
    196.                     Debug.Log("Client successfully started.");
    197.                 }
    198.                 else
    199.                 {
    200.                     Debug.LogError("Failed to start client.");
    201.                     yield break;
    202.                 }
    203.             }
    204.  
    205.             mainMenuCanvas.gameObject.SetActive(false);
    206.         }
    207.         else
    208.         {
    209.             Debug.LogError("Failed to get lobby enter result.");
    210.         }
    211.     }
    212.  
    213.     private void OnLobbyEntered(LobbyEnter_t callback)
    214.     {
    215.         lastLobbyEntered = callback;
    216.         Debug.Log("Joined lobby successfully, Lobby ID: " + callback.m_ulSteamIDLobby);
    217.         Debug.Log($"Attempting to join lobby with ID: {lobbyID} - Steam ID: {SteamUser.GetSteamID().m_SteamID}");
    218.  
    219.         if (!NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsHost && !NetworkManager.Singleton.IsServer)
    220.         {
    221.             NetworkManager.Singleton.StartClient();
    222.             Debug.Log($"In LobbyEnterMethod Start Client Player authenticated - Steam ID: {SteamUser.GetSteamID().m_SteamID}, Username: {SteamFriends.GetPersonaName()}");
    223.         }
    224.     }
    225.  
    226.     private void OnClientConnected(ulong clientId)
    227.     {
    228.         Debug.Log($"Client connected: {clientId}");
    229.  
    230.         if (NetworkManager.Singleton.IsServer)
    231.         {
    232.             // Directly handle the host case
    233.             if (clientId == NetworkManager.Singleton.LocalClientId)
    234.             {
    235.                 Debug.Log("Host player spawned.");
    236.                 // Optionally, ensure the host is also mapped and spawned correctly
    237.                 EnsureHostMappingAndSpawn(clientId);
    238.                 return;
    239.             }
    240.  
    241.             // Check if the client's SteamID is mapped before attempting to spawn
    242.             if (!clientSteamIDMap.ContainsKey(clientId))
    243.             {
    244.                 Debug.LogError($"Client SteamID mapping not found for client ID: {clientId}. Cannot spawn player.");
    245.                 // Consider adding a retry mechanism or a way to request the SteamID again here
    246.                 return;
    247.             }
    248.  
    249.             // If mapped, proceed to spawn the player
    250.             if (!playerSpawnedDict.ContainsKey(clientId))
    251.             {
    252.                 Debug.Log($"Server spawning player for client ID: {clientId}");
    253.                 SpawnPlayer(clientSteamIDMap[clientId]); // This assumes SpawnPlayer can handle CSteamID directly
    254.             }
    255.         }
    256.     }
    257.  
    258.     // Example method to ensure host is correctly mapped and spawned
    259.     private void EnsureHostMappingAndSpawn(ulong clientId)
    260.     {
    261.         CSteamID hostSteamID = SteamUser.GetSteamID(); // Get the host's SteamID
    262.         if (!clientSteamIDMap.ContainsKey(clientId))
    263.         {
    264.             clientSteamIDMap[clientId] = hostSteamID;
    265.         }
    266.  
    267.         // Check if the host player needs spawning
    268.         if (!playerSpawnedDict.ContainsKey(clientId))
    269.         {
    270.             SpawnPlayer(hostSteamID);
    271.         }
    272.     }
    273.  
    274.     private void SpawnPlayer(CSteamID steamID)
    275.     {
    276.         ulong steamIdValue = steamID.m_SteamID;
    277.  
    278.         if (playerSpawnedDict.ContainsKey(steamIdValue))
    279.         {
    280.             Debug.LogWarning($"Player with Steam ID {steamIdValue} already spawned.");
    281.             return;
    282.         }
    283.  
    284.         GameObject player = Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
    285.         NetworkObject networkObject = player.GetComponent<NetworkObject>();
    286.         if (networkObject != null)
    287.         {
    288.             ulong clientID = clientSteamIDMap.FirstOrDefault(x => x.Value == steamID).Key;
    289.             networkObject.SpawnAsPlayerObject(clientID, destroyWithScene: true);
    290.             playerSpawnedDict[steamIdValue] = true;
    291.             Debug.Log($"Spawned player for Steam ID: {steamIdValue}");
    292.         }
    293.         else
    294.         {
    295.             Debug.LogError("SpawnPlayer: Missing NetworkObject component on player prefab.");
    296.         }
    297.     }
    298.  
    299.     public override void OnDestroy()
    300.     {
    301.         if (NetworkManager.Singleton != null)
    302.         {
    303.             NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected;
    304.             NetworkManager.Singleton.OnServerStarted -= () => hostPlayerSpawned = true;
    305.         }
    306.  
    307.         lobbyCreated.Dispose();
    308.         lobbyEntered.Dispose();
    309.  
    310.         base.OnDestroy();
    311.     }
    312.  
    313.     private void OnApplicationQuit()
    314.     {
    315.         if (NetworkManager.Singleton != null)
    316.         {
    317.             NetworkManager.Singleton.Shutdown();
    318.         }
    319.         SteamAPI.Shutdown();
    320.     }
    321.  
    322.     public void Update()
    323.     {
    324.         if (NetworkManager.Singleton != null)
    325.         {
    326.             if (NetworkManager.Singleton.IsHost)
    327.             {
    328.                 Debug.Log("I am the server, checking lobby status.");
    329.             }
    330.             else if (NetworkManager.Singleton.IsClient)
    331.             {
    332.                 Debug.Log("I am a client.");
    333.             }
    334.         }
    335.  
    336.         if (SteamManager.Initialized && NetworkManager.Singleton.IsServer)
    337.         {
    338.             int numLobbyMembers = SteamMatchmaking.GetNumLobbyMembers(new CSteamID(lobbyID));
    339.             Debug.Log($"Lobby has {numLobbyMembers} members.");
    340.  
    341.             for (int i = 0; i < numLobbyMembers; i++)
    342.             {
    343.                 CSteamID memberSteamID = SteamMatchmaking.GetLobbyMemberByIndex(new CSteamID(lobbyID), i);
    344.                 string memberName = SteamFriends.GetFriendPersonaName(memberSteamID);
    345.                 ulong memberSteamIDul = memberSteamID.m_SteamID;
    346.  
    347.                 // Assuming you have a method to convert a SteamID to a Netcode client ID
    348.                 ulong netcodeClientID = GetNetcodeClientIDFromSteamID(memberSteamID);
    349.  
    350.                 Debug.Log($"Member {i}: Name = {memberName}, SteamID = {memberSteamIDul}, Netcode Client ID = {netcodeClientID}");
    351.             }
    352.         }
    353.     }
    354.     private ulong GetNetcodeClientIDFromSteamID(CSteamID steamID)
    355.     {
    356.         foreach (var pair in clientSteamIDMap)
    357.         {
    358.             if (pair.Value == steamID)
    359.             {
    360.                 return pair.Key; // Return the Netcode client ID corresponding to the SteamID
    361.             }
    362.         }
    363.  
    364.         Debug.LogError($"No Netcode client ID found for SteamID: {steamID}");
    365.         return 0; // Consider returning a value that indicates an invalid ID or handle this case appropriately
    366.     }
    367. }
    368.