From c729148cf2474447855b15ccc98e608a708fded5 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Fri, 16 Apr 2021 16:44:11 -0500 Subject: [PATCH 01/18] NetworkPrefab registration and default PlayerPrefab This is the first pass changes required to implement MTT-640. The default player prefab is now a directly assigned value as opposed to a checkbox in the network prefab list. The default player prefab has to also be included in the NetworkPrefab list (this is so the default player prefab can be overridden too) NetworkPrefab entries can be overridden and directly assigned alternate prefabs for clients to spawn. The source prefab (what the server uses) can be a prefab reference or a prefab hash. --- .../Editor/NetworkManagerEditor.cs | 665 +++++++++--------- .../Runtime/Configuration/NetworkConfig.cs | 12 +- .../Runtime/Configuration/NetworkPrefab.cs | 26 + .../Runtime/Core/NetworkManager.cs | 79 ++- .../Runtime/Spawning/NetworkSpawnManager.cs | 51 +- .../Assets/ManualTests/RpcTesting.unity | 18 +- 6 files changed, 486 insertions(+), 365 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs b/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs index 685b9111aa..57e4d6f551 100644 --- a/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs +++ b/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs @@ -3,423 +3,442 @@ using UnityEditor; using UnityEngine; using UnityEditorInternal; -using MLAPI; using MLAPI.Configuration; using MLAPI.Transports; -[CustomEditor(typeof(NetworkManager), true)] -[CanEditMultipleObjects] -public class NetworkManagerEditor : Editor +namespace MLAPI.Editor { - // Properties - private SerializedProperty m_DontDestroyOnLoadProperty; - private SerializedProperty m_RunInBackgroundProperty; - private SerializedProperty m_LogLevelProperty; - - // NetworkConfig - private SerializedProperty m_NetworkConfigProperty; - - // NetworkConfig fields - private SerializedProperty m_ProtocolVersionProperty; - private SerializedProperty m_AllowRuntimeSceneChangesProperty; - private SerializedProperty m_NetworkTransportProperty; - private SerializedProperty m_ReceiveTickrateProperty; - private SerializedProperty m_NetworkTickIntervalSecProperty; - private SerializedProperty m_MaxReceiveEventsPerTickRateProperty; - private SerializedProperty m_EventTickrateProperty; - private SerializedProperty m_MaxObjectUpdatesPerTickProperty; - private SerializedProperty m_ClientConnectionBufferTimeoutProperty; - private SerializedProperty m_ConnectionApprovalProperty; - private SerializedProperty m_EnableTimeResyncProperty; - private SerializedProperty m_TimeResyncIntervalProperty; - private SerializedProperty m_EnableNetworkVariableProperty; - private SerializedProperty m_EnsureNetworkVariableLengthSafetyProperty; - private SerializedProperty m_CreatePlayerPrefabProperty; - private SerializedProperty m_ForceSamePrefabsProperty; - private SerializedProperty m_EnableSceneManagementProperty; - private SerializedProperty m_RecycleNetworkIdsProperty; - private SerializedProperty m_NetworkIdRecycleDelayProperty; - private SerializedProperty m_RpcHashSizeProperty; - private SerializedProperty m_LoadSceneTimeOutProperty; - private SerializedProperty m_EnableMessageBufferingProperty; - private SerializedProperty m_MessageBufferTimeoutProperty; - - private ReorderableList m_NetworkPrefabsList; - private ReorderableList m_RegisteredScenesList; - - private NetworkManager m_NetworkManager; - private bool m_Initialized; - - private readonly List m_TransportTypes = new List(); - private string[] m_TransportNames = { "Select transport..." }; - - private void ReloadTransports() + [CustomEditor(typeof(NetworkManager), true)] + [CanEditMultipleObjects] + public class NetworkManagerEditor : UnityEditor.Editor { - m_TransportTypes.Clear(); - - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - - foreach (var assembly in assemblies) + // Properties + private SerializedProperty m_DontDestroyOnLoadProperty; + private SerializedProperty m_RunInBackgroundProperty; + private SerializedProperty m_LogLevelProperty; + + // NetworkConfig + private SerializedProperty m_NetworkConfigProperty; + + // NetworkConfig fields + private SerializedProperty m_PlayerPrefabProperty; + private SerializedProperty m_ProtocolVersionProperty; + private SerializedProperty m_AllowRuntimeSceneChangesProperty; + private SerializedProperty m_NetworkTransportProperty; + private SerializedProperty m_ReceiveTickrateProperty; + private SerializedProperty m_NetworkTickIntervalSecProperty; + private SerializedProperty m_MaxReceiveEventsPerTickRateProperty; + private SerializedProperty m_EventTickrateProperty; + private SerializedProperty m_MaxObjectUpdatesPerTickProperty; + private SerializedProperty m_ClientConnectionBufferTimeoutProperty; + private SerializedProperty m_ConnectionApprovalProperty; + private SerializedProperty m_EnableTimeResyncProperty; + private SerializedProperty m_TimeResyncIntervalProperty; + private SerializedProperty m_EnableNetworkVariableProperty; + private SerializedProperty m_EnsureNetworkVariableLengthSafetyProperty; + private SerializedProperty m_CreatePlayerPrefabProperty; + private SerializedProperty m_ForceSamePrefabsProperty; + private SerializedProperty m_UsePrefabSyncProperty; + private SerializedProperty m_EnableSceneManagementProperty; + private SerializedProperty m_RecycleNetworkIdsProperty; + private SerializedProperty m_NetworkIdRecycleDelayProperty; + private SerializedProperty m_RpcHashSizeProperty; + private SerializedProperty m_LoadSceneTimeOutProperty; + private SerializedProperty m_EnableMessageBufferingProperty; + private SerializedProperty m_MessageBufferTimeoutProperty; + + private ReorderableList m_NetworkPrefabsList; + private ReorderableList m_RegisteredScenesList; + + private NetworkManager m_NetworkManager; + private bool m_Initialized; + + private readonly List m_TransportTypes = new List(); + private string[] m_TransportNames = { "Select transport..." }; + + private void ReloadTransports() { - var types = assembly.GetTypes(); + m_TransportTypes.Clear(); + + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - foreach (var type in types) + foreach (var assembly in assemblies) { - if (type.IsSubclassOf(typeof(NetworkTransport))) + var types = assembly.GetTypes(); + + foreach (var type in types) { - m_TransportTypes.Add(type); + if (type.IsSubclassOf(typeof(NetworkTransport))) + { + m_TransportTypes.Add(type); + } } } - } - m_TransportNames = new string[m_TransportTypes.Count + 1]; - m_TransportNames[0] = "Select transport..."; + m_TransportNames = new string[m_TransportTypes.Count + 1]; + m_TransportNames[0] = "Select transport..."; - for (int i = 0; i < m_TransportTypes.Count; i++) - { - m_TransportNames[i + 1] = m_TransportTypes[i].Name; + for (int i = 0; i < m_TransportTypes.Count; i++) + { + m_TransportNames[i + 1] = m_TransportTypes[i].Name; + } } - } - private void Init() - { - if (m_Initialized) + private void Initialize() { - return; - } + if (m_Initialized) + { + return; + } - m_Initialized = true; - m_NetworkManager = (NetworkManager)target; - - // Base properties - m_DontDestroyOnLoadProperty = serializedObject.FindProperty(nameof(NetworkManager.DontDestroy)); - m_RunInBackgroundProperty = serializedObject.FindProperty(nameof(NetworkManager.RunInBackground)); - m_LogLevelProperty = serializedObject.FindProperty(nameof(NetworkManager.LogLevel)); - m_NetworkConfigProperty = serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig)); - - // NetworkConfig properties - m_ProtocolVersionProperty = m_NetworkConfigProperty.FindPropertyRelative("ProtocolVersion"); - m_AllowRuntimeSceneChangesProperty = m_NetworkConfigProperty.FindPropertyRelative("AllowRuntimeSceneChanges"); - m_NetworkTransportProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTransport"); - m_ReceiveTickrateProperty = m_NetworkConfigProperty.FindPropertyRelative("ReceiveTickrate"); - m_NetworkTickIntervalSecProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTickIntervalSec"); - m_MaxReceiveEventsPerTickRateProperty = m_NetworkConfigProperty.FindPropertyRelative("MaxReceiveEventsPerTickRate"); - m_EventTickrateProperty = m_NetworkConfigProperty.FindPropertyRelative("EventTickrate"); - m_ClientConnectionBufferTimeoutProperty = m_NetworkConfigProperty.FindPropertyRelative("ClientConnectionBufferTimeout"); - m_ConnectionApprovalProperty = m_NetworkConfigProperty.FindPropertyRelative("ConnectionApproval"); - m_EnableTimeResyncProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableTimeResync"); - m_TimeResyncIntervalProperty = m_NetworkConfigProperty.FindPropertyRelative("TimeResyncInterval"); - m_EnableNetworkVariableProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableNetworkVariable"); - m_EnsureNetworkVariableLengthSafetyProperty = m_NetworkConfigProperty.FindPropertyRelative("EnsureNetworkVariableLengthSafety"); - m_CreatePlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative("CreatePlayerPrefab"); - m_ForceSamePrefabsProperty = m_NetworkConfigProperty.FindPropertyRelative("ForceSamePrefabs"); - m_EnableSceneManagementProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableSceneManagement"); - m_RecycleNetworkIdsProperty = m_NetworkConfigProperty.FindPropertyRelative("RecycleNetworkIds"); - m_NetworkIdRecycleDelayProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkIdRecycleDelay"); - m_RpcHashSizeProperty = m_NetworkConfigProperty.FindPropertyRelative("RpcHashSize"); - m_LoadSceneTimeOutProperty = m_NetworkConfigProperty.FindPropertyRelative("LoadSceneTimeOut"); - m_EnableMessageBufferingProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableMessageBuffering"); - m_MessageBufferTimeoutProperty = m_NetworkConfigProperty.FindPropertyRelative("MessageBufferTimeout"); - - - ReloadTransports(); - } + m_Initialized = true; + m_NetworkManager = (NetworkManager)target; + + // Base properties + m_DontDestroyOnLoadProperty = serializedObject.FindProperty(nameof(NetworkManager.DontDestroy)); + m_RunInBackgroundProperty = serializedObject.FindProperty(nameof(NetworkManager.RunInBackground)); + m_LogLevelProperty = serializedObject.FindProperty(nameof(NetworkManager.LogLevel)); + m_NetworkConfigProperty = serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig)); + + // NetworkConfig properties + m_PlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative(nameof(NetworkConfig.PlayerPrefab)); + m_ProtocolVersionProperty = m_NetworkConfigProperty.FindPropertyRelative("ProtocolVersion"); + m_AllowRuntimeSceneChangesProperty = m_NetworkConfigProperty.FindPropertyRelative("AllowRuntimeSceneChanges"); + m_NetworkTransportProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTransport"); + m_ReceiveTickrateProperty = m_NetworkConfigProperty.FindPropertyRelative("ReceiveTickrate"); + m_NetworkTickIntervalSecProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTickIntervalSec"); + m_MaxReceiveEventsPerTickRateProperty = m_NetworkConfigProperty.FindPropertyRelative("MaxReceiveEventsPerTickRate"); + m_EventTickrateProperty = m_NetworkConfigProperty.FindPropertyRelative("EventTickrate"); + m_ClientConnectionBufferTimeoutProperty = m_NetworkConfigProperty.FindPropertyRelative("ClientConnectionBufferTimeout"); + m_ConnectionApprovalProperty = m_NetworkConfigProperty.FindPropertyRelative("ConnectionApproval"); + m_EnableTimeResyncProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableTimeResync"); + m_TimeResyncIntervalProperty = m_NetworkConfigProperty.FindPropertyRelative("TimeResyncInterval"); + m_EnableNetworkVariableProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableNetworkVariable"); + m_EnsureNetworkVariableLengthSafetyProperty = m_NetworkConfigProperty.FindPropertyRelative("EnsureNetworkVariableLengthSafety"); + m_CreatePlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative("CreatePlayerPrefab"); + m_ForceSamePrefabsProperty = m_NetworkConfigProperty.FindPropertyRelative("ForceSamePrefabs"); + m_UsePrefabSyncProperty = m_NetworkConfigProperty.FindPropertyRelative("UsePrefabSync"); + m_EnableSceneManagementProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableSceneManagement"); + m_RecycleNetworkIdsProperty = m_NetworkConfigProperty.FindPropertyRelative("RecycleNetworkIds"); + m_NetworkIdRecycleDelayProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkIdRecycleDelay"); + m_RpcHashSizeProperty = m_NetworkConfigProperty.FindPropertyRelative("RpcHashSize"); + m_LoadSceneTimeOutProperty = m_NetworkConfigProperty.FindPropertyRelative("LoadSceneTimeOut"); + m_EnableMessageBufferingProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableMessageBuffering"); + m_MessageBufferTimeoutProperty = m_NetworkConfigProperty.FindPropertyRelative("MessageBufferTimeout"); + + + ReloadTransports(); + } - private void CheckNullProperties() - { - // Base properties - m_DontDestroyOnLoadProperty = serializedObject.FindProperty(nameof(NetworkManager.DontDestroy)); - m_RunInBackgroundProperty = serializedObject.FindProperty(nameof(NetworkManager.RunInBackground)); - m_LogLevelProperty = serializedObject.FindProperty(nameof(NetworkManager.LogLevel)); - m_NetworkConfigProperty = serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig)); - - // NetworkConfig properties - m_ProtocolVersionProperty = m_NetworkConfigProperty.FindPropertyRelative("ProtocolVersion"); - m_AllowRuntimeSceneChangesProperty = m_NetworkConfigProperty.FindPropertyRelative("AllowRuntimeSceneChanges"); - m_NetworkTransportProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTransport"); - m_ReceiveTickrateProperty = m_NetworkConfigProperty.FindPropertyRelative("ReceiveTickrate"); - m_NetworkTickIntervalSecProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTickIntervalSec"); - m_MaxReceiveEventsPerTickRateProperty = m_NetworkConfigProperty.FindPropertyRelative("MaxReceiveEventsPerTickRate"); - m_EventTickrateProperty = m_NetworkConfigProperty.FindPropertyRelative("EventTickrate"); - m_ClientConnectionBufferTimeoutProperty = m_NetworkConfigProperty.FindPropertyRelative("ClientConnectionBufferTimeout"); - m_ConnectionApprovalProperty = m_NetworkConfigProperty.FindPropertyRelative("ConnectionApproval"); - m_EnableTimeResyncProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableTimeResync"); - m_TimeResyncIntervalProperty = m_NetworkConfigProperty.FindPropertyRelative("TimeResyncInterval"); - m_EnableNetworkVariableProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableNetworkVariable"); - m_EnsureNetworkVariableLengthSafetyProperty = m_NetworkConfigProperty.FindPropertyRelative("EnsureNetworkVariableLengthSafety"); - m_CreatePlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative("CreatePlayerPrefab"); - m_ForceSamePrefabsProperty = m_NetworkConfigProperty.FindPropertyRelative("ForceSamePrefabs"); - m_EnableSceneManagementProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableSceneManagement"); - m_RecycleNetworkIdsProperty = m_NetworkConfigProperty.FindPropertyRelative("RecycleNetworkIds"); - m_NetworkIdRecycleDelayProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkIdRecycleDelay"); - m_RpcHashSizeProperty = m_NetworkConfigProperty.FindPropertyRelative("RpcHashSize"); - m_LoadSceneTimeOutProperty = m_NetworkConfigProperty.FindPropertyRelative("LoadSceneTimeOut"); - m_EnableMessageBufferingProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableMessageBuffering"); - m_MessageBufferTimeoutProperty = m_NetworkConfigProperty.FindPropertyRelative("MessageBufferTimeout"); - } + private void CheckNullProperties() + { + // Base properties + m_DontDestroyOnLoadProperty = serializedObject.FindProperty(nameof(NetworkManager.DontDestroy)); + m_RunInBackgroundProperty = serializedObject.FindProperty(nameof(NetworkManager.RunInBackground)); + m_LogLevelProperty = serializedObject.FindProperty(nameof(NetworkManager.LogLevel)); + m_NetworkConfigProperty = serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig)); + + // NetworkConfig properties + m_PlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative(nameof(NetworkConfig.PlayerPrefab)); + m_ProtocolVersionProperty = m_NetworkConfigProperty.FindPropertyRelative("ProtocolVersion"); + m_AllowRuntimeSceneChangesProperty = m_NetworkConfigProperty.FindPropertyRelative("AllowRuntimeSceneChanges"); + m_NetworkTransportProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTransport"); + m_ReceiveTickrateProperty = m_NetworkConfigProperty.FindPropertyRelative("ReceiveTickrate"); + m_NetworkTickIntervalSecProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkTickIntervalSec"); + m_MaxReceiveEventsPerTickRateProperty = m_NetworkConfigProperty.FindPropertyRelative("MaxReceiveEventsPerTickRate"); + m_EventTickrateProperty = m_NetworkConfigProperty.FindPropertyRelative("EventTickrate"); + m_ClientConnectionBufferTimeoutProperty = m_NetworkConfigProperty.FindPropertyRelative("ClientConnectionBufferTimeout"); + m_ConnectionApprovalProperty = m_NetworkConfigProperty.FindPropertyRelative("ConnectionApproval"); + m_EnableTimeResyncProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableTimeResync"); + m_TimeResyncIntervalProperty = m_NetworkConfigProperty.FindPropertyRelative("TimeResyncInterval"); + m_EnableNetworkVariableProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableNetworkVariable"); + m_EnsureNetworkVariableLengthSafetyProperty = m_NetworkConfigProperty.FindPropertyRelative("EnsureNetworkVariableLengthSafety"); + m_CreatePlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative("CreatePlayerPrefab"); + m_ForceSamePrefabsProperty = m_NetworkConfigProperty.FindPropertyRelative("ForceSamePrefabs"); + m_EnableSceneManagementProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableSceneManagement"); + m_RecycleNetworkIdsProperty = m_NetworkConfigProperty.FindPropertyRelative("RecycleNetworkIds"); + m_NetworkIdRecycleDelayProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkIdRecycleDelay"); + m_RpcHashSizeProperty = m_NetworkConfigProperty.FindPropertyRelative("RpcHashSize"); + m_LoadSceneTimeOutProperty = m_NetworkConfigProperty.FindPropertyRelative("LoadSceneTimeOut"); + m_EnableMessageBufferingProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableMessageBuffering"); + m_MessageBufferTimeoutProperty = m_NetworkConfigProperty.FindPropertyRelative("MessageBufferTimeout"); + } - private void OnEnable() - { - m_NetworkPrefabsList = new ReorderableList(serializedObject, serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig)).FindPropertyRelative(nameof(NetworkConfig.NetworkPrefabs)), true, true, true, true); - m_NetworkPrefabsList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => + private void OnEnable() { - for (int i = 0; i < m_NetworkManager.NetworkConfig.NetworkPrefabs.Count; i++) + m_NetworkPrefabsList = new ReorderableList(serializedObject, serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig)).FindPropertyRelative(nameof(NetworkConfig.NetworkPrefabs)), true, true, true, true); + m_NetworkPrefabsList.elementHeightCallback = index => { - // Find the first playerPrefab - if (m_NetworkManager.NetworkConfig.NetworkPrefabs[i].IsPlayer) + var networkPrefab = m_NetworkPrefabsList.serializedProperty.GetArrayElementAtIndex(index); + var networkOverrideProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.Override)); + var networkOverrideInt = networkOverrideProp.enumValueIndex; + + return 10 + (networkOverrideInt == 0 ? EditorGUIUtility.singleLineHeight : (EditorGUIUtility.singleLineHeight * 2) + 5); + }; + m_NetworkPrefabsList.drawElementCallback = (rect, index, isActive, isFocused) => + { + rect.y += 5; + + var networkPrefab = m_NetworkPrefabsList.serializedProperty.GetArrayElementAtIndex(index); + var networkPrefabProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.Prefab)); + var networkSourceHashProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.OverridingSourceHash)); + var networkSourcePrefabProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.OverridingSourcePrefab)); + var networkTargetPrefabProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.OverridingTargetPrefab)); + var networkOverrideProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.Override)); + var networkOverrideInt = networkOverrideProp.enumValueIndex; + var networkOverrideEnum = (NetworkPrefabOverride)networkOverrideInt; + EditorGUI.LabelField(new Rect(rect.x + rect.width - 70, rect.y, 60, EditorGUIUtility.singleLineHeight), "Override"); + if (networkOverrideEnum == NetworkPrefabOverride.Unset) { - // Iterate over all other and set player prefab to false - for (int j = 0; j < m_NetworkManager.NetworkConfig.NetworkPrefabs.Count; j++) + if (EditorGUI.Toggle(new Rect(rect.x + rect.width - 15, rect.y, 10, EditorGUIUtility.singleLineHeight), false)) { - if (j != i && m_NetworkManager.NetworkConfig.NetworkPrefabs[j].IsPlayer) - { - m_NetworkManager.NetworkConfig.NetworkPrefabs[j].IsPlayer = false; - } + networkOverrideProp.enumValueIndex = (int)NetworkPrefabOverride.Prefab; } - - break; } - } - - var element = m_NetworkPrefabsList.serializedProperty.GetArrayElementAtIndex(index); - int firstLabelWidth = 50; - int secondLabelWidth = 140; - float secondFieldWidth = 10; - int reduceFirstWidth = 45; - - EditorGUI.LabelField(new Rect(rect.x, rect.y, firstLabelWidth, EditorGUIUtility.singleLineHeight), "Prefab"); - EditorGUI.PropertyField(new Rect(rect.x + firstLabelWidth, rect.y, rect.width - firstLabelWidth - secondLabelWidth - secondFieldWidth - reduceFirstWidth, - EditorGUIUtility.singleLineHeight), element.FindPropertyRelative(nameof(NetworkPrefab.Prefab)), GUIContent.none); - - EditorGUI.LabelField(new Rect(rect.width - secondLabelWidth - secondFieldWidth, rect.y, secondLabelWidth, EditorGUIUtility.singleLineHeight), "Default Player Prefab"); - - int playerPrefabIndex = -1; - - for (int i = 0; i < m_NetworkManager.NetworkConfig.NetworkPrefabs.Count; i++) - { - if (m_NetworkManager.NetworkConfig.NetworkPrefabs[i].IsPlayer) + else { - playerPrefabIndex = i; - break; + if (!EditorGUI.Toggle(new Rect(rect.x + rect.width - 15, rect.y, 10, EditorGUIUtility.singleLineHeight), true)) + { + networkOverrideProp.enumValueIndex = 0; + networkOverrideEnum = NetworkPrefabOverride.Unset; + } } - } - - using (new EditorGUI.DisabledScope(playerPrefabIndex != -1 && playerPrefabIndex != index)) - { - EditorGUI.PropertyField(new Rect(rect.width - secondFieldWidth, rect.y, secondFieldWidth, - EditorGUIUtility.singleLineHeight), element.FindPropertyRelative(nameof(NetworkPrefab.IsPlayer)), GUIContent.none); - } - }; - - m_NetworkPrefabsList.drawHeaderCallback = (Rect rect) => { EditorGUI.LabelField(rect, "NetworkPrefabs"); }; + if (networkOverrideEnum == NetworkPrefabOverride.Unset) + { + EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width - 80, EditorGUIUtility.singleLineHeight), networkPrefabProp, GUIContent.none); + } + else + { + networkOverrideProp.enumValueIndex = GUI.Toolbar(new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight), networkOverrideInt - 1, new[] { "Prefab", "Hash" }) + 1; - m_RegisteredScenesList = new ReorderableList(serializedObject, serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig)).FindPropertyRelative(nameof(NetworkConfig.RegisteredScenes)), true, true, true, true); - m_RegisteredScenesList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => - { - var element = m_RegisteredScenesList.serializedProperty.GetArrayElementAtIndex(index); - int firstLabelWidth = 50; - int padding = 20; + if (networkOverrideEnum == NetworkPrefabOverride.Prefab) + { + EditorGUI.PropertyField(new Rect(rect.x + 110, rect.y, rect.width - 190, EditorGUIUtility.singleLineHeight), networkSourcePrefabProp, GUIContent.none); + } + else + { + EditorGUI.PropertyField(new Rect(rect.x + 110, rect.y, rect.width - 190, EditorGUIUtility.singleLineHeight), networkSourceHashProp, GUIContent.none); + } - EditorGUI.LabelField(new Rect(rect.x, rect.y, firstLabelWidth, EditorGUIUtility.singleLineHeight), "Name"); - EditorGUI.PropertyField(new Rect(rect.x + firstLabelWidth, rect.y, rect.width - firstLabelWidth - padding, - EditorGUIUtility.singleLineHeight), element, GUIContent.none); - }; + rect.y += EditorGUIUtility.singleLineHeight + 5; - m_RegisteredScenesList.drawHeaderCallback = (Rect rect) => { EditorGUI.LabelField(rect, "Registered Scene Names"); }; - } + EditorGUI.LabelField(new Rect(rect.x, rect.y, 100, EditorGUIUtility.singleLineHeight), "Overriding Prefab"); + EditorGUI.PropertyField(new Rect(rect.x + 110, rect.y, rect.width - 110, EditorGUIUtility.singleLineHeight), networkTargetPrefabProp, GUIContent.none); + } + }; + m_NetworkPrefabsList.drawHeaderCallback = rect => EditorGUI.LabelField(rect, "NetworkPrefabs"); - public override void OnInspectorGUI() - { - Init(); - CheckNullProperties(); + m_RegisteredScenesList = new ReorderableList(serializedObject, serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig)).FindPropertyRelative(nameof(NetworkConfig.RegisteredScenes)), true, true, true, true); + m_RegisteredScenesList.drawElementCallback = (rect, index, isActive, isFocused) => + { + var element = m_RegisteredScenesList.serializedProperty.GetArrayElementAtIndex(index); + int firstLabelWidth = 50; + int padding = 20; + + EditorGUI.LabelField(new Rect(rect.x, rect.y, firstLabelWidth, EditorGUIUtility.singleLineHeight), "Name"); + EditorGUI.PropertyField(new Rect(rect.x + firstLabelWidth, rect.y, rect.width - firstLabelWidth - padding, EditorGUIUtility.singleLineHeight), element, GUIContent.none); + }; + m_RegisteredScenesList.drawHeaderCallback = rect => EditorGUI.LabelField(rect, "Registered Scene Names"); + } + public override void OnInspectorGUI() { - var iterator = serializedObject.GetIterator(); + Initialize(); + CheckNullProperties(); - for (bool enterChildren = true; iterator.NextVisible(enterChildren); enterChildren = false) { - using (new EditorGUI.DisabledScope("m_Script" == iterator.propertyPath)) + var iterator = serializedObject.GetIterator(); + + for (bool enterChildren = true; iterator.NextVisible(enterChildren); enterChildren = false) { - EditorGUILayout.PropertyField(iterator, false); + using (new EditorGUI.DisabledScope("m_Script" == iterator.propertyPath)) + { + EditorGUILayout.PropertyField(iterator, false); + } } } - } - if (!m_NetworkManager.IsServer && !m_NetworkManager.IsClient) - { - serializedObject.Update(); - EditorGUILayout.PropertyField(m_DontDestroyOnLoadProperty); - EditorGUILayout.PropertyField(m_RunInBackgroundProperty); - EditorGUILayout.PropertyField(m_LogLevelProperty); - - EditorGUILayout.Space(); - m_NetworkPrefabsList.DoLayoutList(); - - using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableSceneManagement)) + if (!m_NetworkManager.IsServer && !m_NetworkManager.IsClient) { - m_RegisteredScenesList.DoLayoutList(); + serializedObject.Update(); + EditorGUILayout.PropertyField(m_DontDestroyOnLoadProperty); + EditorGUILayout.PropertyField(m_RunInBackgroundProperty); + EditorGUILayout.PropertyField(m_LogLevelProperty); EditorGUILayout.Space(); - } + EditorGUILayout.PropertyField(m_PlayerPrefabProperty); + EditorGUILayout.Space(); + + m_NetworkPrefabsList.DoLayoutList(); + EditorGUILayout.Space(); - EditorGUILayout.LabelField("General", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(m_ProtocolVersionProperty); + using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableSceneManagement)) + { + m_RegisteredScenesList.DoLayoutList(); + EditorGUILayout.Space(); + } - EditorGUILayout.PropertyField(m_NetworkTransportProperty); - if (m_NetworkTransportProperty.objectReferenceValue == null) - { - EditorGUILayout.HelpBox("You have no transport selected. A transport is required for the MLAPI to work. Which one do you want?", MessageType.Warning); + EditorGUILayout.LabelField("General", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_ProtocolVersionProperty); - int selection = EditorGUILayout.Popup(0, m_TransportNames); + EditorGUILayout.PropertyField(m_NetworkTransportProperty); - if (selection > 0) + if (m_NetworkTransportProperty.objectReferenceValue == null) { - ReloadTransports(); + EditorGUILayout.HelpBox("You have no transport selected. A transport is required for the MLAPI to work. Which one do you want?", MessageType.Warning); - var transportComponent = m_NetworkManager.gameObject.GetComponent(m_TransportTypes[selection - 1]); + int selection = EditorGUILayout.Popup(0, m_TransportNames); - if (transportComponent == null) + if (selection > 0) { - transportComponent = m_NetworkManager.gameObject.AddComponent(m_TransportTypes[selection - 1]); - } + ReloadTransports(); - m_NetworkTransportProperty.objectReferenceValue = transportComponent; + var transportComponent = m_NetworkManager.gameObject.GetComponent(m_TransportTypes[selection - 1]); - Repaint(); - } - } + if (transportComponent == null) + { + transportComponent = m_NetworkManager.gameObject.AddComponent(m_TransportTypes[selection - 1]); + } - EditorGUILayout.PropertyField(m_EnableTimeResyncProperty); + m_NetworkTransportProperty.objectReferenceValue = transportComponent; - using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableTimeResync)) - { - EditorGUILayout.PropertyField(m_TimeResyncIntervalProperty); - } + Repaint(); + } + } - EditorGUILayout.LabelField("Performance", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(m_ReceiveTickrateProperty); - EditorGUILayout.PropertyField(m_NetworkTickIntervalSecProperty); - EditorGUILayout.PropertyField(m_MaxReceiveEventsPerTickRateProperty); - EditorGUILayout.PropertyField(m_EventTickrateProperty); - EditorGUILayout.PropertyField(m_EnableNetworkVariableProperty); + EditorGUILayout.PropertyField(m_EnableTimeResyncProperty); - using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableNetworkVariable)) - { - if (m_MaxObjectUpdatesPerTickProperty != null) + using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableTimeResync)) { - EditorGUILayout.PropertyField(m_MaxObjectUpdatesPerTickProperty); + EditorGUILayout.PropertyField(m_TimeResyncIntervalProperty); } - EditorGUILayout.PropertyField(m_EnsureNetworkVariableLengthSafetyProperty); - } - - EditorGUILayout.LabelField("Connection", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(m_ConnectionApprovalProperty); + EditorGUILayout.LabelField("Performance", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_ReceiveTickrateProperty); + EditorGUILayout.PropertyField(m_NetworkTickIntervalSecProperty); + EditorGUILayout.PropertyField(m_MaxReceiveEventsPerTickRateProperty); + EditorGUILayout.PropertyField(m_EventTickrateProperty); + EditorGUILayout.PropertyField(m_EnableNetworkVariableProperty); - using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.ConnectionApproval)) - { - EditorGUILayout.PropertyField(m_ClientConnectionBufferTimeoutProperty); - } + using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableNetworkVariable)) + { + if (m_MaxObjectUpdatesPerTickProperty != null) + { + EditorGUILayout.PropertyField(m_MaxObjectUpdatesPerTickProperty); + } - EditorGUILayout.LabelField("Spawning", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(m_CreatePlayerPrefabProperty); - EditorGUILayout.PropertyField(m_ForceSamePrefabsProperty); + EditorGUILayout.PropertyField(m_EnsureNetworkVariableLengthSafetyProperty); + } - EditorGUILayout.PropertyField(m_RecycleNetworkIdsProperty); + EditorGUILayout.LabelField("Connection", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_ConnectionApprovalProperty); - using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.RecycleNetworkIds)) - { - EditorGUILayout.PropertyField(m_NetworkIdRecycleDelayProperty); - } + using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.ConnectionApproval)) + { + EditorGUILayout.PropertyField(m_ClientConnectionBufferTimeoutProperty); + } - EditorGUILayout.PropertyField(m_EnableMessageBufferingProperty); + EditorGUILayout.LabelField("Spawning", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_CreatePlayerPrefabProperty); + EditorGUILayout.PropertyField(m_ForceSamePrefabsProperty); - using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableMessageBuffering)) - { - EditorGUILayout.PropertyField(m_MessageBufferTimeoutProperty); - } - EditorGUILayout.LabelField("Bandwidth", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(m_RpcHashSizeProperty); + EditorGUILayout.PropertyField(m_RecycleNetworkIdsProperty); - EditorGUILayout.LabelField("Scene Management", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(m_EnableSceneManagementProperty); + using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.RecycleNetworkIds)) + { + EditorGUILayout.PropertyField(m_NetworkIdRecycleDelayProperty); + } - using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableSceneManagement)) - { - EditorGUILayout.PropertyField(m_LoadSceneTimeOutProperty); - EditorGUILayout.PropertyField(m_AllowRuntimeSceneChangesProperty); - } + EditorGUILayout.PropertyField(m_EnableMessageBufferingProperty); - serializedObject.ApplyModifiedProperties(); + using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableMessageBuffering)) + { + EditorGUILayout.PropertyField(m_MessageBufferTimeoutProperty); + } + EditorGUILayout.LabelField("Bandwidth", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_RpcHashSizeProperty); - // Start buttons below - { - string buttonDisabledReasonSuffix = ""; + EditorGUILayout.LabelField("Scene Management", EditorStyles.boldLabel); + EditorGUILayout.PropertyField(m_EnableSceneManagementProperty); - if (!EditorApplication.isPlaying) + using (new EditorGUI.DisabledScope(!m_NetworkManager.NetworkConfig.EnableSceneManagement)) { - buttonDisabledReasonSuffix = ". This can only be done in play mode"; - GUI.enabled = false; + EditorGUILayout.PropertyField(m_LoadSceneTimeOutProperty); + EditorGUILayout.PropertyField(m_AllowRuntimeSceneChangesProperty); } - if (GUILayout.Button(new GUIContent("Start Host", "Starts a host instance" + buttonDisabledReasonSuffix))) - { - m_NetworkManager.StartHost(); - } + serializedObject.ApplyModifiedProperties(); - if (GUILayout.Button(new GUIContent("Start Server", "Starts a server instance" + buttonDisabledReasonSuffix))) - { - m_NetworkManager.StartServer(); - } - if (GUILayout.Button(new GUIContent("Start Client", "Starts a client instance" + buttonDisabledReasonSuffix))) + // Start buttons below { - m_NetworkManager.StartClient(); - } + string buttonDisabledReasonSuffix = ""; - if (!EditorApplication.isPlaying) - { - GUI.enabled = true; - } - } - } - else - { - string instanceType = string.Empty; + if (!EditorApplication.isPlaying) + { + buttonDisabledReasonSuffix = ". This can only be done in play mode"; + GUI.enabled = false; + } - if (m_NetworkManager.IsHost) - { - instanceType = "Host"; - } - else if (m_NetworkManager.IsServer) - { - instanceType = "Server"; - } - else if (m_NetworkManager.IsClient) - { - instanceType = "Client"; - } + if (GUILayout.Button(new GUIContent("Start Host", "Starts a host instance" + buttonDisabledReasonSuffix))) + { + m_NetworkManager.StartHost(); + } + + if (GUILayout.Button(new GUIContent("Start Server", "Starts a server instance" + buttonDisabledReasonSuffix))) + { + m_NetworkManager.StartServer(); + } - EditorGUILayout.HelpBox("You cannot edit the NetworkConfig when a " + instanceType + " is running.", MessageType.Info); + if (GUILayout.Button(new GUIContent("Start Client", "Starts a client instance" + buttonDisabledReasonSuffix))) + { + m_NetworkManager.StartClient(); + } - if (GUILayout.Button(new GUIContent("Stop " + instanceType, "Stops the " + instanceType + " instance."))) + if (!EditorApplication.isPlaying) + { + GUI.enabled = true; + } + } + } + else { + string instanceType = string.Empty; + if (m_NetworkManager.IsHost) { - m_NetworkManager.StopHost(); + instanceType = "Host"; } else if (m_NetworkManager.IsServer) { - m_NetworkManager.StopServer(); + instanceType = "Server"; } else if (m_NetworkManager.IsClient) { - m_NetworkManager.StopClient(); + instanceType = "Client"; + } + + EditorGUILayout.HelpBox("You cannot edit the NetworkConfig when a " + instanceType + " is running.", MessageType.Info); + + if (GUILayout.Button(new GUIContent("Stop " + instanceType, "Stops the " + instanceType + " instance."))) + { + if (m_NetworkManager.IsHost) + { + m_NetworkManager.StopHost(); + } + else if (m_NetworkManager.IsServer) + { + m_NetworkManager.StopServer(); + } + else if (m_NetworkManager.IsClient) + { + m_NetworkManager.StopClient(); + } } } } diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs index 278c6e7b03..50a5c01fea 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs @@ -41,17 +41,19 @@ public class NetworkConfig "If this is true, clients with different initial configurations will not work together.")] public bool AllowRuntimeSceneChanges = false; + /// + /// The default player prefab + /// + public GameObject PlayerPrefab; + /// /// A list of spawnable prefabs /// [Tooltip("The prefabs that can be spawned across the network")] public List NetworkPrefabs = new List(); - /// - /// The default player prefab - /// - [SerializeReference] - internal uint PlayerPrefabHash; + + public Dictionary HashedNetworkPrefabs = new Dictionary(); /// /// Whether or not a player object should be created by default. This value can be overridden on a case by case basis with ConnectionApproval. diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs index c7292b0722..cd3c4f2bd9 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs @@ -4,6 +4,13 @@ namespace MLAPI.Configuration { + public enum NetworkPrefabOverride + { + Unset, + Prefab, + Hash + } + /// /// Class that represents a NetworkPrefab /// @@ -15,6 +22,25 @@ public class NetworkPrefab /// public GameObject Prefab; + public NetworkPrefabOverride Override; + + /// + /// The original "source" prefab + /// + public GameObject OverridingSourcePrefab; + + /// + /// The original "source" prefab's hash + /// This is used typically in multi-project patterns where a separate project contains the + /// source prefab and the GlobalObjectIdHash was copied and pasted into this field. + /// + public uint OverridingSourceHash; + + /// + /// The prefab to replace the OverridingSourcePrefab with + /// + public GameObject OverridingTargetPrefab; + /// /// Whether or not this is a player prefab /// diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index cea24793ac..1699a2f4c1 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -21,7 +21,6 @@ using MLAPI.Transports.Tasks; using MLAPI.Messaging.Buffering; using Unity.Profiling; -using UnityEditor.VersionControl; namespace MLAPI { @@ -245,39 +244,50 @@ private void OnValidate() }; } + if (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab && !NetworkConfig.ConnectionApproval) + { + if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) + { + NetworkLog.LogWarning($"There is no {nameof(NetworkPrefab)} marked as a {nameof(NetworkPrefab.IsPlayer)}"); + } + //Exit if we don't find a player prefab under these conditions + return; + } + + //Clear this out and rebuild + NetworkConfig.HashedNetworkPrefabs.Clear(); + + //Check network prefabs and assign to dictionary for quick look up for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) { if (NetworkConfig.NetworkPrefabs[i] != null && NetworkConfig.NetworkPrefabs[i].Prefab != null) { - if (NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent() == null) + var networkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent(); + if (networkObject == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { NetworkLog.LogWarning($"{nameof(NetworkPrefab)} [{i}] does not have a {nameof(NetworkObject)} component"); } } + else + { + switch (NetworkConfig.NetworkPrefabs[i].Override) + { + default: + case NetworkPrefabOverride.Unset: + NetworkConfig.HashedNetworkPrefabs.Add(networkObject.GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + break; + case NetworkPrefabOverride.Prefab: + NetworkConfig.HashedNetworkPrefabs.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + break; + case NetworkPrefabOverride.Hash: + NetworkConfig.HashedNetworkPrefabs.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourceHash, NetworkConfig.NetworkPrefabs[i]); + break; + } + } } - } - - int playerPrefabCount = NetworkConfig.NetworkPrefabs.Count(x => x.IsPlayer); - - if (playerPrefabCount == 0 && !NetworkConfig.ConnectionApproval && NetworkConfig.CreatePlayerPrefab) - { - if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) - { - NetworkLog.LogWarning($"There is no {nameof(NetworkPrefab)} marked as a {nameof(NetworkPrefab.IsPlayer)}"); - } - } - else if (playerPrefabCount > 1) - { - if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) - { - NetworkLog.LogWarning($"Only one {nameof(NetworkPrefab)} can be marked as a {nameof(NetworkPrefab.IsPlayer)}"); - } - } - - var networkPrefab = NetworkConfig.NetworkPrefabs.FirstOrDefault(x => x.IsPlayer); - NetworkConfig.PlayerPrefabHash = networkPrefab?.Hash ?? (uint)0; + } } #endif @@ -366,6 +376,7 @@ private void Init(bool server) for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) { + var networkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent(); if (NetworkConfig.NetworkPrefabs[i] == null || NetworkConfig.NetworkPrefabs[i].Prefab == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) @@ -380,6 +391,22 @@ private void Init(bool server) NetworkLog.LogError($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") is missing a {nameof(NetworkObject)} component"); } } + if (!NetworkConfig.HashedNetworkPrefabs.ContainsKey(networkObject.GlobalObjectIdHash)) + { + switch (NetworkConfig.NetworkPrefabs[i].Override) + { + default: + case NetworkPrefabOverride.Unset: + NetworkConfig.HashedNetworkPrefabs.Add(networkObject.GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + break; + case NetworkPrefabOverride.Prefab: + NetworkConfig.HashedNetworkPrefabs.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + break; + case NetworkPrefabOverride.Hash: + NetworkConfig.HashedNetworkPrefabs.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourceHash, NetworkConfig.NetworkPrefabs[i]); + break; + } + } } NetworkConfig.NetworkTransport.OnTransportEvent += HandleRawTransportPoll; @@ -1466,7 +1493,7 @@ internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint? if (createPlayerObject) { - var networkObject = SpawnManager.CreateLocalNetworkObject(false, playerPrefabHash ?? NetworkConfig.PlayerPrefabHash, ownerClientId, null, position, rotation); + var networkObject = SpawnManager.CreateLocalNetworkObject(false, playerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent().GlobalObjectIdHash, ownerClientId, null, position, rotation); SpawnManager.SpawnNetworkObjectLocally(networkObject, SpawnManager.GetNetworkObjectId(), false, true, ownerClientId, null, false, 0, false, false); ConnectedClients[ownerClientId].PlayerObject = networkObject; @@ -1555,7 +1582,7 @@ internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint? OnClientConnectedCallback?.Invoke(ownerClientId); - if (!createPlayerObject || (playerPrefabHash == null && NetworkConfig.PlayerPrefabHash == 0)) + if (!createPlayerObject || (playerPrefabHash == null && NetworkConfig.PlayerPrefab == null)) { return; } @@ -1583,7 +1610,7 @@ internal void HandleApproval(ulong ownerClientId, bool createPlayerObject, uint? // This is not a scene object writer.WriteBool(false); - writer.WriteUInt32Packed(playerPrefabHash ?? NetworkConfig.PlayerPrefabHash); + writer.WriteUInt32Packed(playerPrefabHash ?? NetworkConfig.PlayerPrefab.GetComponent().GlobalObjectIdHash); if (ConnectedClients[ownerClientId].PlayerObject.IncludeTransformWhenSpawning == null || ConnectedClients[ownerClientId].PlayerObject.IncludeTransformWhenSpawning(ownerClientId)) { diff --git a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs index 52816b39fd..474fa57fcd 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs @@ -220,20 +220,61 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash } else { - var prefabIndex = GetNetworkPrefabIndexOfHash(prefabHash); + GameObject networkPrefabReference = null; + if(NetworkManager.NetworkConfig.HashedNetworkPrefabs.ContainsKey(prefabHash)) + { + switch (NetworkManager.NetworkConfig.HashedNetworkPrefabs[prefabHash].Override) + { + default: + case NetworkPrefabOverride.Unset: + networkPrefabReference = NetworkManager.NetworkConfig.HashedNetworkPrefabs[prefabHash].Prefab; + break; + case NetworkPrefabOverride.Hash: + case NetworkPrefabOverride.Prefab: + networkPrefabReference = NetworkManager.NetworkConfig.HashedNetworkPrefabs[prefabHash].OverridingTargetPrefab; + break; + } + } - if (prefabIndex < 0) + //for (int i = 0; networkPrefabReference == null && i < NetworkManager.NetworkConfig.NetworkPrefabs.Count; i++) + //{ + // var element = NetworkManager.NetworkConfig.NetworkPrefabs[i]; + + // switch (element.Override) + // { + // default: + // case NetworkPrefabOverride.Unset: + // if (element.Hash == prefabHash) + // { + // networkPrefabReference = element.Prefab; + // } + // break; + // case NetworkPrefabOverride.Prefab: + // if (element.OverridingSourcePrefab.GetComponent().GlobalObjectIdHash == prefabHash) + // { + // networkPrefabReference = element.OverridingTargetPrefab; + // } + // break; + // case NetworkPrefabOverride.Hash: + // if (element.OverridingSourceHash == prefabHash) + // { + // networkPrefabReference = element.OverridingTargetPrefab; + // } + // break; + // } + //} + + if (networkPrefabReference == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) { - NetworkLog.LogError($"Failed to create object locally. [{nameof(prefabHash)}={prefabHash}]. Hash could not be found. Is the prefab registered?"); + NetworkLog.LogError($"Failed to create object locally. [{nameof(prefabHash)}={prefabHash}]. {nameof(NetworkPrefab)} could not be found. Is the prefab registered with {nameof(NetworkManager)}?"); } return null; } - var prefab = NetworkManager.NetworkConfig.NetworkPrefabs[prefabIndex].Prefab; - var networkObject = ((position == null && rotation == null) ? UnityEngine.Object.Instantiate(prefab) : UnityEngine.Object.Instantiate(prefab, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity))).GetComponent(); + var networkObject = ((position == null && rotation == null) ? UnityEngine.Object.Instantiate(networkPrefabReference) : UnityEngine.Object.Instantiate(networkPrefabReference, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity))).GetComponent(); if (parentNetworkObject != null) { diff --git a/testproject/Assets/ManualTests/RpcTesting.unity b/testproject/Assets/ManualTests/RpcTesting.unity index bfca9b276b..69c351c7d9 100644 --- a/testproject/Assets/ManualTests/RpcTesting.unity +++ b/testproject/Assets/ManualTests/RpcTesting.unity @@ -422,7 +422,7 @@ PrefabInstance: - target: {fileID: 6633621479308595792, guid: d725b5588e1b956458798319e6541d84, type: 3} propertyPath: m_AnchorMax.y - value: 0.5 + value: 1 objectReference: {fileID: 0} - target: {fileID: 6633621479308595792, guid: d725b5588e1b956458798319e6541d84, type: 3} @@ -432,7 +432,7 @@ PrefabInstance: - target: {fileID: 6633621479308595792, guid: d725b5588e1b956458798319e6541d84, type: 3} propertyPath: m_AnchorMin.y - value: 0.5 + value: 1 objectReference: {fileID: 0} - target: {fileID: 6633621479308595792, guid: d725b5588e1b956458798319e6541d84, type: 3} @@ -487,7 +487,7 @@ PrefabInstance: - target: {fileID: 6633621479308595792, guid: d725b5588e1b956458798319e6541d84, type: 3} propertyPath: m_AnchoredPosition.y - value: 0 + value: -90 objectReference: {fileID: 0} - target: {fileID: 6633621479308595792, guid: d725b5588e1b956458798319e6541d84, type: 3} @@ -808,11 +808,18 @@ MonoBehaviour: RegisteredScenes: - RpcTesting AllowRuntimeSceneChanges: 0 + PlayerPrefab: {fileID: 4700706668509470175, guid: 7eeaaf9e50c0afc4dab93584a54fb0d6, + type: 3} NetworkPrefabs: - Prefab: {fileID: 4700706668509470175, guid: 7eeaaf9e50c0afc4dab93584a54fb0d6, type: 3} - IsPlayer: 1 - PlayerPrefabHash: 315939022 + Override: 0 + OverridingSourcePrefab: {fileID: 4700706668509470175, guid: 7eeaaf9e50c0afc4dab93584a54fb0d6, + type: 3} + OverridingSourceHash: 0 + OverridingTargetPrefab: {fileID: 8685790303553767886, guid: 96e0a72e30d0c46c8a5c9a750e8f5807, + type: 3} + IsPlayer: 0 CreatePlayerPrefab: 1 ReceiveTickrate: 64 NetworkTickIntervalSec: 0.05 @@ -827,7 +834,6 @@ MonoBehaviour: EnsureNetworkVariableLengthSafety: 0 EnableSceneManagement: 1 ForceSamePrefabs: 1 - UsePrefabSync: 0 RecycleNetworkIds: 1 NetworkIdRecycleDelay: 120 RpcHashSize: 0 From d873eccb1e515560313894453a64890d1cef8ca7 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Fri, 16 Apr 2021 17:56:15 -0500 Subject: [PATCH 02/18] refactor: Naming, Migration, and PlayerPrefab This update is the first pass of making this update as painless as possible to the user by "auto-handling" the v0.1.0 NetworkPrefab pattern as well as there is additional "user-bumper" code that assures the assigned default player prefab is always in the NetworkPrefab list. --- .../Editor/NetworkManagerEditor.cs | 6 +-- .../Runtime/Configuration/NetworkConfig.cs | 2 +- .../Runtime/Configuration/NetworkPrefab.cs | 2 +- .../Runtime/Core/NetworkManager.cs | 52 +++++++++++++++---- .../Runtime/Spawning/NetworkSpawnManager.cs | 38 ++------------ 5 files changed, 51 insertions(+), 49 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs b/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs index 57e4d6f551..38731882d3 100644 --- a/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs +++ b/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs @@ -188,7 +188,7 @@ private void OnEnable() var networkOverrideInt = networkOverrideProp.enumValueIndex; var networkOverrideEnum = (NetworkPrefabOverride)networkOverrideInt; EditorGUI.LabelField(new Rect(rect.x + rect.width - 70, rect.y, 60, EditorGUIUtility.singleLineHeight), "Override"); - if (networkOverrideEnum == NetworkPrefabOverride.Unset) + if (networkOverrideEnum == NetworkPrefabOverride.None) { if (EditorGUI.Toggle(new Rect(rect.x + rect.width - 15, rect.y, 10, EditorGUIUtility.singleLineHeight), false)) { @@ -200,11 +200,11 @@ private void OnEnable() if (!EditorGUI.Toggle(new Rect(rect.x + rect.width - 15, rect.y, 10, EditorGUIUtility.singleLineHeight), true)) { networkOverrideProp.enumValueIndex = 0; - networkOverrideEnum = NetworkPrefabOverride.Unset; + networkOverrideEnum = NetworkPrefabOverride.None; } } - if (networkOverrideEnum == NetworkPrefabOverride.Unset) + if (networkOverrideEnum == NetworkPrefabOverride.None) { EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width - 80, EditorGUIUtility.singleLineHeight), networkPrefabProp, GUIContent.none); } diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs index 50a5c01fea..e07680697b 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs @@ -53,7 +53,7 @@ public class NetworkConfig public List NetworkPrefabs = new List(); - public Dictionary HashedNetworkPrefabs = new Dictionary(); + public DictionaryNetworkPrefabOverrideLinks = new Dictionary(); /// /// Whether or not a player object should be created by default. This value can be overridden on a case by case basis with ConnectionApproval. diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs index cd3c4f2bd9..f60b97ab9b 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs @@ -6,7 +6,7 @@ namespace MLAPI.Configuration { public enum NetworkPrefabOverride { - Unset, + None, Prefab, Hash } diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index 1699a2f4c1..73d48ff8c6 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -254,8 +254,10 @@ private void OnValidate() return; } + var scanForPlayerPrefab = (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab); + //Clear this out and rebuild - NetworkConfig.HashedNetworkPrefabs.Clear(); + NetworkConfig.NetworkPrefabOverrideLinks.Clear(); //Check network prefabs and assign to dictionary for quick look up for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) @@ -272,22 +274,50 @@ private void OnValidate() } else { + //If someone is transitioning to this new format, then go ahead and populate the PlayerPrefab reference for them. + if(scanForPlayerPrefab && NetworkConfig.NetworkPrefabs[i].IsPlayer) + { + NetworkConfig.PlayerPrefab = NetworkConfig.NetworkPrefabs[i].Prefab; + } switch (NetworkConfig.NetworkPrefabs[i].Override) { default: - case NetworkPrefabOverride.Unset: - NetworkConfig.HashedNetworkPrefabs.Add(networkObject.GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + case NetworkPrefabOverride.None: + NetworkConfig.NetworkPrefabOverrideLinks.Add(networkObject.GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); break; case NetworkPrefabOverride.Prefab: - NetworkConfig.HashedNetworkPrefabs.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); break; case NetworkPrefabOverride.Hash: - NetworkConfig.HashedNetworkPrefabs.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourceHash, NetworkConfig.NetworkPrefabs[i]); + NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourceHash, NetworkConfig.NetworkPrefabs[i]); break; } } } - } + } + + //If we have a player prefab then we need to verify it is in the list of NetworkPrefabOverrideLinks for client side spawning. + if (NetworkConfig.PlayerPrefab != null) + { + var playerPrefabNetworkObject = NetworkConfig.PlayerPrefab.GetComponent(); + if (playerPrefabNetworkObject != null) + { + //If we don't have a reference (i.e. someone didn't already add it to the NetworkPrefab list) + if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(NetworkConfig.PlayerPrefab.GetComponent().GlobalObjectIdHash)) + { + //Create a prefab entry + var playerNetworkPrefab = new NetworkPrefab(); + playerNetworkPrefab.Prefab = NetworkConfig.PlayerPrefab; + playerNetworkPrefab.IsPlayer = true; + + //Add it to the prefab list + NetworkConfig.NetworkPrefabs.Add(playerNetworkPrefab); + + //assign its NetworkPrefabOverrideLink + NetworkConfig.NetworkPrefabOverrideLinks.Add(playerPrefabNetworkObject.GlobalObjectIdHash, playerNetworkPrefab); + } + } + } } #endif @@ -391,19 +421,19 @@ private void Init(bool server) NetworkLog.LogError($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") is missing a {nameof(NetworkObject)} component"); } } - if (!NetworkConfig.HashedNetworkPrefabs.ContainsKey(networkObject.GlobalObjectIdHash)) + if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(networkObject.GlobalObjectIdHash)) { switch (NetworkConfig.NetworkPrefabs[i].Override) { default: - case NetworkPrefabOverride.Unset: - NetworkConfig.HashedNetworkPrefabs.Add(networkObject.GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + case NetworkPrefabOverride.None: + NetworkConfig.NetworkPrefabOverrideLinks.Add(networkObject.GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); break; case NetworkPrefabOverride.Prefab: - NetworkConfig.HashedNetworkPrefabs.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); break; case NetworkPrefabOverride.Hash: - NetworkConfig.HashedNetworkPrefabs.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourceHash, NetworkConfig.NetworkPrefabs[i]); + NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourceHash, NetworkConfig.NetworkPrefabs[i]); break; } } diff --git a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs index 474fa57fcd..7152e2e1d4 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs @@ -221,49 +221,21 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash else { GameObject networkPrefabReference = null; - if(NetworkManager.NetworkConfig.HashedNetworkPrefabs.ContainsKey(prefabHash)) + if(NetworkManager.NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(prefabHash)) { - switch (NetworkManager.NetworkConfig.HashedNetworkPrefabs[prefabHash].Override) + switch (NetworkManager.NetworkConfig.NetworkPrefabOverrideLinks[prefabHash].Override) { default: - case NetworkPrefabOverride.Unset: - networkPrefabReference = NetworkManager.NetworkConfig.HashedNetworkPrefabs[prefabHash].Prefab; + case NetworkPrefabOverride.None: + networkPrefabReference = NetworkManager.NetworkConfig.NetworkPrefabOverrideLinks[prefabHash].Prefab; break; case NetworkPrefabOverride.Hash: case NetworkPrefabOverride.Prefab: - networkPrefabReference = NetworkManager.NetworkConfig.HashedNetworkPrefabs[prefabHash].OverridingTargetPrefab; + networkPrefabReference = NetworkManager.NetworkConfig.NetworkPrefabOverrideLinks[prefabHash].OverridingTargetPrefab; break; } } - //for (int i = 0; networkPrefabReference == null && i < NetworkManager.NetworkConfig.NetworkPrefabs.Count; i++) - //{ - // var element = NetworkManager.NetworkConfig.NetworkPrefabs[i]; - - // switch (element.Override) - // { - // default: - // case NetworkPrefabOverride.Unset: - // if (element.Hash == prefabHash) - // { - // networkPrefabReference = element.Prefab; - // } - // break; - // case NetworkPrefabOverride.Prefab: - // if (element.OverridingSourcePrefab.GetComponent().GlobalObjectIdHash == prefabHash) - // { - // networkPrefabReference = element.OverridingTargetPrefab; - // } - // break; - // case NetworkPrefabOverride.Hash: - // if (element.OverridingSourceHash == prefabHash) - // { - // networkPrefabReference = element.OverridingTargetPrefab; - // } - // break; - // } - //} - if (networkPrefabReference == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) From 59511f1c5079f97cb550ec5b9c3e8983bd6ade58 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Fri, 16 Apr 2021 18:19:46 -0500 Subject: [PATCH 03/18] refactor: PlayerPrefab assignment Removing the auto insert within the editor and doing this at runtime. Added additional check to handle assigning the OverridingSourcePrefab if it is null and the Prefab is not. --- .../Runtime/Core/NetworkManager.cs | 96 ++++++++++++------- 1 file changed, 62 insertions(+), 34 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index 73d48ff8c6..a1f7ceeaa2 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -244,21 +244,22 @@ private void OnValidate() }; } - if (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab && !NetworkConfig.ConnectionApproval) - { - if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) - { - NetworkLog.LogWarning($"There is no {nameof(NetworkPrefab)} marked as a {nameof(NetworkPrefab.IsPlayer)}"); - } - //Exit if we don't find a player prefab under these conditions - return; - } + //if (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab && !NetworkConfig.ConnectionApproval) + //{ + // if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) + // { + // NetworkLog.LogWarning($"There is no {nameof(NetworkPrefab)} marked as a {nameof(NetworkPrefab.IsPlayer)}"); + // } + // //Exit if we don't find a player prefab under these conditions + // return; + //} var scanForPlayerPrefab = (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab); //Clear this out and rebuild NetworkConfig.NetworkPrefabOverrideLinks.Clear(); + //Check network prefabs and assign to dictionary for quick look up for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) { @@ -286,7 +287,13 @@ private void OnValidate() NetworkConfig.NetworkPrefabOverrideLinks.Add(networkObject.GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); break; case NetworkPrefabOverride.Prefab: - NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + { + if(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab == null && NetworkConfig.NetworkPrefabs[i].Prefab != null) + { + NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab = NetworkConfig.NetworkPrefabs[i].Prefab; + } + NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + } break; case NetworkPrefabOverride.Hash: NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourceHash, NetworkConfig.NetworkPrefabs[i]); @@ -295,29 +302,6 @@ private void OnValidate() } } } - - //If we have a player prefab then we need to verify it is in the list of NetworkPrefabOverrideLinks for client side spawning. - if (NetworkConfig.PlayerPrefab != null) - { - var playerPrefabNetworkObject = NetworkConfig.PlayerPrefab.GetComponent(); - if (playerPrefabNetworkObject != null) - { - //If we don't have a reference (i.e. someone didn't already add it to the NetworkPrefab list) - if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(NetworkConfig.PlayerPrefab.GetComponent().GlobalObjectIdHash)) - { - //Create a prefab entry - var playerNetworkPrefab = new NetworkPrefab(); - playerNetworkPrefab.Prefab = NetworkConfig.PlayerPrefab; - playerNetworkPrefab.IsPlayer = true; - - //Add it to the prefab list - NetworkConfig.NetworkPrefabs.Add(playerNetworkPrefab); - - //assign its NetworkPrefabOverrideLink - NetworkConfig.NetworkPrefabOverrideLinks.Add(playerPrefabNetworkObject.GlobalObjectIdHash, playerNetworkPrefab); - } - } - } } #endif @@ -404,15 +388,21 @@ private void Init(bool server) NetworkSceneManager.SetCurrentSceneIndex(); } + //Remove entries not needed (only during runtime) + var removeEmptyPrefabs = new List(); for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) { - var networkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent(); + if (NetworkConfig.NetworkPrefabs[i] == null || NetworkConfig.NetworkPrefabs[i].Prefab == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) { NetworkLog.LogError($"{nameof(NetworkPrefab)} cannot be null ({nameof(NetworkPrefab)} at index: {i})"); } + removeEmptyPrefabs.Add(i); + + //Ignore this entry due to the error + continue; } else if (NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent() == null) { @@ -420,7 +410,14 @@ private void Init(bool server) { NetworkLog.LogError($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") is missing a {nameof(NetworkObject)} component"); } + removeEmptyPrefabs.Add(i); + + //Ignore this entry due to the error + continue; } + + var networkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent(); + if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(networkObject.GlobalObjectIdHash)) { switch (NetworkConfig.NetworkPrefabs[i].Override) @@ -439,6 +436,37 @@ private void Init(bool server) } } + //If we have a player prefab then we need to verify it is in the list of NetworkPrefabOverrideLinks for client side spawning. + if (NetworkConfig.PlayerPrefab != null && NetworkConfig.CreatePlayerPrefab) + { + var playerPrefabNetworkObject = NetworkConfig.PlayerPrefab.GetComponent(); + if (playerPrefabNetworkObject != null) + { + //If we don't have a reference (i.e. someone didn't already add it to the NetworkPrefab list) + if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(NetworkConfig.PlayerPrefab.GetComponent().GlobalObjectIdHash)) + { + //Create a prefab entry + var playerNetworkPrefab = new NetworkPrefab(); + playerNetworkPrefab.Prefab = NetworkConfig.PlayerPrefab; + playerNetworkPrefab.IsPlayer = true; + + //Add it to the prefab list + NetworkConfig.NetworkPrefabs.Insert(0, playerNetworkPrefab); + + //assign its NetworkPrefabOverrideLink + NetworkConfig.NetworkPrefabOverrideLinks.Add(playerPrefabNetworkObject.GlobalObjectIdHash, playerNetworkPrefab); + } + } + } + + + foreach ( var networkPrefabIndexToRemove in removeEmptyPrefabs) + { + NetworkConfig.NetworkPrefabs.RemoveAt(networkPrefabIndexToRemove); + } + + removeEmptyPrefabs.Clear(); + NetworkConfig.NetworkTransport.OnTransportEvent += HandleRawTransportPoll; NetworkConfig.NetworkTransport.ResetChannelCache(); From a217e7a0b00f8e811576a0a152f4995f59e4de42 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Fri, 16 Apr 2021 19:22:22 -0500 Subject: [PATCH 04/18] refactor: player prefab selection and blank new entries This will prevent the scenario where a user might want to delete the default player prefab but also has it assigned within the NetworkPrefab list. This assures that a newly created network prefab list entry is blank and that there are not two entries within the list that have the same global object id hash. --- .../Editor/NetworkManagerEditor.cs | 3 +- .../Runtime/Configuration/NetworkConfig.cs | 7 ++ .../Runtime/Core/NetworkManager.cs | 72 ++++++++++++------- 3 files changed, 53 insertions(+), 29 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs b/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs index 38731882d3..8015455178 100644 --- a/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs +++ b/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs @@ -117,7 +117,6 @@ private void Initialize() m_EnsureNetworkVariableLengthSafetyProperty = m_NetworkConfigProperty.FindPropertyRelative("EnsureNetworkVariableLengthSafety"); m_CreatePlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative("CreatePlayerPrefab"); m_ForceSamePrefabsProperty = m_NetworkConfigProperty.FindPropertyRelative("ForceSamePrefabs"); - m_UsePrefabSyncProperty = m_NetworkConfigProperty.FindPropertyRelative("UsePrefabSync"); m_EnableSceneManagementProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableSceneManagement"); m_RecycleNetworkIdsProperty = m_NetworkConfigProperty.FindPropertyRelative("RecycleNetworkIds"); m_NetworkIdRecycleDelayProperty = m_NetworkConfigProperty.FindPropertyRelative("NetworkIdRecycleDelay"); @@ -137,7 +136,7 @@ private void CheckNullProperties() m_RunInBackgroundProperty = serializedObject.FindProperty(nameof(NetworkManager.RunInBackground)); m_LogLevelProperty = serializedObject.FindProperty(nameof(NetworkManager.LogLevel)); m_NetworkConfigProperty = serializedObject.FindProperty(nameof(NetworkManager.NetworkConfig)); - + // NetworkConfig properties m_PlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative(nameof(NetworkConfig.PlayerPrefab)); m_ProtocolVersionProperty = m_NetworkConfigProperty.FindPropertyRelative("ProtocolVersion"); diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs index e07680697b..1cc4a9f466 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs @@ -41,6 +41,13 @@ public class NetworkConfig "If this is true, clients with different initial configurations will not work together.")] public bool AllowRuntimeSceneChanges = false; +#if UNITY_EDITOR + /// + /// The default player prefab + /// + public GameObject PreviousPlayerPrefab; +#endif + /// /// The default player prefab /// diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index a1f7ceeaa2..31f3cd00c5 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -244,22 +244,11 @@ private void OnValidate() }; } - //if (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab && !NetworkConfig.ConnectionApproval) - //{ - // if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) - // { - // NetworkLog.LogWarning($"There is no {nameof(NetworkPrefab)} marked as a {nameof(NetworkPrefab.IsPlayer)}"); - // } - // //Exit if we don't find a player prefab under these conditions - // return; - //} - var scanForPlayerPrefab = (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab); //Clear this out and rebuild NetworkConfig.NetworkPrefabOverrideLinks.Clear(); - //Check network prefabs and assign to dictionary for quick look up for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) { @@ -276,29 +265,57 @@ private void OnValidate() else { //If someone is transitioning to this new format, then go ahead and populate the PlayerPrefab reference for them. - if(scanForPlayerPrefab && NetworkConfig.NetworkPrefabs[i].IsPlayer) + if (scanForPlayerPrefab && NetworkConfig.NetworkPrefabs[i].IsPlayer) { - NetworkConfig.PlayerPrefab = NetworkConfig.NetworkPrefabs[i].Prefab; + if (NetworkConfig.PreviousPlayerPrefab == null) + { + NetworkConfig.PlayerPrefab = NetworkConfig.NetworkPrefabs[i].Prefab; + NetworkConfig.PreviousPlayerPrefab = NetworkConfig.PlayerPrefab; + } + else if (NetworkConfig.NetworkPrefabs[i].Prefab != null) + { + var playerPrefabNetworkObject = NetworkConfig.PreviousPlayerPrefab.GetComponent(); + var prefabNetworkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent(); + if (playerPrefabNetworkObject != null && prefabNetworkObject != null) + { + if (playerPrefabNetworkObject.GlobalObjectIdHash == prefabNetworkObject.GlobalObjectIdHash) + { + NetworkConfig.NetworkPrefabs[i].IsPlayer = false; + NetworkConfig.PreviousPlayerPrefab = null; + } + } + } } + + var globalObjectIdHash = networkObject.GlobalObjectIdHash; + switch (NetworkConfig.NetworkPrefabs[i].Override) { - default: - case NetworkPrefabOverride.None: - NetworkConfig.NetworkPrefabOverrideLinks.Add(networkObject.GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); - break; case NetworkPrefabOverride.Prefab: { - if(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab == null && NetworkConfig.NetworkPrefabs[i].Prefab != null) + if (NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab == null && NetworkConfig.NetworkPrefabs[i].Prefab != null) { NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab = NetworkConfig.NetworkPrefabs[i].Prefab; } - NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + globalObjectIdHash = NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash; + } break; case NetworkPrefabOverride.Hash: - NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourceHash, NetworkConfig.NetworkPrefabs[i]); + globalObjectIdHash = NetworkConfig.NetworkPrefabs[i].OverridingSourceHash; break; } + + //Add to the NetworkPrefabOverrideLinks or handle new (blank) entries + if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(globalObjectIdHash)) + { + NetworkConfig.NetworkPrefabOverrideLinks.Add(globalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + } + else + { + //We just created a new entry or somehow we duplicated one. Turn it into a new blank entry + NetworkConfig.NetworkPrefabs[i] = new NetworkPrefab(); + } } } } @@ -388,16 +405,17 @@ private void Init(bool server) NetworkSceneManager.SetCurrentSceneIndex(); } - //Remove entries not needed (only during runtime) + //This is used to remove entries not needed or invalid var removeEmptyPrefabs = new List(); + + //Prepare our NetworkPrefabOverrideLinks quick look up table for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) { - if (NetworkConfig.NetworkPrefabs[i] == null || NetworkConfig.NetworkPrefabs[i].Prefab == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) { - NetworkLog.LogError($"{nameof(NetworkPrefab)} cannot be null ({nameof(NetworkPrefab)} at index: {i})"); + NetworkLog.LogWarning($"{nameof(NetworkPrefab)} cannot be null ({nameof(NetworkPrefab)} at index: {i})"); } removeEmptyPrefabs.Add(i); @@ -408,7 +426,7 @@ private void Init(bool server) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) { - NetworkLog.LogError($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") is missing a {nameof(NetworkObject)} component"); + NetworkLog.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") is missing a {nameof(NetworkObject)} component"); } removeEmptyPrefabs.Add(i); @@ -418,6 +436,7 @@ private void Init(bool server) var networkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent(); + //Assign the appropriate GlobalObjectIdHash to the appropriate NetworkPrefab if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(networkObject.GlobalObjectIdHash)) { switch (NetworkConfig.NetworkPrefabs[i].Override) @@ -459,12 +478,11 @@ private void Init(bool server) } } - - foreach ( var networkPrefabIndexToRemove in removeEmptyPrefabs) + //Clear out anything that is invalid or not used (for invalid entries we already logged warnings to the user earlier) + foreach (var networkPrefabIndexToRemove in removeEmptyPrefabs) { NetworkConfig.NetworkPrefabs.RemoveAt(networkPrefabIndexToRemove); } - removeEmptyPrefabs.Clear(); NetworkConfig.NetworkTransport.OnTransportEvent += HandleRawTransportPoll; From 25594818da1fe7248726526fdbb2b5899444ff1e Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Fri, 16 Apr 2021 19:53:30 -0500 Subject: [PATCH 05/18] style: comments just adding a few comments --- com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index 31f3cd00c5..b8f5b37c91 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -244,6 +244,7 @@ private void OnValidate() }; } + //Should we see if there is already a defined player prefab in the Network prefab list? var scanForPlayerPrefab = (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab); //Clear this out and rebuild @@ -289,6 +290,7 @@ private void OnValidate() var globalObjectIdHash = networkObject.GlobalObjectIdHash; + //Check to see if the NetworkPrefab has an override switch (NetworkConfig.NetworkPrefabs[i].Override) { case NetworkPrefabOverride.Prefab: From 84f0942fa9eb4d4e196973ef125d3b68daa73004 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Sat, 17 Apr 2021 00:16:49 -0500 Subject: [PATCH 06/18] style: property names and comments Adjusted names of the new NetworkPrefab properties and added additional comments to better clarify some of the "trickery" happening that will help make this a "non-breaking" feature when it comes to existing v0.1.0 NetworkConfigs and the already selected default player prefab. --- .../Editor/NetworkManagerEditor.cs | 4 ++-- .../Runtime/Configuration/NetworkConfig.cs | 23 ++++++++++++++---- .../Runtime/Configuration/NetworkPrefab.cs | 4 ++-- .../Runtime/Core/NetworkManager.cs | 24 ++++++++++++------- .../Runtime/Spawning/NetworkSpawnManager.cs | 23 +++++++++++++----- 5 files changed, 55 insertions(+), 23 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs b/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs index 8015455178..e86305f464 100644 --- a/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs +++ b/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs @@ -180,8 +180,8 @@ private void OnEnable() var networkPrefab = m_NetworkPrefabsList.serializedProperty.GetArrayElementAtIndex(index); var networkPrefabProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.Prefab)); - var networkSourceHashProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.OverridingSourceHash)); - var networkSourcePrefabProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.OverridingSourcePrefab)); + var networkSourceHashProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.SourceHashToOverride)); + var networkSourcePrefabProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.SourcePrefabToOverride)); var networkTargetPrefabProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.OverridingTargetPrefab)); var networkOverrideProp = networkPrefab.FindPropertyRelative(nameof(NetworkPrefab.Override)); var networkOverrideInt = networkOverrideProp.enumValueIndex; diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs index 1cc4a9f466..ecfb253361 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs @@ -41,12 +41,25 @@ public class NetworkConfig "If this is true, clients with different initial configurations will not work together.")] public bool AllowRuntimeSceneChanges = false; -#if UNITY_EDITOR /// - /// The default player prefab - /// - public GameObject PreviousPlayerPrefab; -#endif + /// The previously set default player prefab + /// Note: this is only for an editor specific scenario where we need to determine during the + /// NetworkManager.OnValidate invocation period there is no PlayerPrefab value yet there is a + /// NetworkPrefab entry that has IsPlayer set to true. This is also used to determine if + /// we are loading from a previous MLAPI version where the NetworkPrefab.IsPlayer was predominantly + /// used. + /// There are two scenarios where this is used: + /// 1.) If the PreviousPlayerPrefab and PlayerPrefab values are not set but a NetworkPrefab has + /// an entry with the NetworkPrefab.IsPlayer set to true, then we want to assign the PlayerPrefab + /// and PreviousPlayerPrefab + /// 2.) If the PlayerPrefab is null, the PreviousPlayer prefab is not, a NetworkPrefab entry + /// has its NetworkPrefab.IsPlayer set to true, and that NetworkPrefab entry's prefab's + /// NetworkObject.GlobalObjectIdHash is the same as the PreviousPlayerPrefab's NetworkObject.GlobalObjectIdHash + /// then the user deleted the PlayerPrefab so we can mark the NetworkPrefab.IsPlayer value of the matching + /// NetworkPrefab to false and the PreviousPlayerPrefab to null. + /// (The next time PlayerPrefab is set see scenario #1) + /// + internal GameObject PreviousPlayerPrefab; /// /// The default player prefab diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs index f60b97ab9b..88b2fd4f89 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs @@ -27,14 +27,14 @@ public class NetworkPrefab /// /// The original "source" prefab /// - public GameObject OverridingSourcePrefab; + public GameObject SourcePrefabToOverride; /// /// The original "source" prefab's hash /// This is used typically in multi-project patterns where a separate project contains the /// source prefab and the GlobalObjectIdHash was copied and pasted into this field. /// - public uint OverridingSourceHash; + public uint SourceHashToOverride; /// /// The prefab to replace the OverridingSourcePrefab with diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index b8f5b37c91..2826eb2a9e 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -247,7 +247,8 @@ private void OnValidate() //Should we see if there is already a defined player prefab in the Network prefab list? var scanForPlayerPrefab = (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab); - //Clear this out and rebuild + //During OnValidate we will always clear out NetworkPrefabOverrideLinks and rebuild it in order to + //detect specific edge case scenarios (See PreviousPlayerPrefab comments) NetworkConfig.NetworkPrefabOverrideLinks.Clear(); //Check network prefabs and assign to dictionary for quick look up @@ -268,6 +269,12 @@ private void OnValidate() //If someone is transitioning to this new format, then go ahead and populate the PlayerPrefab reference for them. if (scanForPlayerPrefab && NetworkConfig.NetworkPrefabs[i].IsPlayer) { + //If we find a NetworkPrefab where IsPlayer is true and we have + //no PlayerPrefab nor did we have one previously (i.e. we didn't just delete it), + //then we want to set the default player prefab. We also want to set the + //previous player prefab value in the event the user decides to delete the + //PlayerPrefab value from within the editor inspector view. + //(See PreviousPlayerPrefab comments for more information) if (NetworkConfig.PreviousPlayerPrefab == null) { NetworkConfig.PlayerPrefab = NetworkConfig.NetworkPrefabs[i].Prefab; @@ -295,16 +302,16 @@ private void OnValidate() { case NetworkPrefabOverride.Prefab: { - if (NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab == null && NetworkConfig.NetworkPrefabs[i].Prefab != null) + if (NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride == null && NetworkConfig.NetworkPrefabs[i].Prefab != null) { - NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab = NetworkConfig.NetworkPrefabs[i].Prefab; + NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride = NetworkConfig.NetworkPrefabs[i].Prefab; } - globalObjectIdHash = NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash; + globalObjectIdHash = NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride.GetComponent().GlobalObjectIdHash; } break; case NetworkPrefabOverride.Hash: - globalObjectIdHash = NetworkConfig.NetworkPrefabs[i].OverridingSourceHash; + globalObjectIdHash = NetworkConfig.NetworkPrefabs[i].SourceHashToOverride; break; } @@ -315,7 +322,8 @@ private void OnValidate() } else { - //We just created a new entry or somehow we duplicated one. Turn it into a new blank entry + //This happens when a new duplicate entry is created. + //We just turn it into a new blank entry NetworkConfig.NetworkPrefabs[i] = new NetworkPrefab(); } } @@ -448,10 +456,10 @@ private void Init(bool server) NetworkConfig.NetworkPrefabOverrideLinks.Add(networkObject.GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); break; case NetworkPrefabOverride.Prefab: - NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourcePrefab.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); + NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride.GetComponent().GlobalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); break; case NetworkPrefabOverride.Hash: - NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].OverridingSourceHash, NetworkConfig.NetworkPrefabs[i]); + NetworkConfig.NetworkPrefabOverrideLinks.Add(NetworkConfig.NetworkPrefabs[i].SourceHashToOverride, NetworkConfig.NetworkPrefabs[i]); break; } } diff --git a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs index 7152e2e1d4..3b1cd4762a 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs @@ -181,7 +181,16 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId) } } - // Only ran on Client + /// + /// Only run on the client + /// + /// + /// + /// + /// + /// + /// + /// internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash, ulong ownerClientId, ulong? parentNetworkId, Vector3? position, Quaternion? rotation) { NetworkObject parentNetworkObject = null; @@ -198,12 +207,12 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash } } - if (!NetworkManager.NetworkConfig.EnableSceneManagement || !softCreate) { - // Create the object + // If the prefab hash has a registered INetworkPrefabInstanceHandler derived class if (NetworkManager.PrefabHandler.ContainsHandler(prefabHash)) { + //Let the handler spawn the NetworkObject var networkObject = NetworkManager.PrefabHandler.HandleNetworkPrefabSpawn(prefabHash, ownerClientId, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity)); if (parentNetworkObject != null) @@ -220,6 +229,7 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash } else { + //See if there is a valid registered NetworkPrefabOverrideLink associated with the provided prefabHash GameObject networkPrefabReference = null; if(NetworkManager.NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(prefabHash)) { @@ -236,6 +246,7 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash } } + //If not, then there is an issue (user possibly didn't register the prefab properly?) if (networkPrefabReference == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) @@ -246,6 +257,7 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash return null; } + //Otherwise, instantiate an instance of the NetworkPrefab linked to the prefabHash var networkObject = ((position == null && rotation == null) ? UnityEngine.Object.Instantiate(networkPrefabReference) : UnityEngine.Object.Instantiate(networkPrefabReference, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity))).GetComponent(); if (parentNetworkObject != null) @@ -263,13 +275,12 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash } else { - // SoftSync them by mapping + // Check to see if the hash is in our pending in-scene objects waiting to be "soft synchronized" if (!PendingSoftSyncObjects.ContainsKey(prefabHash)) { - // TODO: Fix this message if (NetworkLog.CurrentLogLevel <= LogLevel.Error) { - NetworkLog.LogError("Cannot find pending soft sync object. Is the projects the same?"); + NetworkLog.LogError($"{nameof(NetworkPrefab)} hash was not found! In-Scene placed NetworkObject soft synchronization failure for Hash: {prefabHash.ToString("X")}!"); } return null; } From b78403e25bb5a506aaffbd3fc14a407cf5326d3f Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Sat, 17 Apr 2021 17:21:59 -0500 Subject: [PATCH 07/18] refactor: Client Sync and Comments This will prevent any future client side soft synchronization issues or related issues where only one (or a few) NetworkObjects are misconfigured and the client fails to synchronize (find or instantiate). As opposed to completely breaking the rest of the pending NetworkObjects to be synchronized/instantiated, it will log an error and continue loading. This also has some additional comments and updates to comments for better clarity. --- .../Runtime/Configuration/NetworkPrefab.cs | 8 ++--- .../Runtime/Core/NetworkManager.cs | 35 ++++++++++++++----- .../Messaging/InternalMessageHandler.cs | 6 ++++ .../SceneManagement/NetworkSceneManager.cs | 7 ++++ 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs index 88b2fd4f89..97ab259a55 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs @@ -25,19 +25,17 @@ public class NetworkPrefab public NetworkPrefabOverride Override; /// - /// The original "source" prefab + /// Used when prefab is selected for the source prefab to override value (i.e. direct reference, the prefab is within the same project) /// public GameObject SourcePrefabToOverride; /// - /// The original "source" prefab's hash - /// This is used typically in multi-project patterns where a separate project contains the - /// source prefab and the GlobalObjectIdHash was copied and pasted into this field. + /// Used when hash is selected for the source prefab to override value (i.e. a direct reference is not possible such as in a multi-project pattern) /// public uint SourceHashToOverride; /// - /// The prefab to replace the OverridingSourcePrefab with + /// The prefab to replace (override) the source prefab with /// public GameObject OverridingTargetPrefab; diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index 2826eb2a9e..c7bcd6e744 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -244,11 +244,13 @@ private void OnValidate() }; } - //Should we see if there is already a defined player prefab in the Network prefab list? + //If true, check to see if there is a defined player prefab in the Network prefab list + //This helps migrate v0.1.0 projects (i.e. no PlayerPrefab was assigned) as well as helps detect + //specific interface related issues related to the NetworkPrefabs list. var scanForPlayerPrefab = (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab); //During OnValidate we will always clear out NetworkPrefabOverrideLinks and rebuild it in order to - //detect specific edge case scenarios (See PreviousPlayerPrefab comments) + //detect specific edge case scenarios (See NtworkConfig.PreviousPlayerPrefab comments) NetworkConfig.NetworkPrefabOverrideLinks.Clear(); //Check network prefabs and assign to dictionary for quick look up @@ -274,7 +276,7 @@ private void OnValidate() //then we want to set the default player prefab. We also want to set the //previous player prefab value in the event the user decides to delete the //PlayerPrefab value from within the editor inspector view. - //(See PreviousPlayerPrefab comments for more information) + //(See NtworkConfig.PreviousPlayerPrefab comments for more information) if (NetworkConfig.PreviousPlayerPrefab == null) { NetworkConfig.PlayerPrefab = NetworkConfig.NetworkPrefabs[i].Prefab; @@ -295,9 +297,10 @@ private void OnValidate() } } + //Defautlt to the standard NetworkPrefab.Prefab's NetworkObject first var globalObjectIdHash = networkObject.GlobalObjectIdHash; - //Check to see if the NetworkPrefab has an override + //Now check to see if it has an override switch (NetworkConfig.NetworkPrefabs[i].Override) { case NetworkPrefabOverride.Prefab: @@ -315,7 +318,7 @@ private void OnValidate() break; } - //Add to the NetworkPrefabOverrideLinks or handle new (blank) entries + //Add to the NetworkPrefabOverrideLinks or handle a new (blank) entries if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(globalObjectIdHash)) { NetworkConfig.NetworkPrefabOverrideLinks.Add(globalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); @@ -418,7 +421,7 @@ private void Init(bool server) //This is used to remove entries not needed or invalid var removeEmptyPrefabs = new List(); - //Prepare our NetworkPrefabOverrideLinks quick look up table + //Build the NetworkPrefabOverrideLinks dictionary for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) { if (NetworkConfig.NetworkPrefabs[i] == null || NetworkConfig.NetworkPrefabs[i].Prefab == null) @@ -427,9 +430,12 @@ private void Init(bool server) { NetworkLog.LogWarning($"{nameof(NetworkPrefab)} cannot be null ({nameof(NetworkPrefab)} at index: {i})"); } + + //Provide the name of the prefab with issues so the user can more easily find the prefab and fix it + UnityEngine.Debug.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") will be removed and ignored."); removeEmptyPrefabs.Add(i); - //Ignore this entry due to the error + //Ignore this entry due to the error (it will be removed during runtime) continue; } else if (NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent() == null) @@ -438,12 +444,16 @@ private void Init(bool server) { NetworkLog.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") is missing a {nameof(NetworkObject)} component"); } + + //Provide the name of the prefab with issues so the user can more easily find the prefab and fix it + UnityEngine.Debug.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") will be removed and ignored."); removeEmptyPrefabs.Add(i); - //Ignore this entry due to the error + //Ignore this entry due to the error (it will be removed during runtime) continue; } + //Get the default NetworkObject first var networkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent(); //Assign the appropriate GlobalObjectIdHash to the appropriate NetworkPrefab @@ -463,9 +473,15 @@ private void Init(bool server) break; } } + else + { + //This should never happen, but in the case it somehow does log an error and remove the duplicate entry + UnityEngine.Debug.LogError($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") has a duplicate GlobalObjectIdHash {networkObject.GlobalObjectIdHash.ToString("X")} entry! Removing entry from list!"); + removeEmptyPrefabs.Add(i); + } } - //If we have a player prefab then we need to verify it is in the list of NetworkPrefabOverrideLinks for client side spawning. + //If we have a player prefab, then we need to verify it is in the list of NetworkPrefabOverrideLinks for client side spawning. if (NetworkConfig.PlayerPrefab != null && NetworkConfig.CreatePlayerPrefab) { var playerPrefabNetworkObject = NetworkConfig.PlayerPrefab.GetComponent(); @@ -491,6 +507,7 @@ private void Init(bool server) //Clear out anything that is invalid or not used (for invalid entries we already logged warnings to the user earlier) foreach (var networkPrefabIndexToRemove in removeEmptyPrefabs) { + NetworkConfig.NetworkPrefabs.RemoveAt(networkPrefabIndexToRemove); } removeEmptyPrefabs.Clear(); diff --git a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs index e69d2e486e..d38eccf3cc 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs @@ -154,6 +154,12 @@ void DelayedSpawnAction(Stream continuationStream) } var networkObject = NetworkManager.Singleton.SpawnManager.CreateLocalNetworkObject(softSync, prefabHash, ownerId, parentNetworkId, pos, rot); + if (networkObject == null) + { + //This will prevent one misconfigured issues from breaking the entire loading process. + Debug.LogError($"Failed to spawn NetowrkObject for Hash {prefabHash}, ignoring and continuing to load."); + continue; + } NetworkManager.Singleton.SpawnManager.SpawnNetworkObjectLocally(networkObject, networkId, softSync, isPlayerObject, ownerId, continuationStream, false, 0, true, false); Queue bufferQueue = NetworkManager.BufferManager.ConsumeBuffersForNetworkId(networkId); diff --git a/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs index 40b3e12ced..12cfe29ac5 100644 --- a/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs @@ -381,6 +381,13 @@ private static void OnSceneUnloadClient(Guid switchSceneGuid, Stream objectStrea } var networkObject = NetworkManager.Singleton.SpawnManager.CreateLocalNetworkObject(true, prefabHash, ownerClientId, parentNetworkId, position, rotation); + if (networkObject == null) + { + //This will prevent one misconfigured issues from breaking the entire loading process. + Debug.LogError($"Failed to spawn NetowrkObject for Hash {prefabHash}, ignoring and continuing to load."); + continue; + } + NetworkManager.Singleton.SpawnManager.SpawnNetworkObjectLocally(networkObject, networkId, true, isPlayerObject, ownerClientId, objectStream, false, 0, true, false); var bufferQueue = NetworkManager.Singleton.BufferManager.ConsumeBuffersForNetworkId(networkId); From c6007247a861ab204514d82280734e260aba6dd8 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Sat, 17 Apr 2021 17:24:20 -0500 Subject: [PATCH 08/18] style: minor change minor change in comments --- .../Runtime/Messaging/InternalMessageHandler.cs | 2 +- .../Runtime/SceneManagement/NetworkSceneManager.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs index d38eccf3cc..15a84cefe7 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs @@ -156,7 +156,7 @@ void DelayedSpawnAction(Stream continuationStream) var networkObject = NetworkManager.Singleton.SpawnManager.CreateLocalNetworkObject(softSync, prefabHash, ownerId, parentNetworkId, pos, rot); if (networkObject == null) { - //This will prevent one misconfigured issues from breaking the entire loading process. + //This will prevent one misconfigured issue (or more) from breaking the entire loading process. Debug.LogError($"Failed to spawn NetowrkObject for Hash {prefabHash}, ignoring and continuing to load."); continue; } diff --git a/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs index 12cfe29ac5..2cd24b5ed6 100644 --- a/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs @@ -383,7 +383,7 @@ private static void OnSceneUnloadClient(Guid switchSceneGuid, Stream objectStrea var networkObject = NetworkManager.Singleton.SpawnManager.CreateLocalNetworkObject(true, prefabHash, ownerClientId, parentNetworkId, position, rotation); if (networkObject == null) { - //This will prevent one misconfigured issues from breaking the entire loading process. + //This will prevent one misconfigured issue (or more) from breaking the entire loading process. Debug.LogError($"Failed to spawn NetowrkObject for Hash {prefabHash}, ignoring and continuing to load."); continue; } From e799b47bab863c3431e0918f7a55cbe1ae310984 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Tue, 20 Apr 2021 13:09:38 -0500 Subject: [PATCH 09/18] refactor: remove CreatePlayerPrefab This removes the CreatePlayerPrefab property from the NetworkConfig and from the NetworkManagerEditor. It is no longer needed as the NetworkConfig.PlayerPrefab property being something other than null tells us that the user wants to have MLAPI automatically spawn the players for them. --- .../Editor/NetworkManagerEditor.cs | 9 ++------- .../Runtime/Configuration/NetworkConfig.cs | 9 +++------ .../Runtime/Core/NetworkManager.cs | 8 ++++---- .../Runtime/Messaging/InternalMessageHandler.cs | 2 +- .../Tests/Runtime/NetworkManagerHelper.cs | 1 - 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs b/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs index e86305f464..d3bcac547f 100644 --- a/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs +++ b/com.unity.multiplayer.mlapi/Editor/NetworkManagerEditor.cs @@ -36,9 +36,7 @@ public class NetworkManagerEditor : UnityEditor.Editor private SerializedProperty m_TimeResyncIntervalProperty; private SerializedProperty m_EnableNetworkVariableProperty; private SerializedProperty m_EnsureNetworkVariableLengthSafetyProperty; - private SerializedProperty m_CreatePlayerPrefabProperty; - private SerializedProperty m_ForceSamePrefabsProperty; - private SerializedProperty m_UsePrefabSyncProperty; + private SerializedProperty m_ForceSamePrefabsProperty; private SerializedProperty m_EnableSceneManagementProperty; private SerializedProperty m_RecycleNetworkIdsProperty; private SerializedProperty m_NetworkIdRecycleDelayProperty; @@ -114,8 +112,7 @@ private void Initialize() m_EnableTimeResyncProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableTimeResync"); m_TimeResyncIntervalProperty = m_NetworkConfigProperty.FindPropertyRelative("TimeResyncInterval"); m_EnableNetworkVariableProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableNetworkVariable"); - m_EnsureNetworkVariableLengthSafetyProperty = m_NetworkConfigProperty.FindPropertyRelative("EnsureNetworkVariableLengthSafety"); - m_CreatePlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative("CreatePlayerPrefab"); + m_EnsureNetworkVariableLengthSafetyProperty = m_NetworkConfigProperty.FindPropertyRelative("EnsureNetworkVariableLengthSafety"); m_ForceSamePrefabsProperty = m_NetworkConfigProperty.FindPropertyRelative("ForceSamePrefabs"); m_EnableSceneManagementProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableSceneManagement"); m_RecycleNetworkIdsProperty = m_NetworkConfigProperty.FindPropertyRelative("RecycleNetworkIds"); @@ -152,7 +149,6 @@ private void CheckNullProperties() m_TimeResyncIntervalProperty = m_NetworkConfigProperty.FindPropertyRelative("TimeResyncInterval"); m_EnableNetworkVariableProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableNetworkVariable"); m_EnsureNetworkVariableLengthSafetyProperty = m_NetworkConfigProperty.FindPropertyRelative("EnsureNetworkVariableLengthSafety"); - m_CreatePlayerPrefabProperty = m_NetworkConfigProperty.FindPropertyRelative("CreatePlayerPrefab"); m_ForceSamePrefabsProperty = m_NetworkConfigProperty.FindPropertyRelative("ForceSamePrefabs"); m_EnableSceneManagementProperty = m_NetworkConfigProperty.FindPropertyRelative("EnableSceneManagement"); m_RecycleNetworkIdsProperty = m_NetworkConfigProperty.FindPropertyRelative("RecycleNetworkIds"); @@ -341,7 +337,6 @@ public override void OnInspectorGUI() } EditorGUILayout.LabelField("Spawning", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(m_CreatePlayerPrefabProperty); EditorGUILayout.PropertyField(m_ForceSamePrefabsProperty); diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs index ecfb253361..47026572eb 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs @@ -72,14 +72,11 @@ public class NetworkConfig [Tooltip("The prefabs that can be spawned across the network")] public List NetworkPrefabs = new List(); - - public DictionaryNetworkPrefabOverrideLinks = new Dictionary(); - /// - /// Whether or not a player object should be created by default. This value can be overridden on a case by case basis with ConnectionApproval. + /// This dictionary provides a quick way to check and see if a NetworkPrefab has a NetworkPrefab override. + /// Generated at runtime and OnValidate /// - [Tooltip("Whether or not a player object should be created by default. This value can be overridden on a case by case basis with ConnectionApproval.")] - public bool CreatePlayerPrefab = true; + public DictionaryNetworkPrefabOverrideLinks = new Dictionary(); /// /// Amount of times per second the receive queue is emptied and all messages inside are processed. diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index 6cb7bfa255..4a2fe6ce12 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -21,7 +21,7 @@ using MLAPI.Transports.Tasks; using MLAPI.Messaging.Buffering; using Unity.Profiling; -using UnityEditor.VersionControl; +//using UnityEditor.VersionControl; namespace MLAPI { @@ -252,7 +252,7 @@ private void OnValidate() //If true, check to see if there is a defined player prefab in the Network prefab list //This helps migrate v0.1.0 projects (i.e. no PlayerPrefab was assigned) as well as helps detect //specific interface related issues related to the NetworkPrefabs list. - var scanForPlayerPrefab = (NetworkConfig.PlayerPrefab == null && NetworkConfig.CreatePlayerPrefab); + var scanForPlayerPrefab = NetworkConfig.PlayerPrefab == null; //During OnValidate we will always clear out NetworkPrefabOverrideLinks and rebuild it in order to //detect specific edge case scenarios (See NtworkConfig.PreviousPlayerPrefab comments) @@ -486,7 +486,7 @@ private void Init(bool server) } //If we have a player prefab, then we need to verify it is in the list of NetworkPrefabOverrideLinks for client side spawning. - if (NetworkConfig.PlayerPrefab != null && NetworkConfig.CreatePlayerPrefab) + if (NetworkConfig.PlayerPrefab != null ) { var playerPrefabNetworkObject = NetworkConfig.PlayerPrefab.GetComponent(); if (playerPrefabNetworkObject != null) @@ -737,7 +737,7 @@ public SocketTasks StartHost() } else { - HandleApproval(ServerClientId, NetworkConfig.CreatePlayerPrefab, null, true, null, null); + HandleApproval(ServerClientId, NetworkConfig.PlayerPrefab != null, null, true, null, null); } SpawnManager.ServerSpawnSceneObjectsOnStartSweep(); diff --git a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs index 8d30c1e94d..d8322b0dea 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs @@ -81,7 +81,7 @@ public void HandleConnectionRequest(ulong clientId, Stream stream) } else { - NetworkManager.HandleApproval(clientId, NetworkManager.NetworkConfig.CreatePlayerPrefab, null, true, null, null); + NetworkManager.HandleApproval(clientId, NetworkManager.NetworkConfig.PlayerPrefab != null, null, true, null, null); } } #if DEVELOPMENT_BUILD || UNITY_EDITOR diff --git a/com.unity.multiplayer.mlapi/Tests/Runtime/NetworkManagerHelper.cs b/com.unity.multiplayer.mlapi/Tests/Runtime/NetworkManagerHelper.cs index 3ce0d2b65d..71da5f438f 100644 --- a/com.unity.multiplayer.mlapi/Tests/Runtime/NetworkManagerHelper.cs +++ b/com.unity.multiplayer.mlapi/Tests/Runtime/NetworkManagerHelper.cs @@ -74,7 +74,6 @@ public static bool StartNetworkManager(out NetworkManager networkManager, Networ NetworkManagerObject.NetworkConfig = new Configuration.NetworkConfig { - CreatePlayerPrefab = false, EnableSceneManagement = false, RegisteredScenes = new List(){SceneManager.GetActiveScene().name} }; From 5926c3cce441fe300f1e4e9f2b22621e6bdb0b80 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Tue, 20 Apr 2021 13:11:22 -0500 Subject: [PATCH 10/18] refactor: cleaning up using removed unused namespace references. --- com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index 4a2fe6ce12..92448191ab 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -4,9 +4,7 @@ using System.ComponentModel; using System.Diagnostics; using UnityEngine; -using System.Linq; using MLAPI.Logging; -using UnityEngine.SceneManagement; using MLAPI.Configuration; using MLAPI.Internal; using MLAPI.Profiling; @@ -21,7 +19,7 @@ using MLAPI.Transports.Tasks; using MLAPI.Messaging.Buffering; using Unity.Profiling; -//using UnityEditor.VersionControl; + namespace MLAPI { From 481e862f12d78a1ee053ac86dec9a4c1e427c497 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Tue, 20 Apr 2021 13:23:23 -0500 Subject: [PATCH 11/18] style: PlayerPrefab tooltip Added a tooltip for the new NetworkConfig.PlayerPrefab property --- .../Runtime/Configuration/NetworkConfig.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs index 47026572eb..b4a34f8c8a 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs @@ -64,6 +64,7 @@ public class NetworkConfig /// /// The default player prefab /// + [Tooltip("When set, the network manager will automatically create and spawn the assigned player prefab. The Player Prefab can be overriden by adding it to the NetworkPrefabs list and selecting override.")] public GameObject PlayerPrefab; /// From 7f2781cb3913a689abfbdb1c6bc977b42fbf589b Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Tue, 20 Apr 2021 14:38:57 -0500 Subject: [PATCH 12/18] style: spaces between slashes and comment text body Added some spaces between the forward slashes and comment's text body --- .../Runtime/Core/NetworkManager.cs | 80 +++++++++---------- .../Messaging/InternalMessageHandler.cs | 2 +- .../SceneManagement/NetworkSceneManager.cs | 20 ++--- .../Runtime/Spawning/NetworkSpawnManager.cs | 8 +- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index 92448191ab..2d89a1a758 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -216,7 +216,7 @@ private void OnValidate() { if (NetworkConfig == null) { - return; //May occur when the component is added + return; // May occur when the component is added } if (GetComponentInChildren() != null) @@ -247,16 +247,16 @@ private void OnValidate() }; } - //If true, check to see if there is a defined player prefab in the Network prefab list - //This helps migrate v0.1.0 projects (i.e. no PlayerPrefab was assigned) as well as helps detect - //specific interface related issues related to the NetworkPrefabs list. + // If true, check to see if there is a defined player prefab in the Network prefab list + // This helps migrate v0.1.0 projects (i.e. no PlayerPrefab was assigned) as well as helps detect + // specific interface related issues related to the NetworkPrefabs list. var scanForPlayerPrefab = NetworkConfig.PlayerPrefab == null; - //During OnValidate we will always clear out NetworkPrefabOverrideLinks and rebuild it in order to - //detect specific edge case scenarios (See NtworkConfig.PreviousPlayerPrefab comments) + // During OnValidate we will always clear out NetworkPrefabOverrideLinks and rebuild it in order to + // detect specific edge case scenarios (See NtworkConfig.PreviousPlayerPrefab comments) NetworkConfig.NetworkPrefabOverrideLinks.Clear(); - //Check network prefabs and assign to dictionary for quick look up + // Check network prefabs and assign to dictionary for quick look up for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) { if (NetworkConfig.NetworkPrefabs[i] != null && NetworkConfig.NetworkPrefabs[i].Prefab != null) @@ -271,15 +271,15 @@ private void OnValidate() } else { - //If someone is transitioning to this new format, then go ahead and populate the PlayerPrefab reference for them. + // If someone is transitioning to this new format, then go ahead and populate the PlayerPrefab reference for them. if (scanForPlayerPrefab && NetworkConfig.NetworkPrefabs[i].IsPlayer) { - //If we find a NetworkPrefab where IsPlayer is true and we have - //no PlayerPrefab nor did we have one previously (i.e. we didn't just delete it), - //then we want to set the default player prefab. We also want to set the - //previous player prefab value in the event the user decides to delete the - //PlayerPrefab value from within the editor inspector view. - //(See NtworkConfig.PreviousPlayerPrefab comments for more information) + // If we find a NetworkPrefab where IsPlayer is true and we have + // no PlayerPrefab nor did we have one previously (i.e. we didn't just delete it), + // then we want to set the default player prefab. We also want to set the + // previous player prefab value in the event the user decides to delete the + // PlayerPrefab value from within the editor inspector view. + // (See NtworkConfig.PreviousPlayerPrefab comments for more information) if (NetworkConfig.PreviousPlayerPrefab == null) { NetworkConfig.PlayerPrefab = NetworkConfig.NetworkPrefabs[i].Prefab; @@ -300,10 +300,10 @@ private void OnValidate() } } - //Defautlt to the standard NetworkPrefab.Prefab's NetworkObject first + // Defautlt to the standard NetworkPrefab.Prefab's NetworkObject first var globalObjectIdHash = networkObject.GlobalObjectIdHash; - //Now check to see if it has an override + // Now check to see if it has an override switch (NetworkConfig.NetworkPrefabs[i].Override) { case NetworkPrefabOverride.Prefab: @@ -321,15 +321,15 @@ private void OnValidate() break; } - //Add to the NetworkPrefabOverrideLinks or handle a new (blank) entries + // Add to the NetworkPrefabOverrideLinks or handle a new (blank) entries if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(globalObjectIdHash)) { NetworkConfig.NetworkPrefabOverrideLinks.Add(globalObjectIdHash, NetworkConfig.NetworkPrefabs[i]); } else { - //This happens when a new duplicate entry is created. - //We just turn it into a new blank entry + // This happens when a new duplicate entry is created. + // We just turn it into a new blank entry NetworkConfig.NetworkPrefabs[i] = new NetworkPrefab(); } } @@ -381,7 +381,7 @@ private void Init(bool server) return; } - //This 'if' should never enter + // This 'if' should never enter if (NetworkTickSystem != null) { NetworkTickSystem.Dispose(); @@ -390,7 +390,7 @@ private void Init(bool server) NetworkTickSystem = new NetworkTickSystem(NetworkConfig.NetworkTickIntervalSec); - //This should never happen, but in the event that it does there should be (at a minimum) a unity error logged. + // This should never happen, but in the event that it does there should be (at a minimum) a unity error logged. if (RpcQueueContainer != null) { UnityEngine.Debug.LogError("Init was invoked, but rpcQueueContainer was already initialized! (destroying previous instance)"); @@ -398,8 +398,8 @@ private void Init(bool server) RpcQueueContainer = null; } - //The RpcQueueContainer must be initialized within the Init method ONLY - //It should ONLY be shutdown and destroyed in the Shutdown method (other than just above) + // The RpcQueueContainer must be initialized within the Init method ONLY + // It should ONLY be shutdown and destroyed in the Shutdown method (other than just above) RpcQueueContainer = new RpcQueueContainer(this); // Register INetworkUpdateSystem (always register this after rpcQueueContainer has been instantiated) @@ -420,10 +420,10 @@ private void Init(bool server) SceneManager.SetCurrentSceneIndex(); } - //This is used to remove entries not needed or invalid + // This is used to remove entries not needed or invalid var removeEmptyPrefabs = new List(); - //Build the NetworkPrefabOverrideLinks dictionary + // Build the NetworkPrefabOverrideLinks dictionary for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) { if (NetworkConfig.NetworkPrefabs[i] == null || NetworkConfig.NetworkPrefabs[i].Prefab == null) @@ -433,11 +433,11 @@ private void Init(bool server) NetworkLog.LogWarning($"{nameof(NetworkPrefab)} cannot be null ({nameof(NetworkPrefab)} at index: {i})"); } - //Provide the name of the prefab with issues so the user can more easily find the prefab and fix it + // Provide the name of the prefab with issues so the user can more easily find the prefab and fix it UnityEngine.Debug.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") will be removed and ignored."); removeEmptyPrefabs.Add(i); - //Ignore this entry due to the error (it will be removed during runtime) + // Ignore this entry due to the error (it will be removed during runtime) continue; } else if (NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent() == null) @@ -447,18 +447,18 @@ private void Init(bool server) NetworkLog.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") is missing a {nameof(NetworkObject)} component"); } - //Provide the name of the prefab with issues so the user can more easily find the prefab and fix it + // Provide the name of the prefab with issues so the user can more easily find the prefab and fix it UnityEngine.Debug.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") will be removed and ignored."); removeEmptyPrefabs.Add(i); - //Ignore this entry due to the error (it will be removed during runtime) + // Ignore this entry due to the error (it will be removed during runtime) continue; } - //Get the default NetworkObject first + // Get the default NetworkObject first var networkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent(); - //Assign the appropriate GlobalObjectIdHash to the appropriate NetworkPrefab + // Assign the appropriate GlobalObjectIdHash to the appropriate NetworkPrefab if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(networkObject.GlobalObjectIdHash)) { switch (NetworkConfig.NetworkPrefabs[i].Override) @@ -477,39 +477,39 @@ private void Init(bool server) } else { - //This should never happen, but in the case it somehow does log an error and remove the duplicate entry + // This should never happen, but in the case it somehow does log an error and remove the duplicate entry UnityEngine.Debug.LogError($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") has a duplicate GlobalObjectIdHash {networkObject.GlobalObjectIdHash.ToString("X")} entry! Removing entry from list!"); removeEmptyPrefabs.Add(i); } } - //If we have a player prefab, then we need to verify it is in the list of NetworkPrefabOverrideLinks for client side spawning. - if (NetworkConfig.PlayerPrefab != null ) + // If we have a player prefab, then we need to verify it is in the list of NetworkPrefabOverrideLinks for client side spawning. + if (NetworkConfig.PlayerPrefab != null) { var playerPrefabNetworkObject = NetworkConfig.PlayerPrefab.GetComponent(); if (playerPrefabNetworkObject != null) { - //If we don't have a reference (i.e. someone didn't already add it to the NetworkPrefab list) + // If we don't have a reference (i.e. someone didn't already add it to the NetworkPrefab list) if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(NetworkConfig.PlayerPrefab.GetComponent().GlobalObjectIdHash)) { - //Create a prefab entry + // Create a prefab entry var playerNetworkPrefab = new NetworkPrefab(); playerNetworkPrefab.Prefab = NetworkConfig.PlayerPrefab; playerNetworkPrefab.IsPlayer = true; - //Add it to the prefab list + // Add it to the prefab list NetworkConfig.NetworkPrefabs.Insert(0, playerNetworkPrefab); - //assign its NetworkPrefabOverrideLink + // assign its NetworkPrefabOverrideLink NetworkConfig.NetworkPrefabOverrideLinks.Add(playerPrefabNetworkObject.GlobalObjectIdHash, playerNetworkPrefab); } } } - //Clear out anything that is invalid or not used (for invalid entries we already logged warnings to the user earlier) + // Clear out anything that is invalid or not used (for invalid entries we already logged warnings to the user earlier) foreach (var networkPrefabIndexToRemove in removeEmptyPrefabs) { - + NetworkConfig.NetworkPrefabs.RemoveAt(networkPrefabIndexToRemove); } removeEmptyPrefabs.Clear(); diff --git a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs index d8322b0dea..b8a5c118a8 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs @@ -156,7 +156,7 @@ void DelayedSpawnAction(Stream continuationStream) var networkObject = NetworkManager.SpawnManager.CreateLocalNetworkObject(softSync, prefabHash, ownerId, parentNetworkId, pos, rot); if (networkObject == null) { - //This will prevent one misconfigured issue (or more) from breaking the entire loading process. + // This will prevent one misconfigured issue (or more) from breaking the entire loading process. Debug.LogError($"Failed to spawn NetowrkObject for Hash {prefabHash}, ignoring and continuing to load."); continue; } diff --git a/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs index 0be004eac7..fd1de772a6 100644 --- a/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs @@ -304,31 +304,31 @@ private void OnSceneUnloadServer(Guid switchSceneGuid) } else { - //We do have a parent + // We do have a parent writer.WriteBool(true); - //Write the parent's NetworkObjectId to be used for linking back to the child + // Write the parent's NetworkObjectId to be used for linking back to the child writer.WriteUInt64Packed(parentNetworkObject.NetworkObjectId); } writer.WriteUInt32Packed(newSceneObjects[i].GlobalObjectIdHash); if (newSceneObjects[i].IncludeTransformWhenSpawning == null || newSceneObjects[i].IncludeTransformWhenSpawning(newSceneObjects[i].OwnerClientId)) { - //Set the position and rotation data marker to true (i.e. flag to know, when reading from the stream, that postion and roation data follows). + // Set the position and rotation data marker to true (i.e. flag to know, when reading from the stream, that postion and roation data follows). writer.WriteBool(true); - //Write position + // Write position writer.WriteSinglePacked(newSceneObjects[i].transform.position.x); writer.WriteSinglePacked(newSceneObjects[i].transform.position.y); writer.WriteSinglePacked(newSceneObjects[i].transform.position.z); - //Write rotation + // Write rotation writer.WriteSinglePacked(newSceneObjects[i].transform.rotation.eulerAngles.x); writer.WriteSinglePacked(newSceneObjects[i].transform.rotation.eulerAngles.y); writer.WriteSinglePacked(newSceneObjects[i].transform.rotation.eulerAngles.z); } else { - //Set the position and rotation data marker to false (i.e. flag to know, when reading from the stream, that postion and roation data *was not included*) + // Set the position and rotation data marker to false (i.e. flag to know, when reading from the stream, that postion and roation data *was not included*) writer.WriteBool(false); } @@ -344,7 +344,7 @@ private void OnSceneUnloadServer(Guid switchSceneGuid) } } - //Tell server that scene load is completed + // Tell server that scene load is completed if (m_NetworkManager.IsHost) { OnClientSwitchSceneCompleted(m_NetworkManager.LocalClientId, switchSceneGuid); @@ -381,7 +381,7 @@ private void OnSceneUnloadClient(Guid switchSceneGuid, Stream objectStream) Vector3? position = null; Quaternion? rotation = null; - //Check to see if we have position and rotation values that follows + // Check to see if we have position and rotation values that follows if (reader.ReadBool()) { position = new Vector3(reader.ReadSinglePacked(), reader.ReadSinglePacked(), reader.ReadSinglePacked()); @@ -391,7 +391,7 @@ private void OnSceneUnloadClient(Guid switchSceneGuid, Stream objectStream) var networkObject = m_NetworkManager.SpawnManager.CreateLocalNetworkObject(true, prefabHash, ownerClientId, parentNetworkId, position, rotation); if (networkObject == null) { - //This will prevent one misconfigured issue (or more) from breaking the entire loading process. + // This will prevent one misconfigured issue (or more) from breaking the entire loading process. Debug.LogError($"Failed to spawn NetowrkObject for Hash {prefabHash}, ignoring and continuing to load."); continue; } @@ -432,7 +432,7 @@ internal void OnClientSwitchSceneCompleted(ulong clientId, Guid switchSceneGuid) { if (switchSceneGuid == Guid.Empty) { - //If Guid is empty it means the client has loaded the start scene of the server and the server would never have a switchSceneProgresses created for the start scene. + // If Guid is empty it means the client has loaded the start scene of the server and the server would never have a switchSceneProgresses created for the start scene. return; } diff --git a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs index f231542113..b07cd5fc99 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs @@ -212,7 +212,7 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash // If the prefab hash has a registered INetworkPrefabInstanceHandler derived class if (NetworkManager.PrefabHandler.ContainsHandler(prefabHash)) { - //Let the handler spawn the NetworkObject + // Let the handler spawn the NetworkObject var networkObject = NetworkManager.PrefabHandler.HandleNetworkPrefabSpawn(prefabHash, ownerClientId, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity)); if (parentNetworkObject != null) @@ -229,7 +229,7 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash } else { - //See if there is a valid registered NetworkPrefabOverrideLink associated with the provided prefabHash + // See if there is a valid registered NetworkPrefabOverrideLink associated with the provided prefabHash GameObject networkPrefabReference = null; if(NetworkManager.NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(prefabHash)) { @@ -246,7 +246,7 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash } } - //If not, then there is an issue (user possibly didn't register the prefab properly?) + // If not, then there is an issue (user possibly didn't register the prefab properly?) if (networkPrefabReference == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) @@ -257,7 +257,7 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash return null; } - //Otherwise, instantiate an instance of the NetworkPrefab linked to the prefabHash + // Otherwise, instantiate an instance of the NetworkPrefab linked to the prefabHash var networkObject = ((position == null && rotation == null) ? UnityEngine.Object.Instantiate(networkPrefabReference) : UnityEngine.Object.Instantiate(networkPrefabReference, position.GetValueOrDefault(Vector3.zero), rotation.GetValueOrDefault(Quaternion.identity))).GetComponent(); if (parentNetworkObject != null) From 3de2cac6500d5e0ab5fce631718cea6a4e1926d1 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Tue, 20 Apr 2021 18:04:19 -0500 Subject: [PATCH 13/18] fix: clearing network prefab links This fixes an issue that can occur with serialization and NetworkPrefabOverrideLinks. The policy is to ALWAYS clear this dictionary before building the links dictionary. --- com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index 2d89a1a758..a79720bd9d 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -423,6 +423,9 @@ private void Init(bool server) // This is used to remove entries not needed or invalid var removeEmptyPrefabs = new List(); + // Always clear our prefab override links before building + NetworkConfig.NetworkPrefabOverrideLinks.Clear(); + // Build the NetworkPrefabOverrideLinks dictionary for (int i = 0; i < NetworkConfig.NetworkPrefabs.Count; i++) { From bb91f176765f91100d5cd5187f6b710a4e4a5007 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Wed, 21 Apr 2021 15:24:16 -0500 Subject: [PATCH 14/18] refactor: NetworkConfig compatibility, NetworkPrefab, and Style This removes the NetworkConfig compatibility checks that auto-upgraded a previous NetworkConfig setting to the new pattern. Updated NetworkPrefab according to this change, isPlayer is no longer needed. Added additional code to NetworkPrefab that will return a hash reflective of the override state. Adjusted some comments. --- .../Runtime/Configuration/NetworkConfig.cs | 24 +-------- .../Runtime/Configuration/NetworkPrefab.cs | 32 ++++++++---- .../Runtime/Core/NetworkManager.cs | 49 +++---------------- .../Runtime/Spawning/NetworkSpawnManager.cs | 9 +--- 4 files changed, 34 insertions(+), 80 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs index b4a34f8c8a..90625533a0 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs @@ -41,30 +41,10 @@ public class NetworkConfig "If this is true, clients with different initial configurations will not work together.")] public bool AllowRuntimeSceneChanges = false; - /// - /// The previously set default player prefab - /// Note: this is only for an editor specific scenario where we need to determine during the - /// NetworkManager.OnValidate invocation period there is no PlayerPrefab value yet there is a - /// NetworkPrefab entry that has IsPlayer set to true. This is also used to determine if - /// we are loading from a previous MLAPI version where the NetworkPrefab.IsPlayer was predominantly - /// used. - /// There are two scenarios where this is used: - /// 1.) If the PreviousPlayerPrefab and PlayerPrefab values are not set but a NetworkPrefab has - /// an entry with the NetworkPrefab.IsPlayer set to true, then we want to assign the PlayerPrefab - /// and PreviousPlayerPrefab - /// 2.) If the PlayerPrefab is null, the PreviousPlayer prefab is not, a NetworkPrefab entry - /// has its NetworkPrefab.IsPlayer set to true, and that NetworkPrefab entry's prefab's - /// NetworkObject.GlobalObjectIdHash is the same as the PreviousPlayerPrefab's NetworkObject.GlobalObjectIdHash - /// then the user deleted the PlayerPrefab so we can mark the NetworkPrefab.IsPlayer value of the matching - /// NetworkPrefab to false and the PreviousPlayerPrefab to null. - /// (The next time PlayerPrefab is set see scenario #1) - /// - internal GameObject PreviousPlayerPrefab; - /// /// The default player prefab /// - [Tooltip("When set, the network manager will automatically create and spawn the assigned player prefab. The Player Prefab can be overriden by adding it to the NetworkPrefabs list and selecting override.")] + [Tooltip("When set, NetworkManager will automatically create and spawn the assigned player prefab. This can be overridden by adding it to the NetworkPrefabs list and selecting override.")] public GameObject PlayerPrefab; /// @@ -77,7 +57,7 @@ public class NetworkConfig /// This dictionary provides a quick way to check and see if a NetworkPrefab has a NetworkPrefab override. /// Generated at runtime and OnValidate /// - public DictionaryNetworkPrefabOverrideLinks = new Dictionary(); + internal Dictionary NetworkPrefabOverrideLinks = new Dictionary(); /// /// Amount of times per second the receive queue is emptied and all messages inside are processed. diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs index 97ab259a55..995385060e 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs @@ -17,15 +17,19 @@ public enum NetworkPrefabOverride [Serializable] public class NetworkPrefab { + /// + /// The override setttings for this NetworkPrefab + /// + public NetworkPrefabOverride Override; + /// /// Asset reference of the network prefab /// public GameObject Prefab; - public NetworkPrefabOverride Override; - /// /// Used when prefab is selected for the source prefab to override value (i.e. direct reference, the prefab is within the same project) + /// We keep a separate value as the user might want to have something different than the default Prefab for the SourcePrefabToOverride /// public GameObject SourcePrefabToOverride; @@ -39,11 +43,6 @@ public class NetworkPrefab /// public GameObject OverridingTargetPrefab; - /// - /// Whether or not this is a player prefab - /// - public bool IsPlayer; - internal uint Hash { get @@ -58,12 +57,27 @@ internal uint Hash return 0; } - var networkObject = Prefab.GetComponent(); + var prefabGameObject = Prefab; + + switch(Override) + { + case NetworkPrefabOverride.Prefab: + { + prefabGameObject = SourcePrefabToOverride; + break; + } + case NetworkPrefabOverride.Hash: + { + return SourceHashToOverride; + } + } + + var networkObject = prefabGameObject.GetComponent(); if (networkObject == null) { if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) { - NetworkLog.LogWarning($"{nameof(NetworkPrefab)} {Prefab.name} does not have a {nameof(NetworkObject)} component"); + NetworkLog.LogWarning($"{nameof(NetworkPrefab)} {prefabGameObject.name} does not have a {nameof(NetworkObject)} component"); } return 0; diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index a79720bd9d..cebfa19d5b 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -247,13 +247,7 @@ private void OnValidate() }; } - // If true, check to see if there is a defined player prefab in the Network prefab list - // This helps migrate v0.1.0 projects (i.e. no PlayerPrefab was assigned) as well as helps detect - // specific interface related issues related to the NetworkPrefabs list. - var scanForPlayerPrefab = NetworkConfig.PlayerPrefab == null; - - // During OnValidate we will always clear out NetworkPrefabOverrideLinks and rebuild it in order to - // detect specific edge case scenarios (See NtworkConfig.PreviousPlayerPrefab comments) + // During OnValidate we will always clear out NetworkPrefabOverrideLinks and rebuild it NetworkConfig.NetworkPrefabOverrideLinks.Clear(); // Check network prefabs and assign to dictionary for quick look up @@ -271,35 +265,6 @@ private void OnValidate() } else { - // If someone is transitioning to this new format, then go ahead and populate the PlayerPrefab reference for them. - if (scanForPlayerPrefab && NetworkConfig.NetworkPrefabs[i].IsPlayer) - { - // If we find a NetworkPrefab where IsPlayer is true and we have - // no PlayerPrefab nor did we have one previously (i.e. we didn't just delete it), - // then we want to set the default player prefab. We also want to set the - // previous player prefab value in the event the user decides to delete the - // PlayerPrefab value from within the editor inspector view. - // (See NtworkConfig.PreviousPlayerPrefab comments for more information) - if (NetworkConfig.PreviousPlayerPrefab == null) - { - NetworkConfig.PlayerPrefab = NetworkConfig.NetworkPrefabs[i].Prefab; - NetworkConfig.PreviousPlayerPrefab = NetworkConfig.PlayerPrefab; - } - else if (NetworkConfig.NetworkPrefabs[i].Prefab != null) - { - var playerPrefabNetworkObject = NetworkConfig.PreviousPlayerPrefab.GetComponent(); - var prefabNetworkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent(); - if (playerPrefabNetworkObject != null && prefabNetworkObject != null) - { - if (playerPrefabNetworkObject.GlobalObjectIdHash == prefabNetworkObject.GlobalObjectIdHash) - { - NetworkConfig.NetworkPrefabs[i].IsPlayer = false; - NetworkConfig.PreviousPlayerPrefab = null; - } - } - } - } - // Defautlt to the standard NetworkPrefab.Prefab's NetworkObject first var globalObjectIdHash = networkObject.GlobalObjectIdHash; @@ -313,7 +278,6 @@ private void OnValidate() NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride = NetworkConfig.NetworkPrefabs[i].Prefab; } globalObjectIdHash = NetworkConfig.NetworkPrefabs[i].SourcePrefabToOverride.GetComponent().GlobalObjectIdHash; - } break; case NetworkPrefabOverride.Hash: @@ -492,13 +456,12 @@ private void Init(bool server) var playerPrefabNetworkObject = NetworkConfig.PlayerPrefab.GetComponent(); if (playerPrefabNetworkObject != null) { - // If we don't have a reference (i.e. someone didn't already add it to the NetworkPrefab list) + //In the event there is no NetworkPrefab entry (i.e. no override for default player prefab) if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(NetworkConfig.PlayerPrefab.GetComponent().GlobalObjectIdHash)) { // Create a prefab entry var playerNetworkPrefab = new NetworkPrefab(); - playerNetworkPrefab.Prefab = NetworkConfig.PlayerPrefab; - playerNetworkPrefab.IsPlayer = true; + playerNetworkPrefab.Prefab = NetworkConfig.PlayerPrefab; // Add it to the prefab list NetworkConfig.NetworkPrefabs.Insert(0, playerNetworkPrefab); @@ -507,12 +470,16 @@ private void Init(bool server) NetworkConfig.NetworkPrefabOverrideLinks.Add(playerPrefabNetworkObject.GlobalObjectIdHash, playerNetworkPrefab); } } + else + { + // Provide the name of the prefab with issues so the user can more easily find the prefab and fix it + UnityEngine.Debug.LogError($"{nameof(NetworkConfig.PlayerPrefab)} (\"{NetworkConfig.PlayerPrefab.name}\") has no NetworkObject assigned to it!."); + } } // Clear out anything that is invalid or not used (for invalid entries we already logged warnings to the user earlier) foreach (var networkPrefabIndexToRemove in removeEmptyPrefabs) { - NetworkConfig.NetworkPrefabs.RemoveAt(networkPrefabIndexToRemove); } removeEmptyPrefabs.Clear(); diff --git a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs index b07cd5fc99..62ddbf291f 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs @@ -182,15 +182,8 @@ internal void ChangeOwnership(NetworkObject networkObject, ulong clientId) } /// - /// Only run on the client + /// Should only run on the client /// - /// - /// - /// - /// - /// - /// - /// internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash, ulong ownerClientId, ulong? parentNetworkId, Vector3? position, Quaternion? rotation) { NetworkObject parentNetworkObject = null; From 0e11960d8e9a75e6d397424179a809f700eb82e3 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Wed, 21 Apr 2021 19:39:48 -0500 Subject: [PATCH 15/18] fix: wrong hash reference Minor adjustment for the right GlobalObjectIdHash check. --- com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index cebfa19d5b..482ff3ad97 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -457,7 +457,7 @@ private void Init(bool server) if (playerPrefabNetworkObject != null) { //In the event there is no NetworkPrefab entry (i.e. no override for default player prefab) - if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(NetworkConfig.PlayerPrefab.GetComponent().GlobalObjectIdHash)) + if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(playerPrefabNetworkObject.GlobalObjectIdHash)) { // Create a prefab entry var playerNetworkPrefab = new NetworkPrefab(); From 5c22c63b2aa9e4e941decf7777faf52bf5e775e6 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Thu, 22 Apr 2021 09:23:15 -0500 Subject: [PATCH 16/18] refactor and style Made the NetworkPrefab internal as well as NetworkPrefabOverride. Removed GetNetworkPrefabIndexOfHash and GetPrefabHashFromIndex as they were used in the old hash generation pattern. Updated comments a bit. --- .../Runtime/Configuration/NetworkConfig.cs | 3 +- .../Runtime/Configuration/NetworkPrefab.cs | 5 ++-- .../Runtime/Core/NetworkManager.cs | 17 ++++------- .../Messaging/InternalMessageHandler.cs | 2 +- .../SceneManagement/NetworkSceneManager.cs | 2 +- .../Runtime/Spawning/NetworkSpawnManager.cs | 30 +------------------ 6 files changed, 12 insertions(+), 47 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs index 90625533a0..e10d58d5ca 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs @@ -50,8 +50,9 @@ public class NetworkConfig /// /// A list of spawnable prefabs /// + [SerializeField] [Tooltip("The prefabs that can be spawned across the network")] - public List NetworkPrefabs = new List(); + internal List NetworkPrefabs = new List(); /// /// This dictionary provides a quick way to check and see if a NetworkPrefab has a NetworkPrefab override. diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs index 995385060e..2321f25863 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs @@ -4,7 +4,7 @@ namespace MLAPI.Configuration { - public enum NetworkPrefabOverride + internal enum NetworkPrefabOverride { None, Prefab, @@ -15,7 +15,7 @@ public enum NetworkPrefabOverride /// Class that represents a NetworkPrefab /// [Serializable] - public class NetworkPrefab + internal class NetworkPrefab { /// /// The override setttings for this NetworkPrefab @@ -53,7 +53,6 @@ internal uint Hash { NetworkLog.LogWarning($"{nameof(NetworkPrefab)} does not have a prefab assigned"); } - return 0; } diff --git a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs index 482ff3ad97..4caa058da1 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Core/NetworkManager.cs @@ -265,7 +265,7 @@ private void OnValidate() } else { - // Defautlt to the standard NetworkPrefab.Prefab's NetworkObject first + // Default to the standard NetworkPrefab.Prefab's NetworkObject first var globalObjectIdHash = networkObject.GlobalObjectIdHash; // Now check to see if it has an override @@ -292,8 +292,8 @@ private void OnValidate() } else { - // This happens when a new duplicate entry is created. - // We just turn it into a new blank entry + // Duplicate entries can happen when adding a new entry into a list of existing entries + // Either this is user error or a new entry, either case we replace it with a new, blank, NetworkPrefab under this condition NetworkConfig.NetworkPrefabs[i] = new NetworkPrefab(); } } @@ -404,7 +404,6 @@ private void Init(bool server) UnityEngine.Debug.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") will be removed and ignored."); removeEmptyPrefabs.Add(i); - // Ignore this entry due to the error (it will be removed during runtime) continue; } else if (NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent() == null) @@ -418,11 +417,9 @@ private void Init(bool server) UnityEngine.Debug.LogWarning($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") will be removed and ignored."); removeEmptyPrefabs.Add(i); - // Ignore this entry due to the error (it will be removed during runtime) continue; } - // Get the default NetworkObject first var networkObject = NetworkConfig.NetworkPrefabs[i].Prefab.GetComponent(); // Assign the appropriate GlobalObjectIdHash to the appropriate NetworkPrefab @@ -445,7 +442,7 @@ private void Init(bool server) else { // This should never happen, but in the case it somehow does log an error and remove the duplicate entry - UnityEngine.Debug.LogError($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") has a duplicate GlobalObjectIdHash {networkObject.GlobalObjectIdHash.ToString("X")} entry! Removing entry from list!"); + UnityEngine.Debug.LogError($"{nameof(NetworkPrefab)} (\"{NetworkConfig.NetworkPrefabs[i].Prefab.name}\") has a duplicate {nameof(NetworkObject.GlobalObjectIdHash)} {networkObject.GlobalObjectIdHash} entry! Removing entry from list!"); removeEmptyPrefabs.Add(i); } } @@ -459,14 +456,10 @@ private void Init(bool server) //In the event there is no NetworkPrefab entry (i.e. no override for default player prefab) if (!NetworkConfig.NetworkPrefabOverrideLinks.ContainsKey(playerPrefabNetworkObject.GlobalObjectIdHash)) { - // Create a prefab entry + //Then add a new entry for the player prefab var playerNetworkPrefab = new NetworkPrefab(); playerNetworkPrefab.Prefab = NetworkConfig.PlayerPrefab; - - // Add it to the prefab list NetworkConfig.NetworkPrefabs.Insert(0, playerNetworkPrefab); - - // assign its NetworkPrefabOverrideLink NetworkConfig.NetworkPrefabOverrideLinks.Add(playerPrefabNetworkObject.GlobalObjectIdHash, playerNetworkPrefab); } } diff --git a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs index b8a5c118a8..068ab5037d 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs @@ -157,7 +157,7 @@ void DelayedSpawnAction(Stream continuationStream) if (networkObject == null) { // This will prevent one misconfigured issue (or more) from breaking the entire loading process. - Debug.LogError($"Failed to spawn NetowrkObject for Hash {prefabHash}, ignoring and continuing to load."); + Debug.LogError($"Failed to spawn {nameof(NetworkObject)} for Hash {prefabHash}, ignoring and continuing to load."); continue; } NetworkManager.SpawnManager.SpawnNetworkObjectLocally(networkObject, networkId, softSync, isPlayerObject, ownerId, continuationStream, false, 0, true, false); diff --git a/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs index fd1de772a6..73cf9dbc2c 100644 --- a/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs @@ -392,7 +392,7 @@ private void OnSceneUnloadClient(Guid switchSceneGuid, Stream objectStream) if (networkObject == null) { // This will prevent one misconfigured issue (or more) from breaking the entire loading process. - Debug.LogError($"Failed to spawn NetowrkObject for Hash {prefabHash}, ignoring and continuing to load."); + Debug.LogError($"Failed to spawn {nameof(NetworkObject)} for Hash {prefabHash}, ignoring and continuing to load."); continue; } diff --git a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs index 62ddbf291f..1835782bcf 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Spawning/NetworkSpawnManager.cs @@ -57,34 +57,6 @@ internal ulong GetNetworkObjectId() return m_NetworkObjectIdCounter; } - /// - /// Gets the prefab index of a given prefab hash - /// - /// The hash of the prefab - /// The index of the prefab - public int GetNetworkPrefabIndexOfHash(uint hash) - { - for (int i = 0; i < NetworkManager.NetworkConfig.NetworkPrefabs.Count; i++) - { - if (NetworkManager.NetworkConfig.NetworkPrefabs[i].Hash == hash) - { - return i; - } - } - - return -1; - } - - /// - /// Returns the prefab hash for the NetworkPrefab with a given index - /// - /// The NetworkPrefab index - /// The prefab hash for the given prefab index - public uint GetPrefabHashFromIndex(int index) - { - return NetworkManager.NetworkConfig.NetworkPrefabs[index].Hash; - } - /// /// Returns the local player object or null if one does not exist /// @@ -273,7 +245,7 @@ internal NetworkObject CreateLocalNetworkObject(bool softCreate, uint prefabHash { if (NetworkLog.CurrentLogLevel <= LogLevel.Error) { - NetworkLog.LogError($"{nameof(NetworkPrefab)} hash was not found! In-Scene placed NetworkObject soft synchronization failure for Hash: {prefabHash.ToString("X")}!"); + NetworkLog.LogError($"{nameof(NetworkPrefab)} hash was not found! In-Scene placed {nameof(NetworkObject)} soft synchronization failure for Hash: {prefabHash}!"); } return null; } From 67f8e66f428f072c25da79061235b96175a02482 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Thu, 22 Apr 2021 09:27:54 -0500 Subject: [PATCH 17/18] refactor: removing NetworkObject check Removing two checks for the failure to spawn a NetworkObject locally. This will be handled via PR-756: https://github.com/Unity-Technologies/com.unity.multiplayer.mlapi/pull/756 --- .../Runtime/Messaging/InternalMessageHandler.cs | 6 ------ .../Runtime/SceneManagement/NetworkSceneManager.cs | 7 ------- 2 files changed, 13 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs index 068ab5037d..cbca3be8d6 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Messaging/InternalMessageHandler.cs @@ -154,12 +154,6 @@ void DelayedSpawnAction(Stream continuationStream) } var networkObject = NetworkManager.SpawnManager.CreateLocalNetworkObject(softSync, prefabHash, ownerId, parentNetworkId, pos, rot); - if (networkObject == null) - { - // This will prevent one misconfigured issue (or more) from breaking the entire loading process. - Debug.LogError($"Failed to spawn {nameof(NetworkObject)} for Hash {prefabHash}, ignoring and continuing to load."); - continue; - } NetworkManager.SpawnManager.SpawnNetworkObjectLocally(networkObject, networkId, softSync, isPlayerObject, ownerId, continuationStream, false, 0, true, false); Queue bufferQueue = NetworkManager.BufferManager.ConsumeBuffersForNetworkId(networkId); diff --git a/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs index 73cf9dbc2c..7f322ae693 100644 --- a/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs +++ b/com.unity.multiplayer.mlapi/Runtime/SceneManagement/NetworkSceneManager.cs @@ -389,13 +389,6 @@ private void OnSceneUnloadClient(Guid switchSceneGuid, Stream objectStream) } var networkObject = m_NetworkManager.SpawnManager.CreateLocalNetworkObject(true, prefabHash, ownerClientId, parentNetworkId, position, rotation); - if (networkObject == null) - { - // This will prevent one misconfigured issue (or more) from breaking the entire loading process. - Debug.LogError($"Failed to spawn {nameof(NetworkObject)} for Hash {prefabHash}, ignoring and continuing to load."); - continue; - } - m_NetworkManager.SpawnManager.SpawnNetworkObjectLocally(networkObject, networkId, true, isPlayerObject, ownerClientId, objectStream, false, 0, true, false); var bufferQueue = m_NetworkManager.BufferManager.ConsumeBuffersForNetworkId(networkId); From 02a726dfbf4fbeb23ef7aa00e44b6f065e61a731 Mon Sep 17 00:00:00 2001 From: NoelStephensUnity <73188597+NoelStephensUnity@users.noreply.github.com> Date: Thu, 22 Apr 2021 10:41:59 -0500 Subject: [PATCH 18/18] refactor: removing NetworkPrefab.Hash This property is no longer being used and where it was used was replaced by the NetworkConfig.NetworkPrefabOverrideLinks --- .../Runtime/Configuration/NetworkConfig.cs | 6 +-- .../Runtime/Configuration/NetworkPrefab.cs | 43 ------------------- .../NetworkPrefabGlobalObjectIdHashTests.cs | 4 +- 3 files changed, 5 insertions(+), 48 deletions(-) diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs index e10d58d5ca..2e74c3f7fe 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkConfig.cs @@ -301,10 +301,10 @@ public ulong GetConfig(bool cache = true) if (ForceSamePrefabs) { - var sortedPrefabList = NetworkPrefabs.OrderBy(x => x.Hash).ToList(); - for (int i = 0; i < sortedPrefabList.Count; i++) + var sortedDictionary = NetworkPrefabOverrideLinks.OrderBy(x => x.Key); + foreach (var sortedEntry in sortedDictionary) { - writer.WriteUInt32Packed(sortedPrefabList[i].Hash); + writer.WriteUInt32Packed(sortedEntry.Key); } } diff --git a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs index 2321f25863..82787a9241 100644 --- a/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs +++ b/com.unity.multiplayer.mlapi/Runtime/Configuration/NetworkPrefab.cs @@ -42,48 +42,5 @@ internal class NetworkPrefab /// The prefab to replace (override) the source prefab with /// public GameObject OverridingTargetPrefab; - - internal uint Hash - { - get - { - if (Prefab == null) - { - if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) - { - NetworkLog.LogWarning($"{nameof(NetworkPrefab)} does not have a prefab assigned"); - } - return 0; - } - - var prefabGameObject = Prefab; - - switch(Override) - { - case NetworkPrefabOverride.Prefab: - { - prefabGameObject = SourcePrefabToOverride; - break; - } - case NetworkPrefabOverride.Hash: - { - return SourceHashToOverride; - } - } - - var networkObject = prefabGameObject.GetComponent(); - if (networkObject == null) - { - if (NetworkLog.CurrentLogLevel <= LogLevel.Normal) - { - NetworkLog.LogWarning($"{nameof(NetworkPrefab)} {prefabGameObject.name} does not have a {nameof(NetworkObject)} component"); - } - - return 0; - } - - return networkObject.GlobalObjectIdHash; - } - } } } diff --git a/com.unity.multiplayer.mlapi/Tests/Runtime/GlobalObjectIdHash/NetworkPrefabGlobalObjectIdHashTests.cs b/com.unity.multiplayer.mlapi/Tests/Runtime/GlobalObjectIdHash/NetworkPrefabGlobalObjectIdHashTests.cs index 97117a8b32..1271b761d0 100644 --- a/com.unity.multiplayer.mlapi/Tests/Runtime/GlobalObjectIdHash/NetworkPrefabGlobalObjectIdHashTests.cs +++ b/com.unity.multiplayer.mlapi/Tests/Runtime/GlobalObjectIdHash/NetworkPrefabGlobalObjectIdHashTests.cs @@ -61,9 +61,9 @@ public void VerifyUniquenessOfNetworkPrefabs() Assert.That(networkManager.NetworkConfig.NetworkPrefabs.Count, Is.GreaterThan(1)); var hashSet = new HashSet(); - foreach (var networkPrefab in networkManager.NetworkConfig.NetworkPrefabs) + foreach (var networkPrefab in networkManager.NetworkConfig.NetworkPrefabOverrideLinks) { - var idHash = networkPrefab.Hash; + var idHash = networkPrefab.Key; Assert.That(idHash, Is.Not.EqualTo(0)); Assert.That(hashSet.Contains(idHash), Is.False); hashSet.Add(idHash);