Hi,
I’ve got a double instantiation problem.
I’m using RiptideNetworking (C# networking library) to create a multiplayer game, and just having a bit of trouble. Note, the library itself and its demo work fine, it’s my changes that broke something (but I don’t know where!)
All of my code can be found here: https://github.com/jordandalby/NetworkBug
Pipeline:
- Player presses Host button, calling NetworkUI::HostClicked
- NetworkUI::HostClicked calls NetworkManager::StartHost
- NetworkManager::StartHost starts the server and connects the host to it with Client::Connect
- When client connects, NetworkManager:: DidConnect is called
- NetworkManager:: DidConnect switches to the game scene and instantiates a player, but there are two players instead of one. See DidConnect and Player.Spawn below
DidConnect:
private void DidConnect(object sender, EventArgs e)
{
StartCoroutine(SwitchScenesAndInstantiateFirstPlayer());
}
IEnumerator SwitchScenesAndInstantiateFirstPlayer()
{
string username = NetworkUI.instance.username.text;
AsyncOperation asyncLoadLevel = SceneManager.LoadSceneAsync("Game", LoadSceneMode.Single);
while (!asyncLoadLevel.isDone)
{
yield return null;
}
yield return new WaitForEndOfFrame();
Player.Spawn(Client.Id, username, true);
}
Player.Spawn:
internal static void Spawn(ushort id, string username, bool shouldSendSpawn = false)
{
Player player;
if (id == NetworkManager.Singleton.Client.Id)
player = Instantiate(new GameObject().AddComponent<Player>(), Vector3.zero, Quaternion.identity).GetComponent<Player>();
else
player = Instantiate(new GameObject().AddComponent<Player>(), Vector3.zero, Quaternion.identity).GetComponent<Player>();
player.Id = id;
player.username = username;
player.name = $"Player {id} ({username})";
List.Add(id, player);
if (shouldSendSpawn)
player.SendSpawn();
}
A few notes:
- NetworkManager is a Singleton with DontDestroyOnLoad
- Player USED to have DontDestroyOnLoad, but I had this same problem so I tried to find a workaround, but it seems that this issue persists even after DontDestroyOnLoad is removed.
- A scene called Boot is run first, which has the NetworkManager instance, allowing it to persist on every subsequent scene, Boot is never visited again.
- There is only ever 1 instance of NetworkManager (NetworkManager alerts when that’s not the case)
- Player.Spawn only gets called once, I’ve debugged that to check.
- One of the instantiated players ignores the
player.name = ...assignment, suggesting further that it isn’t instantiated by Player.Spawn
What I’ve tried:
- Taking Boot out of the equation and simply having NetworkManager in the GameConnection screen by default (no DontDestroyOnLoad)
- Not switching scenes before calling Player.Spawn
- Not using a coroutine for DidConnect
I suppose at this point it has to be a Unity thing (some system that I misunderstand).
A little lost from there, what could be the problem?