c1_unity/Assets/Editor/InspectorTools/CharacterHelperInspector.cs
2023-04-18 16:04:58 +08:00

297 lines
12 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Experimental.SceneManagement;
using BF;
using UnityEditor.SceneManagement;
namespace BFEditor
{
[InitializeOnLoad]
[CustomEditor(typeof(CharacterSpineHelper))]
public class CharacterSpineHelperInspector : Editor
{
private const uint HASH_SEED = 31;
private string m_CurAnimationName;
CharacterSpineHelper helper;
static CharacterSpineHelperInspector()
{
PrefabStage.prefabSaving += OnPrefabSaved;
PrefabStage.prefabStageOpened += OnPrefabStageOpened;
}
void OnEnable()
{
helper = target as CharacterSpineHelper;
}
void OnDisable()
{
}
private static void OnPrefabSaved(GameObject go)
{
var characterSpineHelper = go.GetComponent<CharacterSpineHelper>();
if (characterSpineHelper != null)
{
UpdateCharacterSpineHelper(go, characterSpineHelper);
}
}
private static void OnPrefabStageOpened(PrefabStage go)
{
var characterSpineHelper = go.prefabContentsRoot.GetComponent<CharacterSpineHelper>();
if (characterSpineHelper != null)
{
UpdateCharacterSpineHelper(go.prefabContentsRoot, characterSpineHelper);
}
}
private static void UpdateCharacterSpineHelper(GameObject go, CharacterSpineHelper characterSpineHelper)
{
if(Application.isPlaying) return;
UpdateCharacterInfo(go, characterSpineHelper);
}
private static void UpdateCharacterInfo(GameObject go, CharacterSpineHelper characterSpineHelper)
{
bool dirty = false;
Spine.Unity.SkeletonGraphic rootAni = go.transform.GetComponentInChildren<Spine.Unity.SkeletonGraphic>(true);
//主spine
if (rootAni != null && characterSpineHelper.SpineObject != rootAni.gameObject)
{
characterSpineHelper.SpineObject = rootAni.gameObject;
EditorUtility.SetDirty(characterSpineHelper);
dirty = true;
}
//缓存挂点列表
ISet<GameObject> gameObjectSet = new HashSet<GameObject>(); //用于记录缓存数据
ISet<uint> hashNameSet = new HashSet<uint>(); //用于记录缓存数据
var list = characterSpineHelper.ObjectList;
int len = list.Count;
//遍历缓存数据
for (int i = 0; i < len; i++)
{
CharacterSpineObjectInfo info = list[i];
if (info.gameObject == null)
{
list.RemoveAt(i);
i--;
len--;
dirty = true;
EditorUtility.SetDirty(characterSpineHelper);
continue;
}
else if (!gameObjectSet.Add(info.gameObject))
{
list.RemoveAt(i);
i--;
len--;
dirty = true;
EditorUtility.SetDirty(characterSpineHelper);
Debug.LogError("character list have the same object");
continue;
}
else if (!hashNameSet.Add(info.hashName))
{
gameObjectSet.Remove(info.gameObject);
list.RemoveAt(i);
i--;
len--;
dirty = true;
EditorUtility.SetDirty(characterSpineHelper);
Debug.LogError("character list have the same hash name");
}
}
// 获取当前prefab数据,与缓存数据对比并更新
ISet<GameObject> prefabGameObjectSet = new HashSet<GameObject>();//用于记录prefab数据
ISet<uint> prefabHashNameSet = new HashSet<uint>();//用于记录prefab数据
Transform[] children = go.GetComponentsInChildren<Transform>(true);
int realChildNum = children.Length - 1; // 真实prefab数量 需要和缓存数据对比
foreach (Transform child in children)
{
//非主模型节点
if (child.name.CompareTo(go.name) != 0)
{
//记录prefab 用于对比判断
prefabGameObjectSet.Add(child.gameObject);
if (!prefabHashNameSet.Add(BKDRHash(child.name)))
{
Debug.LogError("character list have the same hash name :" + child.name);
}
//有新增节点
if (!gameObjectSet.Contains(child.gameObject))
{
CharacterSpineObjectInfo info;
info.gameObject = child.gameObject;
info.hashName = BKDRHash(child.name);
gameObjectSet.Add(info.gameObject);
if (hashNameSet.Add(info.hashName))
{
characterSpineHelper.ObjectList.Add(info);
dirty = true;
EditorUtility.SetDirty(characterSpineHelper);
}
else
{
Debug.LogError("character list have the same hash name :" + child.name);
}
}
//已有节点
else
{
//变更了名字
if (!hashNameSet.Contains(BKDRHash(child.name)))
{
var objList = characterSpineHelper.ObjectList;
int listLen = objList.Count;
for (int i = 0; i < listLen; i++)
{
if (objList[i].gameObject == child.gameObject)
{
CharacterSpineObjectInfo info;
info.gameObject = child.gameObject;
info.hashName = BKDRHash(child.name);
objList[i] = info;
dirty = true;
EditorUtility.SetDirty(characterSpineHelper);
break;
}
}
}
}
}
}
//遍历缓存数据 删除不存在的节点
for (int i = 0; i < len; i++)
{
CharacterSpineObjectInfo info = list[i];
if (!prefabGameObjectSet.Contains(info.gameObject) || !hashNameSet.Contains(info.hashName))
{
list.RemoveAt(i);
i--;
len--;
dirty = true;
EditorUtility.SetDirty(characterSpineHelper);
Debug.Log("remove not exist info");
}
}
//check dirty
if (dirty)
{
var prefabStage = PrefabStageUtility.GetPrefabStage(go);
if (prefabStage != null)
{
EditorSceneManager.MarkSceneDirty(prefabStage.scene);
}
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
private void DrawNodeList()
{
for (int i = 0; i < helper.ObjectList.Count; ++i)
{
CharacterSpineObjectInfo info = helper.ObjectList[i];
if (info.gameObject == null)
{
helper.ObjectList.RemoveAt(i);
i--;
SetHelperDirty();
continue;
}
GUILayout.BeginHorizontal();
GUILayout.Label(info.gameObject.name, EditorStyles.label);
EditorGUI.BeginDisabledGroup(true);
GameObject go = (GameObject)EditorGUILayout.ObjectField("", info.gameObject, typeof(GameObject), true, GUILayout.Width(140));
EditorGUI.EndDisabledGroup();
GUILayout.EndHorizontal();
}
}
private void SetHelperDirty()
{
var prefabStage = PrefabStageUtility.GetPrefabStage(helper.gameObject);
if (prefabStage != null)
{
EditorSceneManager.MarkSceneDirty(prefabStage.scene);
}
EditorUtility.SetDirty(helper);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
public override void OnInspectorGUI()
{
UpdateCharacterSpineHelper(helper.gameObject, helper);
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Label("主Spine:", EditorStyles.label);
EditorGUI.BeginDisabledGroup(true);
GameObject go = (GameObject)EditorGUILayout.ObjectField("", helper.SpineObject, typeof(GameObject), true, GUILayout.Width(140));
EditorGUI.EndDisabledGroup();
GUILayout.EndHorizontal();
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
GUILayout.Label("挂点列表:", EditorStyles.label);
DrawNodeList();
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
GUILayout.Label("动作列表:", EditorStyles.label);
DrawAnimationList();
}
private void DrawAnimationList()
{
GUIStyle normalStyle = new GUIStyle(GUI.skin.button);//普通style
normalStyle.alignment = TextAnchor.MiddleLeft;
GUIStyle highlightStyle = new GUIStyle(GUI.skin.button);//高亮style
highlightStyle.alignment = TextAnchor.MiddleLeft;
highlightStyle.normal.textColor = Color.blue;
Spine.Unity.SkeletonGraphic skeletonGraphic = helper.transform.GetComponentInChildren<Spine.Unity.SkeletonGraphic>(true);
var list = skeletonGraphic.skeletonDataAsset.GetAnimationStateData().SkeletonData.Animations;
for (int i = 0; i < list.Count; i ++)
{
bool isPlay = list.Items[i].Name == m_CurAnimationName;
GUILayout.BeginHorizontal();
float keyFrame = 0.0f;
foreach(var t in list.Items[i].Timelines) {
var et = t as Spine.EventTimeline;
if(et != null) {
foreach (var spineEvent in et.Events) {
keyFrame = spineEvent.Time;
break;
}
}
}
if (GUILayout.Button(string.Format("动作:{0}============时长:{1}s============关键帧:{2}s", list.Items[i].Name, list.Items[i].Duration, keyFrame), isPlay ? highlightStyle : normalStyle))
{
}
GUILayout.EndHorizontal();
}
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
}
private static uint BKDRHash(string name)
{
uint h = 0;
for (int i = 0; i < name.Length; ++i)
{
h = h * HASH_SEED + (byte)name[i];
}
return h;
}
}
}