Skip to content

fix: client connected InvokeOnClientConnectedCallback with scene management disabled #1123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1495,14 +1495,17 @@ internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint?
{
SceneManager.SynchronizeNetworkObjects(ownerClientId);
}
else
{
InvokeOnClientConnectedCallback(ownerClientId);
}
}
else // Server just adds itself as an observer to all spawned NetworkObjects
{
SpawnManager.UpdateObservedNetworkObjects(ownerClientId);
InvokeOnClientConnectedCallback(ownerClientId);
}

OnClientConnectedCallback?.Invoke(ownerClientId);

if (!createPlayerObject || (playerPrefabHash == null && NetworkConfig.PlayerPrefab == null))
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ public void HandleConnectionApproved(ulong clientId, Stream stream, float receiv
{
NetworkObject.DeserializeSceneObject(reader.GetStream() as NetworkBuffer, reader, m_NetworkManager);
}

// Mark the client being connected
m_NetworkManager.IsConnectedClient = true;
// When scene management is disabled we notify after everything is synchronized
m_NetworkManager.InvokeOnClientConnectedCallback(clientId);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ private SceneEventProgress ValidateSceneEvent(string sceneName, bool isUnloading
}

var sceneEventProgress = new SceneEventProgress(m_NetworkManager);
sceneEventProgress.SceneIndex = GetBuildIndexFromSceneName(sceneName);
sceneEventProgress.SceneBuildIndex = GetBuildIndexFromSceneName(sceneName);
SceneEventProgressTracking.Add(sceneEventProgress.Guid, sceneEventProgress);

if (!isUnloading)
Expand Down Expand Up @@ -582,7 +582,7 @@ private bool OnSceneEventProgressCompleted(SceneEventProgress sceneEventProgress
{
using var nonNullContext = (InternalCommandContext)context;
ClientSynchEventData.SceneEventGuid = sceneEventProgress.Guid;
ClientSynchEventData.SceneIndex = sceneEventProgress.SceneIndex;
ClientSynchEventData.SceneIndex = sceneEventProgress.SceneBuildIndex;
ClientSynchEventData.SceneEventType = sceneEventProgress.SceneEventType;
ClientSynchEventData.ClientsCompleted = sceneEventProgress.DoneClients;
ClientSynchEventData.ClientsTimedOut = m_NetworkManager.ConnectedClients.Keys.Except(sceneEventProgress.DoneClients).ToList();
Expand All @@ -596,15 +596,15 @@ private bool OnSceneEventProgressCompleted(SceneEventProgress sceneEventProgress
m_NetworkManager.NetworkMetrics.TrackSceneEventSent(
m_NetworkManager.ConnectedClientsIds,
(uint)sceneEventProgress.SceneEventType,
ScenesInBuild[(int)sceneEventProgress.SceneIndex],
ScenesInBuild[(int)sceneEventProgress.SceneBuildIndex],
size);
}

// Send a local notification to the server that all clients are done loading or unloading
OnSceneEvent?.Invoke(new SceneEvent()
{
SceneEventType = sceneEventProgress.SceneEventType,
SceneName = ScenesInBuild[(int)sceneEventProgress.SceneIndex],
SceneName = ScenesInBuild[(int)sceneEventProgress.SceneBuildIndex],
ClientId = m_NetworkManager.ServerClientId,
LoadSceneMode = sceneEventProgress.LoadSceneMode,
ClientsThatCompleted = sceneEventProgress.DoneClients,
Expand Down Expand Up @@ -1377,14 +1377,16 @@ private void HandleClientSceneEvent(Stream stream)

// All scenes are synchronized, let the server know we are done synchronizing
m_NetworkManager.IsConnectedClient = true;
m_NetworkManager.InvokeOnClientConnectedCallback(m_NetworkManager.LocalClientId);

// Notify the client that they have finished synchronizing
OnSceneEvent?.Invoke(new SceneEvent()
{
SceneEventType = SceneEventData.SceneEventType,
ClientId = m_NetworkManager.LocalClientId, // Client sent this to the server
});

// Client is now synchronized and fully "connected". This also means the client can send "RPCs" at this time
m_NetworkManager.InvokeOnClientConnectedCallback(m_NetworkManager.LocalClientId);
}
break;
}
Expand Down Expand Up @@ -1477,6 +1479,10 @@ private void HandleServerSceneEvent(ulong clientId, Stream stream)
ClientId = clientId
});

// While we did invoke the C2S_SyncComplete event notification, we will also call the traditional client connected callback on the server
// which assures the client is "ready to receive RPCs" as well.
m_NetworkManager.InvokeOnClientConnectedCallback(clientId);

if (SceneEventData.ClientNeedsReSynchronization() && !DisableReSynchronization)
{
SceneEventData.SceneEventType = SceneEventData.SceneEventTypes.S2C_ReSync;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ internal class SceneEventProgress
/// </summary>
internal bool AreAllClientsDoneLoading { get; private set; }

internal uint SceneIndex { get; set; }
internal uint SceneBuildIndex { get; set; }

internal Guid Guid { get; } = Guid.NewGuid();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static class NetworkBufferPool
private static Queue<PooledNetworkBuffer> s_Buffers = new Queue<PooledNetworkBuffer>();

private const uint k_MaxBitPoolBuffers = 1024;
private const uint k_MaxCreatedDelta = 768;
private const uint k_MaxCreatedDelta = 512;


/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,60 @@ private void ConnectionApprovalCallback(byte[] connectionData, ulong clientId, N
}
}



private int m_ServerClientConnectedInvocations;

private int m_ClientConnectedInvocations;

/// <summary>
/// Tests that the OnClientConnectedCallback is invoked when scene management is enabled and disabled
/// </summary>
/// <returns></returns>
[UnityTest]
public IEnumerator ClientConnectedCallbackTest([Values(true, false)] bool enableSceneManagement)
{
m_ServerClientConnectedInvocations = 0;
m_ClientConnectedInvocations = 0;

// Create Host and (numClients) clients
Assert.True(MultiInstanceHelpers.Create(3, out NetworkManager server, out NetworkManager[] clients));

server.NetworkConfig.EnableSceneManagement = enableSceneManagement;
server.OnClientConnectedCallback += Server_OnClientConnectedCallback;

foreach (var client in clients)
{
client.NetworkConfig.EnableSceneManagement = enableSceneManagement;
client.OnClientConnectedCallback += Client_OnClientConnectedCallback;
}

// Start the instances
if (!MultiInstanceHelpers.Start(true, server, clients))
{
Assert.Fail("Failed to start instances");
}

// [Client-Side] Wait for a connection to the server
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnected(clients, null, 512));

// [Host-Side] Check to make sure all clients are connected
yield return MultiInstanceHelpers.Run(MultiInstanceHelpers.WaitForClientsConnectedToServer(server, clients.Length + 1, null, 512));

Assert.True(m_ClientConnectedInvocations == 3);
Assert.True(m_ServerClientConnectedInvocations == 4);
}

private void Client_OnClientConnectedCallback(ulong clientId)
{
m_ClientConnectedInvocations++;
}

private void Server_OnClientConnectedCallback(ulong clientId)
{
m_ServerClientConnectedInvocations++;
}

[TearDown]
public void TearDown()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ public IEnumerator Setup()
{
SceneManager.sceneLoaded += OnSceneLoaded;

// We need NetworkManager to be instantiated first before you load scenes externally in order to be able to determine if
// we are running a unit test or not. (it is this or manually setting a property)
Assert.That(MultiInstanceHelpers.Create(k_ClientInstanceCount, out m_ServerNetworkManager, out m_ClientNetworkManagers));

const string scenePath = "Assets/Tests/Runtime/ObjectParenting/" + nameof(NetworkObjectParentingTests) + ".unity";
Expand Down