using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using BF; using UnityEngine.Playables; namespace BFEditor { [CustomEditor(typeof(TimelineHelper))] public class TimelineHelperInspector : Editor { private const uint HASH_SEED = 31; TimelineHelper helper; private ISet gameobjectSet = new HashSet(); private ISet hashNameSet = new HashSet(); private ISet nameSet = new HashSet(); private ISet tlHashNameSet = new HashSet(); private ISet tlNameSet = new HashSet(); void OnEnable() { helper = target as TimelineHelper; } public override void OnInspectorGUI() { gameobjectSet.Clear(); hashNameSet.Clear(); nameSet.Clear(); tlHashNameSet.Clear(); tlNameSet.Clear(); GUILayout.Space(10); for (int i = 0; i < helper.prefabList.Count; ++i) { DrawPrefab(i); HashName(i); CheckPrefabList(i); } DrawAddBtn(); DrawClipBoardBtn(); GUILayout.Space(10); DrawTimelineEvent(); for (int i = 0; i < helper.timelineEventList.Count; ++i) { DrawTimelineEventItem(i); HashTimelineEventName(i); // CheckTimelineEventList(i); } DrawTimelineBtns(); } void DrawPrefab(int index) { if (index < 0 || index >= helper.prefabList.Count) return; GUILayout.BeginHorizontal(); { EditorGUI.BeginChangeCheck(); GameObject go = (GameObject)EditorGUILayout.ObjectField("", helper.prefabList[index].gameObject, typeof(GameObject), true, GUILayout.Width(140)); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(helper, helper.name + "Change GameObject Info GameObject"); GameObjectInfo info = new GameObjectInfo(); string path = ""; if (go == null) { info.gameObject = go; } else { Utils.GetTransformPath(go.transform, helper.transform, ref path); path = path.Replace("/", "."); info.gameObject = go; info.name = path; info.hashName = BKDRHash(path); info.objectType = GetGameObjectType(go); } helper.prefabList[index] = info; EditorUtility.SetDirty(helper); } if (GUILayout.Button("Copy", GUILayout.Width(55))) { Undo.RecordObject(helper, helper.name + "Copy Name"); EditorApplication.Beep(); TextEditor te = new TextEditor(); var goInfo = helper.prefabList[index]; te.text = goInfo.name; te.SelectAll(); te.Copy(); } if (GUILayout.Button("Remove", GUILayout.Width(55))) { Undo.RecordObject(helper, helper.name + "Remove GameObject Info"); EditorApplication.Beep(); helper.prefabList.RemoveAt(index); EditorUtility.SetDirty(helper); } if (GUILayout.Button("Update", GUILayout.Width(55))) { Undo.RecordObject(helper, helper.name + "Update GameObject Info"); EditorApplication.Beep(); var goInfo = helper.prefabList[index]; var newPath = string.Empty; Utils.GetTransformPath(go.transform, helper.transform, ref newPath); newPath = newPath.Replace("/", "."); goInfo.name = newPath; goInfo.hashName = BKDRHash(newPath); helper.prefabList[index] = goInfo; EditorUtility.SetDirty(helper); } GUILayout.Label("Name", EditorStyles.label, GUILayout.Width(35)); EditorGUI.BeginChangeCheck(); string newName = GUILayout.TextField(helper.prefabList[index].name); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(helper, helper.name + "Change GameObject Info name"); GameObjectInfo info = new GameObjectInfo(); info.gameObject = helper.prefabList[index].gameObject; info.name = newName; info.hashName = BKDRHash(newName); info.objectType = GetGameObjectType(info.gameObject); helper.prefabList[index] = info; EditorUtility.SetDirty(helper); } } GUILayout.EndHorizontal(); } void HashName(int index) { if (index < 0 || index >= helper.prefabList.Count) return; if (!string.IsNullOrEmpty(helper.prefabList[index].name)) { uint hashName = BKDRHash(helper.prefabList[index].name); if (hashName != helper.prefabList[index].hashName) { Undo.RecordObject(helper, helper.name + "add hash name"); GameObjectInfo info = new GameObjectInfo(); info.gameObject = helper.prefabList[index].gameObject; info.name = helper.prefabList[index].name; info.hashName = hashName; info.objectType = GetGameObjectType(info.gameObject); helper.prefabList[index] = info; EditorUtility.SetDirty(helper); } } } void CheckPrefabList(int index) { if (index < 0 || index >= helper.prefabList.Count) return; GameObjectInfo info = helper.prefabList[index]; if (info.gameObject == null) { return; } if (!gameobjectSet.Add(info.gameObject)) { Debug.LogError("prefab list have the same GameObject"); } if (!hashNameSet.Add(info.hashName)) { Debug.LogError("prefab list have the same hashName"); } if (!nameSet.Add(info.name)) { Debug.LogError("prefab list have the same name"); } } void DrawAddBtn() { if (GUILayout.Button("Add")) { Undo.RecordObject(helper, helper.name + "Add GameObject Info"); EditorApplication.Beep(); helper.prefabList.Add(new GameObjectInfo()); EditorUtility.SetDirty(helper); } } void DrawClipBoardBtn() { if (GUILayout.Button("ClipBoardMap")) { string content = string.Empty; var list = helper.prefabList; for (int i = 0; i < list.Count; i++) { var info = list[i]; var itemDesc = string.Format("local {0} = uiMap['{1}']\n", info.gameObject.name, info.name); content += itemDesc; } GUIUtility.systemCopyBuffer = content; } } void DrawTimelineEvent() { var playableDir = helper.transform.GetComponent(); if (playableDir) { helper.duration = playableDir.duration; EditorGUI.BeginDisabledGroup(true); EditorGUILayout.LabelField("timeline总时长:", helper.duration.ToString()); EditorGUI.EndDisabledGroup(); } } void DrawTimelineBtns() { if (GUILayout.Button("Add TimeLine Event")) { Undo.RecordObject(helper, helper.name + "Add TimeLine Event"); EditorApplication.Beep(); helper.timelineEventList.TryAdd(new TimelineEventItem()); EditorUtility.SetDirty(helper); } if (GUILayout.Button("TimeLine Sort")) { SortTimelineEvent(); } } void DrawTimelineEventItem(int index) { if (index < 0 || index >= helper.timelineEventList.Count) return; GUILayout.BeginHorizontal(); { EditorGUI.BeginChangeCheck(); GUILayout.Label("事件名称:", EditorStyles.label, GUILayout.Width(50)); var eventName = helper.timelineEventList[index].eventName; eventName = EditorGUILayout.TextField(eventName, GUILayout.Width(140)); GUILayout.Label("触发时间:", EditorStyles.label, GUILayout.Width(50)); var eventTime = helper.timelineEventList[index].eventTime; eventTime = Mathf.Clamp((float)EditorGUILayout.DoubleField(eventTime, GUILayout.Width(140)), 0, (float)helper.duration); GUILayout.Label("回调名:", EditorStyles.label, GUILayout.Width(50)); EditorGUILayout.LabelField(helper.timelineEventList[index].eventHash.ToString(), GUILayout.Width(100)); if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(helper, helper.name + "Change TimelineEventItem"); TimelineEventItem info = new TimelineEventItem(); if (!string.IsNullOrEmpty(eventName)) { info.eventName = eventName; info.eventHash = GetTimelineEventHash(eventName); info.eventTime = eventTime; } helper.timelineEventList[index] = info; EditorUtility.SetDirty(helper); } if (GUILayout.Button("Remove", GUILayout.Width(55))) { Undo.RecordObject(helper, helper.name + "Remove TimelineEventItem"); EditorApplication.Beep(); helper.timelineEventList.RemoveAt(index); EditorUtility.SetDirty(helper); } } GUILayout.EndHorizontal(); } void HashTimelineEventName(int index) { if (index < 0 || index >= helper.timelineEventList.Count) return; if (!string.IsNullOrEmpty(helper.timelineEventList[index].eventName)) { uint hashName = BKDRHash(helper.timelineEventList[index].eventName); if (hashName != helper.timelineEventList[index].eventHash) { Undo.RecordObject(helper, helper.name + "add hash name"); TimelineEventItem info = new TimelineEventItem(); info.eventName = helper.timelineEventList[index].eventName; info.eventHash = hashName; helper.timelineEventList[index] = info; EditorUtility.SetDirty(helper); } } } void CheckTimelineEventList(int index) { if (index < 0 || index >= helper.timelineEventList.Count) return; TimelineEventItem info = helper.timelineEventList[index]; if(string.IsNullOrEmpty(info.eventName)) return; if (!tlHashNameSet.Add(info.eventHash)) { Debug.LogError("timeline event list have the same hashName"); } if (!tlNameSet.Add(info.eventName)) { Debug.LogError("timeline event list have the same name"); } } uint GetTimelineEventHash(string eventName) { var count = helper.timelineEventList.Count; for (int i = 0; i < count; i++) { var item = helper.timelineEventList[i]; if (!string.IsNullOrEmpty(eventName) && item.eventName == eventName) return item.eventHash; } return BKDRHash(eventName); } void SortTimelineEvent() { helper.timelineEventList.Sort((x, y) => { return x.eventTime <= y.eventTime ? -1 : 1; }); } private static uint BKDRHash(string name) { uint h = 0; var chars = name.ToCharArray(); for (int i = 0; i < chars.Length; ++i) { h = h * HASH_SEED + (byte)chars[i]; } return h; } private static string GetGameObjectTypeName(int gameObjectType) { switch (gameObjectType){ case (int)GameObjectType.Default: return "UI"; case (int)GameObjectType.UIObject: return "UI预制件"; case (int)GameObjectType.EffectObject: return "特效"; case (int)GameObjectType.CharacterObject: return "角色"; case (int)GameObjectType.SpineMeshObject: return "MeshSpine"; case (int)GameObjectType.SpineUIObject: return "UISpine"; case (int)GameObjectType.TimelineObject: return "TimeLine"; default: return "UI"; } } private static int GetGameObjectType(GameObject go) { if (go == null) { return (int)GameObjectType.Default; } if (go.GetComponent() != null) { return (int)GameObjectType.UIObject; } else if(go.GetComponent() != null) { return (int)GameObjectType.EffectObject; } else if(go.GetComponent() != null) { return (int)GameObjectType.CharacterObject; } else if(go.GetComponent() != null) { return (int)GameObjectType.TimelineObject; } else if(go.GetComponent() != null) { return (int)GameObjectType.SpineUIObject; } else if(go.GetComponent() != null) { return (int)GameObjectType.SpineMeshObject; } return (int)GameObjectType.Default; } } }