Skip to content

Commit 6bc2289

Browse files
fix: Shutting down client or host/server and not being able to start the client or host/server within same game instance (#496)
* implement NetworkUpdateLoop * remove AdvanceFrame() and FrameCount * update player loop injection points and INetworkUpdateSystem API * add xmldoc and notes * add NetworkUpdateLoopTests * implement NetworkUpdateLoop plain and mixed tests * update xmldoc * small meta fix * replace old network update loop with new RFC-backed network update loop * replace WaitForEndOfFrame with WaitUntil in tests * comment 'default' for NetworkUpdateStage.Update enum value * optimization & refactoring pass * dictionary lookups instead of index access to arrays * optimize array allocation * Fix: PostProcessing and Resetting NetworkingManager transport This fixes two issues: It prevents the postprocessing method ProcessScene from being run during scene transitions while in PlayMode within the editor. This fixes the issue where the transport is no longer being polled for events upon shutting down the server,host, or client. * fix: more robust fix for postprocessing bug This prevents this post processing code from being executed when in PlayMode (editor and stand alone build) * refactor: SceneSwitchProgress This ended up not being needed in the end. Reverting back to the original file. * refactor: removing commented code and merge artifacts Removing the commented out OnDisable function (the containing code was moved into the Shutdown method) and removed the Awake method (the containing code was moved into the Init method). * refactor: merge artifacts This hadn't fully registered the merge. * refactor: Comments and Internal Added some comments regarding where the RpcQueueContainer should be instantiated and shutdown. Made the RpcQueueContainer internal, which also required me to make the QueueHistoryFrame internal and adjust some of the methods to match the same accessibility level. Co-authored-by: M. Fatih MAR <mfatihmar@gmail.com>
1 parent a950848 commit 6bc2289

6 files changed

Lines changed: 55 additions & 50 deletions

File tree

com.unity.multiplayer.mlapi/Editor/PostProcessScene.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ public class NetworkScenePostProcess : MonoBehaviour
1111
[PostProcessScene(int.MaxValue)]
1212
public static void ProcessScene()
1313
{
14-
//If we are in playmode (editor or stand alone) we do not want this to execute
14+
//If we are in playmode (editor or stand alone) we do not want this to execute
1515
if(Application.isPlaying)
1616
{
1717
return;
18-
}
19-
18+
}
19+
2020
List<NetworkedObject> traverseSortedObjects = MonoBehaviour.FindObjectsOfType<NetworkedObject>().ToList();
21-
21+
2222
traverseSortedObjects.Sort((x, y) =>
2323
{
2424
List<int> xSiblingIndex = x.TraversedSiblingIndex();
@@ -28,38 +28,38 @@ public static void ProcessScene()
2828
{
2929
if (xSiblingIndex[0] < ySiblingIndex[0])
3030
return -1;
31-
31+
3232
if (xSiblingIndex[0] > ySiblingIndex[0])
3333
return 1;
3434

3535
xSiblingIndex.RemoveAt(0);
3636
ySiblingIndex.RemoveAt(0);
3737
}
38-
38+
3939
return 0;
4040
});
4141

4242
for (ulong i = 0; i < (ulong)traverseSortedObjects.Count; i++)
4343
traverseSortedObjects[(int)i].NetworkedInstanceId = i;
4444
}
4545
}
46-
46+
4747
internal static class PrefabHelpers
4848
{
4949
internal static List<int> TraversedSiblingIndex(this NetworkedObject networkedObject)
5050
{
5151
List<int> paths = new List<int>();
52-
52+
5353
Transform transform = networkedObject.transform;
54-
54+
5555
while (transform != null)
5656
{
5757
paths.Add(transform.GetSiblingIndex());
5858
transform = transform.parent;
5959
}
6060

6161
paths.Reverse();
62-
62+
6363
return paths;
6464
}
6565
}

com.unity.multiplayer.mlapi/Runtime/Core/NetworkingManager.cs

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public class NetworkingManager : MonoBehaviour, INetworkUpdateSystem
7070
static ProfilerMarker s_MLAPIClientSTDRPCQueued = new ProfilerMarker("MLAPIClientSTDRPCQueued");
7171
static ProfilerMarker s_InvokeRPC = new ProfilerMarker("InvokeRPC");
7272
#endif
73-
public RpcQueueContainer rpcQueueContainer { get; private set; }
73+
internal RpcQueueContainer rpcQueueContainer { get; private set; }
7474

7575
/// <summary>
7676
/// A synchronized time, represents the time in seconds since the server application started. Is replicated across all clients
@@ -383,6 +383,27 @@ private void Init(bool server)
383383
return;
384384
}
385385

386+
387+
//This should never happen, but in the event that it does there should be (at a minimum) a unity error logged.
388+
if(rpcQueueContainer != null)
389+
{
390+
UnityEngine.Debug.LogError("Init was invoked, but rpcQueueContainer was already initialized! (destroying previous instance)");
391+
rpcQueueContainer.Shutdown();
392+
rpcQueueContainer = null;
393+
}
394+
395+
//The RpcQueueContainer must be initialized within the Init method ONLY
396+
//It should ONLY be shutdown and destroyed in the Shutdown method (other than just above)
397+
rpcQueueContainer = new RpcQueueContainer(false);
398+
399+
//Note: Since frame history is not being used, this is set to 0
400+
//To test frame history, increase the number to (n) where n > 0
401+
rpcQueueContainer.Initialize(0);
402+
403+
// Register INetworkUpdateSystem (always register this after rpcQueueContainer has been instantiated)
404+
this.RegisterNetworkUpdate(NetworkUpdateStage.EarlyUpdate);
405+
this.RegisterNetworkUpdate(NetworkUpdateStage.PreUpdate);
406+
386407
try
387408
{
388409
string pfx = null;
@@ -639,14 +660,6 @@ public void SetSingleton()
639660
OnSingletonReady();
640661
}
641662

642-
private void Awake()
643-
{
644-
rpcQueueContainer = new RpcQueueContainer(false);
645-
//Note: Since frame history is not being used, this is set to 0
646-
//To test frame history, increase the number to (n) where n > 0
647-
rpcQueueContainer.Initialize(0);
648-
}
649-
650663
private void OnEnable()
651664
{
652665
if (Singleton != null && Singleton != this)
@@ -655,28 +668,15 @@ private void OnEnable()
655668
return;
656669
}
657670

658-
// Register INetworkUpdateSystem
659-
this.RegisterNetworkUpdate(NetworkUpdateStage.EarlyUpdate);
660-
this.RegisterNetworkUpdate(NetworkUpdateStage.PreUpdate);
661-
662671
SetSingleton();
663672
if (DontDestroy)
664673
DontDestroyOnLoad(gameObject);
665674
if (RunInBackground)
666675
Application.runInBackground = true;
667676
}
668677

669-
private void OnDisable()
670-
{
671-
// Unregister INetworkUpdateSystem
672-
this.UnregisterAllNetworkUpdates();
673-
}
674-
675678
private void OnDestroy()
676679
{
677-
//NSS: This is ok to leave this check here
678-
rpcQueueContainer?.Shutdown();
679-
680680
if (Singleton != null && Singleton == this)
681681
{
682682
Singleton = null;
@@ -687,6 +687,17 @@ private void OnDestroy()
687687
public void Shutdown()
688688
{
689689
if (NetworkLog.CurrentLogLevel <= LogLevel.Developer) NetworkLog.LogInfo("Shutdown()");
690+
691+
// Unregister INetworkUpdateSystem before shutting down the RpcQueueContainer
692+
this.UnregisterAllNetworkUpdates();
693+
694+
//If an instance of the RpcQueueContainer is still around, then shut it down and remove the reference
695+
if (rpcQueueContainer != null)
696+
{
697+
rpcQueueContainer.Shutdown();
698+
rpcQueueContainer = null;
699+
}
700+
690701
NetworkProfiler.Stop();
691702
IsListening = false;
692703
IsServer = false;
@@ -699,11 +710,7 @@ public void Shutdown()
699710
if (NetworkConfig != null && NetworkConfig.NetworkTransport != null)
700711
NetworkConfig.NetworkTransport.Shutdown();
701712

702-
if (rpcQueueContainer != null)
703-
{
704-
rpcQueueContainer.Shutdown();
705-
rpcQueueContainer = null;
706-
}
713+
707714
}
708715

709716
// INetworkUpdateSystem
@@ -1234,7 +1241,7 @@ private static void ReceiveCallback(BitStream messageStream, RpcQueueContainer.Q
12341241
/// Called when an inbound queued RPC is invoked
12351242
/// </summary>
12361243
/// <param name="queueItem">frame queue item to invoke</param>
1237-
public static void InvokeRpc(RpcFrameQueueItem queueItem)
1244+
internal static void InvokeRpc(RpcFrameQueueItem queueItem)
12381245
{
12391246
#if DEVELOPMENT_BUILD || UNITY_EDITOR
12401247
s_InvokeRPC.Begin();

com.unity.multiplayer.mlapi/Runtime/Messaging/RpcQueue/QueueHistoryFrame.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ private RpcFrameQueueItem GetCurrentQueueItem()
159159
/// If none are remaining, then it returns a queue item type of NONE
160160
/// </summary>
161161
/// <returns>FrameQueueItem</returns>
162-
public RpcFrameQueueItem GetNextQueueItem()
162+
internal RpcFrameQueueItem GetNextQueueItem()
163163
{
164164
queueStream.Position = queueItemOffsets[m_QueueItemOffsetIndex];
165165
m_QueueItemOffsetIndex++;
@@ -178,7 +178,7 @@ public RpcFrameQueueItem GetNextQueueItem()
178178
/// This will reset the frame's stream indices and add a new stream and stream writer to the m_CurrentQueueItem instance.
179179
/// </summary>
180180
/// <returns>FrameQueueItem</returns>
181-
public RpcFrameQueueItem GetFirstQueueItem()
181+
internal RpcFrameQueueItem GetFirstQueueItem()
182182
{
183183
if (queueStream.Position > 0)
184184
{

com.unity.multiplayer.mlapi/Runtime/Messaging/RpcQueue/RpcFrameQueueItem.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace MLAPI.Messaging
1212
/// NOTE: This structure will change in the near future and is in a state of flux.
1313
/// This will include removing specific properties or changing property types
1414
/// </summary>
15-
public struct RpcFrameQueueItem
15+
internal struct RpcFrameQueueItem
1616
{
1717
public NetworkUpdateStage updateStage;
1818
public RpcQueueContainer.QueueItemType queueItemType;
@@ -27,4 +27,4 @@ public struct RpcFrameQueueItem
2727
public PooledBitStream itemStream;
2828
public ArraySegment<byte> messageData;
2929
}
30-
}
30+
}

com.unity.multiplayer.mlapi/Runtime/Messaging/RpcQueue/RpcQueueContainer.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace MLAPI.Messaging
1111
/// RpcQueueContainer
1212
/// Handles the management of an Rpc Queue
1313
/// </summary>
14-
public class RpcQueueContainer : INetworkUpdateSystem
14+
internal class RpcQueueContainer : INetworkUpdateSystem
1515
{
1616
private const int k_MinQueueHistory = 2; //We need a minimum of 2 queue history buffers in order to properly handle looping back Rpcs when a host
1717

@@ -571,7 +571,6 @@ public QueueHistoryFrame GetQueueHistoryFrame(QueueHistoryFrame.QueueFrameType f
571571
return QueueHistory[frameType][StreamBufferIndex][updateStage];
572572
}
573573

574-
575574
/// <summary>
576575
/// LoopbackSendFrame
577576
/// Will copy the contents of the current outbound QueueHistoryFrame to the current inbound QueueHistoryFrame
@@ -710,16 +709,16 @@ private void ClearParameters()
710709
/// </summary>
711710
public void Shutdown()
712711
{
713-
//We need to make sure all internal messages (i.e. object destroy) are sent
714-
m_RpcQueueProcessor.InternalMessagesSendAndFlush();
715-
716712
//As long as this instance is using the pre-defined update stages
717713
if (!m_ProcessUpdateStagesExternally)
718714
{
719715
//Remove ourself from the network loop update system
720716
this.UnregisterAllNetworkUpdates();
721717
}
722718

719+
//We need to make sure all internal messages (i.e. object destroy) are sent
720+
m_RpcQueueProcessor.InternalMessagesSendAndFlush();
721+
723722
//Dispose of any readers and writers
724723
foreach (KeyValuePair<QueueHistoryFrame.QueueFrameType, Dictionary<int, Dictionary<NetworkUpdateStage, QueueHistoryFrame>>> queueHistorySection in QueueHistory)
725724
{

com.unity.multiplayer.mlapi/Runtime/SceneManagement/SceneSwitchProgress.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.ComponentModel;
44
using UnityEngine;
@@ -55,7 +55,7 @@ public class SceneSwitchProgress
5555
/// The callback invoked when a client is done loading the scene.
5656
/// </summary>
5757
public event OnClientLoadedSceneDelegate OnClientLoadedScene;
58-
58+
5959
internal Guid guid { get; } = Guid.NewGuid();
6060

6161
private Coroutine timeOutCoroutine;
@@ -110,6 +110,5 @@ internal void SetTimedOut()
110110
OnComplete.Invoke(true);
111111
}
112112
}
113-
114113
}
115114
}

0 commit comments

Comments
 (0)