/// <sumary> /// Import ase file at aPath to aObject /// </sumary> /// <param name="aPath">Path</param> /// <param name="aObject">Aseprite object</param> public static bool Import(string aPath, CAsepriteObject aObject) { bool tExported = CAsepriteExporter.Export(aPath, aObject); if (tExported) { TextureImporter tTexture = AssetImporter.GetAtPath( AssetDatabase.GetAssetPath(aObject.targetTexture)) as TextureImporter; // TODO: See if I can put the texture as an embeded object /* * Texture2D tNewTex = new Texture2D(1, 1); * tNewTex.SetPixel(0, 0, Color.cyan); * tNewTex.Apply(); * AssetDatabase.AddObjectToAsset(tNewTex, aObject); */ CAsepriteImporter.ImportSheet(tTexture, aObject); CAsepriteImporter.ImportAnimation(tTexture, aObject); CAsepriteWindow.CreateAnimator(aObject); } return(tExported); }
/// <sumary> /// Find aseprite asset corresponding to AsepriteObject /// </sumary> /// <param name="aObject">Aseprite object</param> public static Object FindAsepriteAsset(CAsepriteObject aObject) { Object[] tObjects = Resources.FindObjectsOfTypeAll <Object>(); for (int j = 0; j < tObjects.Length; j++) { var asset = tObjects[j]; var path = AssetDatabase.GetAssetPath(asset); if (path.ToLower().EndsWith(".ase")) { AssetImporter tImporter = AssetImporter.GetAtPath(path); JSONNode tData = JSON.Parse(tImporter.userData); JSONNode tID = tData["assetID"]; if (tID != null) { var obj = GetAssetByID <CAsepriteObject>(tID.Value); if (obj != null) { return(asset); } } } } return(null); }
static EditorCurveBinding GetBinding(CAsepriteObject aEnv) { EditorCurveBinding curveBinding = new EditorCurveBinding(); // Set type if (aEnv.animType == AnimationType.SpriteRenderer) { curveBinding.type = typeof(SpriteRenderer); } else if (aEnv.animType == AnimationType.Image) { curveBinding.type = typeof(UnityEngine.UI.Image); } curveBinding.propertyName = "m_Sprite"; if (aEnv.useChild) { curveBinding.path = BINDING_PATH; } else { curveBinding.path = ""; } return(curveBinding); }
/// <sumary> /// Creates a new CAsepriteObject asset on aPath /// </sumary> /// <param name="aPath">Path</param> public static CAsepriteObject CreateAsset(string aPath) { CAsepriteObject tObj = NewInstance(); AssetDatabase.CreateAsset(tObj, Path.GetDirectoryName(aPath) + "/" + Path.GetFileNameWithoutExtension(aPath) + ".asset"); return(tObj); }
/// <summary> /// Creates spritesheet on aTexture using the json aAtlas generated by aseprite /// </summary> /// <param name="aTexture">Spritesheet texture</param> /// <param name="aObj">Aseprite object</param> public static void ImportSheet(TextureImporter aTexture, CAsepriteObject aObj) { // Change metadata CAtlasData tData = JsonConvert.DeserializeObject <CAtlasData>(aObj.targetAtlas.text); List <SpriteMetaData> tMetaData = new List <SpriteMetaData>(); aTexture.textureType = TextureImporterType.Sprite; aTexture.spriteImportMode = SpriteImportMode.Multiple; aTexture.filterMode = FilterMode.Point; #if UNITY_5_6_OR_NEWER aTexture.textureCompression = TextureImporterCompression.Uncompressed; #else aTexture.textureFormat = TextureImporterFormat.AutomaticTruecolor; #endif List <string> tKeys = new List <string>(); tKeys.AddRange(tData.frames.Keys); tKeys.Sort(); Dictionary <string, int> tAnimations = new Dictionary <string, int>(); Vector2 tPivot = aObj.pivot; SpriteAlignment tAlignment = aObj.alignment; for (int i = 0; i < tKeys.Count; i++) { string tKey = tKeys[i]; CAtlasData.Frame tFrame = tData.frames[tKey]; SpriteMetaData tThisData = new SpriteMetaData(); string tTag = GetTag(tKey); if (tTag != "") { if (tAnimations.ContainsKey(tTag)) { tAnimations[tTag] += 1; } else { tAnimations.Add(tTag, 0); } string tName = tTag + "_" + tAnimations[tTag]; tThisData.name = tName; tThisData.rect = new Rect( tFrame.frame.x, tFrame.frame.y, tFrame.frame.w, tFrame.frame.h ); tThisData.rect.y = tData.meta.size.h - tThisData.rect.y - tThisData.rect.height; tThisData.alignment = (int)tAlignment; tThisData.pivot = tPivot; tMetaData.Add(tThisData); } } aTexture.spritesheet = tMetaData.ToArray(); AssetDatabase.ImportAsset(aTexture.assetPath, ImportAssetOptions.ForceUpdate); }
void ApplyChanges() { for (int i = 0; i < m_AssetTargets.Length; i++) { CAsepriteObject tObj = m_AssetTargets[i]; if (m_UseTags.dirty) { tObj.useTags = m_UseTags.value; } if (m_LoopAnim.dirty) { tObj.loopAnim = m_LoopAnim.value; } if (m_UseConfig.dirty) { tObj.useConfig = m_UseConfig.value; } if (m_Border.dirty) { tObj.border = m_Border.value; } if (m_UseChild.dirty) { tObj.useChild = m_UseChild.value; } if (m_Alignment.dirty) { tObj.alignment = m_Alignment.value; } if (m_Pivot.dirty) { tObj.pivot = m_Pivot.value; } if (m_AnimType.dirty) { tObj.animType = m_AnimType.value; } Import(AssetDatabase.GetAssetPath(tObj.asepriteAsset), tObj); EditorUtility.SetDirty(tObj); } m_UseTags.dirty = false; m_LoopAnim.dirty = false; m_UseConfig.dirty = false; m_Border.dirty = false; m_UseChild.dirty = false; m_Alignment.dirty = false; m_Pivot.dirty = false; m_AnimType.dirty = false; }
/// <sumary> /// Creates a new generic CAsepriteObject /// </sumary> public static CAsepriteObject NewInstance() { CAsepriteObject tObj = CreateInstance <CAsepriteObject>(); tObj.useTags = CAsepriteWindow.UseTags; tObj.loopAnim = CAsepriteWindow.LoopAnim; tObj.useConfig = CAsepriteWindow.UseConfig; tObj.border = CAsepriteWindow.Border; tObj.useChild = CAsepriteWindow.UseChild; tObj.alignment = CAsepriteWindow.Alignment; tObj.pivot = CAsepriteWindow.Pivot; tObj.animType = CAsepriteWindow.AnimType; /*tObj.autoImport = CAsepriteWindow.AutoImport; * tObj.importSpritesheet = CAsepriteWindow.ImportSpritesheet; * tObj.importAnimations = CAsepriteWindow.ImportAnimations; * tObj.createAnimator = CAsepriteWindow.CreateAnimatorDefault;*/ tObj.clips = new AnimationClip[0]; return(tObj); }
/// <summary> /// Creates an animator asset using the aseprite object /// </summary> /// <param name="aObj">Aseprite object</param> public static void CreateAnimator(CAsepriteObject aObj) { // Check if animator already exists if (aObj.targetAnimator == null || aObj.targetAnimator.layers == null || aObj.targetAnimator.layers.Length == 0 || aObj.targetAnimator.layers[0].stateMachine == null ) { if (aObj.targetAnimator != null) { DestroyImmediate(aObj.targetAnimator); } aObj.targetAnimator = new AnimatorController(); aObj.targetAnimator.AddLayer("Base"); aObj.targetAnimator.name = aObj.name + " Animator"; AssetDatabase.AddObjectToAsset(aObj.targetAnimator, aObj); Debug.Log("Created animator"); } AnimatorStateMachine tRootStateMachine = aObj.targetAnimator.layers[0].stateMachine; for (int i = 0; i < aObj.clips.Length; i++) { bool tFound = false; AnimationClip tClip = aObj.clips[i]; for (int j = 0; j < tRootStateMachine.states.Length; j++) { if (tRootStateMachine.states[j].state.motion == tClip) { tFound = true; break; } } if (!tFound) { AnimatorState tState = tRootStateMachine.AddState(tClip.name); tState.motion = tClip; } } }
/// <summary> /// Creates AnimationClips using the information in the json atlas created /// by aseprite. /// If CAsepriteWindow.UseTags is true, it separates the animations, /// otherwise it creates only one animation. /// </summary> /// <param name="aTexture">Spritesheet texture</param> /// <param name="aObj">Aseprite object</param> /// <returns>AnimationClips created</returns> public static AnimationClip[] ImportAnimation(TextureImporter aTexture, CAsepriteObject aObj) { CAtlasData tData = JsonConvert.DeserializeObject <CAtlasData>(aObj.targetAtlas.text); aTexture.textureType = TextureImporterType.Sprite; aTexture.spriteImportMode = SpriteImportMode.Multiple; aTexture.filterMode = FilterMode.Point; List <string> tKeys = new List <string>(); tKeys.AddRange(tData.frames.Keys); Dictionary <string, int> tAnimationsIndices = new Dictionary <string, int>(); Dictionary <string, List <Frame> > tAnimations = new Dictionary <string, List <Frame> >(); Sprite[] tSprites = AssetDatabase.LoadAllAssetsAtPath(aTexture.assetPath) .OfType <Sprite>().ToArray(); ResetOptions(); foreach (string tKey in tKeys) { string tTag = GetTag(tKey); if (tTag != "") { List <Frame> tFrameList; if (tAnimations.ContainsKey(tTag)) { tFrameList = tAnimations[tTag]; } else { tAnimationsIndices.Add(tTag, 0); tFrameList = new List <Frame>(); tAnimations.Add(tTag, tFrameList); } ObjectReferenceKeyframe kf = new ObjectReferenceKeyframe(); if (tFrameList.Count > 0) { float tTime = 0; for (int i = 0; i < tFrameList.Count; i++) { tTime += tFrameList[i].length; } kf.time = tTime; } else { kf.time = 0; } kf.value = GetSprite(tSprites, tTag + "_" + tAnimationsIndices[tTag].ToString()); Frame tFrame = new Frame(); tFrame.frame = kf; tFrame.length = tData.frames[tKey].duration / 1000f; tAnimations[tTag].Add(tFrame); tAnimationsIndices[tTag] += 1; } } foreach (KeyValuePair <string, KeyValuePair <int, string[]> > tPair in _frameOptions) { KeyValuePair <int, string[]> tEvent = tPair.Value; for (int i = 0; i < tEvent.Value.Length; i++) { Debug.Log(tEvent.Key + ", " + tEvent.Value[i]); } } EditorCurveBinding tBinding = GetBinding(aObj); AnimationClip[] tClips = new AnimationClip[tAnimations.Keys.Count]; int j = 0; foreach (string tKey in tAnimations.Keys) { int tInd = ClipInList(aObj.clips, tKey); AnimationClip tClip; if (tInd >= 0) { tClip = aObj.clips[tInd]; } else { tClip = new AnimationClip(); } List <Frame> tAnimation = tAnimations[tKey]; int tFramecount = tAnimation.Count; tClip.frameRate = 60; tClip.wrapMode = WrapMode.Loop; ObjectReferenceKeyframe[] keyFrames = new ObjectReferenceKeyframe[tFramecount + 1]; for (int i = 0; i < tFramecount; i++) { keyFrames[i] = tAnimation[i].frame; } ObjectReferenceKeyframe kf = new ObjectReferenceKeyframe(); kf.time = keyFrames[tFramecount - 1].time + tAnimation[0].length; if ((!aObj.useConfig && aObj.loopAnim) || (aObj.useConfig && !HasOption(tKey, NO_LOOP))) { // Make last frame the same as first kf.value = tAnimation[0].frame.value; // Make animation loop AnimationClipSettings tSettings = AnimationUtility.GetAnimationClipSettings(tClip); tSettings.loopTime = true; AnimationUtility.SetAnimationClipSettings(tClip, tSettings); } else { kf.value = tAnimation[tAnimation.Count - 1].frame.value; } keyFrames[tFramecount] = kf; AnimationUtility.SetObjectReferenceCurve(tClip, tBinding, keyFrames); tClip.name = tKey; tClips[j] = tClip; j++; /* * string tAnimPath; * if (aEnv.targetAnimator != null) * { * string tPath = AssetDatabase.GetAssetPath(aEnv.targetAnimator); * tAnimPath = Path.GetDirectoryName(tPath) + "/" + aEnv.name + "_" + tKey + ".anim"; * } * else * { * if (CAsepriteWindow.UseConfiguredTargets) * tAnimPath = CAsepriteWindow.TargetAnimDir; * else * tAnimPath = Path.GetDirectoryName( * AssetDatabase.GetAssetPath(aEnv.targetTexture)); * if (string.IsNullOrEmpty(tAnimPath)) * tAnimPath = Path.GetDirectoryName( * AssetDatabase.GetAssetPath(aEnv.targetTexture)); * tAnimPath += "/" + aEnv.name + "_" + tKey + ".anim"; * } */ if (tInd < 0) { //if (tAnimPath.StartsWith(Application.dataPath)) // tAnimPath = "Assets/" + tAnimPath.Substring(Application.dataPath.Length); //AssetDatabase.CreateAsset(tClip, tAnimPath); AssetDatabase.AddObjectToAsset(tClip, aObj); } } AssetDatabase.SaveAssets(); // Frame options foreach (KeyValuePair <string, KeyValuePair <int, string[]> > tOption in _frameOptions) { AnimationClip tClip = GetClip(tClips, tOption.Key); List <AnimationEvent> tEvents = new List <AnimationEvent>(); if (tClip != null) { ObjectReferenceKeyframe[] tFrameList = AnimationUtility.GetObjectReferenceCurve(tClip, tBinding); int tFrameNum = tOption.Value.Key; if (tFrameNum >= 0 && tFrameNum < tFrameList.Length) { ObjectReferenceKeyframe tFrame = tFrameList[tFrameNum]; for (int i = 0; i < tOption.Value.Value.Length; i++) { string tOptionName = tOption.Value.Value[i]; if (tOptionName.StartsWith(EVENT_PLUS) && tFrameNum < tFrameList.Length - 1) { tFrame = tFrameList[tFrameNum + 1]; AnimationEvent tEvent = new AnimationEvent(); tEvent.time = tFrame.time; string[] tValues = tOptionName.Split(EVENT_SEPARATOR); if (tValues.Length > 1) { tValues = tValues[1].Split(SEPARATOR); if (tValues.Length > 1) { tEvent.functionName = tValues[0]; tEvent.stringParameter = tValues[1]; tEvents.Add(tEvent); } } } else if (tOptionName.StartsWith(EVENT)) { AnimationEvent tEvent = new AnimationEvent(); tEvent.time = tFrame.time; string[] tValues = tOptionName.Split(EVENT_SEPARATOR); if (tValues.Length > 1) { tValues = tValues[1].Split(SEPARATOR); if (tValues.Length > 1) { tEvent.functionName = tValues[0]; tEvent.stringParameter = tValues[1]; tEvents.Add(tEvent); } } } } } AnimationUtility.SetAnimationEvents(tClip, tEvents.ToArray()); } } aObj.clips = tClips; return(tClips); }
static void PostProcessDelayed() { EditorApplication.delayCall -= PostProcessDelayed; if (m_ImportedAssets.Count == 0) { return; } string[] tImportedAssets = m_ImportedAssets[0]; m_ImportedAssets.RemoveAt(0); bool tSaveAssets = false; for (int i = 0; i < tImportedAssets.Length; i++) { string tPath = tImportedAssets[i]; if (tPath.EndsWith(".ase")) { Object tAsset = AssetDatabase.LoadAssetAtPath <Object>(tPath); bool tDirty = false; AssetImporter tImporter = AssetImporter.GetAtPath(tPath); JSONNode tData = JSON.Parse(tImporter.userData); if (tData == null) { tData = new JSONObject(); } JSONNode tID = tData["assetID"]; CAsepriteObject tObj = null; if (tID != null) { tObj = GetAssetByID <CAsepriteObject>(tID.Value); if (tObj == null) { tObj = FindAsepriteObject(tAsset); } } else { tID = new JSONNumber(0); tData["assetID"] = tID; tDirty = true; } if (tObj == null) { tObj = CAsepriteObjectEditor.CreateAsset(tPath); /* * { "targetTexture":"c92e2bd276d32ed4984c0a349da9dcc8", * "targetText":"1cb757cd5d2c60f4cb1d15f7653554bc", * "useTags":"true", * "loopAnim":"false", * "useConfig":"true", * "border":"5", * "useChild":"true", * "alignment":"0", * "pivotX":"0.100000001490116", * "pivotY":"0.200000002980232", * "animType":"0", * "clips":["7ab1c6126e7e91c4d8d19e3f7e8e8f6d","416c940187f463c4f9af57db128e5cbe"], * "autoImport":"false", * "importAnimations":"true", * "importSpritesheet":"true", * "createAnimator":"true", * "targetAnimator":"88400be09d870114491df24486087eb5", * "targetPrefab":"c1df4f5e993e4b347a7ab29909bebb01"} */ SetAssetValue(tData, "targetTexture", ref tObj.targetTexture); SetAssetValue(tData, "targetText", ref tObj.targetAtlas); SetBool(tData, "useTags", ref tObj.useTags); SetBool(tData, "loopAnim", ref tObj.loopAnim); SetBool(tData, "useConfig", ref tObj.useConfig); SetInt(tData, "border", ref tObj.border); SetFloat(tData, "pivotX", ref tObj.pivot.x); SetFloat(tData, "pivotY", ref tObj.pivot.y); int alignment = -1; if (SetInt(tData, "alignment", ref alignment)) { tObj.alignment = (SpriteAlignment)alignment; } var node = tData["clips"]; if (node != null && node.IsArray) { var clips = node.AsArray; tObj.clips = new AnimationClip[clips.Count]; for (int j = 0; j < tObj.clips.Length; j++) { tObj.clips[j] = GetAssetByID <AnimationClip>(clips[j].Value); } } SetAssetValue(tData, "targetAnimator", ref tObj.targetAnimator); SetAssetValue(tData, "targetPrefab", ref tObj.targetPrefab); EditorUtility.SetDirty(tObj); } tID.Value = GetIDByAsset(tObj); tObj.asepriteAsset = tAsset; bool tExported = CAsepriteObjectEditor.Import(tPath, tObj); if (tExported) { tImporter.userData = tData.ToString(); tSaveAssets = true; tDirty = true; } if (tDirty) { EditorUtility.SetDirty(tAsset); AssetDatabase.WriteImportSettingsIfDirty(tPath); } EditorUtility.SetDirty(tObj); } } if (tSaveAssets) { AssetDatabase.SaveAssets(); } }
/// <summary> /// Creates a prefab using the aseprite object /// </summary> /// <param name="aObj">Aseprite object</param> public static void CreatePrefab(CAsepriteObject aObj) { string tPrefabPath = AssetDatabase.GetAssetPath(aObj.targetPrefab); if (string.IsNullOrEmpty(tPrefabPath)) { string tPath = AssetDatabase.GetAssetPath(aObj.asepriteAsset); if (UseConfiguredTargets && !string.IsNullOrEmpty(TargetPrefabsDir)) { if (!Directory.Exists(TargetPrefabsDir)) { Directory.CreateDirectory(TargetPrefabsDir); } tPrefabPath = TargetPrefabsDir + "/" + Path.GetFileNameWithoutExtension(tPath) + ".prefab"; } else { tPrefabPath = Path.GetDirectoryName(tPath) + "/" + Path.GetFileNameWithoutExtension(tPath) + ".prefab"; } } if (tPrefabPath.StartsWith(Application.dataPath)) { tPrefabPath = "Assets" + tPrefabPath.Substring(Application.dataPath.Length); } GameObject tAnimGameObject = new GameObject(); tAnimGameObject.hideFlags = HideFlags.HideInHierarchy; Animator tAnimator = tAnimGameObject.AddComponent <Animator>(); // Create or edit the animator CreateAnimator(aObj); tAnimator.runtimeAnimatorController = null; tAnimator.runtimeAnimatorController = aObj.targetAnimator; bool tUseChild = aObj.useChild; SpriteRenderer tRenderer; Image tImage; EditorCurveBinding spriteBinding = new EditorCurveBinding(); if (aObj.animType == AnimationType.SpriteRenderer) { spriteBinding.type = typeof(SpriteRenderer); } else if (aObj.animType == AnimationType.Image) { spriteBinding.type = typeof(Image); } spriteBinding.propertyName = "m_Sprite"; if (tUseChild) { spriteBinding.path = CAsepriteImporter.BINDING_PATH; } else { spriteBinding.path = ""; } ObjectReferenceKeyframe[] tRef = AnimationUtility.GetObjectReferenceCurve( aObj.clips[0], spriteBinding); if (aObj.animType == AnimationType.SpriteRenderer) { if (tUseChild) { tRenderer = new GameObject(CAsepriteImporter.BINDING_PATH).AddComponent <SpriteRenderer>(); tRenderer.transform.SetParent(tAnimGameObject.transform); } else { tRenderer = tAnimGameObject.AddComponent <SpriteRenderer>(); } if (tRef != null && tRef.Length > 0) { tRenderer.sprite = tRef[0].value as Sprite; } else { Debug.LogWarning("The asset is marked as \"" + (aObj.useChild ? "don't " : "") + "use child object for animation\" but the animation seems to be configured differently." + "\nTry changing this configuration."); } } else if (aObj.animType == AnimationType.Image) { tAnimGameObject.AddComponent <RectTransform>(); if (tUseChild) { tImage = new GameObject(CAsepriteImporter.BINDING_PATH).AddComponent <Image>(); tImage.transform.SetParent(tAnimGameObject.transform); } else { tImage = tAnimGameObject.AddComponent <Image>(); } if (tRef != null && tRef.Length > 0) { tImage.sprite = tRef[0].value as Sprite; } else { Debug.LogWarning("The asset is marked as \"" + (aObj.useChild ? "don't " : "") + "use child object for animation\" but the animation seems to be configured differently." + "\nTry changing this configuration."); } } if (aObj.targetPrefab != null) { aObj.targetPrefab = PrefabUtility.ReplacePrefab(tAnimGameObject, aObj.targetPrefab, ReplacePrefabOptions.ConnectToPrefab); } else { #if UNITY_2019_1_OR_NEWER PrefabUtility.SaveAsPrefabAsset(tAnimGameObject, tPrefabPath); aObj.targetPrefab = AssetDatabase.LoadAssetAtPath <GameObject>(tPrefabPath); #else aObj.targetPrefab = PrefabUtility.CreatePrefab(tPrefabPath, tAnimGameObject); #endif } Selection.activeObject = aObj.targetPrefab; DestroyImmediate(tAnimGameObject); EditorUtility.SetDirty(aObj); }
/// <summary> /// Exports a .ase file to a .json and .png file using Aseprite CLI /// </summary> /// <param name="aFile">.ase file path</param> /// <param name="aObj">Aseprite object</param> /// <returns></returns> public static bool Export(string aFile, CAsepriteObject aObj) { string tExePath = CAsepriteWindow.AsepriteExePath; if (!File.Exists(tExePath)) { UnityEngine.Debug.Log("File " + tExePath + " not found"); return(false); } // Create arguments string tName = Path.GetFileNameWithoutExtension(aFile); string tOutPath; if (aObj.targetTexture == null) { if (!CAsepriteWindow.UseConfiguredTargets || CAsepriteWindow.TargetDir == "") { tOutPath = Path.GetDirectoryName(aFile); } else { tOutPath = CAsepriteWindow.TargetDir; } if (!Directory.Exists(tOutPath)) { Directory.CreateDirectory(tOutPath); } tOutPath += "/" + tName + ".png"; } else { tOutPath = AssetDatabase.GetAssetPath(aObj.targetTexture); } int tBorder = aObj.border; string tFramename = ""; if (aObj.useTags) { tFramename = "{frame000}_{tag}"; } else { tFramename = "{frame000}_{title}"; } string args = "-b \"" + aFile + "\" --filename-format " + tFramename + " --sheet-pack "; if (tBorder > 0) { args += "--inner-padding " + tBorder.ToString() + " "; } args += "--sheet \"" + tOutPath + "\""; // Create process Process tProcess = new Process(); tProcess.StartInfo.FileName = tExePath; tProcess.StartInfo.UseShellExecute = false; tProcess.StartInfo.Arguments = args; tProcess.StartInfo.CreateNoWindow = true; tProcess.StartInfo.RedirectStandardOutput = true; tProcess.StartInfo.RedirectStandardError = true; tProcess.EnableRaisingEvents = true; tProcess.Start(); string tOutput = tProcess.StandardOutput.ReadToEnd(); using (StreamReader s = tProcess.StandardError) { //string error = s.ReadToEnd(); tProcess.WaitForExit(20000); } if (string.IsNullOrEmpty(tOutput)) { return(false); } // Apply border to atlas if (tBorder > 0) { CAtlasData tData = JsonConvert.DeserializeObject <CAtlasData>(tOutput); foreach (CAtlasData.Frame tFrame in tData.frames.Values) { tFrame.frame.x += tBorder; tFrame.frame.w -= tBorder * 2; tFrame.frame.y += tBorder; tFrame.frame.h -= tBorder * 2; } tOutput = JsonConvert.SerializeObject(tData, Formatting.Indented); } string tOutJsonFilePath; if (aObj.targetAtlas == null) { if (!CAsepriteWindow.UseConfiguredTargets || CAsepriteWindow.TargetDir == "") { tOutJsonFilePath = Path.GetDirectoryName(aFile); } else { tOutJsonFilePath = CAsepriteWindow.TargetDir; } if (!Directory.Exists(tOutJsonFilePath)) { Directory.CreateDirectory(tOutJsonFilePath); } tOutJsonFilePath += "/" + tName + ".json"; } else { tOutJsonFilePath = AssetDatabase.GetAssetPath(aObj.targetAtlas); } File.WriteAllText(tOutJsonFilePath, tOutput); if (tOutJsonFilePath.StartsWith(Application.dataPath)) { tOutJsonFilePath = "Assets" + tOutJsonFilePath.Substring(Application.dataPath.Length); } if (tOutPath.StartsWith(Application.dataPath)) { tOutPath = "Assets" + tOutPath.Substring(Application.dataPath.Length); } AssetDatabase.ImportAsset(tOutPath, ImportAssetOptions.ForceSynchronousImport); AssetDatabase.ImportAsset(tOutJsonFilePath, ImportAssetOptions.ForceSynchronousImport); aObj.targetAtlas = AssetDatabase.LoadAssetAtPath <TextAsset>(tOutJsonFilePath); aObj.targetTexture = AssetDatabase.LoadAssetAtPath <Texture2D>(tOutPath); aObj.LastExport = DateTime.Now; return(true); }