Эх сурвалжийг харах

[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.

Harald Csaszar 3 жил өмнө
parent
commit
f04a7b38ca

+ 1 - 0
CHANGELOG.md

@@ -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**
 

+ 1 - 1
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Asset Types/SkeletonDataAssetInspector.cs

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

+ 58 - 1
spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAttributeDrawers.cs

@@ -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("");

+ 19 - 3
spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SkeletonDataAsset.cs

@@ -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]);
 				}
 			}
 		}