Skip to content

Commit

Permalink
fix: FinishLoadSceneHost calls FinishStart host which now calls Start…
Browse files Browse the repository at this point in the history
…HostClient AFTER server online scene was loaded. Previously there was a race condition where StartHostClient was called immediately in StartHost, before the scene change even finished. This was still from UNET.
  • Loading branch information
miwarnec committed Jan 5, 2020
1 parent 4f169b0 commit df9c29a
Showing 1 changed file with 45 additions and 17 deletions.
62 changes: 45 additions & 17 deletions Assets/Mirror/Runtime/NetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,26 @@ void StartHostClient()
OnStartClient();
}

// FinishStartHost is guaranteed to be called after the host server was
// fully started and all the asynchronous StartHost magic is finished
// (= scene loading), or immediately if there was no asynchronous magic.
//
// note: we don't really need FinishStartClient/FinishStartServer. the
// host version is enough.
bool finishStartHostPending;
void FinishStartHost()
{
// server scene was loaded. now spawn all the objects
NetworkServer.SpawnObjects();

// connect client and call OnStartClient AFTER server scene was
// loaded and all objects were spawned.
// DO NOT do this earlier. it would cause race conditions where a
// client will do things before the server is even fully started.
Debug.LogWarning("StartHostClient called");
StartHostClient();
}

/// <summary>
/// This starts a network "host" - a server and client in the same application.
/// <para>The client returned from StartHost() is a special "local" client that communicates to the in-process server using a message queue instead of the real network. But in almost all other cases, it can be treated as a normal client.</para>
Expand All @@ -444,12 +464,13 @@ public virtual void StartHost()
// LoadSceneAsync
// ...
// FinishLoadSceneHost
// SpawnObjects
// FinishStartHost
// SpawnObjects
// StartHostClient <= not guaranteed to happen after SpawnObjects if onlineScene is set!
// ClientAuth
// success: server sends changescene msg to client
// else:
// SpawnObjects
// StartHostClient <= not guaranteed to happen after SpawnObjects if onlineScene is set!
// ClientAuth
// success: server sends changescene msg to client
// FinishStartHost
//
// there is NO WAY to make it synchronous because both LoadSceneAsync
// and LoadScene do not finish loading immediately. as long as we
Expand Down Expand Up @@ -498,22 +519,15 @@ public virtual void StartHost()
// server is still in 'offlineScene'. so load on server first.
if (IsServerOnlineSceneChangeNeeded())
{
// call FinishStartHost after changing scene.
finishStartHostPending = true;
ServerChangeScene(onlineScene);
}
// otherwise spawn directly
// otherwise call FinishStartHost directly
else
{
NetworkServer.SpawnObjects();
FinishStartHost();
}

// connect client and call OnStartClient AFTER host server was fully
// started (after online scene change and SpawnObjects).
// -> do not call this before, we don't want to start the host
// client before the server is fully running.
// TODO if server uses an online scene then we have a race condition
// where in most cases StartHostClient would be called before
// the scene change was finished. that's not good.
StartHostClient();
}

/// <summary>
Expand Down Expand Up @@ -904,7 +918,21 @@ void FinishLoadSceneHost()
clientReadyConnection = null;
}

NetworkServer.SpawnObjects();
// do we need to finish a StartHost() call?
// then call FinishStartHost and let it take care of spawning etc.
if (finishStartHostPending)
{
finishStartHostPending = false;
FinishStartHost();
}
// otherwise we just changed a scene in host mode. simply spawn
// server objects now.
else
{
NetworkServer.SpawnObjects();
}

// call OnServerSceneChanged afterwards in any case
OnServerSceneChanged(networkSceneName);

if (NetworkClient.isConnected)
Expand Down

0 comments on commit df9c29a

Please sign in to comment.