Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

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)
    50.0%
  2. No

    1 vote(s)
    50.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.