Skip to content

Commit 07385cf

Browse files
Fix: Loopback RPCs in host mode (#460)
* fix: Host loopback This fixes issue where Rpcs are not being invoked when in Host mode, but not for nested Rpcs. (that is the next fix coming) * fix: Host nested Rpcs These are the first initial changes to fix the scenario where a Host has a ServerRpc being invoked which inside the Rpc it invokes a ClientRpc (etc.). We now always have no less than 2 QueueHistoryFrames, when we are looping back Rpcs for a Host the looped back packet always gets placed on the next QueueHistory frame. With 0 queue history, we will still have 2 frames to toggle between. * refactor: removing loopback Removed the loopback option since this now is the default mode when running in Host mode. Cleaned up some legacy non-standard code as well. * refactor: syntax Fixing minor syntax related issues. * fix: Host should send to clients as well This fixes the scenario where a Host would properly send to itself but would exclude the remaining clients. * Fix: Host and Clients multiple streams This fixes the scenario where you want to write to two streams but can only return one stream to the ILPP side of the RPC. This will be fixed relatively soon with a mux'd bit serializer. * fix: shutdown send exception This prevents from trying to flush and send any remaining items if we are no longer connected. * refactor: adjustments to bitserializer changes Just making adjustments to the changes in parameters and names from the merged feature/serializable-types. https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/tree/feature/serializable-types * fix: minor adjustment for host loopback serverRpc This fixes an offset issue with a host invoking a serverRpc. * fix: renabling batching Tested everything with batched RPCs disabled, now tested everything with batched RPCs enabled. Host Loopback Unit test passed. Server + Client --> passed. Host + Client --> passed.
1 parent d352dce commit 07385cf

6 files changed

Lines changed: 313 additions & 174 deletions

File tree

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
public class NetworkingManagerEditor : Editor
1313
{
1414
// Properties
15-
private SerializedProperty runInLoopbackModeProperty;
1615
private SerializedProperty dontDestroyOnLoadProperty;
1716
private SerializedProperty runInBackgroundProperty;
1817
private SerializedProperty logLevelProperty;
@@ -96,7 +95,6 @@ private void Init()
9695
networkingManager = (NetworkingManager)target;
9796

9897
// Base properties
99-
runInLoopbackModeProperty = serializedObject.FindProperty("LoopbackEnabled");
10098
dontDestroyOnLoadProperty = serializedObject.FindProperty("DontDestroy");
10199
runInBackgroundProperty = serializedObject.FindProperty("RunInBackground");
102100
logLevelProperty = serializedObject.FindProperty("LogLevel");
@@ -137,7 +135,6 @@ private void Init()
137135
private void CheckNullProperties()
138136
{
139137
// Base properties
140-
runInLoopbackModeProperty = serializedObject.FindProperty("LoopbackEnabled");
141138
dontDestroyOnLoadProperty = serializedObject.FindProperty("DontDestroy");
142139
runInBackgroundProperty = serializedObject.FindProperty("RunInBackground");
143140
logLevelProperty = serializedObject.FindProperty("LogLevel");
@@ -251,7 +248,6 @@ public override void OnInspectorGUI()
251248
if (!networkingManager.IsServer && !networkingManager.IsClient)
252249
{
253250
serializedObject.Update();
254-
EditorGUILayout.PropertyField(runInLoopbackModeProperty);
255251
EditorGUILayout.PropertyField(dontDestroyOnLoadProperty);
256252
EditorGUILayout.PropertyField(runInBackgroundProperty);
257253
EditorGUILayout.PropertyField(logLevelProperty);
@@ -313,7 +309,7 @@ public override void OnInspectorGUI()
313309
{
314310
EditorGUILayout.PropertyField(maxObjectUpdatesPerTickProperty);
315311
}
316-
312+
317313
EditorGUILayout.PropertyField(ensureNetworkedVarLengthSafetyProperty);
318314
}
319315

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

Lines changed: 109 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,40 @@ public BitSerializer __beginSendServerRpc(ServerRpcParams serverRpcParams, bool
6767
#endif
6868
{
6969
var rpcQueueContainer = NetworkingManager.Singleton.rpcQueueContainer;
70-
var writer = rpcQueueContainer.BeginAddQueueItemToOutboundFrame(
71-
RpcQueueContainer.QueueItemType.ServerRpc,
72-
Time.realtimeSinceStartup,
73-
Transport.MLAPI_STDRPC_CHANNEL,
74-
/* sendFlags = */ 0,
75-
NetworkingManager.Singleton.ServerClientId,
76-
/* targetNetworkIds = */ null);
77-
if (!rpcQueueContainer.IsUsingBatching())
70+
PooledBitWriter writer;
71+
var IsUsingBatching = rpcQueueContainer.IsUsingBatching();
72+
if (IsHost)
7873
{
74+
if (serverRpcParams.Send.UpdateStage == NetworkUpdateManager.NetworkUpdateStage.Default)
75+
{
76+
serverRpcParams.Send.UpdateStage = NetworkUpdateManager.NetworkUpdateStage.Update;
77+
}
78+
writer = rpcQueueContainer.BeginAddQueueItemToFrame(RpcQueueContainer.QueueItemType.ServerRpc, Time.realtimeSinceStartup, Transport.MLAPI_STDRPC_CHANNEL, 0,
79+
NetworkingManager.Singleton.ServerClientId, null, QueueHistoryFrame.QueueFrameType.Inbound,serverRpcParams.Send.UpdateStage );
80+
81+
//Under this condition we always treat this like there is no batching
7982
writer.WriteBit(false); // Encrypted
8083
writer.WriteBit(false); // Authenticated
8184
writer.WriteBits(MLAPIConstants.MLAPI_SERVER_RPC, 6); // MessageType
8285
}
86+
else
87+
{
88+
writer = rpcQueueContainer.BeginAddQueueItemToFrame(RpcQueueContainer.QueueItemType.ServerRpc, Time.realtimeSinceStartup, Transport.MLAPI_STDRPC_CHANNEL, 0,
89+
NetworkingManager.Singleton.ServerClientId, null, QueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateManager.NetworkUpdateStage.LateUpdate);
90+
if (!IsUsingBatching)
91+
{
92+
writer.WriteBit(false); // Encrypted
93+
writer.WriteBit(false); // Authenticated
94+
writer.WriteBits(MLAPIConstants.MLAPI_SERVER_RPC, 6); // MessageType
95+
}
96+
}
97+
98+
8399

84100
writer.WriteUInt64Packed(NetworkId); // NetworkObjectId
85101
writer.WriteUInt16Packed(GetBehaviourId()); // NetworkBehaviourId
86102

87-
// Write the update stage in front of RPC related information
103+
//Write the update stage in front of RPC related information
88104
if (serverRpcParams.Send.UpdateStage == NetworkUpdateManager.NetworkUpdateStage.Default)
89105
{
90106
writer.WriteUInt16Packed((ushort)NetworkUpdateManager.NetworkUpdateStage.Update);
@@ -110,7 +126,15 @@ public void __endSendServerRpc(BitSerializer serializer, ServerRpcParams serverR
110126
if (serializer == null) return;
111127

112128
var rpcQueueContainer = NetworkingManager.Singleton.rpcQueueContainer;
113-
rpcQueueContainer.EndAddQueueItemToOutboundFrame(serializer.Writer);
129+
if (IsHost)
130+
{
131+
rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, QueueHistoryFrame.QueueFrameType.Inbound, serverRpcParams.Send.UpdateStage == NetworkUpdateManager.NetworkUpdateStage.Default ? NetworkUpdateManager.NetworkUpdateStage.Update:serverRpcParams.Send.UpdateStage );
132+
}
133+
else
134+
{
135+
rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, QueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateManager.NetworkUpdateStage.LateUpdate);
136+
}
137+
114138
}
115139

116140
[Browsable(false)]
@@ -125,18 +149,57 @@ public BitSerializer __beginSendClientRpc(ClientRpcParams clientRpcParams, bool
125149
{
126150
// This will start a new queue item entry and will then return the writer to the current frame's stream
127151
var rpcQueueContainer = NetworkingManager.Singleton.rpcQueueContainer;
128-
var writer = rpcQueueContainer.BeginAddQueueItemToOutboundFrame(
129-
RpcQueueContainer.QueueItemType.ClientRpc,
130-
Time.realtimeSinceStartup,
131-
Transport.MLAPI_STDRPC_CHANNEL,
132-
/* sendFlags = */ 0,
133-
NetworkId,
134-
clientRpcParams.Send.TargetClientIds ?? NetworkingManager.Singleton.ConnectedClientsList.Select(c => c.ClientId).ToArray());
135-
if (!rpcQueueContainer.IsUsingBatching())
152+
153+
PooledBitWriter writer;
154+
var IsUsingBatching = rpcQueueContainer.IsUsingBatching();
155+
156+
ulong[] ClientIds = clientRpcParams.Send.TargetClientIds ?? NetworkingManager.Singleton.ConnectedClientsList.Select(c => c.ClientId).ToArray();
157+
if(clientRpcParams.Send.TargetClientIds != null && clientRpcParams.Send.TargetClientIds.Length == 0)
136158
{
159+
ClientIds = NetworkingManager.Singleton.ConnectedClientsList.Select(c => c.ClientId).ToArray();
160+
}
161+
162+
var ContainsServerClientId = ClientIds.Contains(NetworkingManager.Singleton.ServerClientId);
163+
if (IsHost && ContainsServerClientId)
164+
{
165+
if(clientRpcParams.Send.UpdateStage == NetworkUpdateManager.NetworkUpdateStage.Default)
166+
{
167+
clientRpcParams.Send.UpdateStage = NetworkUpdateManager.NetworkUpdateStage.Update;
168+
}
169+
170+
writer = rpcQueueContainer.BeginAddQueueItemToFrame(RpcQueueContainer.QueueItemType.ClientRpc, Time.realtimeSinceStartup, Transport.MLAPI_STDRPC_CHANNEL, 0,
171+
NetworkingManager.Singleton.ServerClientId, null, QueueHistoryFrame.QueueFrameType.Inbound,clientRpcParams.Send.UpdateStage );
172+
137173
writer.WriteBit(false); // Encrypted
138174
writer.WriteBit(false); // Authenticated
139175
writer.WriteBits(MLAPIConstants.MLAPI_CLIENT_RPC, 6); // MessageType
176+
177+
//Handle sending to the other clients
178+
if (ClientIds.Length > 1 )
179+
{
180+
rpcQueueContainer.SetLoopBackWriter(writer, QueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateManager.NetworkUpdateStage.LateUpdate);
181+
writer = rpcQueueContainer.BeginAddQueueItemToFrame(RpcQueueContainer.QueueItemType.ClientRpc, Time.realtimeSinceStartup, Transport.MLAPI_STDRPC_CHANNEL, 0, NetworkId,
182+
ClientIds, QueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateManager.NetworkUpdateStage.LateUpdate);
183+
184+
if (!IsUsingBatching)
185+
{
186+
writer.WriteBit(false); // Encrypted
187+
writer.WriteBit(false); // Authenticated
188+
writer.WriteBits(MLAPIConstants.MLAPI_CLIENT_RPC, 6); // MessageType
189+
}
190+
}
191+
}
192+
else
193+
{
194+
writer = rpcQueueContainer.BeginAddQueueItemToFrame(RpcQueueContainer.QueueItemType.ClientRpc, Time.realtimeSinceStartup, Transport.MLAPI_STDRPC_CHANNEL, 0, NetworkId,
195+
ClientIds, QueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateManager.NetworkUpdateStage.LateUpdate);
196+
197+
if (!IsUsingBatching)
198+
{
199+
writer.WriteBit(false); // Encrypted
200+
writer.WriteBit(false); // Authenticated
201+
writer.WriteBits(MLAPIConstants.MLAPI_CLIENT_RPC, 6); // MessageType
202+
}
140203
}
141204

142205
writer.WriteUInt64Packed(NetworkId); // NetworkObjectId
@@ -155,6 +218,7 @@ public BitSerializer __beginSendClientRpc(ClientRpcParams clientRpcParams, bool
155218
return writer.Serializer;
156219
}
157220

221+
158222
[Browsable(false)]
159223
[EditorBrowsable(EditorBrowsableState.Never)]
160224
#if UNITY_2020_2_OR_NEWER
@@ -168,7 +232,33 @@ public void __endSendClientRpc(BitSerializer serializer, ClientRpcParams clientR
168232
if (serializer == null) return;
169233

170234
var rpcQueueContainer = NetworkingManager.Singleton.rpcQueueContainer;
171-
rpcQueueContainer.EndAddQueueItemToOutboundFrame(serializer.Writer);
235+
ulong[] ClientIds = clientRpcParams.Send.TargetClientIds ?? NetworkingManager.Singleton.ConnectedClientsList.Select(c => c.ClientId).ToArray();
236+
if(clientRpcParams.Send.TargetClientIds != null && clientRpcParams.Send.TargetClientIds.Length == 0)
237+
{
238+
ClientIds = NetworkingManager.Singleton.ConnectedClientsList.Select(c => c.ClientId).ToArray();
239+
}
240+
var ContainsServerClientId = ClientIds.Contains(NetworkingManager.Singleton.ServerClientId);
241+
242+
if (IsHost && ContainsServerClientId)
243+
{
244+
PooledBitWriter loopbackWriter = serializer.Writer as PooledBitWriter;
245+
if (ClientIds.Length > 1 )
246+
{
247+
rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, QueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateManager.NetworkUpdateStage.LateUpdate);
248+
249+
loopbackWriter = rpcQueueContainer.GetLoopBackWriter(QueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateManager.NetworkUpdateStage.LateUpdate);
250+
rpcQueueContainer.ClearLoopBackWriter(QueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateManager.NetworkUpdateStage.LateUpdate);
251+
}
252+
253+
if(ContainsServerClientId)
254+
{
255+
rpcQueueContainer.EndAddQueueItemToFrame(loopbackWriter, QueueHistoryFrame.QueueFrameType.Inbound, clientRpcParams.Send.UpdateStage == NetworkUpdateManager.NetworkUpdateStage.Default ? NetworkUpdateManager.NetworkUpdateStage.Update:clientRpcParams.Send.UpdateStage );
256+
}
257+
}
258+
else
259+
{
260+
rpcQueueContainer.EndAddQueueItemToFrame(serializer.Writer, QueueHistoryFrame.QueueFrameType.Outbound, NetworkUpdateManager.NetworkUpdateStage.LateUpdate);
261+
}
172262
}
173263

174264
/// <summary>

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

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,6 @@ public class NetworkingManager : UpdateLoopBehaviour
7070
static ProfilerMarker s_MLAPIClientSTDRPCQueued = new ProfilerMarker("MLAPIClientSTDRPCQueued");
7171
static ProfilerMarker s_InvokeRPC = new ProfilerMarker("InvokeRPC");
7272
#endif
73-
[HideInInspector]
74-
public bool LoopbackEnabled;
75-
7673
public RpcQueueContainer rpcQueueContainer { get; private set; }
7774

7875
/// <summary>
@@ -718,7 +715,7 @@ protected override Action InternalRegisterNetworkUpdateStage(NetworkUpdateManage
718715
/// </summary>
719716
private void Awake()
720717
{
721-
rpcQueueContainer = new RpcQueueContainer(false, LoopbackEnabled);
718+
rpcQueueContainer = new RpcQueueContainer(false);
722719
//Note: Since frame history is not being used, this is set to 0
723720
//To test frame history, increase the number to (n) where n > 0
724721
rpcQueueContainer.Initialize(0);
@@ -744,11 +741,7 @@ private void NetworkPreUpdate()
744741
#if DEVELOPMENT_BUILD || UNITY_EDITOR
745742
s_ReceiveTick.Begin();
746743
#endif
747-
bool IsLoopBack = false;
748-
if (rpcQueueContainer != null)
749-
{
750-
IsLoopBack = rpcQueueContainer.IsLoopBack();
751-
}
744+
var IsLoopBack = false;
752745

753746
NetworkProfiler.StartTick(TickType.Receive);
754747

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ public enum QueueFrameType
1616
Outbound,
1717
}
1818

19-
public uint TotalSize;
19+
public bool isDirty; //Used to determine if this queue history frame has been reset (cleaned) yet
20+
public bool hasLoopbackData; //Used to determine if a dirt frame is dirty because rpcs are being looped back betwen HostClient and HostServer
21+
public uint totalSize;
2022
public List<uint> queueItemOffsets;
2123

2224
public PooledBitStream queueStream;
2325
public PooledBitWriter queueWriter;
24-
public PooledBitReader queueReader;
26+
public PooledBitWriter queueWriterLoopback; //Temporary fix for Host mode loopback work around.
27+
2528

29+
public PooledBitReader queueReader;
2630

2731
private int m_QueueItemOffsetIndex;
2832
private FrameQueueItem m_CurrentQueueItem;

0 commit comments

Comments
 (0)