Browse Source

Merge branch 'master' into 3.6-beta

badlogic 8 years ago
parent
commit
a04c0088cb

+ 1 - 0
spine-c/spine-c/include/spine/AnimationState.h

@@ -64,6 +64,7 @@ struct spTrackEntry {
 	float* timelinesRotation;
 	float* timelinesRotation;
 	int timelinesRotationCount;
 	int timelinesRotationCount;
 	void* rendererObject;
 	void* rendererObject;
+	void* userData;
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 	spTrackEntry() :
 	spTrackEntry() :

+ 15 - 6
spine-csharp/src/Skin.cs

@@ -32,38 +32,47 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
 namespace Spine {
 namespace Spine {
-	/// <summary>Stores attachments by slot index and attachment name.</summary>
+	/// <summary>Stores attachments by slot index and attachment name.
+	/// <para>See SkeletonData <see cref="Spine.SkeletonData.DefaultSkin"/>, Skeleton <see cref="Spine.Skeleton.Skin"/>, and 
+	/// <a href="http://esotericsoftware.com/spine-runtime-skins">Runtime skins</a> in the Spine Runtimes Guide.</para>
+	/// </summary>
 	public class Skin {
 	public class Skin {
 		internal String name;
 		internal String name;
 		private Dictionary<AttachmentKeyTuple, Attachment> attachments =
 		private Dictionary<AttachmentKeyTuple, Attachment> attachments =
 			new Dictionary<AttachmentKeyTuple, Attachment>(AttachmentKeyTupleComparer.Instance);
 			new Dictionary<AttachmentKeyTuple, Attachment>(AttachmentKeyTupleComparer.Instance);
 
 
-		public String Name { get { return name; } }
+		public string Name { get { return name; } }
 		public Dictionary<AttachmentKeyTuple, Attachment> Attachments { get { return attachments; } }
 		public Dictionary<AttachmentKeyTuple, Attachment> Attachments { get { return attachments; } }
 
 
-		public Skin (String name) {
+		public Skin (string name) {
 			if (name == null) throw new ArgumentNullException("name", "name cannot be null.");
 			if (name == null) throw new ArgumentNullException("name", "name cannot be null.");
 			this.name = name;
 			this.name = name;
 		}
 		}
 
 
-		public void AddAttachment (int slotIndex, String name, Attachment attachment) {
+		public void AddAttachment (int slotIndex, string name, Attachment attachment) {
 			if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null.");
 			if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null.");
 			attachments[new AttachmentKeyTuple(slotIndex, name)] = attachment;
 			attachments[new AttachmentKeyTuple(slotIndex, name)] = attachment;
 		}
 		}
 
 
 		/// <returns>May be null.</returns>
 		/// <returns>May be null.</returns>
-		public Attachment GetAttachment (int slotIndex, String name) {
+		public Attachment GetAttachment (int slotIndex, string name) {
 			Attachment attachment;
 			Attachment attachment;
 			attachments.TryGetValue(new AttachmentKeyTuple(slotIndex, name), out attachment);
 			attachments.TryGetValue(new AttachmentKeyTuple(slotIndex, name), out attachment);
 			return attachment;
 			return attachment;
 		}
 		}
 
 
-		public void FindNamesForSlot (int slotIndex, List<String> names) {
+		/// <summary>Finds the skin keys for a given slot. The results are added to the passed List(names).</summary>
+		/// <param name="slotIndex">The target slotIndex. To find the slot index, use <see cref="Spine.Skeleton.FindSlotIndex"/> or <see cref="Spine.SkeletonData.FindSlotIndex"/>
+		/// <param name="names">Found skin key names will be added to this list.</param>
+		public void FindNamesForSlot (int slotIndex, List<string> names) {
 			if (names == null) throw new ArgumentNullException("names", "names cannot be null.");
 			if (names == null) throw new ArgumentNullException("names", "names cannot be null.");
 			foreach (AttachmentKeyTuple key in attachments.Keys)
 			foreach (AttachmentKeyTuple key in attachments.Keys)
 				if (key.slotIndex == slotIndex) names.Add(key.name);
 				if (key.slotIndex == slotIndex) names.Add(key.name);
 		}
 		}
 
 
+		/// <summary>Finds the attachments for a given slot. The results are added to the passed List(Attachment).</summary>
+		/// <param name="slotIndex">The target slotIndex. To find the slot index, use <see cref="Spine.Skeleton.FindSlotIndex"/> or <see cref="Spine.SkeletonData.FindSlotIndex"/>
+		/// <param name="attachments">Found Attachments will be added to this list.</param>
 		public void FindAttachmentsForSlot (int slotIndex, List<Attachment> attachments) {
 		public void FindAttachmentsForSlot (int slotIndex, List<Attachment> attachments) {
 			if (attachments == null) throw new ArgumentNullException("attachments", "attachments cannot be null.");
 			if (attachments == null) throw new ArgumentNullException("attachments", "attachments cannot be null.");
 			foreach (KeyValuePair<AttachmentKeyTuple, Attachment> entry in this.attachments)
 			foreach (KeyValuePair<AttachmentKeyTuple, Attachment> entry in this.attachments)

+ 13 - 3
spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java

@@ -664,14 +664,24 @@ public class SkeletonViewer extends ApplicationAdapter {
 				button.addListener(trackButtonListener);
 				button.addListener(trackButtonListener);
 
 
 			Gdx.input.setInputProcessor(new InputMultiplexer(stage, new InputAdapter() {
 			Gdx.input.setInputProcessor(new InputMultiplexer(stage, new InputAdapter() {
+				float offsetX;
+				float offsetY;
+				
 				public boolean touchDown (int screenX, int screenY, int pointer, int button) {
 				public boolean touchDown (int screenX, int screenY, int pointer, int button) {
-					touchDragged(screenX, screenY, pointer);
+					offsetX = screenX;
+					offsetY = Gdx.graphics.getHeight() - screenY;					
 					return false;
 					return false;
 				}
 				}
 
 
 				public boolean touchDragged (int screenX, int screenY, int pointer) {
 				public boolean touchDragged (int screenX, int screenY, int pointer) {
-					skeletonX = screenX;
-					skeletonY = Gdx.graphics.getHeight() - screenY;
+					float deltaX = screenX - offsetX;
+					float deltaY = Gdx.graphics.getHeight() - screenY - offsetY;
+					
+					skeletonX += deltaX;
+					skeletonY += deltaY;
+					
+					offsetX = screenX;
+					offsetY = Gdx.graphics.getHeight() - screenY;
 					return false;
 					return false;
 				}
 				}
 
 

+ 1 - 1
spine-ue4/README.md

@@ -1,7 +1,7 @@
 # spine-ue4
 # spine-ue4
 The spine-ue4 runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Unreal Engine 4.15+](https://www.unrealengine.com/). spine-ue4 is based on [spine-c](https://github.com/EsotericSoftware/spine-runtimes/tree/master/spine-c).
 The spine-ue4 runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Unreal Engine 4.15+](https://www.unrealengine.com/). spine-ue4 is based on [spine-c](https://github.com/EsotericSoftware/spine-runtimes/tree/master/spine-c).
 
 
-# WARNING This plugin will only work with Unreal Engine 4.15 and later versions as these include a [fix](https://github.com/EpicGames/UnrealEngine/pull/3015) for compiling plain `.c` files in Visual Studio.
+### WARNING This plugin will only work with Unreal Engine 4.15 and later when this [fix](https://github.com/EpicGames/UnrealEngine/pull/3185) for compiling plain `.c` files is applied.
 
 
 ## Licensing
 ## Licensing
 
 

+ 1 - 1
spine-unity/Assets/Examples/Getting Started/Scripts/BasicPlatformerController.cs

@@ -93,7 +93,7 @@ namespace Spine.Unity.Examples {
 
 
 		void Start () {
 		void Start () {
 			// Register a callback for Spine Events (in this case, Footstep)
 			// Register a callback for Spine Events (in this case, Footstep)
-			skeletonAnimation.state.Event += HandleEvent;
+			skeletonAnimation.AnimationState.Event += HandleEvent;
 		}
 		}
 
 
 		void HandleEvent (Spine.TrackEntry trackEntry, Spine.Event e) {
 		void HandleEvent (Spine.TrackEntry trackEntry, Spine.Event e) {

+ 2 - 2
spine-unity/Assets/Examples/Getting Started/Scripts/SpineBeginnerTwo.cs

@@ -59,8 +59,8 @@ namespace Spine.Unity.Examples {
 		void Start () {
 		void Start () {
 			// Make sure you get these AnimationState and Skeleton references in Start or Later. Getting and using them in Awake is not guaranteed by default execution order.
 			// Make sure you get these AnimationState and Skeleton references in Start or Later. Getting and using them in Awake is not guaranteed by default execution order.
 			skeletonAnimation = GetComponent<SkeletonAnimation>();
 			skeletonAnimation = GetComponent<SkeletonAnimation>();
-			spineAnimationState = skeletonAnimation.state;
-			skeleton = skeletonAnimation.skeleton;
+			spineAnimationState = skeletonAnimation.AnimationState;
+			skeleton = skeletonAnimation.Skeleton;
 
 
 			StartCoroutine(DoDemoRoutine());
 			StartCoroutine(DoDemoRoutine());
 		}
 		}

+ 1 - 1
spine-unity/Assets/Examples/Getting Started/Scripts/SpineBlinkPlayer.cs

@@ -44,7 +44,7 @@ namespace Spine.Unity.Examples {
 		IEnumerator Start () {
 		IEnumerator Start () {
 			var skeletonAnimation = GetComponent<SkeletonAnimation>(); if (skeletonAnimation == null) yield break;
 			var skeletonAnimation = GetComponent<SkeletonAnimation>(); if (skeletonAnimation == null) yield break;
 			while (true) {
 			while (true) {
-				skeletonAnimation.state.SetAnimation(SpineBlinkPlayer.BlinkTrack, blinkAnimation, false);
+				skeletonAnimation.AnimationState.SetAnimation(SpineBlinkPlayer.BlinkTrack, blinkAnimation, false);
 				yield return new WaitForSeconds(Random.Range(minimumDelay, maximumDelay));
 				yield return new WaitForSeconds(Random.Range(minimumDelay, maximumDelay));
 			}
 			}
 		}
 		}

+ 5 - 5
spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerView.cs

@@ -57,7 +57,7 @@ namespace Spine.Unity.Examples {
 		void Start () {
 		void Start () {
 			if (skeletonAnimation == null) return;
 			if (skeletonAnimation == null) return;
 			model.ShootEvent += PlayShoot;
 			model.ShootEvent += PlayShoot;
-			skeletonAnimation.state.Event += HandleEvent;
+			skeletonAnimation.AnimationState.Event += HandleEvent;
 		}
 		}
 
 
 		void HandleEvent (Spine.TrackEntry trackEntry, Spine.Event e) {
 		void HandleEvent (Spine.TrackEntry trackEntry, Spine.Event e) {
@@ -104,7 +104,7 @@ namespace Spine.Unity.Examples {
 				}
 				}
 			}
 			}
 
 
-			skeletonAnimation.state.SetAnimation(0, nextAnimation, true);
+			skeletonAnimation.AnimationState.SetAnimation(0, nextAnimation, true);
 		}
 		}
 
 
 		void PlayFootstepSound () {
 		void PlayFootstepSound () {
@@ -114,7 +114,7 @@ namespace Spine.Unity.Examples {
 
 
 		[ContextMenu("Check Tracks")]
 		[ContextMenu("Check Tracks")]
 		void CheckTracks () {
 		void CheckTracks () {
-			var state = skeletonAnimation.state;
+			var state = skeletonAnimation.AnimationState;
 			Debug.Log(state.GetCurrent(0));
 			Debug.Log(state.GetCurrent(0));
 			Debug.Log(state.GetCurrent(1));
 			Debug.Log(state.GetCurrent(1));
 		}
 		}
@@ -122,7 +122,7 @@ namespace Spine.Unity.Examples {
 		#region Transient Actions
 		#region Transient Actions
 		public void PlayShoot () {
 		public void PlayShoot () {
 			// Play the shoot animation on track 1.
 			// Play the shoot animation on track 1.
-			skeletonAnimation.state.SetAnimation(1, shoot, false);
+			skeletonAnimation.AnimationState.SetAnimation(1, shoot, false);
 			//skeletonAnimation.state.AddEmptyAnimation(1, 0.1f, 0f);
 			//skeletonAnimation.state.AddEmptyAnimation(1, 0.1f, 0f);
 			gunSource.pitch = GetRandomPitch(gunsoundPitchOffset);
 			gunSource.pitch = GetRandomPitch(gunsoundPitchOffset);
 			gunSource.Play();
 			gunSource.Play();
@@ -131,7 +131,7 @@ namespace Spine.Unity.Examples {
 		}
 		}
 
 
 		public void Turn (bool facingLeft) {
 		public void Turn (bool facingLeft) {
-			skeletonAnimation.skeleton.FlipX = facingLeft;
+			skeletonAnimation.Skeleton.FlipX = facingLeft;
 			// Maybe play a transient turning animation too, then call ChangeStableAnimation.
 			// Maybe play a transient turning animation too, then call ChangeStableAnimation.
 		}
 		}
 		#endregion
 		#endregion

+ 3 - 3
spine-unity/Assets/Examples/Scripts/AttackSpineboy.cs

@@ -47,13 +47,13 @@ namespace Spine.Unity.Examples {
 				healthText.text = currentHealth + "/" + maxHealth;
 				healthText.text = currentHealth + "/" + maxHealth;
 
 
 				if (currentHealth > 0) {
 				if (currentHealth > 0) {
-					spineboy.state.SetAnimation(0, "hit", false);
-					spineboy.state.AddAnimation(0, "idle", true, 0);
+					spineboy.AnimationState.SetAnimation(0, "hit", false);
+					spineboy.AnimationState.AddAnimation(0, "idle", true, 0);
 					gauge.fillPercent = (float)currentHealth/(float)maxHealth;
 					gauge.fillPercent = (float)currentHealth/(float)maxHealth;
 				} else {
 				} else {
 					if (currentHealth >= 0) {
 					if (currentHealth >= 0) {
 						gauge.fillPercent = 0;
 						gauge.fillPercent = 0;
-						spineboy.state.SetAnimation(0, "death", false).TrackEnd = float.PositiveInfinity;
+						spineboy.AnimationState.SetAnimation(0, "death", false).TrackEnd = float.PositiveInfinity;
 					}
 					}
 				}
 				}
 			}
 			}

+ 4 - 4
spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs

@@ -80,11 +80,11 @@ namespace Spine.Unity.Examples {
 			} else {
 			} else {
 				if (Input.GetKey(rightKey)) {
 				if (Input.GetKey(rightKey)) {
 					skeletonAnimation.AnimationName = moveAnimation;
 					skeletonAnimation.AnimationName = moveAnimation;
-					skeletonAnimation.skeleton.FlipX = false;
+					skeletonAnimation.Skeleton.FlipX = false;
 					transform.Translate(moveSpeed * Time.deltaTime, 0, 0);
 					transform.Translate(moveSpeed * Time.deltaTime, 0, 0);
 				} else if(Input.GetKey(leftKey)) {
 				} else if(Input.GetKey(leftKey)) {
 					skeletonAnimation.AnimationName = moveAnimation;
 					skeletonAnimation.AnimationName = moveAnimation;
-					skeletonAnimation.skeleton.FlipX = true;
+					skeletonAnimation.Skeleton.FlipX = true;
 					transform.Translate(-moveSpeed * Time.deltaTime, 0, 0);
 					transform.Translate(-moveSpeed * Time.deltaTime, 0, 0);
 				} else {
 				} else {
 					skeletonAnimation.AnimationName = idleAnimation;
 					skeletonAnimation.AnimationName = idleAnimation;
@@ -95,9 +95,9 @@ namespace Spine.Unity.Examples {
 		IEnumerator Blink() {
 		IEnumerator Blink() {
 			while (true) {
 			while (true) {
 				yield return new WaitForSeconds(Random.Range(0.25f, 3f));
 				yield return new WaitForSeconds(Random.Range(0.25f, 3f));
-				skeletonAnimation.skeleton.SetAttachment(eyesSlot, blinkAttachment);
+				skeletonAnimation.Skeleton.SetAttachment(eyesSlot, blinkAttachment);
 				yield return new WaitForSeconds(blinkDuration);
 				yield return new WaitForSeconds(blinkDuration);
-				skeletonAnimation.skeleton.SetAttachment(eyesSlot, eyesOpenAttachment);
+				skeletonAnimation.Skeleton.SetAttachment(eyesSlot, eyesOpenAttachment);
 			}
 			}
 		}
 		}
 	}
 	}

+ 6 - 6
spine-unity/Assets/Examples/Scripts/Goblins.cs

@@ -43,7 +43,7 @@ namespace Spine.Unity.Examples {
 		
 		
 		public void Start () {
 		public void Start () {
 			skeletonAnimation = GetComponent<SkeletonAnimation>();
 			skeletonAnimation = GetComponent<SkeletonAnimation>();
-			headBone = skeletonAnimation.skeleton.FindBone("head");
+			headBone = skeletonAnimation.Skeleton.FindBone("head");
 			skeletonAnimation.UpdateLocal += UpdateLocal;
 			skeletonAnimation.UpdateLocal += UpdateLocal;
 		}
 		}
 
 
@@ -53,16 +53,16 @@ namespace Spine.Unity.Examples {
 		}
 		}
 		
 		
 		public void OnMouseDown () {
 		public void OnMouseDown () {
-			skeletonAnimation.skeleton.SetSkin(girlSkin ? "goblin" : "goblingirl");
-			skeletonAnimation.skeleton.SetSlotsToSetupPose();
+			skeletonAnimation.Skeleton.SetSkin(girlSkin ? "goblin" : "goblingirl");
+			skeletonAnimation.Skeleton.SetSlotsToSetupPose();
 			
 			
 			girlSkin = !girlSkin;
 			girlSkin = !girlSkin;
 			
 			
 			if (girlSkin) {
 			if (girlSkin) {
-				skeletonAnimation.skeleton.SetAttachment("right hand item", null);
-				skeletonAnimation.skeleton.SetAttachment("left hand item", "spear");
+				skeletonAnimation.Skeleton.SetAttachment("right hand item", null);
+				skeletonAnimation.Skeleton.SetAttachment("left hand item", "spear");
 			} else
 			} else
-				skeletonAnimation.skeleton.SetAttachment("left hand item", "dagger");
+				skeletonAnimation.Skeleton.SetAttachment("left hand item", "dagger");
 		}
 		}
 	}
 	}
 }
 }

+ 1 - 1
spine-unity/Assets/Examples/Scripts/MixAndMatch.cs

@@ -76,7 +76,7 @@ namespace Spine.Unity.Examples {
 			// Case 1: Create an attachment from an atlas.
 			// Case 1: Create an attachment from an atlas.
 			RegionAttachment newHand = handSource.GetAtlas().FindRegion(handRegion).ToRegionAttachment("new hand");
 			RegionAttachment newHand = handSource.GetAtlas().FindRegion(handRegion).ToRegionAttachment("new hand");
 			newHand.SetPositionOffset(newHandOffset);
 			newHand.SetPositionOffset(newHandOffset);
-			newHand.rotation = newHandRotation;
+			newHand.Rotation = newHandRotation;
 			newHand.UpdateOffset();
 			newHand.UpdateOffset();
 			int handSlotIndex = skeleton.FindSlotIndex(handSlot);
 			int handSlotIndex = skeleton.FindSlotIndex(handSlot);
 			handTexture = newHand.GetRegion().ToTexture();
 			handTexture = newHand.GetRegion().ToTexture();

+ 8 - 8
spine-unity/Assets/Examples/Scripts/Spineboy.cs

@@ -29,7 +29,6 @@
  *****************************************************************************/
  *****************************************************************************/
 
 
 using UnityEngine;
 using UnityEngine;
-
 using Spine;
 using Spine;
 using Spine.Unity;
 using Spine.Unity;
 
 
@@ -39,21 +38,22 @@ namespace Spine.Unity.Examples {
 
 
 		public void Start () {
 		public void Start () {
 			skeletonAnimation = GetComponent<SkeletonAnimation>(); // Get the SkeletonAnimation component for the GameObject this script is attached to.
 			skeletonAnimation = GetComponent<SkeletonAnimation>(); // Get the SkeletonAnimation component for the GameObject this script is attached to.
+			var animationState = skeletonAnimation.AnimationState;
 
 
-			skeletonAnimation.state.Event += HandleEvent;; // Call our method any time an animation fires an event.
-			skeletonAnimation.state.End += (entry) => Debug.Log("start: " + entry.trackIndex); // A lambda can be used for the callback instead of a method.
+			animationState.Event += HandleEvent;; // Call our method any time an animation fires an event.
+			animationState.End += (entry) => Debug.Log("start: " + entry.TrackIndex); // A lambda can be used for the callback instead of a method.
 
 
-			skeletonAnimation.state.AddAnimation(0, "jump", false, 2);	// Queue jump to be played on track 0 two seconds after the starting animation.
-			skeletonAnimation.state.AddAnimation(0, "run", true, 0); // Queue walk to be looped on track 0 after the jump animation.
+			animationState.AddAnimation(0, "jump", false, 2);	// Queue jump to be played on track 0 two seconds after the starting animation.
+			animationState.AddAnimation(0, "run", true, 0); // Queue walk to be looped on track 0 after the jump animation.
 		}
 		}
 
 
 		void HandleEvent (TrackEntry trackEntry, Spine.Event e) {
 		void HandleEvent (TrackEntry trackEntry, Spine.Event e) {
-			Debug.Log(trackEntry.trackIndex + " " + trackEntry.animation.name + ": event " + e + ", " + e.Int);
+			Debug.Log(trackEntry.TrackIndex + " " + trackEntry.Animation.Name + ": event " + e + ", " + e.Int);
 		}
 		}
 
 
 		public void OnMouseDown () {
 		public void OnMouseDown () {
-			skeletonAnimation.state.SetAnimation(0, "jump", false); // Set jump to be played on track 0 immediately.
-			skeletonAnimation.state.AddAnimation(0, "run", true, 0); // Queue walk to be looped on track 0 after the jump animation.
+			skeletonAnimation.AnimationState.SetAnimation(0, "jump", false); // Set jump to be played on track 0 immediately.
+			skeletonAnimation.AnimationState.AddAnimation(0, "run", true, 0); // Queue walk to be looped on track 0 after the jump animation.
 		}
 		}
 	}
 	}
 
 

+ 13 - 7
spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs

@@ -74,6 +74,13 @@ namespace Spine.Unity.Editor {
 			targetBoneFollower = (BoneFollower)target;
 			targetBoneFollower = (BoneFollower)target;
 			if (targetBoneFollower.SkeletonRenderer != null)
 			if (targetBoneFollower.SkeletonRenderer != null)
 				targetBoneFollower.SkeletonRenderer.Initialize(false);
 				targetBoneFollower.SkeletonRenderer.Initialize(false);
+
+			if (!targetBoneFollower.valid || needsReset) {
+				targetBoneFollower.Initialize();
+				targetBoneFollower.LateUpdate();
+				needsReset = false;
+				SceneView.RepaintAll();
+			}
 		}
 		}
 
 
 		public void OnSceneGUI () {
 		public void OnSceneGUI () {
@@ -114,7 +121,7 @@ namespace Spine.Unity.Editor {
 				return;
 				return;
 			}
 			}
 
 
-			if (needsReset) {
+			if (needsReset && UnityEngine.Event.current.type == EventType.Layout) {
 				targetBoneFollower.Initialize();
 				targetBoneFollower.Initialize();
 				targetBoneFollower.LateUpdate();
 				targetBoneFollower.LateUpdate();
 				needsReset = false;
 				needsReset = false;
@@ -143,11 +150,8 @@ namespace Spine.Unity.Editor {
 			if (targetBoneFollower.valid) {
 			if (targetBoneFollower.valid) {
 				EditorGUI.BeginChangeCheck();
 				EditorGUI.BeginChangeCheck();
 				EditorGUILayout.PropertyField(boneName);
 				EditorGUILayout.PropertyField(boneName);
-				if (EditorGUI.EndChangeCheck()) {
-					serializedObject.ApplyModifiedProperties();
-					needsReset = true;
-					serializedObject.Update();
-				}
+				needsReset |= EditorGUI.EndChangeCheck();
+
 				EditorGUILayout.PropertyField(followBoneRotation);
 				EditorGUILayout.PropertyField(followBoneRotation);
 				EditorGUILayout.PropertyField(followZPosition);
 				EditorGUILayout.PropertyField(followZPosition);
 				EditorGUILayout.PropertyField(followLocalScale);
 				EditorGUILayout.PropertyField(followLocalScale);
@@ -169,8 +173,10 @@ namespace Spine.Unity.Editor {
 
 
 			var current = UnityEngine.Event.current;
 			var current = UnityEngine.Event.current;
 			bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed");
 			bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed");
-			if (serializedObject.ApplyModifiedProperties() || wasUndo)
+			if (wasUndo)
 				targetBoneFollower.Initialize();
 				targetBoneFollower.Initialize();
+
+			serializedObject.ApplyModifiedProperties();
 		}
 		}
 	}
 	}
 
 

+ 1 - 1
spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs

@@ -341,7 +341,7 @@ namespace Spine.Unity.Modules.AttachmentTools {
 			return Sprite.Create(ar.GetMainTexture(), ar.GetUnityRect(), new Vector2(0.5f, 0.5f), pixelsPerUnit);
 			return Sprite.Create(ar.GetMainTexture(), ar.GetUnityRect(), new Vector2(0.5f, 0.5f), pixelsPerUnit);
 		}
 		}
 
 
-		internal static Texture2D ToTexture (this AtlasRegion ar, bool applyImmediately = true) {
+		public static Texture2D ToTexture (this AtlasRegion ar, bool applyImmediately = true) {
 			Texture2D sourceTexture = ar.GetMainTexture();
 			Texture2D sourceTexture = ar.GetMainTexture();
 			Rect r = ar.GetUnityRect(sourceTexture.height);
 			Rect r = ar.GetUnityRect(sourceTexture.height);
 			Texture2D output = new Texture2D((int)r.width, (int)r.height);
 			Texture2D output = new Texture2D((int)r.width, (int)r.height);

+ 1 - 0
spine-unity/Assets/spine-unity/version.txt

@@ -0,0 +1 @@
+This Spine-Unity runtime works with data exported from Spine Editor version: 3.5.xx

+ 8 - 0
spine-unity/Assets/spine-unity/version.txt.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 80c06a67282e71043a4b1fad3e0c5654
+timeCreated: 1485965987
+licenseType: Free
+TextScriptImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: