[unity] Fixed exception after changing animation name with existing custom mix duration, closes #1874. Displaying animation/bone/etc name in red in Inspector fields when it no longer exists at the skeleton data.

This commit is contained in:
Harald Csaszar 2022-04-27 20:47:24 +02:00
parent a23217c8f7
commit f04a7b38ca
4 changed files with 79 additions and 5 deletions

View File

@ -80,6 +80,7 @@
* Added another fadeout example component named `SkeletonRenderTextureFadeout` which takes over transparency fadeout when enabled. You can use this component as-is, attach it in disabled state and enable it to start a fadeout effect.
* Timeline clips now offer an additional `Alpha` parameter for setting a custom constant mix alpha value other than 1.0, just as `TrackEntry.Alpha`. Defaults to 1.0.
* `GetRemappedClone` copying from `Sprite` now provides additional `pmaCloneTextureFormat` and `pmaCloneMipmaps` parameters to explicitly specify the texture format of a newly created PMA texture.
* Spine property Inspector fields (`Animation Name`, `Bone Name`, `Slot` and similar) now display the name in red when the respective animation/bone/etc no longer exists at the skeleton data. This may be helpful when such items have been renamed or deleted.
* **Breaking changes**

View File

@ -455,7 +455,7 @@ namespace Spine.Unity.Editor {
}
if (cc.changed) {
targetSkeletonDataAsset.FillStateData();
targetSkeletonDataAsset.FillStateData(quiet: true);
EditorUtility.SetDirty(targetSkeletonDataAsset);
serializedObject.ApplyModifiedProperties();
}

View File

@ -61,11 +61,34 @@ namespace Spine.Unity.Editor {
return noneLabel;
}
static GUIStyle errorPopupStyle;
GUIStyle ErrorPopupStyle {
get {
if (errorPopupStyle == null) errorPopupStyle = new GUIStyle(EditorStyles.popup);
errorPopupStyle.normal.textColor = Color.red;
errorPopupStyle.hover.textColor = Color.red;
errorPopupStyle.focused.textColor = Color.red;
errorPopupStyle.active.textColor = Color.red;
return errorPopupStyle;
}
}
protected T TargetAttribute { get { return (T)attribute; } }
protected SerializedProperty SerializedProperty { get; private set; }
protected abstract Texture2D Icon { get; }
protected bool IsValueValid (SerializedProperty property) {
if (skeletonDataAsset != null) {
SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true);
if (skeletonData != null && !string.IsNullOrEmpty(property.stringValue))
return IsValueValid(skeletonData, property);
}
return true;
}
protected virtual bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) { return true; }
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
SerializedProperty = property;
@ -123,8 +146,10 @@ namespace Spine.Unity.Editor {
position = EditorGUI.PrefixLabel(position, label);
Texture2D image = Icon;
GUIStyle usedStyle = IsValueValid(property) ? EditorStyles.popup : ErrorPopupStyle;
string propertyStringValue = (property.hasMultipleDifferentValues) ? SpineInspectorUtility.EmDash : property.stringValue;
if (GUI.Button(position, string.IsNullOrEmpty(propertyStringValue) ? NoneLabel(image) : SpineInspectorUtility.TempContent(propertyStringValue, image), EditorStyles.popup))
if (GUI.Button(position, string.IsNullOrEmpty(propertyStringValue) ? NoneLabel(image) :
SpineInspectorUtility.TempContent(propertyStringValue, image), usedStyle))
Selector(property);
}
@ -174,6 +199,10 @@ namespace Spine.Unity.Editor {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.slot; } }
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
return skeletonData.FindSlot(property.stringValue) != null;
}
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineSlot targetAttribute, SkeletonData data) {
if (TargetAttribute.includeNone)
menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property));
@ -223,6 +252,10 @@ namespace Spine.Unity.Editor {
internal override string NoneString { get { return TargetAttribute.defaultAsEmptyString ? DefaultSkinName : NoneStringConstant; } }
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
return skeletonData.FindSkin(property.stringValue) != null;
}
public static void GetSkinMenuItems (SkeletonData data, List<string> outputNames, List<GUIContent> outputMenuItems, bool includeNone = true) {
if (data == null) return;
if (outputNames == null) return;
@ -269,6 +302,10 @@ namespace Spine.Unity.Editor {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.animation; } }
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
return skeletonData.FindAnimation(property.stringValue) != null;
}
public static void GetAnimationMenuItems (SkeletonData data, List<string> outputNames, List<GUIContent> outputMenuItems, bool includeNone = true) {
if (data == null) return;
if (outputNames == null) return;
@ -311,6 +348,10 @@ namespace Spine.Unity.Editor {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.userEvent; } }
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
return skeletonData.FindEvent(property.stringValue) != null;
}
public static void GetEventMenuItems (SkeletonData data, List<string> eventNames, List<GUIContent> menuItems, bool includeNone = true) {
if (data == null) return;
@ -356,6 +397,10 @@ namespace Spine.Unity.Editor {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintIK; } }
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
return skeletonData.FindIkConstraint(property.stringValue) != null;
}
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineIkConstraint targetAttribute, SkeletonData data) {
var constraints = skeletonDataAsset.GetSkeletonData(false).IkConstraints;
@ -376,6 +421,10 @@ namespace Spine.Unity.Editor {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintTransform; } }
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
return skeletonData.FindTransformConstraint(property.stringValue) != null;
}
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineTransformConstraint targetAttribute, SkeletonData data) {
var constraints = skeletonDataAsset.GetSkeletonData(false).TransformConstraints;
@ -395,6 +444,10 @@ namespace Spine.Unity.Editor {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintPath; } }
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
return skeletonData.FindPathConstraint(property.stringValue) != null;
}
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpinePathConstraint targetAttribute, SkeletonData data) {
var constraints = skeletonDataAsset.GetSkeletonData(false).PathConstraints;
@ -516,6 +569,10 @@ namespace Spine.Unity.Editor {
protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.bone; } }
protected override bool IsValueValid (SkeletonData skeletonData, SerializedProperty property) {
return skeletonData.FindBone(property.stringValue) != null;
}
protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineBone targetAttribute, SkeletonData data) {
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
menu.AddSeparator("");

View File

@ -217,14 +217,30 @@ namespace Spine.Unity {
FillStateData();
}
public void FillStateData () {
public void FillStateData (bool quiet = false) {
if (stateData != null) {
stateData.DefaultMix = defaultMix;
for (int i = 0, n = fromAnimation.Length; i < n; i++) {
if (fromAnimation[i].Length == 0 || toAnimation[i].Length == 0)
string fromAnimationName = fromAnimation[i];
string toAnimationName = toAnimation[i];
if (fromAnimationName.Length == 0 || toAnimationName.Length == 0)
continue;
stateData.SetMix(fromAnimation[i], toAnimation[i], duration[i]);
#if UNITY_EDITOR
if (skeletonData.FindAnimation(fromAnimationName) == null) {
if (!quiet) Debug.LogError(
string.Format("Custom Mix Durations: Animation '{0}' not found, was it renamed?",
fromAnimationName), this);
continue;
}
if (skeletonData.FindAnimation(toAnimationName) == null) {
if (!quiet) Debug.LogError(
string.Format("Custom Mix Durations: Animation '{0}' not found, was it renamed?",
toAnimationName), this);
continue;
}
#endif
stateData.SetMix(fromAnimationName, toAnimationName, duration[i]);
}
}
}