NetworkManagerEditor.cs 6.23 KB
Newer Older
cann-alberto's avatar
cann-alberto committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

namespace Mirror
{
    [CustomEditor(typeof(NetworkManager), true)]
    [CanEditMultipleObjects]
    public class NetworkManagerEditor : Editor
    {
        SerializedProperty spawnListProperty;
        ReorderableList spawnList;
        protected NetworkManager networkManager;

        protected void Init()
        {
            if (spawnList == null)
            {
                networkManager = target as NetworkManager;
                spawnListProperty = serializedObject.FindProperty("spawnPrefabs");
                spawnList = new ReorderableList(serializedObject, spawnListProperty)
                {
                    drawHeaderCallback = DrawHeader,
                    drawElementCallback = DrawChild,
                    onReorderCallback = Changed,
                    onRemoveCallback = RemoveButton,
                    onChangedCallback = Changed,
                    onAddCallback = AddButton,
                    // this uses a 16x16 icon. other sizes make it stretch.
                    elementHeight = 16
                };
            }
        }

        public override void OnInspectorGUI()
        {
            Init();
            DrawDefaultInspector();
            EditorGUI.BeginChangeCheck();
            spawnList.DoLayoutList();
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
            }

            if (GUILayout.Button("Populate Spawnable Prefabs"))
            {
                ScanForNetworkIdentities();
            }
        }

        void ScanForNetworkIdentities()
        {
            List<GameObject> identities = new List<GameObject>();
            bool cancelled = false;
            try
            {
                string[] paths = EditorHelper.IterateOverProject("t:prefab").ToArray();
                int count = 0;
                foreach (string path in paths)
                {
                    // ignore test & example prefabs.
                    // users sometimes keep the folders in their projects.
                    if (path.Contains("Mirror/Tests/") ||
                        path.Contains("Mirror/Examples/"))
                    {
                        continue;
                    }

                    if (EditorUtility.DisplayCancelableProgressBar("Searching for NetworkIdentities..",
                            $"Scanned {count}/{paths.Length} prefabs. Found {identities.Count} new ones",
                            count / (float)paths.Length))
                    {
                        cancelled = true;
                        break;
                    }

                    count++;

                    NetworkIdentity ni = AssetDatabase.LoadAssetAtPath<NetworkIdentity>(path);
                    if (!ni)
                    {
                        continue;
                    }

                    if (!networkManager.spawnPrefabs.Contains(ni.gameObject))
                    {
                        identities.Add(ni.gameObject);
                    }

                }
            }
            finally
            {

                EditorUtility.ClearProgressBar();
                if (!cancelled)
                {
                    // RecordObject is needed for "*" to show up in Scene.
                    // however, this only saves List.Count without the entries.
                    Undo.RecordObject(networkManager, "NetworkManager: populated prefabs");

                    // add the entries
                    networkManager.spawnPrefabs.AddRange(identities);

                    // sort alphabetically for better UX
                    networkManager.spawnPrefabs = networkManager.spawnPrefabs.OrderBy(go => go.name).ToList();

                    // SetDirty is required to save the individual entries properly.
                    EditorUtility.SetDirty(target);
                }
                // Loading assets might use a lot of memory, so try to unload them after
                Resources.UnloadUnusedAssets();
            }
        }

        static void DrawHeader(Rect headerRect)
        {
            GUI.Label(headerRect, "Registered Spawnable Prefabs:");
        }

        internal void DrawChild(Rect r, int index, bool isActive, bool isFocused)
        {
            SerializedProperty prefab = spawnListProperty.GetArrayElementAtIndex(index);
            GameObject go = (GameObject)prefab.objectReferenceValue;

            GUIContent label;
            if (go == null)
            {
                label = new GUIContent("Empty", "Drag a prefab with a NetworkIdentity here");
            }
            else
            {
                NetworkIdentity identity = go.GetComponent<NetworkIdentity>();
                label = new GUIContent(go.name, identity != null ? $"AssetId: [{identity.assetId}]" : "No Network Identity");
            }

            GameObject newGameObject = (GameObject)EditorGUI.ObjectField(r, label, go, typeof(GameObject), false);

            if (newGameObject != go)
            {
                if (newGameObject != null && !newGameObject.GetComponent<NetworkIdentity>())
                {
                    Debug.LogError($"Prefab {newGameObject} cannot be added as spawnable as it doesn't have a NetworkIdentity.");
                    return;
                }
                prefab.objectReferenceValue = newGameObject;
            }
        }

        internal void Changed(ReorderableList list)
        {
            EditorUtility.SetDirty(target);
        }

        internal void AddButton(ReorderableList list)
        {
            spawnListProperty.arraySize += 1;
            list.index = spawnListProperty.arraySize - 1;

            SerializedProperty obj = spawnListProperty.GetArrayElementAtIndex(spawnListProperty.arraySize - 1);
            obj.objectReferenceValue = null;

            spawnList.index = spawnList.count - 1;

            Changed(list);
        }

        internal void RemoveButton(ReorderableList list)
        {
            spawnListProperty.DeleteArrayElementAtIndex(spawnList.index);
            if (list.index >= spawnListProperty.arraySize)
            {
                list.index = spawnListProperty.arraySize - 1;
            }
        }
    }
}