Skip to content

Commit 19afa41

Browse files
committed
Fixed bugs & prototype components
Fixes major bug with RPC methods and improves their usability
1 parent fdfe9af commit 19afa41

File tree

12 files changed

+239
-218
lines changed

12 files changed

+239
-218
lines changed

MLAPI-Editor/MLAPIProfiler.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System.Collections.Generic;
22
using System.IO;
3-
using MLAPI.Collections;
4-
using MLAPI.Profiler;
3+
using MLAPI.Profiling;
54
using MLAPI.Serialization;
65
using UnityEngine;
76
using BitStream = MLAPI.Serialization.BitStream;

MLAPI-Editor/NetworkingManagerEditor.cs

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ public class NetworkingManagerEditor : Editor
1414

1515
private ReorderableList networkPrefabsList;
1616
private ReorderableList channelsList;
17-
private ReorderableList messageTypesList;
1817
private ReorderableList registeredScenesList;
1918

2019
private NetworkingManager networkingManager;
@@ -51,16 +50,6 @@ private void OnEnable()
5150
networkPrefabsList = new ReorderableList(serializedObject, serializedObject.FindProperty("NetworkConfig").FindPropertyRelative("NetworkedPrefabs"), true, true, true, true);
5251
networkPrefabsList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
5352
{
54-
/*
55-
SerializedProperty element = networkPrefabsList.serializedProperty.GetArrayElementAtIndex(index);
56-
rect.y += 2;
57-
EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width - 30, EditorGUIUtility.singleLineHeight),
58-
element.FindPropertyRelative("prefab"), GUIContent.none);
59-
EditorGUI.PropertyField(new Rect(rect.x + rect.width - 30, rect.y, 30, EditorGUIUtility.singleLineHeight),
60-
element.FindPropertyRelative("playerPrefab"), GUIContent.none);
61-
62-
*/
63-
6453
SerializedProperty element = networkPrefabsList.serializedProperty.GetArrayElementAtIndex(index);
6554
int firstLabelWidth = 50;
6655
int secondLabelWidth = 140;
@@ -80,36 +69,6 @@ private void OnEnable()
8069
EditorGUI.LabelField(rect, "NetworkedPrefabs (Auto Sorted)");
8170
};
8271

83-
/*
84-
messageTypesList = new ReorderableList(serializedObject, serializedObject.FindProperty("NetworkConfig").FindPropertyRelative("MessageTypes"), true, true, true, true);
85-
messageTypesList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
86-
{
87-
SerializedProperty element = messageTypesList.serializedProperty.GetArrayElementAtIndex(index);
88-
89-
90-
int firstLabelWidth = 50;
91-
int secondLabelWidth = networkingManager.NetworkConfig.AllowPassthroughMessages ? 90 : 0;
92-
float secondFieldWidth = networkingManager.NetworkConfig.AllowPassthroughMessages ? 10 : 0;
93-
int reduceFirstWidth = networkingManager.NetworkConfig.AllowPassthroughMessages ? 45 : 20;
94-
95-
EditorGUI.LabelField(new Rect(rect.x, rect.y, firstLabelWidth, EditorGUIUtility.singleLineHeight), "Name");
96-
EditorGUI.PropertyField(new Rect(rect.x + firstLabelWidth, rect.y, rect.width - firstLabelWidth - secondLabelWidth - secondFieldWidth - reduceFirstWidth,
97-
EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("Name"), GUIContent.none);
98-
99-
if (networkingManager.NetworkConfig.AllowPassthroughMessages)
100-
{
101-
EditorGUI.LabelField(new Rect(rect.width - secondLabelWidth - secondFieldWidth, rect.y, secondLabelWidth, EditorGUIUtility.singleLineHeight), "Passthrough");
102-
EditorGUI.PropertyField(new Rect(rect.width - secondFieldWidth, rect.y, secondFieldWidth,
103-
EditorGUIUtility.singleLineHeight), element.FindPropertyRelative("Passthrough"), GUIContent.none);
104-
}
105-
};
106-
107-
messageTypesList.drawHeaderCallback = (Rect rect) => {
108-
EditorGUI.LabelField(rect, "MessageTypes (Auto Sorted)");
109-
};
110-
*/
111-
112-
11372
channelsList = new ReorderableList(serializedObject, serializedObject.FindProperty("NetworkConfig").FindPropertyRelative("Channels"), true, true, true, true);
11473
channelsList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
11574
{
@@ -181,8 +140,6 @@ public override void OnInspectorGUI()
181140
networkPrefabsList.DoLayoutList();
182141
}
183142
EditorGUILayout.Space();
184-
messageTypesList.DoLayoutList();
185-
EditorGUILayout.Space();
186143
channelsList.DoLayoutList();
187144
EditorGUILayout.Space();
188145
if (networkingManager.NetworkConfig.EnableSceneSwitching)

MLAPI/Data/NetworkProfiler/NetworkProfiler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
using System.Collections.Generic;
2+
using MLAPI.Collections;
23
using MLAPI.Data;
34
using MLAPI.Internal;
4-
using MLAPI.Profiler;
55
using UnityEngine;
66

7-
namespace MLAPI.Collections
7+
namespace MLAPI.Profiling
88
{
99
/// <summary>
1010
/// NetworkProfiler for profiling network traffic

MLAPI/Data/NetworkProfiler/ProfilerTickData.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
using System.IO;
33
using MLAPI.Serialization;
44

5-
namespace MLAPI.Profiler
5+
namespace MLAPI.Profiling
66
{
77
/// <summary>
88
/// The type of Tick

MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs

Lines changed: 90 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@ public abstract class NetworkedBehaviour : MonoBehaviour
3030
/// <summary>
3131
/// Gets if we are executing as server
3232
/// </summary>
33-
protected bool isServer => NetworkingManager.singleton.isServer;
33+
protected bool isServer => isRunning && NetworkingManager.singleton.isServer;
3434
/// <summary>
3535
/// Gets if we are executing as client
3636
/// </summary>
37-
protected bool isClient => NetworkingManager.singleton.isClient;
37+
protected bool isClient => isRunning && NetworkingManager.singleton.isClient;
3838
/// <summary>
3939
/// Gets if we are executing as Host, I.E Server and Client
4040
/// </summary>
41-
protected bool isHost => NetworkingManager.singleton.isHost;
41+
protected bool isHost => isRunning && NetworkingManager.singleton.isHost;
42+
private bool isRunning => NetworkingManager.singleton == null || NetworkingManager.singleton.isListening;
4243
/// <summary>
4344
/// Gets wheter or not the object has a owner
4445
/// </summary>
@@ -75,10 +76,23 @@ private void OnEnable()
7576
if (_networkedObject == null)
7677
_networkedObject = GetComponentInParent<NetworkedObject>();
7778

78-
CacheAttributes();
7979
NetworkedObject.NetworkedBehaviours.Add(this);
8080
OnEnabled();
8181
}
82+
83+
private void OnDisable()
84+
{
85+
OnDisabled();
86+
}
87+
88+
private void OnDestroy()
89+
{
90+
NetworkedObject.NetworkedBehaviours.Remove(this); // O(n)
91+
CachedClientRpcs.Remove(this);
92+
CachedServerRpcs.Remove(this);
93+
OnDestroyed();
94+
}
95+
8296
internal bool networkedStartInvoked = false;
8397
/// <summary>
8498
/// Gets called when message handlers are ready to be registered and the networking is setup
@@ -189,17 +203,6 @@ protected NetworkedBehaviour GetBehaviour(ushort id)
189203
return networkedObject.GetBehaviourAtOrderIndex(id);
190204
}
191205

192-
private void OnDisable()
193-
{
194-
OnDisabled();
195-
}
196-
197-
private void OnDestroy()
198-
{
199-
NetworkedObject.NetworkedBehaviours.Remove(this); // O(n)
200-
OnDestroyed();
201-
}
202-
203206
#region NetworkedVar
204207

205208
private bool networkedVarInit = false;
@@ -296,7 +299,7 @@ internal void NetworkedVarUpdate()
296299
if (isServer)
297300
InternalMessageHandler.Send(clientId, MLAPIConstants.MLAPI_NETWORKED_VAR_DELTA, channelsForVarGroups[j], stream);
298301
else
299-
InternalMessageHandler.Send(NetworkingManager.singleton.NetworkConfig.NetworkTransport.ServerClientId, MLAPIConstants.MLAPI_NETWORKED_VAR_DELTA, channelsForVarGroups[j], stream);
302+
InternalMessageHandler.Send(NetworkingManager.singleton.ServerClientId, MLAPIConstants.MLAPI_NETWORKED_VAR_DELTA, channelsForVarGroups[j], stream);
300303
}
301304
}
302305
}
@@ -360,10 +363,10 @@ internal void HandleNetworkedVarUpdate(Stream stream, uint clientId)
360363
#endregion
361364

362365
#region MESSAGING_SYSTEM
363-
private static readonly Dictionary<Type, Dictionary<ulong, ClientRPC>> CachedClientRpcs = new Dictionary<Type, Dictionary<ulong, ClientRPC>>();
364-
private static readonly Dictionary<Type, Dictionary<ulong, ServerRPC>> CachedServerRpcs = new Dictionary<Type, Dictionary<ulong, ServerRPC>>();
366+
private readonly Dictionary<NetworkedBehaviour, Dictionary<ulong, ClientRPC>> CachedClientRpcs = new Dictionary<NetworkedBehaviour, Dictionary<ulong, ClientRPC>>();
367+
private readonly Dictionary<NetworkedBehaviour, Dictionary<ulong, ServerRPC>> CachedServerRpcs = new Dictionary<NetworkedBehaviour, Dictionary<ulong, ServerRPC>>();
368+
private static readonly Dictionary<Type, MethodInfo[]> Methods = new Dictionary<Type, MethodInfo[]>();
365369
private static readonly Dictionary<ulong, string> HashResults = new Dictionary<ulong, string>();
366-
private static readonly HashSet<Type> CachedTypes = new HashSet<Type>();
367370

368371
private ulong HashMethodName(string name)
369372
{
@@ -382,13 +385,18 @@ private ulong HashMethodName(string name)
382385
private void CacheAttributes()
383386
{
384387
Type type = GetType();
385-
if (CachedTypes.Contains(type)) return; //Already cached
386388

387-
CachedTypes.Add(type);
388-
CachedClientRpcs.Add(type, new Dictionary<ulong, ClientRPC>());
389-
CachedServerRpcs.Add(type, new Dictionary<ulong, ServerRPC>());
390-
391-
MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
389+
CachedClientRpcs.Add(this, new Dictionary<ulong, ClientRPC>());
390+
CachedServerRpcs.Add(this, new Dictionary<ulong, ServerRPC>());
391+
392+
MethodInfo[] methods;
393+
if (Methods.ContainsKey(type)) methods = Methods[type];
394+
else
395+
{
396+
methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
397+
Methods.Add(type, methods);
398+
}
399+
392400
for (int i = 0; i < methods.Length; i++)
393401
{
394402
if (methods[i].IsDefined(typeof(ServerRPC), true))
@@ -403,7 +411,7 @@ private void CacheAttributes()
403411
if (parameters.Length == 2 && parameters[0].ParameterType == typeof(uint) && parameters[1].ParameterType == typeof(Stream))
404412
{
405413
//use delegate
406-
attributes[0].rpcDelegate = (RpcDelegate)Delegate.CreateDelegate(typeof(RpcDelegate), this, methods[i], true);
414+
attributes[0].rpcDelegate = (RpcDelegate)Delegate.CreateDelegate(typeof(RpcDelegate), this, methods[i].Name);
407415
}
408416
else
409417
{
@@ -415,12 +423,12 @@ private void CacheAttributes()
415423
{
416424
if (LogHelper.CurrentLogLevel <= LogLevel.Error) LogHelper.LogError("Hash collision detected for RPC method. The method \"" + methods[i].Name + "\" collides with the method \"" + HashResults[hash] + "\". This can be solved by increasing the amount of bytes to use for hashing in the NetworkConfig or changing the name of one of the conflicting methods.");
417425
}
418-
else
426+
else if (!HashResults.ContainsKey(hash))
419427
{
420428
HashResults.Add(hash, methods[i].Name);
421429
}
422430

423-
CachedServerRpcs[type].Add(hash, attributes[0]);
431+
CachedServerRpcs[this].Add(hash, attributes[0]);
424432
}
425433

426434
if (methods[i].IsDefined(typeof(ClientRPC), true))
@@ -435,21 +443,31 @@ private void CacheAttributes()
435443
if (parameters.Length == 2 && parameters[0].ParameterType == typeof(uint) && parameters[1].ParameterType == typeof(Stream))
436444
{
437445
//use delegate
438-
attributes[0].rpcDelegate = (RpcDelegate)Delegate.CreateDelegate(typeof(RpcDelegate), this, methods[i], true);
446+
attributes[0].rpcDelegate = (RpcDelegate)Delegate.CreateDelegate(typeof(RpcDelegate), this, methods[i].Name);
439447
}
440448
else
441449
{
442450
attributes[0].reflectionMethod = new ReflectionMehtod(methods[i]);
443451
}
444-
445-
CachedClientRpcs[type].Add(HashMethodName(methods[i].Name), attributes[0]);
452+
453+
ulong hash = HashMethodName(methods[i].Name);
454+
if (HashResults.ContainsKey(hash) && HashResults[hash] != methods[i].Name)
455+
{
456+
if (LogHelper.CurrentLogLevel <= LogLevel.Error) LogHelper.LogError("Hash collision detected for RPC method. The method \"" + methods[i].Name + "\" collides with the method \"" + HashResults[hash] + "\". This can be solved by increasing the amount of bytes to use for hashing in the NetworkConfig or changing the name of one of the conflicting methods.");
457+
}
458+
else if (!HashResults.ContainsKey(hash))
459+
{
460+
HashResults.Add(hash, methods[i].Name);
461+
}
462+
463+
CachedClientRpcs[this].Add(HashMethodName(methods[i].Name), attributes[0]);
446464
}
447465
}
448466
}
449467

450468
internal void OnRemoteServerRPC(ulong hash, uint senderClientId, Stream stream)
451469
{
452-
if (!CachedServerRpcs.ContainsKey(GetType()) || !CachedServerRpcs[GetType()].ContainsKey(hash))
470+
if (!CachedServerRpcs.ContainsKey(this) || !CachedServerRpcs[this].ContainsKey(hash))
453471
{
454472
if (LogHelper.CurrentLogLevel <= LogLevel.Normal) LogHelper.LogWarning("ServerRPC request method not found");
455473
return;
@@ -459,7 +477,7 @@ internal void OnRemoteServerRPC(ulong hash, uint senderClientId, Stream stream)
459477

460478
internal void OnRemoteClientRPC(ulong hash, uint senderClientId, Stream stream)
461479
{
462-
if (!CachedClientRpcs.ContainsKey(GetType()) || !CachedClientRpcs[GetType()].ContainsKey(hash))
480+
if (!CachedClientRpcs.ContainsKey(this) || !CachedClientRpcs[this].ContainsKey(hash))
463481
{
464482
if (LogHelper.CurrentLogLevel <= LogLevel.Normal) LogHelper.LogWarning("ClientRPC request method not found");
465483
return;
@@ -469,43 +487,57 @@ internal void OnRemoteClientRPC(ulong hash, uint senderClientId, Stream stream)
469487

470488
private void InvokeServerRPCLocal(ulong hash, uint senderClientId, Stream stream)
471489
{
472-
if (!CachedServerRpcs.ContainsKey(GetType()) || !CachedServerRpcs[GetType()].ContainsKey(hash))
490+
if (!CachedServerRpcs.ContainsKey(this) || !CachedServerRpcs[this].ContainsKey(hash))
473491
return;
474492

475-
ServerRPC rpc = CachedServerRpcs[GetType()][hash];
493+
ServerRPC rpc = CachedServerRpcs[this][hash];
476494

477495
if (rpc.RequireOwnership && senderClientId != OwnerClientId)
478496
{
479497
if (LogHelper.CurrentLogLevel <= LogLevel.Normal) LogHelper.LogWarning("Only owner can invoke ServerRPC that is marked to require ownership");
480498
return;
481499
}
482-
483-
if (rpc.reflectionMethod != null)
484-
{
485-
rpc.reflectionMethod.Invoke(this, stream);
486-
}
487500

488-
if (rpc.rpcDelegate != null)
501+
//Create a new stream so that the stream they get ONLY contains user data and not MLAPI headers
502+
using (PooledBitStream userStream = PooledBitStream.Get())
489503
{
490-
rpc.rpcDelegate(senderClientId, stream);
504+
userStream.CopyUnreadFrom(stream);
505+
userStream.Position = 0;
506+
507+
if (rpc.reflectionMethod != null)
508+
{
509+
rpc.reflectionMethod.Invoke(this, userStream);
510+
}
511+
512+
if (rpc.rpcDelegate != null)
513+
{
514+
rpc.rpcDelegate(senderClientId, userStream);
515+
}
491516
}
492517
}
493518

494519
private void InvokeClientRPCLocal(ulong hash, uint senderClientId, Stream stream)
495520
{
496-
if (!CachedClientRpcs.ContainsKey(GetType()) || !CachedClientRpcs[GetType()].ContainsKey(hash))
521+
if (!CachedClientRpcs.ContainsKey(this) || !CachedClientRpcs[this].ContainsKey(hash))
497522
return;
498523

499-
ClientRPC rpc = CachedClientRpcs[GetType()][hash];
500-
501-
if (rpc.reflectionMethod != null)
502-
{
503-
rpc.reflectionMethod.Invoke(this, stream);
504-
}
524+
ClientRPC rpc = CachedClientRpcs[this][hash];
505525

506-
if (rpc.rpcDelegate != null)
526+
//Create a new stream so that the stream they get ONLY contains user data and not MLAPI headers
527+
using (PooledBitStream userStream = PooledBitStream.Get())
507528
{
508-
rpc.rpcDelegate(senderClientId, stream);
529+
userStream.CopyUnreadFrom(stream);
530+
userStream.Position = 0;
531+
532+
if (rpc.reflectionMethod != null)
533+
{
534+
rpc.reflectionMethod.Invoke(this, userStream);
535+
}
536+
537+
if (rpc.rpcDelegate != null)
538+
{
539+
rpc.rpcDelegate(senderClientId, userStream);
540+
}
509541
}
510542
}
511543

@@ -552,7 +584,7 @@ internal void SendClientRPCBoxed(ulong hash, uint clientId, params object[] para
552584

553585
internal void SendServerRPCPerformance(ulong hash, Stream messageStream)
554586
{
555-
if (!isClient)
587+
if (!isClient && isRunning)
556588
{
557589
//We are ONLY a server.
558590
if (LogHelper.CurrentLogLevel <= LogLevel.Normal) LogHelper.LogWarning("Only server and host can invoke ServerRPC");
@@ -573,14 +605,16 @@ internal void SendServerRPCPerformance(ulong hash, Stream messageStream)
573605
messageStream.Position = 0;
574606
InvokeServerRPCLocal(hash, NetworkingManager.singleton.LocalClientId, messageStream);
575607
}
576-
577-
InternalMessageHandler.Send(NetworkingManager.singleton.ServerClientId, MLAPIConstants.MLAPI_SERVER_RPC, "MLAPI_DEFAULT_MESSAGE", stream);
608+
else
609+
{
610+
InternalMessageHandler.Send(NetworkingManager.singleton.ServerClientId, MLAPIConstants.MLAPI_SERVER_RPC, "MLAPI_DEFAULT_MESSAGE", stream);
611+
}
578612
}
579613
}
580614

581615
internal void SendClientRPCPerformance(ulong hash, List<uint> clientIds, Stream messageStream)
582616
{
583-
if (!isServer)
617+
if (!isServer && isRunning)
584618
{
585619
//We are NOT a server.
586620
if (LogHelper.CurrentLogLevel <= LogLevel.Normal) LogHelper.LogWarning("Only clients and host can invoke ClientRPC");
@@ -631,7 +665,7 @@ internal void SendClientRPCPerformance(ulong hash, List<uint> clientIds, Stream
631665

632666
internal void SendClientRPCPerformance(ulong hash, uint clientId, Stream messageStream)
633667
{
634-
if (!isServer)
668+
if (!isServer && isRunning)
635669
{
636670
//We are NOT a server.
637671
if (LogHelper.CurrentLogLevel <= LogLevel.Normal) LogHelper.LogWarning("Only clients and host can invoke ClientRPC");

0 commit comments

Comments
 (0)