using System; using System.Reflection; using UnityEditor; using UnityEngine; namespace Mirror { [CustomEditor(typeof(NetworkBehaviour), true)] [CanEditMultipleObjects] public class NetworkBehaviourInspector : Editor { bool syncsAnything; SyncObjectCollectionsDrawer syncObjectCollectionsDrawer; // does this type sync anything? otherwise we don't need to show syncInterval bool SyncsAnything(Type scriptClass) { // check for all SyncVar fields, they don't have to be visible foreach (FieldInfo field in InspectorHelper.GetAllFields(scriptClass, typeof(NetworkBehaviour))) { if (field.IsSyncVar()) { return true; } } // has OnSerialize that is not in NetworkBehaviour? // then it either has a syncvar or custom OnSerialize. either way // this means we have something to sync. MethodInfo method = scriptClass.GetMethod("OnSerialize"); if (method != null && method.DeclaringType != typeof(NetworkBehaviour)) { return true; } // SyncObjects are serialized in NetworkBehaviour.OnSerialize, which // is always there even if we don't use SyncObjects. so we need to // search for SyncObjects manually. // Any SyncObject should be added to syncObjects when unity creates an // object so we can check length of list so see if sync objects exists return ((NetworkBehaviour)serializedObject.targetObject).HasSyncObjects(); } void OnEnable() { // sometimes target is null. just return early. if (target == null) return; // If target's base class is changed from NetworkBehaviour to MonoBehaviour // then Unity temporarily keep using this Inspector causing things to break if (!(target is NetworkBehaviour)) { return; } Type scriptClass = target.GetType(); syncObjectCollectionsDrawer = new SyncObjectCollectionsDrawer(serializedObject.targetObject); syncsAnything = SyncsAnything(scriptClass); } public override void OnInspectorGUI() { DrawDefaultInspector(); DrawSyncObjectCollections(); DrawDefaultSyncSettings(); } // Draws Sync Objects that are IEnumerable protected void DrawSyncObjectCollections() { // Need this check in case OnEnable returns early if (syncObjectCollectionsDrawer == null) return; syncObjectCollectionsDrawer.Draw(); } // Draws SyncSettings if the NetworkBehaviour has anything to sync protected void DrawDefaultSyncSettings() { // does it sync anything? then show extra properties // (no need to show it if the class only has Cmds/Rpcs and no sync) if (!syncsAnything) { return; } EditorGUILayout.Space(); EditorGUILayout.LabelField("Sync Settings", EditorStyles.boldLabel); // sync direction SerializedProperty syncDirection = serializedObject.FindProperty("syncDirection"); EditorGUILayout.PropertyField(syncDirection); // sync mdoe: only show for ServerToClient components if (syncDirection.enumValueIndex == (int)SyncDirection.ServerToClient) EditorGUILayout.PropertyField(serializedObject.FindProperty("syncMode")); // sync interval EditorGUILayout.PropertyField(serializedObject.FindProperty("syncInterval")); // apply serializedObject.ApplyModifiedProperties(); } } }