181 lines
7.1 KiB
C#
181 lines
7.1 KiB
C#
|
|
using System.Collections.Generic;
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEditorInternal;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
namespace AlicizaX
|
||
|
|
{
|
||
|
|
[CustomEditor(typeof(PoolConfigScriptableObject))]
|
||
|
|
public sealed class PoolConfigScriptableObjectEditor : UnityEditor.Editor
|
||
|
|
{
|
||
|
|
private const float VerticalSpacing = 4f;
|
||
|
|
private ReorderableList _configList;
|
||
|
|
private SerializedProperty _configsProperty;
|
||
|
|
|
||
|
|
private void OnEnable()
|
||
|
|
{
|
||
|
|
_configsProperty = serializedObject.FindProperty("configs");
|
||
|
|
_configList = new ReorderableList(serializedObject, _configsProperty, true, true, true, true)
|
||
|
|
{
|
||
|
|
drawHeaderCallback = rect => EditorGUI.LabelField(rect, "Pool Configs"),
|
||
|
|
drawElementCallback = DrawElement,
|
||
|
|
elementHeightCallback = GetElementHeight
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
public override void OnInspectorGUI()
|
||
|
|
{
|
||
|
|
serializedObject.Update();
|
||
|
|
|
||
|
|
EditorGUILayout.HelpBox(
|
||
|
|
"每条配置定义一条匹配规则;真正的池按具体 assetPath 实例化,不再共享一个目录级总容量。",
|
||
|
|
MessageType.Info);
|
||
|
|
|
||
|
|
EditorGUILayout.BeginHorizontal();
|
||
|
|
if (GUILayout.Button("Normalize"))
|
||
|
|
{
|
||
|
|
serializedObject.ApplyModifiedProperties();
|
||
|
|
NormalizeAndSort(shouldSort: false);
|
||
|
|
serializedObject.Update();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GUILayout.Button("Normalize And Sort"))
|
||
|
|
{
|
||
|
|
serializedObject.ApplyModifiedProperties();
|
||
|
|
NormalizeAndSort(shouldSort: true);
|
||
|
|
serializedObject.Update();
|
||
|
|
}
|
||
|
|
|
||
|
|
EditorGUILayout.EndHorizontal();
|
||
|
|
EditorGUILayout.Space();
|
||
|
|
|
||
|
|
_configList.DoLayoutList();
|
||
|
|
|
||
|
|
serializedObject.ApplyModifiedProperties();
|
||
|
|
|
||
|
|
DrawValidation();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DrawElement(Rect rect, int index, bool isActive, bool isFocused)
|
||
|
|
{
|
||
|
|
SerializedProperty element = _configsProperty.GetArrayElementAtIndex(index);
|
||
|
|
rect.y += 2f;
|
||
|
|
|
||
|
|
float lineHeight = EditorGUIUtility.singleLineHeight;
|
||
|
|
float wideFieldWidth = rect.width * 0.6f;
|
||
|
|
float narrowFieldWidth = rect.width - wideFieldWidth - 6f;
|
||
|
|
|
||
|
|
SerializedProperty group = element.FindPropertyRelative("group");
|
||
|
|
SerializedProperty assetPath = element.FindPropertyRelative("assetPath");
|
||
|
|
SerializedProperty matchMode = element.FindPropertyRelative("matchMode");
|
||
|
|
SerializedProperty loaderType = element.FindPropertyRelative("resourceLoaderType");
|
||
|
|
SerializedProperty capacity = element.FindPropertyRelative("capacity");
|
||
|
|
SerializedProperty prewarmCount = element.FindPropertyRelative("prewarmCount");
|
||
|
|
SerializedProperty idleTimeout = element.FindPropertyRelative("instanceIdleTimeout");
|
||
|
|
SerializedProperty unloadDelay = element.FindPropertyRelative("prefabUnloadDelay");
|
||
|
|
SerializedProperty preloadOnInitialize = element.FindPropertyRelative("preloadOnInitialize");
|
||
|
|
|
||
|
|
Rect line1 = new Rect(rect.x, rect.y, rect.width, lineHeight);
|
||
|
|
Rect line2 = new Rect(rect.x, line1.yMax + VerticalSpacing, rect.width, lineHeight);
|
||
|
|
Rect line3Left = new Rect(rect.x, line2.yMax + VerticalSpacing, wideFieldWidth, lineHeight);
|
||
|
|
Rect line3Right = new Rect(line3Left.xMax + 6f, line3Left.y, narrowFieldWidth, lineHeight);
|
||
|
|
Rect line4Left = new Rect(rect.x, line3Left.yMax + VerticalSpacing, wideFieldWidth, lineHeight);
|
||
|
|
Rect line4Right = new Rect(line4Left.xMax + 6f, line4Left.y, narrowFieldWidth, lineHeight);
|
||
|
|
Rect line5Left = new Rect(rect.x, line4Left.yMax + VerticalSpacing, wideFieldWidth, lineHeight);
|
||
|
|
Rect line5Right = new Rect(line5Left.xMax + 6f, line5Left.y, narrowFieldWidth, lineHeight);
|
||
|
|
|
||
|
|
EditorGUI.PropertyField(line1, assetPath);
|
||
|
|
EditorGUI.PropertyField(line2, group);
|
||
|
|
EditorGUI.PropertyField(line3Left, matchMode);
|
||
|
|
EditorGUI.PropertyField(line3Right, loaderType);
|
||
|
|
EditorGUI.PropertyField(line4Left, capacity);
|
||
|
|
EditorGUI.PropertyField(line4Right, prewarmCount);
|
||
|
|
EditorGUI.PropertyField(line5Left, idleTimeout);
|
||
|
|
EditorGUI.PropertyField(line5Right, unloadDelay);
|
||
|
|
|
||
|
|
Rect line6 = new Rect(rect.x, line5Left.yMax + VerticalSpacing, rect.width, lineHeight);
|
||
|
|
EditorGUI.PropertyField(line6, preloadOnInitialize);
|
||
|
|
}
|
||
|
|
|
||
|
|
private float GetElementHeight(int index)
|
||
|
|
{
|
||
|
|
float lineHeight = EditorGUIUtility.singleLineHeight;
|
||
|
|
return lineHeight * 6f + VerticalSpacing * 7f;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void NormalizeAndSort(bool shouldSort)
|
||
|
|
{
|
||
|
|
var asset = (PoolConfigScriptableObject)target;
|
||
|
|
asset.Normalize();
|
||
|
|
|
||
|
|
if (shouldSort)
|
||
|
|
{
|
||
|
|
asset.configs.Sort(PoolConfig.CompareByPriority);
|
||
|
|
}
|
||
|
|
|
||
|
|
EditorUtility.SetDirty(asset);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DrawValidation()
|
||
|
|
{
|
||
|
|
var asset = (PoolConfigScriptableObject)target;
|
||
|
|
if (asset.configs == null || asset.configs.Count == 0)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
List<string> warnings = BuildWarnings(asset.configs);
|
||
|
|
for (int i = 0; i < warnings.Count; i++)
|
||
|
|
{
|
||
|
|
EditorGUILayout.HelpBox(warnings[i], MessageType.Warning);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static List<string> BuildWarnings(List<PoolConfig> configs)
|
||
|
|
{
|
||
|
|
var warnings = new List<string>();
|
||
|
|
|
||
|
|
for (int i = 0; i < configs.Count; i++)
|
||
|
|
{
|
||
|
|
PoolConfig config = configs[i];
|
||
|
|
if (config == null)
|
||
|
|
{
|
||
|
|
warnings.Add($"Element {i} is null.");
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (string.IsNullOrWhiteSpace(config.assetPath))
|
||
|
|
{
|
||
|
|
warnings.Add($"Element {i} has an empty asset path.");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (config.matchMode == PoolMatchMode.Prefix && config.preloadOnInitialize)
|
||
|
|
{
|
||
|
|
warnings.Add($"Element {i} uses Prefix matching and preloadOnInitialize. Prefix rules cannot infer a concrete asset to prewarm.");
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int j = i + 1; j < configs.Count; j++)
|
||
|
|
{
|
||
|
|
PoolConfig other = configs[j];
|
||
|
|
if (other == null)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool duplicate =
|
||
|
|
string.Equals(config.group, other.group, System.StringComparison.Ordinal) &&
|
||
|
|
config.matchMode == other.matchMode &&
|
||
|
|
string.Equals(config.assetPath, other.assetPath, System.StringComparison.Ordinal);
|
||
|
|
|
||
|
|
if (duplicate)
|
||
|
|
{
|
||
|
|
warnings.Add($"Duplicate rule detected between elements {i} and {j}: {config.group}:{config.assetPath}.");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return warnings;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|