slowpoker/Assets/Mirror/Editor/NetworkManagerEditor.cs

182 lines
6.2 KiB
C#
Raw Normal View History

2024-10-17 17:23:05 +03:00
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;
}
}
}
}