Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question How do I start a Netcode server if NetworkManager is in a different scene?

Discussion in 'Scripting' started by LiterallyCoder, Mar 17, 2023.

  1. LiterallyCoder

    LiterallyCoder

    Joined:
    Jul 25, 2020
    Posts:
    87
    Hello everyone,

    I've recently been trying to learn Netcode for Gameobjects and ran into a problem. I've created two scenes: a menu scene and a game scene. I placed the NetworkManager in the game scene, and I'm trying to access it in the menu scene. I have three buttons in my menu scene, one to start the server, one to start the host, and one to start the client. As is, I am getting null reference exceptions (obviously) when I press a button in the menu. Since the game scene isn't loaded yet (that's the whole point of the menu scene), the NetworkManager gameobject cannot be accessed. I tried turning it into a prefab and dragging it into the menu scene, but that doesn't work either. I'm still a beginner with Netcode stuff, so forgive me if this question is stupid. Is there a specific way to start a host when the NetworkManager is in a different scene?

    The menu scene:
    upload_2023-3-16_21-56-54.png

    The game scene:
    upload_2023-3-16_21-57-24.png

    The NetworkManager from the game scene:
    upload_2023-3-16_21-57-54.png

    I'm also following this tutorial by CodeMonkey:
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,882
    This isn't really a netcode thing, it's just standard Unity cross-scene management stuff.

    It would probably make more sense to put the network manager in another scene that is persistent between both, or have it lazily initialise itself and protect itself with
    DontDestroyOnLoad
    .

    Just anywhere that will be persistent so it can be accessed by its singleton instance. You might need to code your own, small, intermediary component that will initialise itself when accessed.
     
    LiterallyCoder likes this.
  3. LiterallyCoder

    LiterallyCoder

    Joined:
    Jul 25, 2020
    Posts:
    87
    The NetworkManager already protects itself with DontDestroyOnLoad at runtime, but something weird still happens.

    I put the NetworkManager in the menu scene like this:
    upload_2023-3-16_23-2-22.png

    As you can see, I've assigned the player prefab and added it to the NetworkPrefabs list, so it should get instantiated as soon as a button is pressed. However, it is not in the game scene. Wait... I just realized something. The reason it's not in the game scene is that it gets instantiated in the menu scene before the scenemanager switches to the game scene. OH MY GOD. MY PLAYER IS INSIDE OF THE MENU, HAHA!
     
  4. LiterallyCoder

    LiterallyCoder

    Joined:
    Jul 25, 2020
    Posts:
    87
    But from here, another question arises. How would I actually make sure that the player gets instantiated in the game scene and not in the menu, where the NetworkManager is originally from?

    Code (CSharp):
    1. hostButton.onClick.AddListener(() => {
    2.             SceneManager.LoadScene(0); // Load the game scene
    3.             NetworkManager.Singleton.StartHost(); // player gets instantiated in the menu scene
    4.             print(FindObjectOfType<PlayerMovement>().gameObject.scene.name);
    5.         });
    I load the game scene before starting the host, but the player still gets instantiated in the menu. Am I missing something?
     
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,882
    Admittedly I've never used networking stuff so I realise it is a bit different than I expected.

    Sounds like the Networking manager instantiates the player prefab in whatever the active scene is. So you will probably need to work with an additive scene loading solution. I imagine the menu button should have no responsibility with network stuff either.

    For example you could have a loading screen that loads the gameplay scene additively - waiting for it to be completely loaded in (and making it the active scene) - before starting the host/whatever networking stuff.

    This is the kind of stuff where you're going to have to code a lot more than three lines. You'll need to engineer a solution that works for your specific implementation.
     
    LiterallyCoder likes this.
  6. LiterallyCoder

    LiterallyCoder

    Joined:
    Jul 25, 2020
    Posts:
    87
    Yeah... Engineering a solution for multiple hours just to run into a ton of bugs, or a quick conversation with ChatGPT.

    LOL! It works FLAWLESSLY. Thanks GPT-4!


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using Unity.Netcode;
    6. using UnityEngine.SceneManagement;
    7.  
    8. public class MenuManager : MonoBehaviour
    9. {
    10.     [SerializeField] Button serverButton;
    11.     [SerializeField] Button hostButton;
    12.     [SerializeField] Button clientButton;
    13.  
    14.     private void Start()
    15.     {
    16.         NetworkManager.Singleton.OnServerStarted += HandleServerStarted;
    17.     }
    18.  
    19.     private void OnDestroy()
    20.     {
    21.         if (NetworkManager.Singleton)
    22.         {
    23.             NetworkManager.Singleton.OnServerStarted -= HandleServerStarted;
    24.         }
    25.     }
    26.  
    27.     void Awake()
    28.     {
    29.         hostButton.onClick.AddListener(() =>
    30.         {
    31.             NetworkManager.Singleton.StartHost();
    32.         });
    33.     }
    34.  
    35.     private void HandleServerStarted()
    36.     {
    37.         if (NetworkManager.Singleton.IsHost)
    38.         {
    39.             var status = NetworkManager.Singleton.SceneManager.LoadScene("FirstPersonMovement", LoadSceneMode.Single);
    40.  
    41.             if (status != SceneEventProgressStatus.Started)
    42.             {
    43.                 Debug.LogWarning($"Failed to load FirstPersonMovement with a {nameof(SceneEventProgressStatus)}: {status}");
    44.             }
    45.         }
    46.     }
    47. }
     
  7. LiterallyCoder

    LiterallyCoder

    Joined:
    Jul 25, 2020
    Posts:
    87
    upload_2023-3-17_0-4-6.png
    There is only one thing more satisfying than seeing this... and it's probably bubblewrap
     
  8. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,882
    Seems like a missed learning opportunity. The pattern recognition machine has just given you a very basic band-aid solution that won't scale.
     
  9. LiterallyCoder

    LiterallyCoder

    Joined:
    Jul 25, 2020
    Posts:
    87
    I will spend more time actually learning how this particular case works later on. For now, I just needed something that works for testing, since I'm just beginning to learn Netcode and this whole thing is just one big prototype. It doesn't even make sense to scale this since I'm just messing around. In a real game, I would make an actual lobby instead of a sloppy menu like this one. So no, I don't think this is a "missed learning opportunity". I just don't want to get too off track since I'm following the tutorial I listed above. I feel like if I really stressed that much about every little detail, I'd never really get through Code Monkey's tutorial. Basics first, then the "good" approach.