diff --git a/CHANGELOG.md b/CHANGELOG.md index ccc85de62..9d46c1f74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,13 +75,14 @@ * **Two color tinting** is currently supported via extra UV2 and UV3 mesh vertex streams. To use Two color tinting, you need to: * switch on "Tint Black" under "Advanced...", * use the new `Spine/Skeleton Tint Black` shader, or your own shader that treats the UV2 and UV3 streams similarly. - * **Clipping** is now supported. The SkeletonRenderers switches to slightly slower mesh generation code when clipping so limit your use of `ClippingAttachment`s when using on large numbers of skeletons. + * **Clipping** is now supported. The SkeletonAnimation switches to slightly slower mesh generation code when clipping so limit your use of `ClippingAttachment`s when using on large numbers of skeletons. * **[SpineAttribute] Improvements** * **Icons have been added to SpineAttributeDrawers**. This should make your default inspectors easier to understand at a glance. + * **Added Constraint Attributes** You can now use `[SpineIkConstraint]` `[SpineTransformConstraint]` `[SpinePathConstraint]` * **SpineAttribute dataField** parameter can also now detect sibling fields within arrays and serializable structs/classes. * **[SpineAttribute(includeNone:false)]** SpineAttributes now have an `includeNone` optional parameter to specify if you want to include or exclude a none ("") value option in the dropdown menu. Default is `includeNone:true`. * **[SpineAttachment(skinField:"mySkin")]** The SpineAttachment attribute now has a skinField optional parameter to limit the dropdown items to attachments in a specific skin instead of the just default skin or all the skins in SkeletonData. - * **SkeletonDebugWindow**. Debugging tools have been moved from the SkeletonRenderer and SkeletonUtility component inspectors into its own utility window. You can access "Skeleton Debug" under the `Advanced...` foldout in the SkeletonRenderer inspector, or in SkeletonRenderer's right-click/context menu. + * **SkeletonDebugWindow**. Debugging tools have been moved from the SkeletonAnimation and SkeletonUtility component inspectors into its own utility window. You can access "Skeleton Debug" under the `Advanced...` foldout in the SkeletonAnimation inspector, or in SkeletonAnimation's right-click/context menu. * **Skeleton Baking Window** The old Skeleton Baking feature is also now accessible through the SkeletonDataAsset's right-click/context menu. * **AttachmentTools source material**. `AttachmentTools` methods can now accept a `sourceMaterial` argument to copy material properties from. * **AttachmentTools Skin Extensions**. Using AttachmentTools, you can now add entries by slot name by also providing a skeleton argument. Also `Append(Skin)`, `RemoveAttachment` and `Clear` have been added. diff --git a/spine-unity/Assets/Examples/Scripts/Sample Components/SpineEventUnityHandler.cs b/spine-unity/Assets/Examples/Scripts/Sample Components/SpineEventUnityHandler.cs new file mode 100644 index 000000000..bbe2564bc --- /dev/null +++ b/spine-unity/Assets/Examples/Scripts/Sample Components/SpineEventUnityHandler.cs @@ -0,0 +1,82 @@ +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +namespace Spine.Unity.Modules { + + public class SpineEventUnityHandler : MonoBehaviour { + + [System.Serializable] + public class EventPair { + [SpineEvent] public string spineEvent; + public UnityEvent unityHandler; + public AnimationState.TrackEntryEventDelegate eventDelegate; + } + + public List events = new List(); + + ISkeletonComponent skeletonComponent; + IAnimationStateComponent animationStateComponent; + + void Start () { + skeletonComponent = skeletonComponent ?? GetComponent(); + if (skeletonComponent == null) return; + animationStateComponent = animationStateComponent ?? skeletonComponent as IAnimationStateComponent; + if (animationStateComponent == null) return; + var skeleton = skeletonComponent.Skeleton; + if (skeleton == null) return; + + + var skeletonData = skeleton.Data; + var state = animationStateComponent.AnimationState; + foreach (var ep in events) { + var eventData = skeletonData.FindEvent(ep.spineEvent); + ep.eventDelegate = ep.eventDelegate ?? delegate(TrackEntry trackEntry, Event e) { if (e.Data == eventData) ep.unityHandler.Invoke(); }; + state.Event += ep.eventDelegate; + } + } + + void OnDestroy () { + animationStateComponent = animationStateComponent ?? GetComponent(); + if (animationStateComponent == null) return; + + var state = animationStateComponent.AnimationState; + foreach (var ep in events) { + if (ep.eventDelegate != null) state.Event -= ep.eventDelegate; + ep.eventDelegate = null; + } + } + + } +} + diff --git a/spine-unity/Assets/Examples/Scripts/Sample Components/SpineEventUnityHandler.cs.meta b/spine-unity/Assets/Examples/Scripts/Sample Components/SpineEventUnityHandler.cs.meta new file mode 100644 index 000000000..2c88df0d7 --- /dev/null +++ b/spine-unity/Assets/Examples/Scripts/Sample Components/SpineEventUnityHandler.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 90293750f472d3340b452cec6fea2606 +timeCreated: 1495263964 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs b/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs index caf9b8c66..2ac1d1293 100644 --- a/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs @@ -52,7 +52,7 @@ namespace Spine.Unity.Editor { if (spriteSlicesLabel == null) { spriteSlicesLabel = new GUIContent( "Apply Regions as Texture Sprite Slices", - SpineInspectorUtility.UnityIcon(typeof(SceneAsset)), + SpineEditorUtilities.Icons.unity, "Adds Sprite slices to atlas texture(s). " + "Updates existing slices if ones with matching names exist. \n\n" + "If your atlas was exported with Premultiply Alpha, " + diff --git a/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs index c4b6d2811..67c609fcf 100644 --- a/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs @@ -259,10 +259,10 @@ namespace Spine.Unity.Editor { void DrawUnityTools () { #if SPINE_SKELETON_ANIMATOR using (new SpineInspectorUtility.BoxScope()) { - isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, SpineInspectorUtility.TempContent("SkeletonAnimator", SpineInspectorUtility.UnityIcon(typeof(SceneAsset)))); + isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, SpineInspectorUtility.TempContent("SkeletonAnimator", SpineInspectorUtility.UnityIcon())); if (isMecanimExpanded) { EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(controller, SpineInspectorUtility.TempContent("Controller", SpineInspectorUtility.UnityIcon(typeof(Animator)))); + EditorGUILayout.PropertyField(controller, SpineInspectorUtility.TempContent("Controller", SpineInspectorUtility.UnityIcon())); if (controller.objectReferenceValue == null) { // Generate Mecanim Controller Button diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonDebugWindow.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonDebugWindow.cs index 37ab3303b..ac9e02f1a 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonDebugWindow.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonDebugWindow.cs @@ -60,6 +60,7 @@ namespace Spine.Unity.Editor { static AnimBool showConstraintsTree = new AnimBool(false); static AnimBool showDrawOrderTree = new AnimBool(false); static AnimBool showEventDataTree = new AnimBool(false); + static AnimBool showDataTree = new AnimBool(false); static AnimBool showInspectBoneTree = new AnimBool(false); Vector2 scrollPos; @@ -488,9 +489,25 @@ namespace Spine.Unity.Editor { } } - // TODO: Data counts. bones, slots, constraints, skins, etc... + showDataTree.target = EditorGUILayout.Foldout(showDataTree.target, SpineInspectorUtility.TempContent("Data Counts", Icons.spine), BoldFoldoutStyle); + if (showDataTree.faded > 0) { + using (new SpineInspectorUtility.IndentScope()) { + using (new EditorGUILayout.FadeGroupScope(showDataTree.faded)) { + using (new SpineInspectorUtility.LabelWidthScope()) { + var skeletonData = skeleton.Data; + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Bones", Icons.bone, "Skeleton.Data.Bones"), new GUIContent(skeletonData.Bones.Count.ToString())); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Slots", Icons.slotRoot, "Skeleton.Data.Slots"), new GUIContent(skeletonData.Slots.Count.ToString())); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Skins", Icons.skinsRoot, "Skeleton.Data.Skins"), new GUIContent(skeletonData.Skins.Count.ToString())); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Events", Icons.userEvent, "Skeleton.Data.Events"), new GUIContent(skeletonData.Events.Count.ToString())); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("IK Constraints", Icons.constraintIK, "Skeleton.Data.IkConstraints"), new GUIContent(skeletonData.IkConstraints.Count.ToString())); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Transform Constraints", Icons.constraintTransform, "Skeleton.Data.TransformConstraints"), new GUIContent(skeletonData.TransformConstraints.Count.ToString())); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Path Constraints", Icons.constraintPath, "Skeleton.Data.PathConstraints"), new GUIContent(skeletonData.PathConstraints.Count.ToString())); + } + } + } + } - if (IsAnimating(showSlotsTree, showSkeleton, showConstraintsTree, showDrawOrderTree, showEventDataTree, showInspectBoneTree)) + if (IsAnimating(showSlotsTree, showSkeleton, showConstraintsTree, showDrawOrderTree, showEventDataTree, showInspectBoneTree, showDataTree)) Repaint(); } diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs index a32a733e5..8bfae3072 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs @@ -294,7 +294,7 @@ namespace Spine.Unity.Editor { EditorGUILayout.Space(); using (new SpineInspectorUtility.LabelWidthScope()) { - EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Vertex Data", SpineInspectorUtility.UnityIcon(typeof(MeshFilter))), EditorStyles.boldLabel); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Vertex Data", SpineInspectorUtility.UnityIcon()), EditorStyles.boldLabel); if (pmaVertexColors != null) EditorGUILayout.PropertyField(pmaVertexColors, PMAVertexColorsLabel); EditorGUILayout.PropertyField(tintBlack, TintBlackLabel); diff --git a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs index 5a9be7ce4..a01a4cf1a 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs @@ -245,6 +245,64 @@ namespace Spine.Unity.Editor { } + [CustomPropertyDrawer(typeof(SpineIkConstraint))] + public class SpineIkConstraintDrawer : SpineTreeItemDrawerBase { + + protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintIK; } } + + protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineIkConstraint targetAttribute, SkeletonData data) { + var constraints = skeletonDataAsset.GetSkeletonData(false).IkConstraints; + + if (TargetAttribute.includeNone) + menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); + + for (int i = 0; i < constraints.Count; i++) { + string name = constraints.Items[i].Name; + if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + } + + } + + [CustomPropertyDrawer(typeof(SpineTransformConstraint))] + public class SpineTransformConstraintDrawer : SpineTreeItemDrawerBase { + + protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintTransform; } } + + protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineTransformConstraint targetAttribute, SkeletonData data) { + var constraints = skeletonDataAsset.GetSkeletonData(false).TransformConstraints; + + if (TargetAttribute.includeNone) + menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); + + for (int i = 0; i < constraints.Count; i++) { + string name = constraints.Items[i].Name; + if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + } + } + + [CustomPropertyDrawer(typeof(SpinePathConstraint))] + public class SpinePathConstraintDrawer : SpineTreeItemDrawerBase { + + protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.constraintPath; } } + + protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpinePathConstraint targetAttribute, SkeletonData data) { + var constraints = skeletonDataAsset.GetSkeletonData(false).PathConstraints; + + if (TargetAttribute.includeNone) + menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); + + for (int i = 0; i < constraints.Count; i++) { + string name = constraints.Items[i].Name; + if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) + menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + } + } + } + [CustomPropertyDrawer(typeof(SpineAttachment))] public class SpineAttachmentDrawer : SpineTreeItemDrawerBase { diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs index 03e7c0fff..3c61907e9 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs @@ -82,7 +82,7 @@ namespace Spine.Unity.Editor { public static Texture2D info; -// public static Texture2D unityIcon; + public static Texture2D unity; // public static Texture2D controllerIcon; public static void Initialize () { @@ -120,7 +120,7 @@ namespace Spine.Unity.Editor { path = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-path.png"); info = EditorGUIUtility.FindTexture("console.infoicon.sml"); -// unityIcon = EditorGUIUtility.FindTexture("SceneAsset Icon"); + unity = EditorGUIUtility.FindTexture("SceneAsset Icon"); // controllerIcon = EditorGUIUtility.FindTexture("AnimatorController Icon"); } diff --git a/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs b/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs index 285aff0f6..49889d3ea 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs @@ -75,7 +75,11 @@ namespace Spine.Unity.Editor { return current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed"; } - public static Texture2D UnityIcon (System.Type type) { + public static Texture2D UnityIcon() { + return EditorGUIUtility.ObjectContent(null, typeof(T)).image as Texture2D; + } + + public static Texture2D UnityIcon(System.Type type) { return EditorGUIUtility.ObjectContent(null, type).image as Texture2D; } diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBuffered.cs b/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBuffered.cs index 425efc2f5..0a674387c 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBuffered.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBuffered.cs @@ -34,6 +34,10 @@ namespace Spine.Unity { readonly T b = new T(); bool usingA; + public T GetCurrent () { + return usingA ? a : b; + } + public T GetNext () { usingA = !usingA; return usingA ? a : b; diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs index 79b1ce471..364d34811 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs @@ -113,7 +113,17 @@ namespace Spine.Unity.Editor { [MenuItem("CONTEXT/SkeletonGraphic/Match RectTransform with Mesh Bounds")] static void MatchRectTransformWithBounds (MenuCommand command) { var skeletonGraphic = (SkeletonGraphic)command.context; - var mesh = skeletonGraphic.GetComponent().sharedMesh; + Mesh mesh = skeletonGraphic.GetLastMesh(); + if (mesh == null) { + Debug.Log("Mesh was not previously generated."); + return; + } + + if (mesh.vertexCount == 0) { + skeletonGraphic.rectTransform.sizeDelta = new Vector2(50f, 50f); + skeletonGraphic.rectTransform.pivot = new Vector2(0.5f, 0.5f); + return; + } mesh.RecalculateBounds(); var bounds = mesh.bounds; @@ -143,33 +153,6 @@ namespace Spine.Unity.Editor { EditorGUIUtility.PingObject(Selection.activeObject); } -// [MenuItem("Assets/Spine/Instantiate (UnityUI)", false, 20)] -// static void InstantiateSkeletonGraphic () { -// Object[] arr = Selection.objects; -// foreach (Object o in arr) { -// string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(o)); -// string skinName = EditorPrefs.GetString(guid + "_lastSkin", ""); -// -// InstantiateSkeletonGraphic((SkeletonDataAsset)o, skinName); -// SceneView.RepaintAll(); -// } -// } -// -// [MenuItem("Assets/Spine/Instantiate (UnityUI)", true, 20)] -// static bool ValidateInstantiateSkeletonGraphic () { -// Object[] arr = Selection.objects; -// -// if (arr.Length == 0) -// return false; -// -// foreach (var selected in arr) { -// if (selected.GetType() != typeof(SkeletonDataAsset)) -// return false; -// } -// -// return true; -// } - // SpineEditorUtilities.InstantiateDelegate. Used by drag and drop. public static Component SpawnSkeletonGraphicFromDrop (SkeletonDataAsset data) { return InstantiateSkeletonGraphic(data); diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs index 108768b97..694a05d05 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs @@ -67,6 +67,18 @@ namespace Spine.Unity { Debug.LogError("Unity UI does not support multiple textures per Renderer. Your skeleton will not be rendered correctly. Recommend using SkeletonAnimation instead. This requires the use of a Screen space camera canvas."); } else { if (freeze) return; + + if (!string.IsNullOrEmpty(initialSkinName)) { + var skin = skeleton.data.FindSkin(initialSkinName); + if (skin != null) { + if (skin == skeleton.data.defaultSkin) + skeleton.SetSkin((Skin)null); + else + skeleton.SetSkin(skin); + } + + } + skeleton.SetToSetupPose(); if (!string.IsNullOrEmpty(startingAnimation)) skeleton.PoseWithAnimation(startingAnimation, 0f, false); @@ -171,6 +183,10 @@ namespace Spine.Unity { DoubleBuffered meshBuffers; SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction(); + public Mesh GetLastMesh () { + return meshBuffers.GetCurrent().mesh; + } + public event UpdateBonesDelegate UpdateLocal; public event UpdateBonesDelegate UpdateWorld; public event UpdateBonesDelegate UpdateComplete;