297 lines
12 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|