Browse Source

Importer improvements
Attributes
Multiple atlas support
More examples

Fenrisul 10 năm trước cách đây
mục cha
commit
444a536dad
66 tập tin đã thay đổi với 3696 bổ sung432 xóa
  1. 19 7
      spine-csharp/src/Attachments/AtlasAttachmentLoader.cs
  2. 2 2
      spine-csharp/src/SkeletonJson.cs
  3. BIN
      spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity
  4. 4 0
      spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity.meta
  5. BIN
      spine-unity/Assets/Examples/Scenes/Mix and Match.unity
  6. 4 0
      spine-unity/Assets/Examples/Scenes/Mix and Match.unity.meta
  7. 6 0
      spine-unity/Assets/Examples/Scripts/BasicPlatformerController.cs
  8. 17 0
      spine-unity/Assets/Examples/Scripts/Chimera.cs
  9. 8 0
      spine-unity/Assets/Examples/Scripts/Chimera.cs.meta
  10. 51 0
      spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs
  11. 8 0
      spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs.meta
  12. BIN
      spine-unity/Assets/Examples/Spine/Dragon/dragon_SkeletonData.asset
  13. BIN
      spine-unity/Assets/Examples/Spine/Eyes/eyes_SkeletonData.asset
  14. 5 0
      spine-unity/Assets/Examples/Spine/FootSoldier.meta
  15. 5 0
      spine-unity/Assets/Examples/Spine/FootSoldier/Equipment.meta
  16. 34 0
      spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.atlas.txt
  17. 4 0
      spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.atlas.txt.meta
  18. BIN
      spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.png
  19. 47 0
      spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.png.meta
  20. BIN
      spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset
  21. 4 0
      spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset.meta
  22. BIN
      spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat
  23. 4 0
      spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat.meta
  24. 90 0
      spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.atlas.txt
  25. 4 0
      spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.atlas.txt.meta
  26. BIN
      spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.png
  27. 47 0
      spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.png.meta
  28. BIN
      spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Atlas.asset
  29. 4 0
      spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Atlas.asset.meta
  30. BIN
      spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Material.mat
  31. 4 0
      spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Material.mat.meta
  32. 1754 0
      spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json
  33. 4 0
      spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json.meta
  34. BIN
      spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset
  35. 4 0
      spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset.meta
  36. 5 0
      spine-unity/Assets/Examples/Spine/FootSoldier/license.txt
  37. 4 0
      spine-unity/Assets/Examples/Spine/FootSoldier/license.txt.meta
  38. BIN
      spine-unity/Assets/Examples/Spine/Goblins/goblins-mesh_Material.mat
  39. BIN
      spine-unity/Assets/Examples/Spine/Goblins/goblins-mesh_SkeletonData.asset
  40. BIN
      spine-unity/Assets/Examples/Spine/Hero.prefab
  41. BIN
      spine-unity/Assets/Examples/Spine/Hero/Hero_SkeletonData.asset
  42. 5 0
      spine-unity/Assets/Examples/Spine/Hero/license.txt
  43. 4 0
      spine-unity/Assets/Examples/Spine/Hero/license.txt.meta
  44. BIN
      spine-unity/Assets/Examples/Spine/Raptor/raptor_Material.mat
  45. BIN
      spine-unity/Assets/Examples/Spine/Raptor/raptor_SkeletonData.asset
  46. BIN
      spine-unity/Assets/Examples/Spine/Spineboy/spineboy_SkeletonData.asset
  47. BIN
      spine-unity/Assets/Examples/Spine/dragon.prefab
  48. 49 0
      spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs
  49. 8 0
      spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs.meta
  50. 21 1
      spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs
  51. BIN
      spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png
  52. 47 0
      spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png.meta
  53. 7 7
      spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png.meta
  54. BIN
      spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png
  55. 47 0
      spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png.meta
  56. 405 227
      spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs
  57. 8 3
      spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs
  58. 456 0
      spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs
  59. 8 0
      spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs.meta
  60. 310 163
      spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs
  61. 26 8
      spine-unity/Assets/spine-unity/SkeletonDataAsset.cs
  62. 12 12
      spine-unity/Assets/spine-unity/SkeletonExtensions.cs
  63. 17 1
      spine-unity/Assets/spine-unity/SkeletonRenderer.cs
  64. 5 1
      spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs
  65. 111 0
      spine-unity/Assets/spine-unity/SpineAttributes.cs
  66. 8 0
      spine-unity/Assets/spine-unity/SpineAttributes.cs.meta

+ 19 - 7
spine-csharp/src/Attachments/AtlasAttachmentLoader.cs

@@ -32,15 +32,15 @@ using System;
 
 namespace Spine {
 	public class AtlasAttachmentLoader : AttachmentLoader {
-		private Atlas atlas;
+		private Atlas[] atlasArray;
 
-		public AtlasAttachmentLoader (Atlas atlas) {
-			if (atlas == null) throw new ArgumentNullException("atlas cannot be null.");
-			this.atlas = atlas;
+		public AtlasAttachmentLoader (params Atlas[] atlasArray) {
+			if (atlasArray == null) throw new ArgumentNullException("atlas array cannot be null.");
+			this.atlasArray = atlasArray;
 		}
 
 		public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) {
-			AtlasRegion region = atlas.FindRegion(path);
+			AtlasRegion region = FindRegion(path);
 			if (region == null) throw new Exception("Region not found in atlas: " + path + " (region attachment: " + name + ")");
 			RegionAttachment attachment = new RegionAttachment(name);
 			attachment.RendererObject = region;
@@ -55,7 +55,7 @@ namespace Spine {
 		}
 
 		public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) {
-			AtlasRegion region = atlas.FindRegion(path);
+			AtlasRegion region = FindRegion(path);
 			if (region == null) throw new Exception("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
 			MeshAttachment attachment = new MeshAttachment(name);
 			attachment.RendererObject = region;
@@ -74,7 +74,7 @@ namespace Spine {
 		}
 
 		public SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, String name, String path) {
-			AtlasRegion region = atlas.FindRegion(path);
+			AtlasRegion region = FindRegion(path);
 			if (region == null) throw new Exception("Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")");
 			SkinnedMeshAttachment attachment = new SkinnedMeshAttachment(name);
 			attachment.RendererObject = region;
@@ -95,5 +95,17 @@ namespace Spine {
 		public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) {
 			return new BoundingBoxAttachment(name);
 		}
+
+		public AtlasRegion FindRegion(string name) {
+			AtlasRegion region;
+
+			for (int i = 0; i < atlasArray.Length; i++) {
+				region = atlasArray[i].FindRegion(name);
+				if (region != null)
+					return region;
+			}
+
+			return null;
+		}
 	}
 }

+ 2 - 2
spine-csharp/src/SkeletonJson.cs

@@ -42,8 +42,8 @@ namespace Spine {
 		private AttachmentLoader attachmentLoader;
 		public float Scale { get; set; }
 
-		public SkeletonJson (Atlas atlas)
-			: this(new AtlasAttachmentLoader(atlas)) {
+		public SkeletonJson (params Atlas[] atlasArray)
+			: this(new AtlasAttachmentLoader(atlasArray)) {
 		}
 
 		public SkeletonJson (AttachmentLoader attachmentLoader) {

BIN
spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity


+ 4 - 0
spine-unity/Assets/Examples/Scenes/Attributes and AtlasRegions.unity.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: 63212ccaf5776bd489cba58fb67a2233
+DefaultImporter:
+  userData: 

BIN
spine-unity/Assets/Examples/Scenes/Mix and Match.unity


+ 4 - 0
spine-unity/Assets/Examples/Scenes/Mix and Match.unity.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: c5673b83016f67a4c99772dfb7b3c437
+DefaultImporter:
+  userData: 

+ 6 - 0
spine-unity/Assets/Examples/Scripts/BasicPlatformerController.cs

@@ -71,11 +71,17 @@ public class BasicPlatformerController : MonoBehaviour {
 #if UNITY_4_5
 	[Header("Animation")]
 #endif
+	[SpineAnimation(dataSource: "skeletonAnimation")]
 	public string walkName = "Walk";
+	[SpineAnimation(dataSource: "skeletonAnimation")]
 	public string runName = "Run";
+	[SpineAnimation(dataSource: "skeletonAnimation")]
 	public string idleName = "Idle";
+	[SpineAnimation(dataSource: "skeletonAnimation")]
 	public string jumpName = "Jump";
+	[SpineAnimation(dataSource: "skeletonAnimation")]
 	public string fallName = "Fall";
+	[SpineAnimation(dataSource: "skeletonAnimation")]
 	public string crouchName = "Crouch";
 
 #if UNITY_4_5

+ 17 - 0
spine-unity/Assets/Examples/Scripts/Chimera.cs

@@ -0,0 +1,17 @@
+using UnityEngine;
+using System.Collections;
+
+public class Chimera : MonoBehaviour {
+
+	public SkeletonDataAsset skeletonDataSource;
+
+	[SpineAttachment(currentSkinOnly: false, returnFullPath: true, dataSource: "skeletonDataSource")]
+	public string attachmentPath;
+
+	[SpineSlot]
+	public string targetSlot;
+
+	void Start() {
+		GetComponent<SkeletonRenderer>().skeleton.FindSlot(targetSlot).Attachment = SpineAttachment.GetAttachment(attachmentPath, skeletonDataSource);
+	}
+}

+ 8 - 0
spine-unity/Assets/Examples/Scripts/Chimera.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5053fe97a7657b5418b0c307b7338b0c
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 51 - 0
spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs

@@ -0,0 +1,51 @@
+using UnityEngine;
+using System.Collections;
+
+public class FootSoldierExample : MonoBehaviour {
+	[SpineAnimation("Idle")]
+	public string idleAnimation;
+
+	[SpineAnimation]
+	public string attackAnimation;
+
+	[SpineSlot]
+	public string eyesSlot;
+
+	[SpineAttachment(currentSkinOnly: true, slot: "eyesSlot")]
+	public string eyesOpenAttachment;
+
+	[SpineAttachment(currentSkinOnly: true, slot: "eyesSlot")]
+	public string blinkAttachment;
+
+	[Range(0, 0.2f)]
+	public float blinkDuration = 0.05f;
+
+	private SkeletonAnimation skeletonAnimation;
+
+	void Awake() {
+		skeletonAnimation = GetComponent<SkeletonAnimation>();
+	}
+
+	void Start() {
+		skeletonAnimation.state.SetAnimation(0, idleAnimation, true);
+		StartCoroutine("Blink");
+	}
+
+	void Update() {
+		if (Input.GetKey(KeyCode.Space)) {
+			if (skeletonAnimation.state.GetCurrent(0).Animation.Name != attackAnimation) {
+				skeletonAnimation.state.SetAnimation(0, attackAnimation, false);
+				skeletonAnimation.state.AddAnimation(0, idleAnimation, true, 0);
+			}
+		}
+	}
+
+	IEnumerator Blink() {
+		while (true) {
+			yield return new WaitForSeconds(Random.Range(0.25f, 3f));
+			skeletonAnimation.skeleton.SetAttachment(eyesSlot, blinkAttachment);
+			yield return new WaitForSeconds(blinkDuration);
+			skeletonAnimation.skeleton.SetAttachment(eyesSlot, eyesOpenAttachment);
+		}
+	}
+}

+ 8 - 0
spine-unity/Assets/Examples/Scripts/FootSoldierExample.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3c826b50b0cfee343be3bdbbf59d0f7c
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

BIN
spine-unity/Assets/Examples/Spine/Dragon/dragon_SkeletonData.asset


BIN
spine-unity/Assets/Examples/Spine/Eyes/eyes_SkeletonData.asset


+ 5 - 0
spine-unity/Assets/Examples/Spine/FootSoldier.meta

@@ -0,0 +1,5 @@
+fileFormatVersion: 2
+guid: 7a709e690449c1b40b198bb86f707c41
+folderAsset: yes
+DefaultImporter:
+  userData: 

+ 5 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/Equipment.meta

@@ -0,0 +1,5 @@
+fileFormatVersion: 2
+guid: e90f1603e5c99c745a28d42e61afe5b2
+folderAsset: yes
+DefaultImporter:
+  userData: 

+ 34 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.atlas.txt

@@ -0,0 +1,34 @@
+
+Equipment.png
+size: 512,128
+format: RGBA8888
+filter: Linear,Linear
+repeat: none
+Equipment/shield1
+  rotate: true
+  xy: 220, 33
+  size: 71, 118
+  orig: 256, 256
+  offset: 92, 69
+  index: -1
+Equipment/shield2
+  rotate: true
+  xy: 340, 22
+  size: 82, 111
+  orig: 256, 256
+  offset: 87, 72
+  index: -1
+Equipment/sword1
+  rotate: false
+  xy: 2, 2
+  size: 161, 31
+  orig: 512, 256
+  offset: 217, 112
+  index: -1
+Equipment/sword4
+  rotate: false
+  xy: 2, 35
+  size: 216, 69
+  orig: 512, 256
+  offset: 200, 94
+  index: -1

+ 4 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.atlas.txt.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: 4f0639ff8bc42314d8d62ee0f7ba541f
+TextScriptImporter:
+  userData: 

BIN
spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.png


+ 47 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment.png.meta

@@ -0,0 +1,47 @@
+fileFormatVersion: 2
+guid: ddb89f63d0296cf4f8572b0448bb6b30
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  seamlessCubemap: 0
+  textureFormat: -3
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 

BIN
spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset


+ 4 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: c574489dd067c2b4cb4dc165a4c410cc
+NativeFormatImporter:
+  userData: 

BIN
spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat


+ 4 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: e6e388faa521c96449984cfa4b60d74e
+NativeFormatImporter:
+  userData: 

+ 90 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.atlas.txt

@@ -0,0 +1,90 @@
+
+FS_White.png
+size: 256,256
+format: RGBA8888
+filter: Linear,Linear
+repeat: none
+White/arm
+  rotate: false
+  xy: 143, 156
+  size: 111, 98
+  orig: 111, 98
+  offset: 0, 0
+  index: -1
+White/arm 2
+  rotate: false
+  xy: 95, 36
+  size: 46, 79
+  orig: 46, 79
+  offset: 0, 0
+  index: -1
+White/body
+  rotate: false
+  xy: 2, 12
+  size: 91, 103
+  orig: 91, 103
+  offset: 0, 0
+  index: -1
+White/eyes
+  rotate: true
+  xy: 195, 87
+  size: 67, 31
+  orig: 67, 31
+  offset: 0, 0
+  index: -1
+White/eyes blink
+  rotate: true
+  xy: 228, 87
+  size: 67, 22
+  orig: 67, 22
+  offset: 0, 0
+  index: -1
+White/feet
+  rotate: false
+  xy: 95, 2
+  size: 50, 32
+  orig: 50, 32
+  offset: 0, 0
+  index: -1
+White/feet 2
+  rotate: false
+  xy: 193, 58
+  size: 55, 27
+  orig: 55, 27
+  offset: 0, 0
+  index: -1
+White/hand
+  rotate: false
+  xy: 147, 9
+  size: 32, 28
+  orig: 32, 28
+  offset: 0, 0
+  index: -1
+White/head 1
+  rotate: false
+  xy: 2, 117
+  size: 139, 137
+  orig: 139, 137
+  offset: 0, 0
+  index: -1
+White/leg
+  rotate: false
+  xy: 143, 39
+  size: 48, 55
+  orig: 48, 55
+  offset: 0, 0
+  index: -1
+White/leg 2
+  rotate: false
+  xy: 143, 96
+  size: 50, 58
+  orig: 50, 58
+  offset: 0, 0
+  index: -1
+White/mouth
+  rotate: false
+  xy: 193, 35
+  size: 28, 21
+  orig: 28, 21
+  offset: 0, 0
+  index: -1

+ 4 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.atlas.txt.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: 5ca7c05342912804eb0a2fd5bbe85b58
+TextScriptImporter:
+  userData: 

BIN
spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.png


+ 47 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/FS_White.png.meta

@@ -0,0 +1,47 @@
+fileFormatVersion: 2
+guid: 57b57f94df266f94ea0981915a4472e1
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    linearTexture: 0
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  seamlessCubemap: 0
+  textureFormat: -3
+  maxTextureSize: 2048
+  textureSettings:
+    filterMode: -1
+    aniso: -1
+    mipBias: -1
+    wrapMode: -1
+  nPOTScale: 1
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 0
+  textureType: -1
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 

BIN
spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Atlas.asset


+ 4 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Atlas.asset.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: e3c7e74834cd8424f8735ba05e94a688
+NativeFormatImporter:
+  userData: 

BIN
spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Material.mat


+ 4 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/FS_White_Material.mat.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: 5a3598dafa118754db95756064347da7
+NativeFormatImporter:
+  userData: 

+ 1754 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json

@@ -0,0 +1,1754 @@
+{
+"skeleton": { "hash": "uZfvh80BNvvngM3EGMfAkHebg00", "spine": "2.1.08", "width": 147.68, "height": 268.92, "images": "./images/" },
+"bones": [
+	{ "name": "Root" },
+	{ "name": "Hip", "parent": "Root", "x": -0.93, "y": 73.4 },
+	{ "name": "Body", "parent": "Hip", "length": 60.98, "x": 2.46, "y": -7.69, "rotation": 89.52 },
+	{ "name": "Leg", "parent": "Hip", "length": 31.39, "x": -20.32, "y": -13.85, "rotation": -105.82 },
+	{ "name": "Leg2", "parent": "Hip", "length": 31.09, "x": 22.48, "y": -12.01, "rotation": -74.17 },
+	{ "name": "Arm", "parent": "Body", "length": 51.63, "x": 49.91, "y": 37.35, "rotation": 166.67 },
+	{ "name": "Arm2", "parent": "Body", "length": 52.61, "x": 53.81, "y": -28.52, "rotation": -157.17 },
+	{ "name": "Feet", "parent": "Leg", "length": 15.4, "x": 39.56, "y": 1.59, "rotation": 14.56 },
+	{ "name": "Feet2", "parent": "Leg2", "length": 12.32, "x": 41.33, "y": 0.12, "rotation": -17.19 },
+	{ "name": "Head", "parent": "Body", "length": 65.29, "x": 73.6, "y": 1.09, "rotation": -88.23 },
+	{ "name": "Shield", "parent": "Arm", "x": 45.01, "y": -2.1, "rotation": 123.56 },
+	{ "name": "Weapon", "parent": "Arm2", "length": 137.65, "x": 48.2, "y": 12.78, "rotation": 92.5 }
+],
+"slots": [
+	{ "name": "Arm2", "bone": "Arm2", "attachment": "Arm2" },
+	{ "name": "Weapon", "bone": "Weapon" },
+	{ "name": "Hand", "bone": "Arm2", "attachment": "Hand" },
+	{ "name": "Leg2", "bone": "Leg2", "attachment": "Leg2" },
+	{ "name": "Feet2", "bone": "Feet2", "attachment": "Feet2" },
+	{ "name": "Leg", "bone": "Leg", "attachment": "Leg" },
+	{ "name": "Feet", "bone": "Feet", "attachment": "Feet" },
+	{ "name": "Body", "bone": "Body", "attachment": "body" },
+	{ "name": "Arm", "bone": "Arm", "attachment": "Arm" },
+	{ "name": "Head", "bone": "Head", "attachment": "Head" },
+	{ "name": "Eyes", "bone": "Head", "attachment": "Open" },
+	{ "name": "Shield", "bone": "Shield" },
+	{ "name": "Mouth", "bone": "Head", "attachment": "Closed" }
+],
+"skins": {
+	"default": {},
+	"White": {
+		"Arm": {
+			"Arm": { "name": "arm", "path": "White/arm", "x": 21.18, "y": 21.04, "rotation": 109.17, "width": 111, "height": 98 }
+		},
+		"Arm2": {
+			"Arm2": { "name": "arm 2", "path": "White/arm 2", "x": 23.03, "y": -1.29, "rotation": 78.03, "width": 46, "height": 79 }
+		},
+		"Body": {
+			"body": { "path": "White/body", "x": 23.73, "y": 7.21, "rotation": -89.52, "width": 91, "height": 103 }
+		},
+		"Eyes": {
+			"Blink": { "path": "White/eyes blink", "x": 10.41, "y": 31.16, "rotation": -1.13, "width": 67, "height": 22 },
+			"Open": { "path": "White/eyes", "x": 11.07, "y": 26.12, "rotation": -4.55, "width": 67, "height": 31 }
+		},
+		"Feet": {
+			"Feet": { "name": "feet", "path": "White/feet", "x": 6.08, "y": -1.36, "rotation": 91.26, "width": 50, "height": 32 }
+		},
+		"Feet2": {
+			"Feet2": { "name": "feet 2", "path": "White/feet 2", "x": 4.26, "y": -4.34, "rotation": 91.37, "width": 55, "height": 27 }
+		},
+		"Hand": {
+			"Hand": { "name": "hand", "path": "White/hand", "x": 49.06, "y": 2.06, "rotation": 67.64, "width": 32, "height": 28 }
+		},
+		"Head": {
+			"Head": { "name": "head 1", "path": "White/head 1", "x": -3.5, "y": 58.44, "rotation": -2.76, "width": 139, "height": 137 }
+		},
+		"Leg": {
+			"Leg": { "name": "leg", "path": "White/leg", "x": 16.86, "y": -4.3, "rotation": 104.82, "width": 48, "height": 55 }
+		},
+		"Leg2": {
+			"Leg2": { "name": "leg 2", "path": "White/leg 2", "x": 16.44, "y": -2.11, "rotation": 74.17, "width": 50, "height": 58 }
+		},
+		"Mouth": {
+			"Closed": { "path": "White/mouth", "x": 10.96, "y": 3.69, "rotation": -1.29, "width": 28, "height": 21 }
+		}
+	}
+},
+"events": {
+	"Hit": {}
+},
+"animations": {
+	"Attack": {
+		"bones": {
+			"Arm": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -10.02,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.3333, "angle": -50.06 },
+					{ "time": 0.4, "angle": -15.89 },
+					{ "time": 0.4666, "angle": -29.45, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"angle": -29.45,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "angle": -10.02 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.3333, "x": 2.53, "y": -1.01 },
+					{ "time": 0.4666, "x": -5.05, "y": -2.57, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"x": -5.05,
+						"y": -2.57,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "x": 0, "y": 0 }
+				]
+			},
+			"Root": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Hip": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.3333, "angle": 0, "curve": "stepped" },
+					{ "time": 0.8333, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.3333, "x": 0, "y": 0 },
+					{ "time": 0.4666, "x": 9.25, "y": -5.94, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"x": 9.25,
+						"y": -5.94,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "x": 0, "y": 0 }
+				]
+			},
+			"Body": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.3333, "angle": 8.25 },
+					{ "time": 0.4666, "angle": -15.92, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"angle": -15.92,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.3333, "x": -1.07, "y": 3.56 },
+					{ "time": 0.8333, "x": 0, "y": 0 }
+				]
+			},
+			"Leg": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.3333, "angle": 0 },
+					{ "time": 0.4666, "angle": -18.61, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"angle": -18.61,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.3333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.8333, "x": 0, "y": 0 }
+				]
+			},
+			"Leg2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.3333, "angle": 15.02 },
+					{ "time": 0.4666, "angle": 4.71, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"angle": 4.71,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.3333, "x": -2.61, "y": 4.37 },
+					{ "time": 0.4666, "x": 5.74, "y": 4.37, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"x": 5.74,
+						"y": 4.37,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "x": 0, "y": 0 }
+				]
+			},
+			"Arm2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.3333, "angle": 148.07 },
+					{ "time": 0.4666, "angle": 335.98, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"angle": 335.98,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.3333, "x": 4.5, "y": -0.72 },
+					{ "time": 0.4666, "x": -1.04, "y": -2.35, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"x": -1.04,
+						"y": -2.35,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "x": 0, "y": 0 }
+				]
+			},
+			"Feet": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.3333, "angle": 0 },
+					{ "time": 0.4666, "angle": 18.36, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"angle": 18.36,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.3333, "x": 0, "y": 0 },
+					{ "time": 0.4666, "x": -1.43, "y": 2.2, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"x": -1.43,
+						"y": 2.2,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "x": 0, "y": 0 }
+				]
+			},
+			"Feet2": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.3333, "angle": 0 },
+					{ "time": 0.4666, "angle": -2.99, "curve": "stepped" },
+					{
+						"time": 0.6,
+						"angle": -2.99,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8333, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.3333, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.8333, "x": 0, "y": 0 }
+				]
+			},
+			"Head": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.3333, "angle": 19.17 },
+					{ "time": 0.4666, "angle": -2.33 },
+					{ "time": 0.8333, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.3333, "x": -1.36, "y": -0.46 },
+					{ "time": 0.8333, "x": 0, "y": 0 }
+				]
+			},
+			"Weapon": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			}
+		},
+		"events": [
+			{ "time": 0.4333, "name": "Hit" }
+		]
+	},
+	"DeathBackward": {
+		"bones": {
+			"Root": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Hip": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.3333, "angle": 87.75 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 },
+					{ "time": 0.2, "x": -50.02, "y": -6.59 },
+					{ "time": 0.3333, "x": -83.36, "y": -37.67 }
+				]
+			},
+			"Body": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 },
+					{ "time": 0.3333, "x": 5.06, "y": -0.04 }
+				]
+			},
+			"Leg": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.3333, "angle": 33.36 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Leg2": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.3333, "angle": -48.11 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Arm": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.3333, "angle": -346.22 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 },
+					{ "time": 0.3333, "x": -4.06, "y": -12.11 }
+				]
+			},
+			"Arm2": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.3333, "angle": 278.31 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Feet": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.3333, "angle": -46.46 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Feet2": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Head": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.3333, "angle": 17.02 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 },
+					{ "time": 0.3333, "x": -3.67, "y": -21.86 }
+				]
+			},
+			"Weapon": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.3333, "angle": -38.52 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			}
+		}
+	},
+	"DeathForward": {
+		"bones": {
+			"Root": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Hip": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "angle": -87.3 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.243, 0, 0.638, 0.47 ]
+					},
+					{
+						"time": 0.2,
+						"x": 36.63,
+						"y": 0.08,
+						"curve": [ 0.386, 0.35, 0.748, 0.73 ]
+					},
+					{ "time": 0.3333, "x": 74.83, "y": -43.12 }
+				]
+			},
+			"Body": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Leg": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "angle": 52.39 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "x": -4.47, "y": 3.29 }
+				]
+			},
+			"Leg2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "angle": -34.64 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Arm": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "angle": -306.5 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 },
+					{ "time": 0.3333, "x": -2.42, "y": -20.41 }
+				]
+			},
+			"Arm2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "angle": 160 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 },
+					{ "time": 0.3333, "x": -0.79, "y": 16.15 }
+				]
+			},
+			"Feet": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "angle": -19.93 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "x": -0.19, "y": -2.03 }
+				]
+			},
+			"Feet2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "angle": 30.89 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Head": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "angle": 47.13 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Weapon": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 0,
+						"curve": [ 0.25, 0, 0.758, 0.67 ]
+					},
+					{ "time": 0.3333, "angle": 43.72 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			}
+		}
+	},
+	"Idle": {
+		"bones": {
+			"Body": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.5,
+						"x": 0,
+						"y": -3.51,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 1, "x": 0, "y": 0 }
+				]
+			},
+			"Head": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -1.03,
+						"y": 0,
+						"curve": [ 0.212, 0.29, 0.75, 1 ]
+					},
+					{
+						"time": 0.1333,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.6333,
+						"x": -1.75,
+						"y": -0.01,
+						"curve": [ 0.25, 0, 0.755, 0.68 ]
+					},
+					{ "time": 1, "x": -1.03, "y": 0 }
+				]
+			},
+			"Arm": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -10.63,
+						"curve": [ 0.337, 0.34, 0.757, 1 ]
+					},
+					{
+						"time": 0.3666,
+						"angle": -13.14,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8666, "angle": -10 },
+					{ "time": 1, "angle": -10.63 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.44,
+						"y": 0,
+						"curve": [ 0.337, 0.34, 0.757, 1 ]
+					},
+					{
+						"time": 0.3666,
+						"x": -2.17,
+						"y": -0.01,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8666, "x": 0, "y": 0 },
+					{ "time": 1, "x": -0.44, "y": 0 }
+				]
+			},
+			"Arm2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -0.47,
+						"curve": [ 0.337, 0.34, 0.757, 1 ]
+					},
+					{
+						"time": 0.3666,
+						"angle": -2.34,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8666, "angle": 0 },
+					{ "time": 1, "angle": -0.47 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.46,
+						"y": 0,
+						"curve": [ 0.337, 0.34, 0.757, 1 ]
+					},
+					{
+						"time": 0.3666,
+						"x": -2.29,
+						"y": -0.01,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.8666,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 1, "x": -0.46, "y": 0 }
+				]
+			},
+			"Leg": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": -0.26,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{ "time": 0.1, "x": 0, "y": 0 },
+					{
+						"time": 0.6,
+						"x": 0,
+						"y": -2.03,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": 0, "y": -0.26 }
+				]
+			},
+			"Feet": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.25,
+						"y": -0.07,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{
+						"time": 0.1,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.6,
+						"x": -1.95,
+						"y": -0.55,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": -0.25, "y": -0.07 }
+				]
+			},
+			"Leg2": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": -0.33,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{ "time": 0.1, "x": 0, "y": 0 },
+					{
+						"time": 0.6,
+						"x": 0,
+						"y": -2.54,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": 0, "y": -0.33 }
+				]
+			},
+			"Feet2": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.31,
+						"y": 0.09,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{
+						"time": 0.1,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.6,
+						"x": -2.44,
+						"y": 0.69,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": -0.31, "y": 0.09 }
+				]
+			},
+			"Root": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Hip": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Weapon": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			}
+		}
+	},
+	"Idle2": {
+		"bones": {
+			"Body": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.5,
+						"x": 0,
+						"y": -3.51,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 1, "x": 0, "y": 0 }
+				]
+			},
+			"Head": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.1666, "angle": 22.27, "curve": "stepped" },
+					{ "time": 0.7333, "angle": 22.27 },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -1.03,
+						"y": 0,
+						"curve": [ 0.212, 0.29, 0.75, 1 ]
+					},
+					{
+						"time": 0.1333,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.4,
+						"x": -1.75,
+						"y": -0.01,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 1, "x": -1.03, "y": 0 }
+				]
+			},
+			"Arm": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -10.63,
+						"curve": [ 0.337, 0.34, 0.757, 1 ]
+					},
+					{
+						"time": 0.3666,
+						"angle": -13.14,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8666, "angle": -10 },
+					{ "time": 1, "angle": -10.63 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.44,
+						"y": 0,
+						"curve": [ 0.337, 0.34, 0.757, 1 ]
+					},
+					{
+						"time": 0.3666,
+						"x": -2.17,
+						"y": -0.01,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8666, "x": 0, "y": 0 },
+					{ "time": 1, "x": -0.44, "y": 0 }
+				]
+			},
+			"Arm2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -0.47,
+						"curve": [ 0.315, 0.27, 0.661, 0.65 ]
+					},
+					{ "time": 0.1666, "angle": 79.53, "curve": "stepped" },
+					{
+						"time": 0.7333,
+						"angle": 79.53,
+						"curve": [ 0.337, 0.34, 0.757, 1 ]
+					},
+					{ "time": 0.9666, "angle": -0.47, "curve": "stepped" },
+					{ "time": 1, "angle": -0.47 }
+				],
+				"translate": [
+					{ "time": 0, "x": -0.46, "y": 0, "curve": "stepped" },
+					{ "time": 1, "x": -0.46, "y": 0 }
+				]
+			},
+			"Leg": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": -0.26,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{ "time": 0.1, "x": 0, "y": 0 },
+					{
+						"time": 0.6,
+						"x": 0,
+						"y": -2.03,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": 0, "y": -0.26 }
+				]
+			},
+			"Feet": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.25,
+						"y": -0.07,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{
+						"time": 0.1,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.6,
+						"x": -1.95,
+						"y": -0.55,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": -0.25, "y": -0.07 }
+				]
+			},
+			"Leg2": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": -0.33,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{ "time": 0.1, "x": 0, "y": 0 },
+					{
+						"time": 0.6,
+						"x": 0,
+						"y": -2.54,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": 0, "y": -0.33 }
+				]
+			},
+			"Feet2": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.31,
+						"y": 0.09,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{
+						"time": 0.1,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.6,
+						"x": -2.44,
+						"y": 0.69,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": -0.31, "y": 0.09 }
+				]
+			},
+			"Root": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Hip": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Weapon": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.1666, "angle": -15.07, "curve": "stepped" },
+					{ "time": 0.7333, "angle": -15.07 },
+					{ "time": 0.9666, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			}
+		}
+	},
+	"Idle3": {
+		"bones": {
+			"Body": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.5,
+						"x": 0,
+						"y": -3.51,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 1, "x": 0, "y": 0 }
+				]
+			},
+			"Head": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -1.03,
+						"y": 0,
+						"curve": [ 0.212, 0.29, 0.75, 1 ]
+					},
+					{
+						"time": 0.1333,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.6333,
+						"x": -1.75,
+						"y": -0.01,
+						"curve": [ 0.25, 0, 0.755, 0.68 ]
+					},
+					{ "time": 1, "x": -1.03, "y": 0 }
+				]
+			},
+			"Arm": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -10.63,
+						"curve": [ 0.337, 0.34, 0.757, 1 ]
+					},
+					{
+						"time": 0.3666,
+						"angle": -13.14,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8666, "angle": -10 },
+					{ "time": 1, "angle": -10.63 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.44,
+						"y": 0,
+						"curve": [ 0.337, 0.34, 0.757, 1 ]
+					},
+					{
+						"time": 0.3666,
+						"x": -2.17,
+						"y": -0.01,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.8666, "x": 0, "y": 0 },
+					{ "time": 1, "x": -0.44, "y": 0 }
+				]
+			},
+			"Arm2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -0.47,
+						"curve": [ 0.322, 0.29, 0.658, 0.63 ]
+					},
+					{
+						"time": 0.1666,
+						"angle": 322.37,
+						"curve": [ 0.339, 0.35, 0.673, 0.68 ]
+					},
+					{
+						"time": 0.2666,
+						"angle": 335.29,
+						"curve": [ 0.336, 0.34, 0.67, 0.67 ]
+					},
+					{
+						"time": 0.3666,
+						"angle": 322.1,
+						"curve": [ 0.381, 0.58, 0.729, 1 ]
+					},
+					{
+						"time": 0.4666,
+						"angle": 331.22,
+						"curve": [ 0.333, 0.33, 0.667, 0.66 ]
+					},
+					{
+						"time": 0.5666,
+						"angle": 322.25,
+						"curve": [ 0.33, 0.32, 0.664, 0.66 ]
+					},
+					{
+						"time": 0.6666,
+						"angle": 322.37,
+						"curve": [ 0.386, 0, 0.755, 1 ]
+					},
+					{ "time": 1, "angle": -0.47 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.46,
+						"y": 0,
+						"curve": [ 0.322, 0.29, 0.658, 0.63 ]
+					},
+					{
+						"time": 0.1666,
+						"x": -12.22,
+						"y": -0.1,
+						"curve": [ 0.332, 0.33, 0.682, 0.71 ]
+					},
+					{
+						"time": 0.4333,
+						"x": -10.84,
+						"y": -0.08,
+						"curve": [ 0.381, 0.58, 0.729, 1 ]
+					},
+					{
+						"time": 0.6666,
+						"x": -12.22,
+						"y": -0.1,
+						"curve": [ 0.361, 0.43, 0.755, 1 ]
+					},
+					{ "time": 1, "x": -0.46, "y": 0 }
+				]
+			},
+			"Leg": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": -0.26,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{ "time": 0.1, "x": 0, "y": 0 },
+					{
+						"time": 0.6,
+						"x": 0,
+						"y": -2.03,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": 0, "y": -0.26 }
+				]
+			},
+			"Feet": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.25,
+						"y": -0.07,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{
+						"time": 0.1,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.6,
+						"x": -1.95,
+						"y": -0.55,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": -0.25, "y": -0.07 }
+				]
+			},
+			"Leg2": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": -0.33,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{ "time": 0.1, "x": 0, "y": 0 },
+					{
+						"time": 0.6,
+						"x": 0,
+						"y": -2.54,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": 0, "y": -0.33 }
+				]
+			},
+			"Feet2": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.1, "angle": 0, "curve": "stepped" },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.31,
+						"y": 0.09,
+						"curve": [ 0.374, 0.61, 0.715, 1 ]
+					},
+					{
+						"time": 0.1,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.6,
+						"x": -2.44,
+						"y": 0.69,
+						"curve": [ 0.242, 0, 0.679, 0.71 ]
+					},
+					{ "time": 1, "x": -0.31, "y": 0.09 }
+				]
+			},
+			"Root": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Hip": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Weapon": {
+				"rotate": [
+					{ "time": 0, "angle": 0 },
+					{ "time": 0.1666, "angle": -7.41, "curve": "stepped" },
+					{ "time": 0.6666, "angle": -7.41 },
+					{ "time": 1, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 1, "x": 0, "y": 0 }
+				]
+			}
+		}
+	},
+	"Move": {
+		"bones": {
+			"Arm": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -345.33,
+						"curve": [ 0.235, 0.29, 0.75, 1 ]
+					},
+					{
+						"time": 0.2,
+						"angle": -8.71,
+						"curve": [ 0.25, 0, 0.592, 1 ]
+					},
+					{
+						"time": 0.5333,
+						"angle": -338.66,
+						"curve": [ 0.25, 0, 0.715, 0.63 ]
+					},
+					{ "time": 0.6666, "angle": -345.33 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -2.81,
+						"y": -0.06,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.2,
+						"x": -0.69,
+						"y": -0.92,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.3333,
+						"x": -2.81,
+						"y": -0.06,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.5333,
+						"x": 0.36,
+						"y": 0.38,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.6666, "x": -2.81, "y": -0.06 }
+				]
+			},
+			"Leg": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 26.56,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.2,
+						"angle": 52.94,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.5333,
+						"angle": -1.83,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.6666, "angle": 26.56 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.2,
+						"x": 19.08,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.6666, "x": 0, "y": 0 }
+				]
+			},
+			"Leg2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -33.11,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.2,
+						"angle": -49.48,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.5333,
+						"angle": -1.66,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.6666, "angle": -33.11 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": 0,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.2,
+						"x": -22.21,
+						"y": 0,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.4,
+						"x": -11.24,
+						"y": 6.26,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.6666, "x": 0, "y": 0 }
+				]
+			},
+			"Feet": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -23.86,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.2,
+						"angle": -51.25,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.3333,
+						"angle": -29.88,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.4333,
+						"angle": -14.06,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.5333,
+						"angle": -18.03,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.6666, "angle": -23.48 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.84,
+						"y": -4.45,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.2, "x": -1.03, "y": -4.7, "curve": "stepped" },
+					{
+						"time": 0.5333,
+						"x": -1.03,
+						"y": -4.7,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.6666, "x": -0.84, "y": -4.45 }
+				]
+			},
+			"Feet2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": 33.53,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.2,
+						"angle": 9.39,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.5333,
+						"angle": 14.85,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.6666, "angle": 33.53 }
+				],
+				"translate": [
+					{
+						"time": 0,
+						"x": -0.98,
+						"y": 3.98,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.2,
+						"x": 0.28,
+						"y": -0.42,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.5333,
+						"x": 0.31,
+						"y": 2.54,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{ "time": 0.6666, "x": -0.98, "y": 3.98 }
+				]
+			},
+			"Hip": {
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 },
+					{ "time": 0.2, "x": 0, "y": 3.84 },
+					{ "time": 0.3333, "x": 0, "y": 0 },
+					{ "time": 0.5333, "x": 0, "y": 3.84 },
+					{ "time": 0.6666, "x": 0, "y": 0 }
+				]
+			},
+			"Head": {
+				"rotate": [
+					{ "time": 0, "angle": 6.58 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0.95, "y": 0 },
+					{ "time": 0.0666, "x": 0, "y": 0 },
+					{ "time": 0.2666, "x": 1.91, "y": 0.01 },
+					{ "time": 0.4, "x": 0, "y": 0 },
+					{ "time": 0.6, "x": 1.91, "y": 0.01 },
+					{ "time": 0.6666, "x": 0.95, "y": 0 }
+				]
+			},
+			"Arm2": {
+				"rotate": [
+					{
+						"time": 0,
+						"angle": -5.89,
+						"curve": [ 0.244, 0.31, 0.75, 1 ]
+					},
+					{
+						"time": 0.2,
+						"angle": 4.17,
+						"curve": [ 0.25, 0, 0.75, 1 ]
+					},
+					{
+						"time": 0.5333,
+						"angle": -10.86,
+						"curve": [ 0.25, 0, 0.781, 0.72 ]
+					},
+					{ "time": 0.6666, "angle": -5.89 }
+				]
+			},
+			"Body": {
+				"rotate": [
+					{ "time": 0, "angle": -5.26 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 2.51 },
+					{ "time": 0.0666, "x": 0, "y": 0 },
+					{ "time": 0.2666, "x": 0, "y": 3.02 },
+					{ "time": 0.4, "x": 0, "y": 0 },
+					{ "time": 0.6, "x": 0, "y": 5.03 },
+					{ "time": 0.6666, "x": 0, "y": 2.51 }
+				]
+			}
+		}
+	},
+	"Parried": {
+		"bones": {
+			"Arm": {
+				"rotate": [
+					{ "time": 0, "angle": -22.67 },
+					{ "time": 0.1, "angle": -46.87 },
+					{ "time": 0.2333, "angle": -5.32 },
+					{ "time": 0.4, "angle": -10.02 }
+				],
+				"translate": [
+					{ "time": 0, "x": -3.15, "y": -2.18 },
+					{ "time": 0.4, "x": 0, "y": 0 }
+				]
+			},
+			"Root": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			},
+			"Hip": {
+				"rotate": [
+					{ "time": 0, "angle": 0, "curve": "stepped" },
+					{ "time": 0.4, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 6.94, "y": -4.46 },
+					{ "time": 0.4, "x": 0, "y": 0 }
+				]
+			},
+			"Body": {
+				"rotate": [
+					{ "time": 0, "angle": -9.88 },
+					{ "time": 0.1, "angle": 7.82 },
+					{ "time": 0.4, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": -0.86, "y": 2.85 },
+					{ "time": 0.1, "x": -3.19, "y": 2.13 },
+					{ "time": 0.4, "x": 0, "y": 0 }
+				]
+			},
+			"Leg": {
+				"rotate": [
+					{ "time": 0, "angle": -13.95 },
+					{ "time": 0.4, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
+					{ "time": 0.4, "x": 0, "y": 0 }
+				]
+			},
+			"Leg2": {
+				"rotate": [
+					{ "time": 0, "angle": 7.29 },
+					{ "time": 0.1, "angle": 19.32 },
+					{ "time": 0.4, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 3.65, "y": 4.37 },
+					{ "time": 0.1, "x": -3.88, "y": 5.46 },
+					{ "time": 0.4, "x": 0, "y": 0 }
+				]
+			},
+			"Arm2": {
+				"rotate": [
+					{ "time": 0, "angle": 19 },
+					{ "time": 0.1, "angle": 88.31 },
+					{ "time": 0.4, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0.34, "y": -1.94 },
+					{ "time": 0.1, "x": -1.61, "y": 3.91 },
+					{ "time": 0.4, "x": 0, "y": 0 }
+				]
+			},
+			"Feet": {
+				"rotate": [
+					{ "time": 0, "angle": 13.77 },
+					{ "time": 0.4, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": -1.07, "y": 1.65 },
+					{ "time": 0.4, "x": 0, "y": 0 }
+				]
+			},
+			"Feet2": {
+				"rotate": [
+					{ "time": 0, "angle": -2.24 },
+					{ "time": 0.1, "angle": 3.22 },
+					{ "time": 0.4, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 },
+					{ "time": 0.1, "x": -1.56, "y": 1.1 },
+					{ "time": 0.4, "x": 0, "y": 0 }
+				]
+			},
+			"Head": {
+				"rotate": [
+					{ "time": 0, "angle": 3.04 },
+					{ "time": 0.1, "angle": 11.84 },
+					{ "time": 0.4, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": -1.08, "y": -0.37 },
+					{ "time": 0.4, "x": 0, "y": 0 }
+				]
+			},
+			"Weapon": {
+				"rotate": [
+					{ "time": 0, "angle": 0 }
+				],
+				"translate": [
+					{ "time": 0, "x": 0, "y": 0 }
+				]
+			}
+		}
+	}
+}
+}

+ 4 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier.json.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: b075ad1d14f5db64b941d266e53de57d
+TextScriptImporter:
+  userData: 

BIN
spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset


+ 4 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: e57cdb51287d3924ebb2ececf816733b
+NativeFormatImporter:
+  userData: 

+ 5 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/license.txt

@@ -0,0 +1,5 @@
+Copyright (c) 2014, XDTech
+
+The project file and images in this "FootSoldier" project are provided for
+demonstration purposes only and may not be redistributed for any reason nor
+used as the basis for derivative work.

+ 4 - 0
spine-unity/Assets/Examples/Spine/FootSoldier/license.txt.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: 6fe8b327d2ab4bd438a63ffec150a911
+TextScriptImporter:
+  userData: 

BIN
spine-unity/Assets/Examples/Spine/Goblins/goblins-mesh_Material.mat


BIN
spine-unity/Assets/Examples/Spine/Goblins/goblins-mesh_SkeletonData.asset


BIN
spine-unity/Assets/Examples/Spine/Hero.prefab


BIN
spine-unity/Assets/Examples/Spine/Hero/Hero_SkeletonData.asset


+ 5 - 0
spine-unity/Assets/Examples/Spine/Hero/license.txt

@@ -0,0 +1,5 @@
+Copyright (c) 2014, XDTech
+
+The project file and images in this "Hero" project are provided for
+demonstration purposes only and may not be redistributed for any reason nor
+used as the basis for derivative work.

+ 4 - 0
spine-unity/Assets/Examples/Spine/Hero/license.txt.meta

@@ -0,0 +1,4 @@
+fileFormatVersion: 2
+guid: 0d9db1748e0cf9f408129df308299463
+TextScriptImporter:
+  userData: 

BIN
spine-unity/Assets/Examples/Spine/Raptor/raptor_Material.mat


BIN
spine-unity/Assets/Examples/Spine/Raptor/raptor_SkeletonData.asset


BIN
spine-unity/Assets/Examples/Spine/Spineboy/spineboy_SkeletonData.asset


BIN
spine-unity/Assets/Examples/Spine/dragon.prefab


+ 49 - 0
spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs

@@ -0,0 +1,49 @@
+using UnityEngine;
+using System.Collections;
+using Spine;
+
+
+public class AtlasRegionAttacher : MonoBehaviour {
+
+	[System.Serializable]
+	public class SlotRegionPair {
+		[SpineSlot]
+		public string slot;
+
+		[SpineAtlasRegion]
+		public string region;
+	}
+
+	public AtlasAsset atlasAsset;
+	public SlotRegionPair[] attachments;
+
+	[HideInInspector]
+	public SkeletonRenderer skeletonRenderer;
+
+
+	Atlas atlas;
+
+	void Start() {
+		atlas = atlasAsset.GetAtlas();
+		this.skeletonRenderer = GetComponent<SkeletonRenderer>();
+
+		AtlasAttachmentLoader loader = new AtlasAttachmentLoader(atlas);
+
+		float scaleMultiplier = skeletonRenderer.skeletonDataAsset.scale;
+
+		var enumerator = attachments.GetEnumerator();
+		while (enumerator.MoveNext()) {
+			var entry = (SlotRegionPair)enumerator.Current;
+			var regionAttachment = loader.NewRegionAttachment(null, entry.region, entry.region);
+			regionAttachment.Width = regionAttachment.RegionOriginalWidth * scaleMultiplier;
+			regionAttachment.Height = regionAttachment.RegionOriginalHeight * scaleMultiplier;
+
+			regionAttachment.SetColor(new Color(1, 1, 1, 1));
+			regionAttachment.UpdateOffset();
+
+			var slot = this.skeletonRenderer.skeleton.FindSlot(entry.slot);
+			slot.Attachment = regionAttachment;
+		}
+	}
+
+}

+ 8 - 0
spine-unity/Assets/spine-unity/AtlasRegionAttacher.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: afde57cc4fd39bb4dbd61b73403ae6a8
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 21 - 1
spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs

@@ -28,8 +28,14 @@
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
 using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
 using UnityEditor;
 using UnityEngine;
+using Spine;
+
 
 [CustomEditor(typeof(AtlasAsset))]
 public class AtlasAssetInspector : Editor {
@@ -46,9 +52,23 @@ public class AtlasAssetInspector : Editor {
 
 		EditorGUILayout.PropertyField(atlasFile);
 		EditorGUILayout.PropertyField(materials, true);
+
+
+		if (atlasFile.objectReferenceValue != null) {
+			Atlas atlas = asset.GetAtlas();
+			FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic);
+			List<AtlasRegion> regions = (List<AtlasRegion>)field.GetValue(atlas);
+			EditorGUILayout.LabelField("Regions");
+			EditorGUI.indentLevel++;
+			for (int i = 0; i < regions.Count; i++) {
+				EditorGUILayout.LabelField(regions[i].name);
+			}
+			EditorGUI.indentLevel--;
+		}
+
 		
 		if (serializedObject.ApplyModifiedProperties() ||
-			(Event.current.type == EventType.ValidateCommand && Event.current.commandName == "UndoRedoPerformed")
+			(UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed")
 		) {
 			asset.Reset();
 		}

BIN
spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png


+ 47 - 0
spine-unity/Assets/spine-unity/Editor/GUI/icon-slotRoot.png.meta

@@ -0,0 +1,47 @@
+fileFormatVersion: 2
+guid: 4a1646cf39026224c85ecba92d7d6948
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    linearTexture: 1
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 1024
+  textureSettings:
+    filterMode: -1
+    aniso: 1
+    mipBias: -1
+    wrapMode: 1
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 1
+  textureType: 2
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 

+ 7 - 7
spine-unity/Assets/spine-unity/Editor/GUI/icon-subMeshRenderer.png.meta

@@ -5,8 +5,8 @@ TextureImporter:
   serializedVersion: 2
   mipmaps:
     mipMapMode: 0
-    enableMipMap: 1
-    linearTexture: 0
+    enableMipMap: 0
+    linearTexture: 1
     correctGamma: 0
     fadeOut: 0
     borderMipMap: 0
@@ -25,10 +25,10 @@ TextureImporter:
   maxTextureSize: 1024
   textureSettings:
     filterMode: -1
-    aniso: -1
+    aniso: 1
     mipBias: -1
-    wrapMode: -1
-  nPOTScale: 1
+    wrapMode: 1
+  nPOTScale: 0
   lightmap: 0
   compressionQuality: 50
   spriteMode: 0
@@ -38,8 +38,8 @@ TextureImporter:
   spritePivot: {x: .5, y: .5}
   spriteBorder: {x: 0, y: 0, z: 0, w: 0}
   spritePixelsToUnits: 100
-  alphaIsTransparency: 0
-  textureType: -1
+  alphaIsTransparency: 1
+  textureType: 2
   buildTargetSettings: []
   spriteSheet:
     sprites: []

BIN
spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png


+ 47 - 0
spine-unity/Assets/spine-unity/Editor/GUI/icon-weights.png.meta

@@ -0,0 +1,47 @@
+fileFormatVersion: 2
+guid: 0b1bcb09fa228d049ba3c9ea6a57e1ee
+TextureImporter:
+  fileIDToRecycleName: {}
+  serializedVersion: 2
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    linearTexture: 1
+    correctGamma: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: .25
+    normalMapFilter: 0
+  isReadable: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 0
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 1024
+  textureSettings:
+    filterMode: -1
+    aniso: 1
+    mipBias: -1
+    wrapMode: 1
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: .5, y: .5}
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spritePixelsToUnits: 100
+  alphaIsTransparency: 1
+  textureType: 2
+  buildTargetSettings: []
+  spriteSheet:
+    sprites: []
+  spritePackingTag: 
+  userData: 

+ 405 - 227
spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs

@@ -44,42 +44,46 @@ using Spine;
 
 [CustomEditor(typeof(SkeletonDataAsset))]
 public class SkeletonDataAssetInspector : Editor {
-	private SerializedProperty atlasAsset, skeletonJSON, scale, fromAnimation, toAnimation, duration, defaultMix;
-	private bool showAnimationStateData = true;
-	
-	#if UNITY_4_3
-	private bool m_showAnimationList = true;
-	#else
-	private AnimBool m_showAnimationList = new AnimBool(true);
-	#endif
-	
+	static bool showAnimationStateData = true;
+	static bool showAnimationList = true;
+	static bool showSlotList = false;
+	static bool showAttachments = false;
+
+	private SerializedProperty atlasAssets, skeletonJSON, scale, fromAnimation, toAnimation, duration, defaultMix;
+
 	private bool m_initialized = false;
 	private SkeletonDataAsset m_skeletonDataAsset;
+	private SkeletonData m_skeletonData;
 	private string m_skeletonDataAssetGUID;
-	
-	void OnEnable () {
-		try {
 
-			atlasAsset = serializedObject.FindProperty("atlasAsset");
+	List<string> warnings = new List<string>();
+
+	void OnEnable() {
+
+		try {
+			atlasAssets = serializedObject.FindProperty("atlasAssets");
 			skeletonJSON = serializedObject.FindProperty("skeletonJSON");
 			scale = serializedObject.FindProperty("scale");
 			fromAnimation = serializedObject.FindProperty("fromAnimation");
 			toAnimation = serializedObject.FindProperty("toAnimation");
 			duration = serializedObject.FindProperty("duration");
 			defaultMix = serializedObject.FindProperty("defaultMix");
-			
+
 			m_skeletonDataAsset = (SkeletonDataAsset)target;
 			m_skeletonDataAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_skeletonDataAsset));
-			
-			EditorApplication.update += Update;
 
+			EditorApplication.update += Update;
 		} catch {
 
 
 		}
+
+		m_skeletonData = m_skeletonDataAsset.GetSkeletonData(true);
+
+		RepopulateWarnings();
 	}
-	
-	void OnDestroy () {
+
+	void OnDestroy() {
 		m_initialized = false;
 		EditorApplication.update -= Update;
 		this.DestroyPreviewInstances();
@@ -88,13 +92,13 @@ public class SkeletonDataAssetInspector : Editor {
 			this.m_previewUtility = null;
 		}
 	}
-	
-	override public void OnInspectorGUI () {
+
+	override public void OnInspectorGUI() {
 		serializedObject.Update();
 		SkeletonDataAsset asset = (SkeletonDataAsset)target;
-		
+
 		EditorGUI.BeginChangeCheck();
-		EditorGUILayout.PropertyField(atlasAsset);
+		EditorGUILayout.PropertyField(atlasAssets, true);
 		EditorGUILayout.PropertyField(skeletonJSON);
 		EditorGUILayout.PropertyField(scale);
 		if (EditorGUI.EndChangeCheck()) {
@@ -102,142 +106,301 @@ public class SkeletonDataAssetInspector : Editor {
 				m_previewUtility.Cleanup();
 				m_previewUtility = null;
 			}
+
+			RepopulateWarnings();
 		}
+
 		
-		SkeletonData skeletonData = asset.GetSkeletonData(asset.atlasAsset == null || asset.skeletonJSON == null);
-		if (skeletonData != null) {
-			showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data");
-			if (showAnimationStateData) {
-				EditorGUILayout.PropertyField(defaultMix);
-				
-				// Animation names
-				String[] animations = new String[skeletonData.Animations.Count];
-				for (int i = 0; i < animations.Length; i++)
-					animations[i] = skeletonData.Animations[i].Name;
-				
-				for (int i = 0; i < fromAnimation.arraySize; i++) {
-					SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i);
-					SerializedProperty to = toAnimation.GetArrayElementAtIndex(i);
-					SerializedProperty durationProp = duration.GetArrayElementAtIndex(i);
-					EditorGUILayout.BeginHorizontal();
-					from.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, from.stringValue), 0), animations)];
-					to.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, to.stringValue), 0), animations)];
-					durationProp.floatValue = EditorGUILayout.FloatField(durationProp.floatValue);
-					if (GUILayout.Button("Delete")) {
-						duration.DeleteArrayElementAtIndex(i);
-						toAnimation.DeleteArrayElementAtIndex(i);
-						fromAnimation.DeleteArrayElementAtIndex(i);
+		if (m_skeletonData != null) {
+
+			DrawAnimationStateInfo();
+			DrawAnimationList();
+			DrawSlotList();
+			
+		} else {
+			//Show Warnings
+			foreach (var str in warnings)
+				EditorGUILayout.LabelField(new GUIContent(str, SpineEditorUtilities.Icons.warning));
+		}
+
+		if (!Application.isPlaying) {
+			if (serializedObject.ApplyModifiedProperties() ||
+				(UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed")
+					) {
+				asset.Reset();
+			}
+		}
+	}
+
+	void DrawAnimationStateInfo() {
+		showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data");
+		if (!showAnimationStateData)
+			return;
+
+		EditorGUILayout.PropertyField(defaultMix);
+
+		// Animation names
+		String[] animations = new String[m_skeletonData.Animations.Count];
+		for (int i = 0; i < animations.Length; i++)
+			animations[i] = m_skeletonData.Animations[i].Name;
+
+		for (int i = 0; i < fromAnimation.arraySize; i++) {
+			SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i);
+			SerializedProperty to = toAnimation.GetArrayElementAtIndex(i);
+			SerializedProperty durationProp = duration.GetArrayElementAtIndex(i);
+			EditorGUILayout.BeginHorizontal();
+			from.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, from.stringValue), 0), animations)];
+			to.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, to.stringValue), 0), animations)];
+			durationProp.floatValue = EditorGUILayout.FloatField(durationProp.floatValue);
+			if (GUILayout.Button("Delete")) {
+				duration.DeleteArrayElementAtIndex(i);
+				toAnimation.DeleteArrayElementAtIndex(i);
+				fromAnimation.DeleteArrayElementAtIndex(i);
+			}
+			EditorGUILayout.EndHorizontal();
+		}
+		EditorGUILayout.BeginHorizontal();
+		EditorGUILayout.Space();
+		if (GUILayout.Button("Add Mix")) {
+			duration.arraySize++;
+			toAnimation.arraySize++;
+			fromAnimation.arraySize++;
+		}
+		EditorGUILayout.Space();
+		EditorGUILayout.EndHorizontal();
+		
+	}
+	void DrawAnimationList() {
+		showAnimationList = EditorGUILayout.Foldout(showAnimationList, new GUIContent("Animations", SpineEditorUtilities.Icons.animationRoot));
+		if (!showAnimationList)
+			return;
+
+		if (GUILayout.Button(new GUIContent("Setup Pose", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) {
+			StopAnimation();
+			m_skeletonAnimation.skeleton.SetToSetupPose();
+			m_requireRefresh = true;
+		}
+
+		EditorGUILayout.LabelField("Name", "Duration");
+		foreach (Spine.Animation a in m_skeletonData.Animations) {
+			GUILayout.BeginHorizontal();
+
+			if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) {
+				if (m_skeletonAnimation.state.GetCurrent(0) != null && m_skeletonAnimation.state.GetCurrent(0).Animation == a) {
+					GUI.contentColor = Color.black;
+					if (GUILayout.Button("\u25BA", GUILayout.Width(24))) {
+						StopAnimation();
+					}
+					GUI.contentColor = Color.white;
+				} else {
+					if (GUILayout.Button("\u25BA", GUILayout.Width(24))) {
+						PlayAnimation(a.Name, true);
 					}
-					EditorGUILayout.EndHorizontal();
-				}
-				EditorGUILayout.BeginHorizontal();
-				EditorGUILayout.Space();
-				if (GUILayout.Button("Add Mix")) {
-					duration.arraySize++;
-					toAnimation.arraySize++;
-					fromAnimation.arraySize++;
 				}
-				EditorGUILayout.Space();
-				EditorGUILayout.EndHorizontal();
-			}
-			
-			if (GUILayout.Button(new GUIContent("Setup Pose", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) {
-				StopAnimation();
-				m_skeletonAnimation.skeleton.SetToSetupPose();
-				m_requireRefresh = true;
+			} else {
+				GUILayout.Label("?", GUILayout.Width(24));
 			}
-			
-			#if UNITY_4_3
-			m_showAnimationList = EditorGUILayout.Foldout(m_showAnimationList, new GUIContent("Animations", SpineEditorUtilities.Icons.animationRoot));
-			if(m_showAnimationList){
-			#else
-			m_showAnimationList.target = EditorGUILayout.Foldout(m_showAnimationList.target, new GUIContent("Animations", SpineEditorUtilities.Icons.animationRoot));
-			if (EditorGUILayout.BeginFadeGroup(m_showAnimationList.faded)) {
-				#endif
-					
-					
+			EditorGUILayout.LabelField(new GUIContent(a.Name, SpineEditorUtilities.Icons.animation), new GUIContent(a.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(a.Duration * 30)) + ")").PadLeft(12, ' ')));
+			GUILayout.EndHorizontal();
+		}
+	}
+
+	
+	void DrawSlotList() {
+		showSlotList = EditorGUILayout.Foldout(showSlotList, new GUIContent("Slots", SpineEditorUtilities.Icons.slotRoot));
+
+		if (!showSlotList)
+			return;
+
+		if (m_skeletonAnimation == null || m_skeletonAnimation.skeleton == null)
+			return;
+
+		EditorGUI.indentLevel++;
+		try {
+			showAttachments = EditorGUILayout.ToggleLeft("Show Attachments", showAttachments);
+		} catch {
+			return;
+		}
+
+		
+		List<Attachment> slotAttachments = new List<Attachment>();
+		List<string> slotAttachmentNames = new List<string>();
+		List<string> defaultSkinAttachmentNames = new List<string>();
+		var defaultSkin = m_skeletonData.Skins[0];
+		Skin skin = m_skeletonAnimation.skeleton.Skin;
+		if (skin == null) {
+			skin = defaultSkin;
+		}
+
+		for (int i = m_skeletonAnimation.skeleton.Slots.Count-1; i >= 0; i--) {
+			Slot slot = m_skeletonAnimation.skeleton.Slots[i];
+			EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, SpineEditorUtilities.Icons.slot));
+			if (showAttachments) {
+				
+
+				EditorGUI.indentLevel++;
+				slotAttachments.Clear();
+				slotAttachmentNames.Clear();
+				defaultSkinAttachmentNames.Clear();
+
+				skin.FindNamesForSlot(i, slotAttachmentNames);
+				skin.FindAttachmentsForSlot(i, slotAttachments);
+
+				
+				if (skin != defaultSkin) {
+					defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames);
+					defaultSkin.FindNamesForSlot(i, slotAttachmentNames);
+					defaultSkin.FindAttachmentsForSlot(i, slotAttachments);
+				} else {
+					defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames);
+				}
+				
+
+
+				for (int a = 0; a < slotAttachments.Count; a++) {
+					Attachment attachment = slotAttachments[a];
+					string name = slotAttachmentNames[a];
+
+					Texture2D icon = null;
+					var type = attachment.GetType();
+
+					if (type == typeof(RegionAttachment))
+						icon = SpineEditorUtilities.Icons.image;
+					else if (type == typeof(MeshAttachment))
+						icon = SpineEditorUtilities.Icons.mesh;
+					else if (type == typeof(BoundingBoxAttachment))
+						icon = SpineEditorUtilities.Icons.boundingBox;
+					else if (type == typeof(SkinnedMeshAttachment))
+						icon = SpineEditorUtilities.Icons.weights;
+					else
+						icon = SpineEditorUtilities.Icons.warning;
+
+					//TODO:  Waterboard Nate
+					//if (name != attachment.Name)
+						//icon = SpineEditorUtilities.Icons.skinPlaceholder;
+
+					bool initialState = slot.Attachment == attachment;
 					
+					bool toggled = EditorGUILayout.ToggleLeft(new GUIContent(name, icon), slot.Attachment == attachment);
+
+					if (!defaultSkinAttachmentNames.Contains(name)) {
+						Rect skinPlaceHolderIconRect = GUILayoutUtility.GetLastRect();
+						skinPlaceHolderIconRect.width = SpineEditorUtilities.Icons.skinPlaceholder.width;
+						skinPlaceHolderIconRect.height = SpineEditorUtilities.Icons.skinPlaceholder.height;
+						GUI.DrawTexture(skinPlaceHolderIconRect, SpineEditorUtilities.Icons.skinPlaceholder);
+					}
 					
-				EditorGUILayout.LabelField("Name", "Duration");
-				foreach (Spine.Animation a in skeletonData.Animations) {
-					GUILayout.BeginHorizontal();
-						
-					if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) {
-						if (m_skeletonAnimation.state.GetCurrent(0) != null && m_skeletonAnimation.state.GetCurrent(0).Animation == a) {
-							GUI.contentColor = Color.black;
-							if (GUILayout.Button("\u25BA", GUILayout.Width(24))) {
-								StopAnimation();
-							}
-							GUI.contentColor = Color.white;
+
+					if (toggled != initialState) {
+						if (toggled) {
+							slot.Attachment = attachment;
 						} else {
-							if (GUILayout.Button("\u25BA", GUILayout.Width(24))) {
-								PlayAnimation(a.Name, true);
-							}
+							slot.Attachment = null;
 						}
-					} else {
-						GUILayout.Label("?", GUILayout.Width(24));
+						m_requireRefresh = true;
 					}
-					EditorGUILayout.LabelField(new GUIContent(a.Name, SpineEditorUtilities.Icons.animation), new GUIContent(a.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(a.Duration * 30)) + ")").PadLeft(12, ' ')));
-					GUILayout.EndHorizontal();
 				}
+				
+				
+				EditorGUI.indentLevel--;
 			}
-			#if !UNITY_4_3
-			EditorGUILayout.EndFadeGroup();
-			#endif
 		}
-			
-		if (!Application.isPlaying) {
-			if (serializedObject.ApplyModifiedProperties() ||
-				(UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed")
-				    ) {
-				asset.Reset();
+
+		EditorGUI.indentLevel--;
+	}
+
+
+	void RepopulateWarnings() {
+		warnings.Clear();
+
+		if (skeletonJSON.objectReferenceValue == null)
+			warnings.Add("Missing Skeleton JSON");
+		else {
+
+			if (SpineEditorUtilities.IsSpineJSON((TextAsset)skeletonJSON.objectReferenceValue) == false) {
+				warnings.Add("Skeleton JSON is not a Valid JSON file");
+			} else {
+				bool detectedNullAtlasEntry = false;
+				List<Atlas> atlasList = new List<Atlas>();
+				for (int i = 0; i < atlasAssets.arraySize; i++) {
+					if (atlasAssets.GetArrayElementAtIndex(i).objectReferenceValue == null) {
+						detectedNullAtlasEntry = true;
+						break;
+					} else {
+						atlasList.Add(((AtlasAsset)atlasAssets.GetArrayElementAtIndex(i).objectReferenceValue).GetAtlas());
+					}
+				}
+
+				if (detectedNullAtlasEntry)
+					warnings.Add("AtlasAsset elements cannot be Null");
+				else {
+					//get requirements
+					var missingPaths = SpineEditorUtilities.GetRequiredAtlasRegions(AssetDatabase.GetAssetPath((TextAsset)skeletonJSON.objectReferenceValue));
+
+					foreach (var atlas in atlasList) {
+						for (int i = 0; i < missingPaths.Count; i++) {
+							if (atlas.FindRegion(missingPaths[i]) != null) {
+								missingPaths.RemoveAt(i);
+								i--;
+							}
+						}
+					}
+
+					foreach (var str in missingPaths)
+						warnings.Add("Missing Region: '" + str + "'");
+
+
+
+				}
 			}
+
+
 		}
 	}
-		
+
 	//preview window stuff
 	private PreviewRenderUtility m_previewUtility;
 	private GameObject m_previewInstance;
 	private Vector2 previewDir;
 	private SkeletonAnimation m_skeletonAnimation;
-	private SkeletonData m_skeletonData;
+	//private SkeletonData m_skeletonData;
 	private static int sliderHash = "Slider".GetHashCode();
 	private float m_lastTime;
 	private bool m_playing;
 	private bool m_requireRefresh;
 	private Color m_originColor = new Color(0.3f, 0.3f, 0.3f, 1);
-		
-	private void StopAnimation () {
+
+	private void StopAnimation() {
 		m_skeletonAnimation.state.ClearTrack(0);
 		m_playing = false;
 	}
-		
+
 	List<Spine.Event> m_animEvents = new List<Spine.Event>();
 	List<float> m_animEventFrames = new List<float>();
 
-	private void PlayAnimation (string animName, bool loop) {
+	private void PlayAnimation(string animName, bool loop) {
 		m_animEvents.Clear();
 		m_animEventFrames.Clear();
-			
+
 		m_skeletonAnimation.state.SetAnimation(0, animName, loop);
-			
+
 		Spine.Animation a = m_skeletonAnimation.state.GetCurrent(0).Animation;
 		foreach (Timeline t in a.Timelines) {
 			if (t.GetType() == typeof(EventTimeline)) {
 				EventTimeline et = (EventTimeline)t;
-					
+
 				for (int i = 0; i < et.Events.Length; i++) {
 					m_animEvents.Add(et.Events[i]);
 					m_animEventFrames.Add(et.Frames[i]);
 				}
-					
+
 			}
 		}
-			
+
 		m_playing = true;
 	}
-		
-	private void InitPreview () {
+
+	private void InitPreview() {
 		if (this.m_previewUtility == null) {
 			this.m_lastTime = Time.realtimeSinceStartup;
 			this.m_previewUtility = new PreviewRenderUtility(true);
@@ -247,48 +410,59 @@ public class SkeletonDataAssetInspector : Editor {
 			this.CreatePreviewInstances();
 		}
 	}
-		
-	private void CreatePreviewInstances () {
+
+	private void CreatePreviewInstances() {
 		this.DestroyPreviewInstances();
 		if (this.m_previewInstance == null) {
-			string skinName = EditorPrefs.GetString(m_skeletonDataAssetGUID + "_lastSkin", "");
-				
-			m_previewInstance = SpineEditorUtilities.SpawnAnimatedSkeleton((SkeletonDataAsset)target, skinName).gameObject;
-			m_previewInstance.hideFlags = HideFlags.HideAndDontSave;
-			m_previewInstance.layer = 0x1f;
-				
-				
-			m_skeletonAnimation = m_previewInstance.GetComponent<SkeletonAnimation>();
-			m_skeletonAnimation.initialSkinName = skinName;
-			m_skeletonAnimation.LateUpdate();
-				
-			m_skeletonData = m_skeletonAnimation.skeletonDataAsset.GetSkeletonData(true);
-				
-			m_previewInstance.renderer.enabled = false;
-				
-			m_initialized = true;
-			AdjustCameraGoals(true);
+			try {
+				string skinName = EditorPrefs.GetString(m_skeletonDataAssetGUID + "_lastSkin", "");
+
+				m_previewInstance = SpineEditorUtilities.SpawnAnimatedSkeleton((SkeletonDataAsset)target, skinName).gameObject;
+				m_previewInstance.hideFlags = HideFlags.HideAndDontSave;
+				m_previewInstance.layer = 0x1f;
+
+
+				m_skeletonAnimation = m_previewInstance.GetComponent<SkeletonAnimation>();
+				m_skeletonAnimation.initialSkinName = skinName;
+				m_skeletonAnimation.LateUpdate();
+
+				m_skeletonData = m_skeletonAnimation.skeletonDataAsset.GetSkeletonData(true);
+
+				m_previewInstance.renderer.enabled = false;
+
+				m_initialized = true;
+				AdjustCameraGoals(true);
+			} catch {
+
+			}
 		}
 	}
-		
-	private void DestroyPreviewInstances () {
+
+	private void DestroyPreviewInstances() {
 		if (this.m_previewInstance != null) {
 			DestroyImmediate(this.m_previewInstance);
 			m_previewInstance = null;
 		}
 		m_initialized = false;
 	}
-		
-	public override bool HasPreviewGUI () {
+
+	public override bool HasPreviewGUI() {
 		//TODO: validate json data
+
+		for (int i = 0; i < atlasAssets.arraySize; i++) {
+			var prop = atlasAssets.GetArrayElementAtIndex(i);
+			if (prop.objectReferenceValue == null)
+				return false;
+		}
+
 		return skeletonJSON.objectReferenceValue != null;
 	}
-		
+
 	Texture m_previewTex = new Texture();
 
-	public override void OnInteractivePreviewGUI (Rect r, GUIStyle background) {
+	public override void OnInteractivePreviewGUI(Rect r, GUIStyle background) {
 		this.InitPreview();
-			
+
 		if (UnityEngine.Event.current.type == EventType.Repaint) {
 			if (m_requireRefresh) {
 				this.m_previewUtility.BeginPreview(r, background);
@@ -299,50 +473,54 @@ public class SkeletonDataAssetInspector : Editor {
 			if (this.m_previewTex != null)
 				GUI.DrawTexture(r, m_previewTex, ScaleMode.StretchToFill, false);
 		}
-			
+
 		DrawSkinToolbar(r);
 		NormalizedTimeBar(r);
 		//TODO: implement panning
 		//		this.previewDir = Drag2D(this.previewDir, r);
 		MouseScroll(r);
 	}
-		
+
 	float m_orthoGoal = 1;
 	Vector3 m_posGoal = new Vector3(0, 0, -10);
 	double m_adjustFrameEndTime = 0;
 
-	private void AdjustCameraGoals (bool calculateMixTime) {
+	private void AdjustCameraGoals(bool calculateMixTime) {
+		if (this.m_previewInstance == null)
+			return;
+
 		if (calculateMixTime) {
 			if (m_skeletonAnimation.state.GetCurrent(0) != null) {
 				m_adjustFrameEndTime = EditorApplication.timeSinceStartup + m_skeletonAnimation.state.GetCurrent(0).Mix;
 			}
 		}
-			
-			
+
+
 		GameObject go = this.m_previewInstance;
+
 		Bounds bounds = go.renderer.bounds;
 		m_orthoGoal = bounds.size.y;
-			
+
 		m_posGoal = bounds.center + new Vector3(0, 0, -10);
 	}
-		
-	private void AdjustCameraGoals () {
+
+	private void AdjustCameraGoals() {
 		AdjustCameraGoals(false);
 	}
-		
-	private void AdjustCamera () {
+
+	private void AdjustCamera() {
 		if (m_previewUtility == null)
 			return;
-			
-			
+
+
 		if (EditorApplication.timeSinceStartup < m_adjustFrameEndTime) {
 			AdjustCameraGoals();
 		}
-			
+
 		float orthoSet = Mathf.Lerp(this.m_previewUtility.m_Camera.orthographicSize, m_orthoGoal, 0.1f);
-			
+
 		this.m_previewUtility.m_Camera.orthographicSize = orthoSet;
-			
+
 		float dist = Vector3.Distance(m_previewUtility.m_Camera.transform.position, m_posGoal);
 		if (dist > 60f * ((SkeletonDataAsset)target).scale) {
 			Vector3 pos = Vector3.Lerp(this.m_previewUtility.m_Camera.transform.position, m_posGoal, 0.1f);
@@ -352,138 +530,138 @@ public class SkeletonDataAssetInspector : Editor {
 			m_requireRefresh = true;
 		}
 	}
-		
-	private void DoRenderPreview (bool drawHandles) {
+
+	private void DoRenderPreview(bool drawHandles) {
 		GameObject go = this.m_previewInstance;
-			
-		if (m_requireRefresh) {
+
+		if (m_requireRefresh && go != null) {
 			go.renderer.enabled = true;
-				
+
 			if (EditorApplication.isPlaying) {
 				//do nothing
 			} else {
 				m_skeletonAnimation.Update((Time.realtimeSinceStartup - m_lastTime));
 			}
-				
+
 			m_lastTime = Time.realtimeSinceStartup;
-				
+
 			if (!EditorApplication.isPlaying)
 				m_skeletonAnimation.LateUpdate();
-				
+
 			if (drawHandles) {
 				Handles.SetCamera(m_previewUtility.m_Camera);
 				Handles.color = m_originColor;
-					
+
 				Handles.DrawLine(new Vector3(-1000 * m_skeletonDataAsset.scale, 0, 0), new Vector3(1000 * m_skeletonDataAsset.scale, 0, 0));
 				Handles.DrawLine(new Vector3(0, 1000 * m_skeletonDataAsset.scale, 0), new Vector3(0, -1000 * m_skeletonDataAsset.scale, 0));
 			}
-				
+
 			this.m_previewUtility.m_Camera.Render();
 			go.renderer.enabled = false;
 		}
-			
-			
+
+
 	}
-		
-	void Update () {
+
+	void Update() {
 		AdjustCamera();
-			
+
 		if (m_playing) {
 			m_requireRefresh = true;
 			Repaint();
 		} else if (m_requireRefresh) {
-				Repaint();
-			} else {
-				#if !UNITY_4_3
-				if (m_showAnimationList.isAnimating)
-					Repaint();
-				#endif
-			}
+			Repaint();
+		} else {
+			//only needed if using smooth menus
+		}
 	}
-		
-	void DrawSkinToolbar (Rect r) {
+
+	void DrawSkinToolbar(Rect r) {
 		if (m_skeletonAnimation == null)
 			return;
-			
+
 		if (m_skeletonAnimation.skeleton != null) {
 			string label = (m_skeletonAnimation.skeleton != null && m_skeletonAnimation.skeleton.Skin != null) ? m_skeletonAnimation.skeleton.Skin.Name : "default";
-				
+
 			Rect popRect = new Rect(r);
 			popRect.y += 32;
 			popRect.x += 4;
 			popRect.height = 24;
 			popRect.width = 40;
 			EditorGUI.DropShadowLabel(popRect, new GUIContent("Skin", SpineEditorUtilities.Icons.skinsRoot));
-				
+
 			popRect.y += 11;
 			popRect.width = 150;
 			popRect.x += 44;
-				
+
 			if (GUI.Button(popRect, label, EditorStyles.popup)) {
 				SelectSkinContext();
 			}
 		}
 	}
-		
-	void SelectSkinContext () {
+
+	void SelectSkinContext() {
 		GenericMenu menu = new GenericMenu();
-			
+
 		foreach (Skin s in m_skeletonData.Skins) {
 			menu.AddItem(new GUIContent(s.Name), this.m_skeletonAnimation.skeleton.Skin == s, SetSkin, (object)s);
 		}
-			
+
 		menu.ShowAsContext();
 	}
-		
-	void SetSkin (object o) {
+
+	void SetSkin(object o) {
 		Skin skin = (Skin)o;
-			
+
 		m_skeletonAnimation.initialSkinName = skin.Name;
 		m_skeletonAnimation.Reset();
 		m_requireRefresh = true;
-			
+
 		EditorPrefs.SetString(m_skeletonDataAssetGUID + "_lastSkin", skin.Name);
 	}
-		
-	void NormalizedTimeBar (Rect r) {
+
+	void NormalizedTimeBar(Rect r) {
+		if (m_skeletonAnimation == null)
+			return;
+
 		Rect barRect = new Rect(r);
 		barRect.height = 32;
 		barRect.x += 4;
 		barRect.width -= 4;
-			
+
 		GUI.Box(barRect, "");
-			
+
 		Rect lineRect = new Rect(barRect);
 		float width = lineRect.width;
 		TrackEntry t = m_skeletonAnimation.state.GetCurrent(0);
-			
+
 		if (t != null) {
 			int loopCount = (int)(t.Time / t.EndTime);
 			float currentTime = t.Time - (t.EndTime * loopCount);
-				
+
 			float normalizedTime = currentTime / t.Animation.Duration;
-				
+
 			lineRect.x = barRect.x + (width * normalizedTime) - 0.5f;
 			lineRect.width = 2;
-				
+
 			GUI.color = Color.red;
 			GUI.DrawTexture(lineRect, EditorGUIUtility.whiteTexture);
 			GUI.color = Color.white;
-				
+
 			for (int i = 0; i < m_animEvents.Count; i++) {
 				//TODO: Tooltip
 				//Spine.Event spev = animEvents[i];
-					
+
 				float fr = m_animEventFrames[i];
-					
+
 				Rect evRect = new Rect(barRect);
 				evRect.x = Mathf.Clamp(((fr / t.Animation.Duration) * width) - (SpineEditorUtilities.Icons._event.width / 2), barRect.x, float.MaxValue);
 				evRect.width = SpineEditorUtilities.Icons._event.width;
 				evRect.height = SpineEditorUtilities.Icons._event.height;
 				evRect.y += SpineEditorUtilities.Icons._event.height;
 				GUI.DrawTexture(evRect, SpineEditorUtilities.Icons._event);
-					
-					
+
+
 				//TODO:  Tooltip
 				/*
 				UnityEngine.Event ev = UnityEngine.Event.current;
@@ -500,24 +678,24 @@ public class SkeletonDataAssetInspector : Editor {
 			}
 		}
 	}
-		
-	void MouseScroll (Rect position) {
+
+	void MouseScroll(Rect position) {
 		UnityEngine.Event current = UnityEngine.Event.current;
 		int controlID = GUIUtility.GetControlID(sliderHash, FocusType.Passive);
-			
+
 		switch (current.GetTypeForControl(controlID)) {
-		case EventType.ScrollWheel:
-			if (position.Contains(current.mousePosition)) {
-					
-				m_orthoGoal += current.delta.y * ((SkeletonDataAsset)target).scale * 10;
-				GUIUtility.hotControl = controlID;
-				current.Use();
-			}
-			break;
+			case EventType.ScrollWheel:
+				if (position.Contains(current.mousePosition)) {
+
+					m_orthoGoal += current.delta.y * ((SkeletonDataAsset)target).scale * 10;
+					GUIUtility.hotControl = controlID;
+					current.Use();
+				}
+				break;
 		}
-			
+
 	}
-		
+
 	//TODO:  Implement preview panning
 	/*
 	static Vector2 Drag2D(Vector2 scrollPosition, Rect position)
@@ -559,45 +737,45 @@ public class SkeletonDataAssetInspector : Editor {
 		return scrollPosition;
 	}
 	*/
-		
-	public override GUIContent GetPreviewTitle () {
+
+	public override GUIContent GetPreviewTitle() {
 		return new GUIContent("Preview");
 	}
-		
-	public override void OnPreviewSettings () {
+
+	public override void OnPreviewSettings() {
 		if (!m_initialized) {
 			GUILayout.HorizontalSlider(0, 0, 2, GUILayout.MaxWidth(64));
 		} else {
 			float speed = GUILayout.HorizontalSlider(m_skeletonAnimation.timeScale, 0, 2, GUILayout.MaxWidth(64));
-				
+
 			//snap to nearest 0.25
 			float y = speed / 0.25f;
 			int q = Mathf.RoundToInt(y);
 			speed = q * 0.25f;
-				
+
 			m_skeletonAnimation.timeScale = speed;
 		}
 	}
-		
+
 	//TODO:  Fix first-import error
 	//TODO:  Update preview without thumbnail
-	public override Texture2D RenderStaticPreview (string assetPath, UnityEngine.Object[] subAssets, int width, int height) {
+	public override Texture2D RenderStaticPreview(string assetPath, UnityEngine.Object[] subAssets, int width, int height) {
 		Texture2D tex = new Texture2D(width, height, TextureFormat.ARGB32, false);
-			
+
 		this.InitPreview();
-			
+
 		if (this.m_previewUtility.m_Camera == null)
 			return null;
-			
+
 		m_requireRefresh = true;
 		this.DoRenderPreview(false);
 		AdjustCameraGoals(false);
-			
+
 		this.m_previewUtility.m_Camera.orthographicSize = m_orthoGoal / 2;
 		this.m_previewUtility.m_Camera.transform.position = m_posGoal;
 		this.m_previewUtility.BeginStaticPreview(new Rect(0, 0, width, height));
 		this.DoRenderPreview(false);
-			
+
 		//TODO:  Figure out why this is throwing errors on first attempt
 		//		if(m_previewUtility != null){
 		//			Handles.SetCamera(this.m_previewUtility.m_Camera);

+ 8 - 3
spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs

@@ -33,7 +33,7 @@ using UnityEngine;
 
 [CustomEditor(typeof(SkeletonRenderer))]
 public class SkeletonRendererInspector : Editor {
-	protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles;
+	protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, submeshSeparators;
 
 	protected virtual void OnEnable () {
 		skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset");
@@ -42,6 +42,7 @@ public class SkeletonRendererInspector : Editor {
 		tangents = serializedObject.FindProperty("calculateTangents");
 		meshes = serializedObject.FindProperty("renderMeshes");
 		immutableTriangles = serializedObject.FindProperty("immutableTriangles");
+		submeshSeparators = serializedObject.FindProperty("submeshSeparators");
 	}
 
 	protected virtual void gui () {
@@ -52,8 +53,11 @@ public class SkeletonRendererInspector : Editor {
 		float reloadWidth = GUI.skin.label.CalcSize(new GUIContent("Reload")).x + 20;
 		if (GUILayout.Button("Reload", GUILayout.Width(reloadWidth))) {
 			if (component.skeletonDataAsset != null) {
-				if (component.skeletonDataAsset.atlasAsset != null)
-					component.skeletonDataAsset.atlasAsset.Reset();
+				foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) {
+					if (aa != null)
+						aa.Reset();
+				}
+				
 				component.skeletonDataAsset.Reset();
 			}
 			component.Reset();
@@ -92,6 +96,7 @@ public class SkeletonRendererInspector : Editor {
 			new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility"));
 		EditorGUILayout.PropertyField(normals);
 		EditorGUILayout.PropertyField(tangents);
+		EditorGUILayout.PropertyField(submeshSeparators, true);
 	}
 
 	override public void OnInspectorGUI () {

+ 456 - 0
spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs

@@ -0,0 +1,456 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Linq;
+using System.Reflection;
+using Spine;
+
+
+public struct SpineDrawerValuePair {
+	public string str;
+	public SerializedProperty property;
+
+	public SpineDrawerValuePair(string val, SerializedProperty property) {
+		this.str = val;
+		this.property = property;
+	}
+}
+
+[CustomPropertyDrawer(typeof(SpineSlot))]
+public class SpineSlotDrawer : PropertyDrawer {
+	SkeletonDataAsset skeletonDataAsset;
+
+
+	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
+		if (property.propertyType != SerializedPropertyType.String) {
+			EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
+			return;
+		}
+
+		SpineSlot attrib = (SpineSlot)attribute;
+
+		var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
+
+		if (skeletonDataAssetProperty != null) {
+			if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
+				skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
+			} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
+				var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
+				if (renderer != null)
+					skeletonDataAsset = renderer.skeletonDataAsset;
+			} else {
+				EditorGUI.LabelField(position, "ERROR:", "Invalid reference type");
+				return;
+			}
+
+		} else if (property.serializedObject.targetObject is Component) {
+			var component = (Component)property.serializedObject.targetObject;
+			if (component.GetComponent<SkeletonRenderer>() != null) {
+				var skeletonRenderer = component.GetComponent<SkeletonRenderer>();
+				skeletonDataAsset = skeletonRenderer.skeletonDataAsset;
+			}
+		}
+
+		if (skeletonDataAsset == null) {
+			EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset");
+			return;
+		}
+
+		position = EditorGUI.PrefixLabel(position, label);
+
+		if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
+			Selector(property);
+		}
+
+	}
+
+	void Selector(SerializedProperty property) {
+		SpineSlot attrib = (SpineSlot)attribute;
+		SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
+		if (data == null)
+			return;
+
+		GenericMenu menu = new GenericMenu();
+
+		menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
+		menu.AddSeparator("");
+
+		for (int i = 0; i < data.Slots.Count; i++) {
+			string name = data.Slots[i].Name;
+			if (name.StartsWith(attrib.startsWith))
+				menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
+		}
+
+		menu.ShowAsContext();
+	}
+
+	void HandleSelect(object val) {
+		var pair = (SpineDrawerValuePair)val;
+		pair.property.stringValue = pair.str;
+		pair.property.serializedObject.ApplyModifiedProperties();
+	}
+
+	public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
+		return 18;
+	}
+}
+
+[CustomPropertyDrawer(typeof(SpineSkin))]
+public class SpineSkinDrawer : PropertyDrawer {
+	SkeletonDataAsset skeletonDataAsset;
+
+
+	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
+		if (property.propertyType != SerializedPropertyType.String) {
+			EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
+			return;
+		}
+
+		SpineSkin attrib = (SpineSkin)attribute;
+
+		var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
+
+		if (skeletonDataAssetProperty != null) {
+			if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
+				skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
+			} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
+				var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
+				if (renderer != null)
+					skeletonDataAsset = renderer.skeletonDataAsset;
+			} else {
+				EditorGUI.LabelField(position, "ERROR:", "Invalid reference type");
+				return;
+			}
+
+		} else if (property.serializedObject.targetObject is Component) {
+			var component = (Component)property.serializedObject.targetObject;
+			if (component.GetComponent<SkeletonRenderer>() != null) {
+				var skeletonRenderer = component.GetComponent<SkeletonRenderer>();
+				skeletonDataAsset = skeletonRenderer.skeletonDataAsset;
+			}
+		}
+
+		if (skeletonDataAsset == null) {
+			EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset");
+			return;
+		}
+
+		position = EditorGUI.PrefixLabel(position, label);
+
+		if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
+			Selector(property);
+		}
+
+	}
+
+	void Selector(SerializedProperty property) {
+		SpineSkin attrib = (SpineSkin)attribute;
+		SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
+		if (data == null)
+			return;
+
+		GenericMenu menu = new GenericMenu();
+
+		menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
+		menu.AddSeparator("");
+
+		for (int i = 0; i < data.Skins.Count; i++) {
+			string name = data.Skins[i].Name;
+			if (name.StartsWith(attrib.startsWith))
+				menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
+		}
+
+		menu.ShowAsContext();
+	}
+
+	void HandleSelect(object val) {
+		var pair = (SpineDrawerValuePair)val;
+		pair.property.stringValue = pair.str;
+		pair.property.serializedObject.ApplyModifiedProperties();
+	}
+
+	public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
+		return 18;
+	}
+}
+
+[CustomPropertyDrawer(typeof(SpineAtlasRegion))]
+public class SpineAtlasRegionDrawer : PropertyDrawer {
+	Component component;
+	SerializedProperty atlasProp;
+
+	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
+		if (property.propertyType != SerializedPropertyType.String) {
+			EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
+			return;
+		}
+
+		component = (Component)property.serializedObject.targetObject;
+
+		if (component != null)
+			atlasProp = property.serializedObject.FindProperty("atlasAsset");
+		else
+			atlasProp = null;
+
+
+		if (atlasProp == null) {
+			EditorGUI.LabelField(position, "ERROR:", "Must have AtlasAsset variable!");
+			return;
+		} else if (atlasProp.objectReferenceValue == null) {
+			EditorGUI.LabelField(position, "ERROR:", "Atlas variable must not be null!");
+			return;
+		} else if (atlasProp.objectReferenceValue.GetType() != typeof(AtlasAsset)) {
+			EditorGUI.LabelField(position, "ERROR:", "Atlas variable must be of type AtlasAsset!");
+		}
+
+		position = EditorGUI.PrefixLabel(position, label);
+
+		if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
+			Selector(property);
+		}
+
+	}
+
+	void Selector(SerializedProperty property) {
+		GenericMenu menu = new GenericMenu();
+		AtlasAsset atlasAsset = (AtlasAsset)atlasProp.objectReferenceValue;
+		Atlas atlas = atlasAsset.GetAtlas();
+		FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic);
+		List<AtlasRegion> regions = (List<AtlasRegion>)field.GetValue(atlas);
+
+		for (int i = 0; i < regions.Count; i++) {
+			string name = regions[i].name;
+			menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
+		}
+
+
+		menu.ShowAsContext();
+	}
+
+	void HandleSelect(object val) {
+		var pair = (SpineDrawerValuePair)val;
+		pair.property.stringValue = pair.str;
+		pair.property.serializedObject.ApplyModifiedProperties();
+	}
+
+	public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
+		return 18;
+	}
+}
+
+[CustomPropertyDrawer(typeof(SpineAnimation))]
+public class SpineAnimationDrawer : PropertyDrawer {
+	SkeletonDataAsset skeletonDataAsset;
+
+
+	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
+
+
+		if (property.propertyType != SerializedPropertyType.String) {
+			EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
+			return;
+		}
+
+		SpineAnimation attrib = (SpineAnimation)attribute;
+
+		var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
+
+		if (skeletonDataAssetProperty != null) {
+			if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
+				skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
+			} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
+				var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
+				if (renderer != null)
+					skeletonDataAsset = renderer.skeletonDataAsset;
+			} else {
+				EditorGUI.LabelField(position, "ERROR:", "Invalid reference type");
+				return;
+			}
+		} else if (property.serializedObject.targetObject is Component) {
+			var component = (Component)property.serializedObject.targetObject;
+			if (component.GetComponent<SkeletonRenderer>() != null) {
+				var skeletonRenderer = component.GetComponent<SkeletonRenderer>();
+				skeletonDataAsset = skeletonRenderer.skeletonDataAsset;
+			}
+		}
+
+		if (skeletonDataAsset == null) {
+			EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset");
+			return;
+		}
+
+		position = EditorGUI.PrefixLabel(position, label);
+
+		if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
+			Selector(property);
+		}
+
+	}
+
+	void Selector(SerializedProperty property) {
+
+		SpineAnimation attrib = (SpineAnimation)attribute;
+
+		GenericMenu menu = new GenericMenu();
+
+		var animations = skeletonDataAsset.GetAnimationStateData().SkeletonData.Animations;
+		for (int i = 0; i < animations.Count; i++) {
+			string name = animations[i].Name;
+			if (name.StartsWith(attrib.startsWith))
+				menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
+		}
+
+		menu.ShowAsContext();
+	}
+
+	void HandleSelect(object val) {
+		var pair = (SpineDrawerValuePair)val;
+		pair.property.stringValue = pair.str;
+		pair.property.serializedObject.ApplyModifiedProperties();
+	}
+
+	public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
+		return 18;
+	}
+}
+
+[CustomPropertyDrawer(typeof(SpineAttachment))]
+public class SpineAttachmentDrawer : PropertyDrawer {
+
+	SkeletonDataAsset skeletonDataAsset;
+	SkeletonRenderer skeletonRenderer;
+
+	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
+
+		if (property.propertyType != SerializedPropertyType.String) {
+			EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
+			return;
+		}
+
+		SpineAttachment attrib = (SpineAttachment)attribute;
+
+		var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
+
+		if (skeletonDataAssetProperty != null) {
+			if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
+				skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
+			} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
+				var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
+				if (renderer != null)
+					skeletonDataAsset = renderer.skeletonDataAsset;
+				else {
+					EditorGUI.LabelField(position, "ERROR:", "No SkeletonRenderer");
+				}
+			} else {
+				EditorGUI.LabelField(position, "ERROR:", "Invalid reference type");
+				return;
+			}
+
+		} else if (property.serializedObject.targetObject is Component) {
+			var component = (Component)property.serializedObject.targetObject;
+			if (component.GetComponent<SkeletonRenderer>() != null) {
+				skeletonRenderer = component.GetComponent<SkeletonRenderer>();
+				skeletonDataAsset = skeletonRenderer.skeletonDataAsset;
+			}
+		}
+
+		if (skeletonDataAsset == null && skeletonRenderer == null) {
+			EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset or SkeletonRenderer");
+			return;
+		}
+
+		position = EditorGUI.PrefixLabel(position, label);
+
+		if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
+			Selector(property);
+		}
+
+	}
+
+	void Selector(SerializedProperty property) {
+		SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
+
+		if (data == null)
+			return;
+
+		SpineAttachment attrib = (SpineAttachment)attribute;
+
+		List<Skin> validSkins = new List<Skin>();
+
+		if (skeletonRenderer != null && attrib.currentSkinOnly) {
+			if (skeletonRenderer.skeleton.Skin != null)
+				validSkins.Add(skeletonRenderer.skeleton.Skin);
+		} else {
+			foreach (Skin skin in data.Skins) {
+				if (skin != null)
+					validSkins.Add(skin);
+			}
+		}
+
+		GenericMenu menu = new GenericMenu();
+		List<string> attachmentNames = new List<string>();
+		string prefix = "";
+
+		if (skeletonRenderer != null && attrib.currentSkinOnly)
+			menu.AddDisabledItem(new GUIContent(skeletonRenderer.gameObject.name + " (SkeletonRenderer)"));
+		else
+			menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
+		menu.AddSeparator("");
+
+		menu.AddItem(new GUIContent("Null"), property.stringValue == "", HandleSelect, new SpineDrawerValuePair("", property));
+		menu.AddSeparator("");
+
+		Skin defaultSkin = data.Skins[0];
+
+		SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotSource);
+		string slotMatch = "";
+		if (slotProperty != null) {
+			if (slotProperty.propertyType == SerializedPropertyType.String) {
+				slotMatch = slotProperty.stringValue.ToLower();
+			}
+		}
+
+		foreach (Skin skin in validSkins) {
+			string skinPrefix = skin.Name + "/";
+
+			if (validSkins.Count > 1)
+				prefix = skinPrefix;
+
+			for (int i = 0; i < data.Slots.Count; i++) {
+				if (slotMatch.Length > 0 && data.Slots[i].Name.ToLower().Contains(slotMatch) == false)
+					continue;
+
+				attachmentNames.Clear();
+				skin.FindNamesForSlot(i, attachmentNames);
+				if (skin != defaultSkin)
+					defaultSkin.FindNamesForSlot(i, attachmentNames);
+
+				for (int a = 0; a < attachmentNames.Count; a++) {
+					string attachmentPath = attachmentNames[a];
+					string menuPath = prefix + data.Slots[i].Name + "/" + attachmentPath;
+					string name = attachmentNames[a];
+
+					if (attrib.returnFullPath)
+						name = skin.Name + "/" + data.Slots[i].Name + "/" + attachmentPath;
+					menu.AddItem(new GUIContent(menuPath), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
+				}
+			}
+		}
+
+
+		menu.ShowAsContext();
+	}
+
+	void HandleSelect(object val) {
+		var pair = (SpineDrawerValuePair)val;
+		pair.property.stringValue = pair.str;
+		pair.property.serializedObject.ApplyModifiedProperties();
+	}
+
+	public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
+		return 18;
+	}
+}

+ 8 - 0
spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f2de282d583d4a641bf1c349f0a3eef9
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 310 - 163
spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs

@@ -39,6 +39,8 @@ using System.Collections;
 using System.Collections.Generic;
 using System.IO;
 using System.Text;
+using System.Linq;
+using System.Reflection;
 using Spine;
 
 [InitializeOnLoad]
@@ -51,10 +53,12 @@ public class SpineEditorUtilities : AssetPostprocessor {
 		public static Texture2D poseBones;
 		public static Texture2D boneNib;
 		public static Texture2D slot;
+		public static Texture2D slotRoot;
 		public static Texture2D skinPlaceholder;
 		public static Texture2D image;
 		public static Texture2D boundingBox;
 		public static Texture2D mesh;
+		public static Texture2D weights;
 		public static Texture2D skin;
 		public static Texture2D skinsRoot;
 		public static Texture2D animation;
@@ -78,7 +82,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
 						new Vector3(0.1f, 0.1f, 0)
 					};
 					_boneMesh.uv = new Vector2[4];
-					_boneMesh.triangles = new int[6]{0,1,2,2,3,0};
+					_boneMesh.triangles = new int[6] { 0, 1, 2, 2, 3, 0 };
 					_boneMesh.RecalculateBounds();
 					_boneMesh.RecalculateNormals();
 				}
@@ -108,17 +112,19 @@ public class SpineEditorUtilities : AssetPostprocessor {
 
 		internal static Material _boneMaterial;
 
-		public static void Initialize () {
+		public static void Initialize() {
 			skeleton = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skeleton.png");
 			nullBone = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-null.png");
 			bone = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-bone.png");
 			poseBones = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-poseBones.png");
 			boneNib = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-boneNib.png");
 			slot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-slot.png");
+			slotRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-slotRoot.png");
 			skinPlaceholder = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png");
 			image = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-image.png");
 			boundingBox = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-boundingBox.png");
 			mesh = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-mesh.png");
+			weights = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-weights.png");
 			skin = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinPlaceholder.png");
 			skinsRoot = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-skinsRoot.png");
 			animation = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-animation.png");
@@ -140,12 +146,12 @@ public class SpineEditorUtilities : AssetPostprocessor {
 	public static float defaultScale = 0.01f;
 	public static float defaultMix = 0.2f;
 	public static string defaultShader = "Spine/Skeleton";
-	
-	static SpineEditorUtilities () {
+
+	static SpineEditorUtilities() {
 		DirectoryInfo rootDir = new DirectoryInfo(Application.dataPath);
 		FileInfo[] files = rootDir.GetFiles("SpineEditorUtilities.cs", SearchOption.AllDirectories);
 		editorPath = Path.GetDirectoryName(files[0].FullName.Replace("\\", "/").Replace(Application.dataPath, "Assets"));
-		editorGUIPath = editorPath + "/GUI";	
+		editorGUIPath = editorPath + "/GUI";
 
 		Icons.Initialize();
 
@@ -158,7 +164,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
 		HierarchyWindowChanged();
 	}
 
-	static void HierarchyWindowChanged () {
+	static void HierarchyWindowChanged() {
 		skeletonRendererTable.Clear();
 		skeletonUtilityBoneTable.Clear();
 
@@ -172,122 +178,299 @@ public class SpineEditorUtilities : AssetPostprocessor {
 			skeletonUtilityBoneTable.Add(b.gameObject.GetInstanceID(), b);
 	}
 
-	static void HierarchyWindowItemOnGUI (int instanceId, Rect selectionRect) {
+	static void HierarchyWindowItemOnGUI(int instanceId, Rect selectionRect) {
 		if (skeletonRendererTable.ContainsKey(instanceId)) {
-			Rect r = new Rect(selectionRect); 
+			Rect r = new Rect(selectionRect);
 			r.x = r.width - 15;
 			r.width = 15;
 
 			GUI.Label(r, Icons.spine);
 		} else if (skeletonUtilityBoneTable.ContainsKey(instanceId)) {
-				Rect r = new Rect(selectionRect); 
-				r.x -= 26;
-
-				if (skeletonUtilityBoneTable[instanceId] != null) {
-					if (skeletonUtilityBoneTable[instanceId].transform.childCount == 0)
-						r.x += 13;
-				
-					r.y += 2;
-
-					r.width = 13;
-					r.height = 13;
-
-					if (skeletonUtilityBoneTable[instanceId].mode == SkeletonUtilityBone.Mode.Follow) {
-						GUI.DrawTexture(r, Icons.bone);
-					} else {
-						GUI.DrawTexture(r, Icons.poseBones);
-					}
-				}
+			Rect r = new Rect(selectionRect);
+			r.x -= 26;
+
+			if (skeletonUtilityBoneTable[instanceId] != null) {
+				if (skeletonUtilityBoneTable[instanceId].transform.childCount == 0)
+					r.x += 13;
+
+				r.y += 2;
 
+				r.width = 13;
+				r.height = 13;
+
+				if (skeletonUtilityBoneTable[instanceId].mode == SkeletonUtilityBone.Mode.Follow) {
+					GUI.DrawTexture(r, Icons.bone);
+				} else {
+					GUI.DrawTexture(r, Icons.poseBones);
+				}
 			}
 
+		}
+
 	}
-	
-	[MenuItem("Assets/Spine/Ingest")]
-	static void IngestSpineProjectFromSelection () {
-		TextAsset spineJson = null;
-		TextAsset atlasText = null;
 
-		List<TextAsset> spineJsonList = new List<TextAsset>();
 
-		foreach (UnityEngine.Object o in Selection.objects) {
-			if (o.GetType() != typeof(TextAsset))
-				continue;
-			
-			string fileName = Path.GetFileName(AssetDatabase.GetAssetPath(o));
-			
-			if (fileName.EndsWith(".json"))
-				spineJson = (TextAsset)o;
-			else if (fileName.EndsWith(".atlas.txt"))
-					atlasText = (TextAsset)o;
-		}
-		
-		if (spineJson == null) {
-			EditorUtility.DisplayDialog("Error!", "Spine JSON file not found in selection!", "OK");
-			return;
+	static void OnPostprocessAllAssets(string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) {
+
+		List<string> atlasPaths = new List<string>();
+		List<string> imagePaths = new List<string>();
+		List<string> skeletonPaths = new List<string>();
+
+		foreach (string str in imported) {
+			string extension = Path.GetExtension(str).ToLower();
+			switch (extension) {
+				case ".txt":
+					if (str.EndsWith(".atlas.txt")) {
+						atlasPaths.Add(str);
+					}
+					break;
+				case ".png":
+				case ".jpg":
+					imagePaths.Add(str);
+					break;
+				case ".json":
+					TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset));
+					if (IsSpineJSON(spineJson)) {
+						skeletonPaths.Add(str);
+					}
+					break;
+			}
 		}
-		
-		string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
-		string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
-		
-		if (atlasText == null) {
-			string atlasPath = assetPath + "/" + primaryName + ".atlas.txt";
-			atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset));
+
+
+		List<AtlasAsset> atlases = new List<AtlasAsset>();
+
+		//import atlases first
+		foreach (string ap in atlasPaths) {
+			TextAsset atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(ap, typeof(TextAsset));
+			AtlasAsset atlas = IngestSpineAtlas(atlasText);
+			atlases.Add(atlas);
 		}
 
-		AtlasAsset atlasAsset = IngestSpineAtlas(atlasText);
+		//import skeletons and match them with atlases
+		bool abortSkeletonImport = false;
+		foreach (string sp in skeletonPaths) {
+			string dir = Path.GetDirectoryName(sp);
+			var localAtlases = FindAtlasesAtPath(dir);
+			var requiredPaths = GetRequiredAtlasRegions(sp);
+			var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases);
+
+			if (atlasMatch != null) {
+				IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch);
+			} else {
+				bool resolved = false;
+				while (!resolved) {
+					int result = EditorUtility.DisplayDialogComplex("Skeleton JSON Import Error!", "Could not find matching AtlasAsset for " + Path.GetFileNameWithoutExtension(sp), "Select", "Skip", "Abort");
+					switch (result) {
+						case -1:
+							Debug.Log("Select Atlas");
+							AtlasAsset selectedAtlas = GetAtlasDialog(Path.GetDirectoryName(sp));
+							if (selectedAtlas != null) {
+								localAtlases.Clear();
+								localAtlases.Add(selectedAtlas);
+								atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases);
+								if (atlasMatch != null) {
+									resolved = true;
+									IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch);
+								}
+							}
+
+							break;
+						case 0:
+							var atlasList = MultiAtlasDialog(requiredPaths, Path.GetDirectoryName(sp), Path.GetFileNameWithoutExtension(sp));
+
+							if (atlasList != null)
+								IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasList.ToArray());
+
+							resolved = true;
+							break;
+
+						case 1:
+							Debug.Log("Skipped importing: " + Path.GetFileName(sp));
+							resolved = true;
+							break;
+						
+
+						case 2:
+							//abort
+							abortSkeletonImport = true;
+							resolved = true;
+							break;
+					}
+				}
+			}
+
+			if (abortSkeletonImport)
+				break;
+		}
 
-		IngestSpineProject(spineJson, atlasAsset);
+		//TODO:  any post processing of images
 	}
 
-	static void OnPostprocessAllAssets (string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) {
-		//debug
-//		return;
+	static List<AtlasAsset> MultiAtlasDialog(List<string> requiredPaths, string initialDirectory, string header = "") {
 
-		AtlasAsset sharedAtlas = null;
+		List<AtlasAsset> atlasAssets = new List<AtlasAsset>();
 
-		System.Array.Sort<string>(imported);
+		bool resolved = false;
+		string lastAtlasPath = initialDirectory;
+		while (!resolved) {
+			StringBuilder sb = new StringBuilder();
+			sb.AppendLine(header);
+			sb.AppendLine("Atlases:");
+			if (atlasAssets.Count == 0) {
+				sb.AppendLine("\t--none--");
+			}
+			for (int i = 0; i < atlasAssets.Count; i++) {
+				sb.AppendLine("\t" + atlasAssets[i].name);
+			}
 
-		foreach (string str in imported) {
-			if (Path.GetExtension(str).ToLower() == ".json") {
-				TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset));
-				if (IsSpineJSON(spineJson)) {
-
-					if (sharedAtlas != null) {
-						string spinePath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
-						string atlasPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(sharedAtlas));
-						if (spinePath != atlasPath)
-							sharedAtlas = null;
-					}
+				sb.AppendLine();
+			sb.AppendLine("Missing Regions:");
 
-					SkeletonDataAsset data = AutoIngestSpineProject(spineJson, sharedAtlas);
-					if (data == null)
-						continue;
+			List<string> missingRegions = new List<string>(requiredPaths);
 
-					sharedAtlas = data.atlasAsset;
+			foreach (var atlasAsset in atlasAssets) {
+				var atlas = atlasAsset.GetAtlas();
+				for (int i = 0; i < missingRegions.Count; i++) {
+					if (atlas.FindRegion(missingRegions[i]) != null) {
+						missingRegions.RemoveAt(i);
+						i--;
+					}
+				}
+			}
 
+			if (missingRegions.Count == 0) {
+				break;
+			}
 
-					string dir = Path.GetDirectoryName(Path.GetDirectoryName(AssetDatabase.GetAssetPath(data)));
-					string prefabPath = Path.Combine(dir, data.skeletonJSON.name + ".prefab").Replace("\\", "/");
+			for (int i = 0; i < missingRegions.Count; i++) {
+				sb.AppendLine("\t" + missingRegions[i]);
+			}
 
-					if (File.Exists(prefabPath) == false) {
-						SkeletonAnimation anim = SpawnAnimatedSkeleton(data);
-						PrefabUtility.CreatePrefab(prefabPath, anim.gameObject, ReplacePrefabOptions.ReplaceNameBased);
-						if (EditorApplication.isPlaying)
-							GameObject.Destroy(anim.gameObject);
-						else
-							GameObject.DestroyImmediate(anim.gameObject);
-					} else {
+			int result = EditorUtility.DisplayDialogComplex("Atlas Selection", sb.ToString(), "Select", "Finish", "Abort");
+
+			switch(result){
+				case 0:
+					AtlasAsset selectedAtlasAsset = GetAtlasDialog(lastAtlasPath);
+					if (selectedAtlasAsset != null) {
+						var atlas = selectedAtlasAsset.GetAtlas();
+						bool hasValidRegion = false;
+						foreach (string str in missingRegions) {
+							if (atlas.FindRegion(str) != null) {
+								hasValidRegion = true;
+								break;
+							}
+						}
 
+						atlasAssets.Add(selectedAtlasAsset);
 					}
+					break;
+
+				case 1:
+					resolved = true;
+					break;
+
+				case 2:
+					atlasAssets = null;
+					resolved = true;
+					break;
+			}
+
+
+		}
+		
+
+		return atlasAssets;
+	}
+
+	static AtlasAsset GetAtlasDialog(string dirPath) {
+		string path = EditorUtility.OpenFilePanel("Select AtlasAsset...", dirPath, "asset");
+		if (path == "")
+			return null;
 
+		int subLen = Application.dataPath.Length - 6;
+		string assetRelativePath = path.Substring(subLen, path.Length - subLen).Replace("\\", "/");
 
+		Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAsset));
+
+		if (obj == null || obj.GetType() != typeof(AtlasAsset))
+			return null;
+
+		return (AtlasAsset)obj;
+	}
+
+	public static List<string> GetRequiredAtlasRegions(string jsonPath) {
+		List<string> requiredPaths = new List<string>();
+
+		TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(jsonPath, typeof(TextAsset));
+
+		StringReader reader = new StringReader(spineJson.text);
+		var root = Json.Deserialize(reader) as Dictionary<string, object>;
+
+		foreach (KeyValuePair<string, object> entry in (Dictionary<string, object>)root["skins"]) {
+			foreach (KeyValuePair<string, object> slotEntry in (Dictionary<string, object>)entry.Value) {
+
+				foreach (KeyValuePair<string, object> attachmentEntry in ((Dictionary<string, object>)slotEntry.Value)) {
+					var data = ((Dictionary<string, object>)attachmentEntry.Value);
+					if (data.ContainsKey("path"))
+						requiredPaths.Add((string)data["path"]);
+					else if (data.ContainsKey("name"))
+						requiredPaths.Add((string)data["name"]);
+					else
+						requiredPaths.Add(attachmentEntry.Key);
+					//requiredPaths.Add((string)sdf["path"]);
 				}
 			}
 		}
+
+		return requiredPaths;
 	}
+	static AtlasAsset GetMatchingAtlas(List<string> requiredPaths, List<AtlasAsset> atlasAssets) {
+		AtlasAsset atlasAssetMatch = null;
+
+		foreach (AtlasAsset a in atlasAssets) {
+			Atlas atlas = a.GetAtlas();
+			bool failed = false;
+			foreach (string regionPath in requiredPaths) {
+				if (atlas.FindRegion(regionPath) == null) {
+					failed = true;
+					break;
+				}
+			}
 
-	static bool IsSpineJSON (TextAsset asset) {
+			if (!failed) {
+				atlasAssetMatch = a;
+				break;
+			}
+
+		}
+
+		return atlasAssetMatch;
+	}
+
+	static List<AtlasAsset> FindAtlasesAtPath(string path) {
+		List<AtlasAsset> arr = new List<AtlasAsset>();
+
+		DirectoryInfo dir = new DirectoryInfo(path);
+		FileInfo[] assetInfoArr = dir.GetFiles("*.asset");
+
+		int subLen = Application.dataPath.Length - 6;
+
+		foreach (var f in assetInfoArr) {
+			string assetRelativePath = f.FullName.Substring(subLen, f.FullName.Length - subLen).Replace("\\", "/");
+
+			Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAsset));
+			if (obj != null) {
+				arr.Add(obj as AtlasAsset);
+			}
+
+		}
+
+
+		return arr;
+	}
+
+	public static bool IsSpineJSON(TextAsset asset) {
 		object obj = Json.Deserialize(new StringReader(asset.text));
 		if (obj == null) {
 			Debug.LogError("Is not valid JSON");
@@ -307,51 +490,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
 		return true;
 	}
 
-	static SkeletonDataAsset AutoIngestSpineProject (TextAsset spineJson, Object atlasSource = null) {
-		TextAsset atlasText = null;
-		AtlasAsset atlasAsset = null;
-
-		if (atlasSource != null) {
-			if (atlasSource.GetType() == typeof(TextAsset)) {
-				atlasText = (TextAsset)atlasSource;
-			} else if (atlasSource.GetType() == typeof(AtlasAsset)) {
-					atlasAsset = (AtlasAsset)atlasSource;
-				}
-		}
-
-		if (atlasText == null && atlasAsset == null) {
-			string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
-			string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
-			
-			if (atlasText == null) {
-				string atlasPath = assetPath + "/" + primaryName + ".atlas.txt";
-				atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset));
-
-				if (atlasText == null) {
-					//can't find atlas, likely because using a shared atlas
-					bool abort = !EditorUtility.DisplayDialog("Atlas not Found", "Expecting " + spineJson.name + ".atlas\n" + "Press OK to select Atlas", "OK", "Abort");
-					if (abort) {
-						//do nothing, let it error later
-					} else {
-						string path = EditorUtility.OpenFilePanel("Find Atlas source...", Path.GetDirectoryName(Application.dataPath) + "/" + assetPath, "txt");
-						if (path != "") {
-							path = path.Replace("\\", "/");
-							path = path.Replace(Application.dataPath.Replace("\\", "/"), "Assets");
-							atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(path, typeof(TextAsset));
-						}
-					}
-
-				}
-			}
-		}
-
-		if (atlasAsset == null)
-			atlasAsset = IngestSpineAtlas(atlasText);
-
-		return IngestSpineProject(spineJson, atlasAsset);
-	}
-
-	static AtlasAsset IngestSpineAtlas (TextAsset atlasText) {
+	static AtlasAsset IngestSpineAtlas(TextAsset atlasText) {
 		if (atlasText == null) {
 			Debug.LogWarning("Atlas source cannot be null!");
 			return null;
@@ -376,17 +515,17 @@ public class SpineEditorUtilities : AssetPostprocessor {
 
 		string[] atlasLines = atlasStr.Split('\n');
 		List<string> pageFiles = new List<string>();
-		for (int i = 0; i < atlasLines.Length-1; i++) {
+		for (int i = 0; i < atlasLines.Length - 1; i++) {
 			if (atlasLines[i].Length == 0)
 				pageFiles.Add(atlasLines[i + 1]);
 		}
-		
+
 		atlasAsset.materials = new Material[pageFiles.Count];
-		
+
 		for (int i = 0; i < pageFiles.Count; i++) {
 			string texturePath = assetPath + "/" + pageFiles[i];
 			Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));
-			
+
 			TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
 			texImporter.textureFormat = TextureImporterFormat.AutomaticTruecolor;
 			texImporter.mipmapEnabled = false;
@@ -396,13 +535,13 @@ public class SpineEditorUtilities : AssetPostprocessor {
 			EditorUtility.SetDirty(texImporter);
 			AssetDatabase.ImportAsset(texturePath);
 			AssetDatabase.SaveAssets();
-			
+
 			string pageName = Path.GetFileNameWithoutExtension(pageFiles[i]);
-			
+
 			//because this looks silly
 			if (pageName == primaryName && pageFiles.Count == 1)
 				pageName = "Material";
-			
+
 			string materialPath = assetPath + "/" + primaryName + "_" + pageName + ".mat";
 			Material mat = (Material)AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material));
 
@@ -410,12 +549,12 @@ public class SpineEditorUtilities : AssetPostprocessor {
 				mat = new Material(Shader.Find(defaultShader));
 				AssetDatabase.CreateAsset(mat, materialPath);
 			}
-			
+
 			mat.mainTexture = texture;
 			EditorUtility.SetDirty(mat);
 
 			AssetDatabase.SaveAssets();
-			
+
 			atlasAsset.materials[i] = mat;
 		}
 
@@ -429,40 +568,41 @@ public class SpineEditorUtilities : AssetPostprocessor {
 		return (AtlasAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAsset));
 	}
 
-	static SkeletonDataAsset IngestSpineProject (TextAsset spineJson, AtlasAsset atlasAsset = null) {
+	static SkeletonDataAsset IngestSpineProject(TextAsset spineJson, params AtlasAsset[] atlasAssets) {
 		string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
 		string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
 		string filePath = assetPath + "/" + primaryName + "_SkeletonData.asset";
 
-		if (spineJson != null && atlasAsset != null) {
+		if (spineJson != null && atlasAssets != null) {
 
 			SkeletonDataAsset skelDataAsset = (SkeletonDataAsset)AssetDatabase.LoadAssetAtPath(filePath, typeof(SkeletonDataAsset));
 			if (skelDataAsset == null) {
 				skelDataAsset = SkeletonDataAsset.CreateInstance<SkeletonDataAsset>();
-				skelDataAsset.atlasAsset = atlasAsset;
+				skelDataAsset.atlasAssets = atlasAssets;
 				skelDataAsset.skeletonJSON = spineJson;
 				skelDataAsset.fromAnimation = new string[0];
 				skelDataAsset.toAnimation = new string[0];
 				skelDataAsset.duration = new float[0];
 				skelDataAsset.defaultMix = defaultMix;
 				skelDataAsset.scale = defaultScale;
-				
+
 				AssetDatabase.CreateAsset(skelDataAsset, filePath);
 				AssetDatabase.SaveAssets();
 			} else {
+				skelDataAsset.atlasAssets = atlasAssets;
 				skelDataAsset.Reset();
 				skelDataAsset.GetSkeletonData(true);
 			}
 
 			return skelDataAsset;
 		} else {
-			EditorUtility.DisplayDialog("Error!", "Must specify both Spine JSON and Atlas TextAsset", "OK");
+			EditorUtility.DisplayDialog("Error!", "Must specify both Spine JSON and AtlasAsset array", "OK");
 			return null;
 		}
 	}
 
 	[MenuItem("Assets/Spine/Spawn")]
-	static void SpawnAnimatedSkeleton () {
+	static void SpawnAnimatedSkeleton() {
 		Object[] arr = Selection.objects;
 		foreach (Object o in arr) {
 			string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(o));
@@ -474,59 +614,66 @@ public class SpineEditorUtilities : AssetPostprocessor {
 	}
 
 	[MenuItem("Assets/Spine/Spawn", true)]
-	static bool ValidateSpawnAnimatedSkeleton () {
+	static bool ValidateSpawnAnimatedSkeleton() {
 		Object[] arr = Selection.objects;
-		
+
 		if (arr.Length == 0)
 			return false;
-		
+
 		foreach (Object o in arr) {
 			if (o.GetType() != typeof(SkeletonDataAsset))
 				return false;
 		}
-		
+
 		return true;
 	}
 
-	public static SkeletonAnimation SpawnAnimatedSkeleton (SkeletonDataAsset skeletonDataAsset, string skinName) {
+	public static SkeletonAnimation SpawnAnimatedSkeleton(SkeletonDataAsset skeletonDataAsset, string skinName) {
 		return SpawnAnimatedSkeleton(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName));
 	}
 
-	public static SkeletonAnimation SpawnAnimatedSkeleton (SkeletonDataAsset skeletonDataAsset, Skin skin = null) {
+	public static SkeletonAnimation SpawnAnimatedSkeleton(SkeletonDataAsset skeletonDataAsset, Skin skin = null) {
 		GameObject go = new GameObject(skeletonDataAsset.name.Replace("_SkeletonData", ""), typeof(MeshFilter), typeof(MeshRenderer), typeof(SkeletonAnimation));
 		SkeletonAnimation anim = go.GetComponent<SkeletonAnimation>();
 		anim.skeletonDataAsset = skeletonDataAsset;
 
 		bool requiresNormals = false;
 
-		foreach (Material m in anim.skeletonDataAsset.atlasAsset.materials) {
-			if (m.shader.name.Contains("Lit")) {
-				requiresNormals = true;
-				break;
+		foreach (AtlasAsset atlasAsset in anim.skeletonDataAsset.atlasAssets) {
+			foreach (Material m in atlasAsset.materials) {
+				if (m.shader.name.Contains("Lit")) {
+					requiresNormals = true;
+					break;
+				}
 			}
 		}
 
+		
+
 		anim.calculateNormals = requiresNormals;
 
 		SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
 
 		if (data == null) {
-			string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAsset);
-			skeletonDataAsset.atlasAsset = (AtlasAsset)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAsset));
+			for(int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++){
+				string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]);
+				skeletonDataAsset.atlasAssets[i] = (AtlasAsset)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAsset));
+			}			
+			
 			data = skeletonDataAsset.GetSkeletonData(true);
 		}
 
 		if (skin == null)
 			skin = data.DefaultSkin;
-			
+
 		if (skin == null)
 			skin = data.Skins[0];
 
 		anim.Reset();
-		
+
 		anim.skeleton.SetSkin(skin);
 		anim.initialSkinName = skin.Name;
-		
+
 		anim.skeleton.Update(1);
 		anim.state.Update(1);
 		anim.state.Apply(anim.skeleton);
@@ -534,4 +681,4 @@ public class SpineEditorUtilities : AssetPostprocessor {
 
 		return anim;
 	}
-}
+}

+ 26 - 8
spine-unity/Assets/spine-unity/SkeletonDataAsset.cs

@@ -35,7 +35,7 @@ using UnityEngine;
 using Spine;
 
 public class SkeletonDataAsset : ScriptableObject {
-	public AtlasAsset atlasAsset;
+	public AtlasAsset[] atlasAssets;
 	public TextAsset skeletonJSON;
 	public float scale = 1;
 	public String[] fromAnimation;
@@ -45,13 +45,14 @@ public class SkeletonDataAsset : ScriptableObject {
 	private SkeletonData skeletonData;
 	private AnimationStateData stateData;
 
-	public void Reset () {
+	public void Reset() {
 		skeletonData = null;
 		stateData = null;
 	}
 
-	public SkeletonData GetSkeletonData (bool quiet) {
-		if (atlasAsset == null) {
+	public SkeletonData GetSkeletonData(bool quiet) {
+		if (atlasAssets == null) {
+			atlasAssets = new AtlasAsset[0];
 			if (!quiet)
 				Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
 			Reset();
@@ -65,16 +66,33 @@ public class SkeletonDataAsset : ScriptableObject {
 			return null;
 		}
 
-		Atlas atlas = atlasAsset.GetAtlas();
-		if (atlas == null) {
+
+
+		if (atlasAssets.Length == 0) {
 			Reset();
 			return null;
 		}
 
+		Atlas[] atlasArr = new Atlas[atlasAssets.Length];
+		for (int i = 0; i < atlasAssets.Length; i++) {
+			if (atlasAssets[i] == null) {
+				Reset();
+				return null;
+			}
+			atlasArr[i] = atlasAssets[i].GetAtlas();
+			if (atlasArr[i] == null) {
+				Reset();
+				return null;
+			}
+		}
+
+
+
+
 		if (skeletonData != null)
 			return skeletonData;
 
-		SkeletonJson json = new SkeletonJson(atlas);
+		SkeletonJson json = new SkeletonJson(atlasArr);
 		json.Scale = scale;
 		try {
 			skeletonData = json.ReadSkeletonData(new StringReader(skeletonJSON.text));
@@ -95,7 +113,7 @@ public class SkeletonDataAsset : ScriptableObject {
 		return skeletonData;
 	}
 
-	public AnimationStateData GetAnimationStateData () {
+	public AnimationStateData GetAnimationStateData() {
 		if (stateData != null)
 			return stateData;
 		GetSkeletonData(false);

+ 12 - 12
spine-unity/Assets/spine-unity/SkeletonExtensions.cs

@@ -38,71 +38,71 @@ using System.Collections;
 using Spine;
 
 public static class SkeletonExtensions {
-	
-	public static void SetColor (this Slot slot, Color color) {
+
+	public static void SetColor(this Slot slot, Color color) {
 		slot.A = color.a;
 		slot.R = color.r;
 		slot.G = color.g;
 		slot.B = color.b;
 	}
 
-	public static void SetColor (this Slot slot, Color32 color) {
+	public static void SetColor(this Slot slot, Color32 color) {
 		slot.A = color.a / 255f;
 		slot.R = color.r / 255f;
 		slot.G = color.g / 255f;
 		slot.B = color.b / 255f;
 	}
 
-	public static void SetColor (this RegionAttachment attachment, Color color) {
+	public static void SetColor(this RegionAttachment attachment, Color color) {
 		attachment.A = color.a;
 		attachment.R = color.r;
 		attachment.G = color.g;
 		attachment.B = color.b;
 	}
 
-	public static void SetColor (this RegionAttachment attachment, Color32 color) {
+	public static void SetColor(this RegionAttachment attachment, Color32 color) {
 		attachment.A = color.a / 255f;
 		attachment.R = color.r / 255f;
 		attachment.G = color.g / 255f;
 		attachment.B = color.b / 255f;
 	}
 
-	public static void SetColor (this MeshAttachment attachment, Color color) {
+	public static void SetColor(this MeshAttachment attachment, Color color) {
 		attachment.A = color.a;
 		attachment.R = color.r;
 		attachment.G = color.g;
 		attachment.B = color.b;
 	}
 
-	public static void SetColor (this MeshAttachment attachment, Color32 color) {
+	public static void SetColor(this MeshAttachment attachment, Color32 color) {
 		attachment.A = color.a / 255f;
 		attachment.R = color.r / 255f;
 		attachment.G = color.g / 255f;
 		attachment.B = color.b / 255f;
 	}
 
-	public static void SetColor (this SkinnedMeshAttachment attachment, Color color) {
+	public static void SetColor(this SkinnedMeshAttachment attachment, Color color) {
 		attachment.A = color.a;
 		attachment.R = color.r;
 		attachment.G = color.g;
 		attachment.B = color.b;
 	}
 
-	public static void SetColor (this SkinnedMeshAttachment attachment, Color32 color) {
+	public static void SetColor(this SkinnedMeshAttachment attachment, Color32 color) {
 		attachment.A = color.a / 255f;
 		attachment.R = color.r / 255f;
 		attachment.G = color.g / 255f;
 		attachment.B = color.b / 255f;
 	}
 
-	public static void SetPosition (this Bone bone, Vector2 position) {
+	public static void SetPosition(this Bone bone, Vector2 position) {
 		bone.X = position.x;
 		bone.Y = position.y;
 	}
 
-	public static void SetPosition (this Bone bone, Vector3 position) {
+	public static void SetPosition(this Bone bone, Vector3 position) {
 		bone.X = position.x;
 		bone.Y = position.y;
 	}
 
-}
+}

+ 17 - 1
spine-unity/Assets/spine-unity/SkeletonRenderer.cs

@@ -51,6 +51,14 @@ public class SkeletonRenderer : MonoBehaviour {
 	public float zSpacing;
 	public bool renderMeshes = true, immutableTriangles;
 	public bool logErrors = false;
+
+	[SpineSlot]
+	public string[] submeshSeparators = new string[0];
+
+	[HideInInspector]
+	public List<Slot> submeshSeparatorSlots = new List<Slot>();
+
+
 	private MeshFilter meshFilter;
 	private Mesh mesh1, mesh2;
 	private bool useMesh1;
@@ -62,6 +70,7 @@ public class SkeletonRenderer : MonoBehaviour {
 	private Material[] sharedMaterials = new Material[0];
 	private readonly List<Material> submeshMaterials = new List<Material>();
 	private readonly List<Submesh> submeshes = new List<Submesh>();
+	
 
 	public virtual void Reset () {
 		if (meshFilter != null)
@@ -99,6 +108,12 @@ public class SkeletonRenderer : MonoBehaviour {
 		skeleton = new Skeleton(skeletonData);
 		if (initialSkinName != null && initialSkinName.Length > 0 && initialSkinName != "default")
 			skeleton.SetSkin(initialSkinName);
+
+		submeshSeparatorSlots.Clear();
+		for (int i = 0; i < submeshSeparators.Length; i++) {
+			submeshSeparatorSlots.Add(skeleton.FindSlot(submeshSeparators[i]));
+		}
+
 		if (OnReset != null)
 			OnReset(this);
 	}
@@ -156,7 +171,8 @@ public class SkeletonRenderer : MonoBehaviour {
 
 			// Populate submesh when material changes.
 			Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
-			if ((lastMaterial != material && lastMaterial != null) || slot.Data.name[0] == '*') {
+
+			if ((lastMaterial != material && lastMaterial != null) || submeshSeparatorSlots.Contains(slot)) {
 				AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false);
 				submeshTriangleCount = 0;
 				submeshFirstVertex = vertexCount;

+ 5 - 1
spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityKinematicShadow.cs

@@ -4,6 +4,7 @@ using System.Collections.Generic;
 
 public class SkeletonUtilityKinematicShadow : MonoBehaviour {
 	public bool hideShadow = true;
+	public Transform parent;
 	Dictionary<Transform, Transform> shadowTable;
 	GameObject shadowRoot;
 
@@ -12,7 +13,10 @@ public class SkeletonUtilityKinematicShadow : MonoBehaviour {
 		if (hideShadow)
 			shadowRoot.hideFlags = HideFlags.HideInHierarchy;
 
-		shadowRoot.transform.parent = transform.root;
+		if(parent == null)
+			shadowRoot.transform.parent = transform.root;
+		else
+			shadowRoot.transform.parent = parent;
 
 		shadowTable = new Dictionary<Transform, Transform>();
 

+ 111 - 0
spine-unity/Assets/spine-unity/SpineAttributes.cs

@@ -0,0 +1,111 @@
+using UnityEngine;
+using System.Collections;
+
+public class SpineSlot : PropertyAttribute {
+	public string startsWith = "";
+	public string dataSource = "";
+
+	/// <summary>
+	/// 
+	/// </summary>
+	/// <param name="startsWith"></param>
+	/// <param name="dataSource">SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset</param>
+	public SpineSlot(string startsWith = "", string dataSource = "") {
+		this.startsWith = startsWith;
+		this.dataSource = dataSource;
+	}
+}
+
+public class SpineSkin : PropertyAttribute {
+	public string startsWith = "";
+	public string dataSource = "";
+
+	/// <summary>
+	/// 
+	/// </summary>
+	/// <param name="startsWith"></param>
+	/// <param name="dataSource">SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset</param>
+	public SpineSkin(string startsWith = "", string dataSource = "") {
+		this.startsWith = startsWith;
+		this.dataSource = dataSource;
+	}
+}
+
+public class SpineAtlasRegion : PropertyAttribute {
+
+}
+
+public class SpineAnimation : PropertyAttribute {
+	public string startsWith = "";
+	public string dataSource = "";
+
+	/// <summary>
+	/// 
+	/// </summary>
+	/// <param name="startsWith"></param>
+	/// <param name="dataSource">SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset</param>
+	public SpineAnimation(string startsWith = "", string dataSource = "") {
+		this.startsWith = startsWith;
+		this.dataSource = dataSource;
+	}
+}
+
+public class SpineAttachment : PropertyAttribute {
+	public bool returnFullPath;
+	public bool currentSkinOnly;
+	public string dataSource = "";
+	public string slotSource = "";
+
+
+	public SpineAttachment() {
+
+	}
+
+	public SpineAttachment(bool currentSkinOnly = true, bool returnFullPath = false, string slot = "", string dataSource = "") {
+		this.currentSkinOnly = currentSkinOnly;
+		this.returnFullPath = returnFullPath;
+		this.slotSource = slot;
+		this.dataSource = dataSource;		
+	}
+
+	public static Hierarchy GetHierarchy(string fullPath) {
+		return new Hierarchy(fullPath);
+	}
+
+	public static Spine.Attachment GetAttachment(string fullPath, Spine.SkeletonData skeletonData) {
+		var hierarchy = SpineAttachment.GetHierarchy(fullPath);
+		if (hierarchy.name == "")
+			return null;
+
+		return skeletonData.FindSkin(hierarchy.skin).GetAttachment(skeletonData.FindSlotIndex(hierarchy.slot), hierarchy.name);
+	}
+
+	public static Spine.Attachment GetAttachment(string fullPath, SkeletonDataAsset skeletonDataAsset) {
+		return GetAttachment(fullPath, skeletonDataAsset.GetSkeletonData(true));
+	}
+
+	public struct Hierarchy {
+		public string skin;
+		public string slot;
+		public string name;
+
+		public Hierarchy(string fullPath) {
+			string[] chunks = fullPath.Split(new char[]{'/'}, System.StringSplitOptions.RemoveEmptyEntries);
+			if (chunks.Length == 0) {
+				skin = "";
+				slot = "";
+				name = "";
+				return;
+			}
+			else if (chunks.Length < 2) {
+				throw new System.Exception("Cannot generate Attachment Hierarchy from string! Not enough components! [" + fullPath + "]");
+			}
+			skin = chunks[0];
+			slot = chunks[1];
+			name = "";
+			for (int i = 2; i < chunks.Length; i++) {
+				name += chunks[i];
+			}
+		}
+	}
+}

+ 8 - 0
spine-unity/Assets/spine-unity/SpineAttributes.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ce216f51ebc1d3f40929f4e58d1c65e5
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: