Files
MinFt/Client/Assets/Editor/CampTool/PlayableDirectorBindingValidator.cs
Liubing\LB 3d8d4d18f3 first commit
先修复一下,错误的场景

删除不必要的钓场资产

修复into场景

update:更新meta文件,修复报错

update:修复资源

修复第一章节建造

修复建造第三章

update:删除多余内容

update:更新README.md

update:还原图标

update:更新README

update:更新配置
2026-04-28 02:17:22 +08:00

184 lines
6.3 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEditor;
using UnityEngine;
using UnityEngine.Playables;
/// <summary>
/// 自动检测并清理 PlayableDirector 中 missing 的 Binding 引用。
/// 不使用 [CustomEditor],不影响原生 Inspector 显示。
/// 触发时机:选中带有 PlayableDirector 的物体时自动检测清理。
/// 手动触发PlayableDirector 组件右上角菜单 → "检查并清理 Missing Binding 引用"。
/// </summary>
[InitializeOnLoad]
public class PlayableDirectorBindingValidator
{
static PlayableDirectorBindingValidator()
{
Selection.selectionChanged += OnSelectionChanged;
}
[MenuItem("CONTEXT/PlayableDirector/检查并清理 Missing Binding 引用")]
private static void ContextMenuClean(MenuCommand command)
{
var director = command.context as PlayableDirector;
if (director == null) return;
int cleaned = CleanMissingBindings(director);
if (cleaned > 0)
{
Debug.Log($"[PlayableDirector Cleaner] {director.gameObject.name}: 清理了 {cleaned} 个 missing 引用");
ActiveEditorTracker.sharedTracker.ForceRebuild();
}
else
{
Debug.Log($"[PlayableDirector Cleaner] {director.gameObject.name}: 未发现 missing 引用,一切正常 ✓");
}
}
private static void OnSelectionChanged()
{
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
if (Selection.activeGameObject == null) return;
var directors = Selection.activeGameObject.GetComponents<PlayableDirector>();
if (directors == null || directors.Length == 0) return;
// 先快速扫描是否有需要清理的,没有则跳过
bool hasMissing = false;
foreach (var director in directors)
{
if (director == null) continue;
if (HasMissingBindings(director))
{
hasMissing = true;
break;
}
}
if (!hasMissing) return;
// 有 missing 引用时,延迟到下一帧清理,然后强制 Inspector 重建
EditorApplication.delayCall += () =>
{
bool anyCleaned = false;
foreach (var director in directors)
{
if (director == null) continue;
int cleaned = CleanMissingBindings(director);
if (cleaned > 0)
{
anyCleaned = true;
Debug.Log($"[PlayableDirector Cleaner] 自动清理 <b>{director.gameObject.name}</b>: {cleaned} 个 missing 引用");
}
}
if (anyCleaned)
{
// 强制 Inspector 重建,让原生 DirectorEditor 重新读取已修改的序列化数据
ActiveEditorTracker.sharedTracker.ForceRebuild();
}
};
}
private static bool HasMissingBindings(PlayableDirector director)
{
var so = new SerializedObject(director);
var sceneBindings = so.FindProperty("m_SceneBindings");
if (sceneBindings != null)
{
for (int i = 0; i < sceneBindings.arraySize; i++)
{
var element = sceneBindings.GetArrayElementAtIndex(i);
if (IsMissingReference(element.FindPropertyRelative("key"))
|| IsMissingReference(element.FindPropertyRelative("value")))
{
so.Dispose();
return true;
}
}
}
var exposedRefs = so.FindProperty("m_ExposedReferences.m_References");
if (exposedRefs != null)
{
for (int i = 0; i < exposedRefs.arraySize; i++)
{
if (IsMissingReference(exposedRefs.GetArrayElementAtIndex(i).FindPropertyRelative("second")))
{
so.Dispose();
return true;
}
}
}
so.Dispose();
return false;
}
private static int CleanMissingBindings(PlayableDirector director)
{
int cleaned = 0;
var so = new SerializedObject(director);
// 清理 m_SceneBindings 中 missing 的条目
var sceneBindings = so.FindProperty("m_SceneBindings");
if (sceneBindings != null)
{
for (int i = sceneBindings.arraySize - 1; i >= 0; i--)
{
var element = sceneBindings.GetArrayElementAtIndex(i);
var key = element.FindPropertyRelative("key");
if (IsMissingReference(key))
{
sceneBindings.DeleteArrayElementAtIndex(i);
cleaned++;
continue;
}
// key 有效但 value 是 missing 引用时,清空 value只解绑不删除整条记录
var value = element.FindPropertyRelative("value");
if (IsMissingReference(value))
{
value.objectReferenceValue = null;
cleaned++;
}
}
}
// 清理 m_ExposedReferences 中 missing 的条目
var exposedRefs = so.FindProperty("m_ExposedReferences.m_References");
if (exposedRefs != null)
{
for (int i = exposedRefs.arraySize - 1; i >= 0; i--)
{
var second = exposedRefs.GetArrayElementAtIndex(i).FindPropertyRelative("second");
if (IsMissingReference(second))
{
exposedRefs.DeleteArrayElementAtIndex(i);
cleaned++;
}
}
}
if (cleaned > 0)
{
so.ApplyModifiedProperties();
EditorUtility.SetDirty(director);
}
so.Dispose();
return cleaned;
}
/// <summary>
/// 判断一个 ObjectReference 属性是否为 missing 引用:
/// 对象已被删除(无法解析),但序列化数据中仍残留非零的 instanceID。
/// </summary>
private static bool IsMissingReference(SerializedProperty prop)
{
if (prop == null) return false;
if (prop.propertyType != SerializedPropertyType.ObjectReference) return false;
return prop.objectReferenceValue == null
&& prop.objectReferenceInstanceIDValue != 0;
}
}