mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 23:34:53 +08:00
[unity] Providing error dialog and verbose error log message in case of version mismatch. Also providing error description when viewing skeletonData in inspector. Closes #1463.
This commit is contained in:
parent
45362e60bf
commit
38d0204e72
@ -40,7 +40,7 @@ using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
using Spine;
|
||||
using CompatibilityProblemInfo = Spine.Unity.SkeletonDataCompatibility.CompatibilityProblemInfo;
|
||||
|
||||
namespace Spine.Unity.Editor {
|
||||
using Event = UnityEngine.Event;
|
||||
@ -69,6 +69,7 @@ namespace Spine.Unity.Editor {
|
||||
SkeletonData targetSkeletonData;
|
||||
|
||||
readonly List<string> warnings = new List<string>();
|
||||
CompatibilityProblemInfo compatibilityProblemInfo = null;
|
||||
readonly SkeletonInspectorPreview preview = new SkeletonInspectorPreview();
|
||||
|
||||
GUIStyle activePlayButtonStyle, idlePlayButtonStyle;
|
||||
@ -140,9 +141,9 @@ namespace Spine.Unity.Editor {
|
||||
return;
|
||||
}
|
||||
|
||||
targetSkeletonData = warnings.Count == 0 ? targetSkeletonDataAsset.GetSkeletonData(false) : null;
|
||||
targetSkeletonData = NoProblems() ? targetSkeletonDataAsset.GetSkeletonData(false) : null;
|
||||
|
||||
if (targetSkeletonData != null && warnings.Count <= 0) {
|
||||
if (targetSkeletonData != null && NoProblems()) {
|
||||
preview.Initialize(this.Repaint, targetSkeletonDataAsset, this.LastSkinName);
|
||||
}
|
||||
|
||||
@ -174,12 +175,15 @@ namespace Spine.Unity.Editor {
|
||||
// Header
|
||||
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(target.name + " (SkeletonDataAsset)", Icons.spine), EditorStyles.whiteLargeLabel);
|
||||
if (targetSkeletonData != null) EditorGUILayout.LabelField("(Drag and Drop to instantiate.)", EditorStyles.miniLabel);
|
||||
|
||||
|
||||
// Main Serialized Fields
|
||||
using (var changeCheck = new EditorGUI.ChangeCheckScope()) {
|
||||
using (new SpineInspectorUtility.BoxScope())
|
||||
DrawSkeletonDataFields();
|
||||
|
||||
if (compatibilityProblemInfo != null)
|
||||
return;
|
||||
|
||||
using (new SpineInspectorUtility.BoxScope()) {
|
||||
DrawAtlasAssetsFields();
|
||||
HandleAtlasAssetsNulls();
|
||||
@ -197,11 +201,11 @@ namespace Spine.Unity.Editor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Unity Quirk: Some code depends on valid preview. If preview is initialized elsewhere, this can cause contents to change between Layout and Repaint events, causing GUILayout control count errors.
|
||||
if (warnings.Count <= 0)
|
||||
if (NoProblems())
|
||||
preview.Initialize(this.Repaint, targetSkeletonDataAsset, this.LastSkinName);
|
||||
|
||||
|
||||
if (targetSkeletonData != null) {
|
||||
GUILayout.Space(20f);
|
||||
|
||||
@ -317,6 +321,12 @@ namespace Spine.Unity.Editor {
|
||||
}
|
||||
}
|
||||
EditorGUILayout.PropertyField(skeletonJSON, SpineInspectorUtility.TempContent(skeletonJSON.displayName, Icons.spine));
|
||||
|
||||
if (compatibilityProblemInfo != null) {
|
||||
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(compatibilityProblemInfo.DescriptionString(), Icons.warning), GUILayout.Height(52));
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.DelayedFloatField(scale); //EditorGUILayout.PropertyField(scale);
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.PropertyField(skeletonDataModifiers, true);
|
||||
@ -581,12 +591,14 @@ namespace Spine.Unity.Editor {
|
||||
|
||||
void PopulateWarnings () {
|
||||
warnings.Clear();
|
||||
compatibilityProblemInfo = null;
|
||||
|
||||
if (skeletonJSON.objectReferenceValue == null) {
|
||||
warnings.Add("Missing Skeleton JSON");
|
||||
} else {
|
||||
var fieldValue = (TextAsset)skeletonJSON.objectReferenceValue;
|
||||
if (!AssetUtility.IsSpineData(fieldValue)) {
|
||||
|
||||
if (!AssetUtility.IsSpineData(fieldValue, out compatibilityProblemInfo)) {
|
||||
warnings.Add("Skeleton data file is not a valid Spine JSON or binary file.");
|
||||
} else {
|
||||
#if SPINE_TK2D
|
||||
@ -657,6 +669,10 @@ namespace Spine.Unity.Editor {
|
||||
EditorPrefs.SetString(LastSkinKey, skinName);
|
||||
}
|
||||
|
||||
bool NoProblems() {
|
||||
return warnings.Count == 0 && compatibilityProblemInfo == null;
|
||||
}
|
||||
|
||||
#region Preview Handlers
|
||||
void HandleOnDestroyPreview () {
|
||||
EditorApplication.update -= preview.HandleEditorUpdate;
|
||||
@ -677,7 +693,7 @@ namespace Spine.Unity.Editor {
|
||||
}
|
||||
|
||||
override public void OnInteractivePreviewGUI (Rect r, GUIStyle background) {
|
||||
if (warnings.Count <= 0) {
|
||||
if (NoProblems()) {
|
||||
preview.Initialize(this.Repaint, targetSkeletonDataAsset, this.LastSkinName);
|
||||
preview.HandleInteractivePreviewGUI(r, background);
|
||||
}
|
||||
|
||||
@ -46,18 +46,17 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Globalization;
|
||||
|
||||
using CompatibilityProblemInfo = Spine.Unity.SkeletonDataCompatibility.CompatibilityProblemInfo;
|
||||
|
||||
namespace Spine.Unity.Editor {
|
||||
using PathAndProblemInfo = System.Collections.Generic.KeyValuePair<string, CompatibilityProblemInfo>;
|
||||
|
||||
public static class AssetUtility {
|
||||
|
||||
public const string SkeletonDataSuffix = "_SkeletonData";
|
||||
public const string AtlasSuffix = "_Atlas";
|
||||
|
||||
static readonly int[][] compatibleBinaryVersions = { new[] { 3, 8, 0 }, new[] { 3, 9, 0 } };
|
||||
static readonly int[][] compatibleJsonVersions = { new[] { 3, 8, 0 }, new[] { 3, 9, 0 } };
|
||||
//static bool isFixVersionRequired = false;
|
||||
|
||||
/// HACK: This list keeps the asset reference temporarily during importing.
|
||||
///
|
||||
/// In cases of very large projects/sufficient RAM pressure, when AssetDatabase.SaveAssets is called,
|
||||
@ -125,7 +124,11 @@ namespace Spine.Unity.Editor {
|
||||
if (root == null || !root.ContainsKey("skins"))
|
||||
return requiredPaths;
|
||||
|
||||
foreach (Dictionary<string, object> skinMap in (List<object>)root["skins"]) {
|
||||
var skinsList = root["skins"] as List<object>;
|
||||
if (skinsList == null)
|
||||
return requiredPaths;
|
||||
|
||||
foreach (Dictionary<string, object> skinMap in skinsList) {
|
||||
if (!skinMap.ContainsKey("attachments"))
|
||||
continue;
|
||||
foreach (var slot in (Dictionary<string, object>)skinMap["attachments"]) {
|
||||
@ -243,7 +246,8 @@ namespace Spine.Unity.Editor {
|
||||
public static void ImportSpineContent (string[] imported, bool reimport = false) {
|
||||
var atlasPaths = new List<string>();
|
||||
var imagePaths = new List<string>();
|
||||
var skeletonPaths = new List<string>();
|
||||
var skeletonPaths = new List<PathAndProblemInfo>();
|
||||
CompatibilityProblemInfo compatibilityProblemInfo = null;
|
||||
|
||||
foreach (string str in imported) {
|
||||
string extension = Path.GetExtension(str).ToLower();
|
||||
@ -263,13 +267,13 @@ namespace Spine.Unity.Editor {
|
||||
break;
|
||||
case ".json":
|
||||
var jsonAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(str);
|
||||
if (jsonAsset != null && IsSpineData(jsonAsset))
|
||||
skeletonPaths.Add(str);
|
||||
if (jsonAsset != null && IsSpineData(jsonAsset, out compatibilityProblemInfo))
|
||||
skeletonPaths.Add(new PathAndProblemInfo(str, compatibilityProblemInfo));
|
||||
break;
|
||||
case ".bytes":
|
||||
if (str.ToLower().EndsWith(".skel.bytes", System.StringComparison.Ordinal)) {
|
||||
if (IsSpineData(AssetDatabase.LoadAssetAtPath<TextAsset>(str)))
|
||||
skeletonPaths.Add(str);
|
||||
if (IsSpineData(AssetDatabase.LoadAssetAtPath<TextAsset>(str), out compatibilityProblemInfo))
|
||||
skeletonPaths.Add(new PathAndProblemInfo(str, compatibilityProblemInfo));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -287,24 +291,32 @@ namespace Spine.Unity.Editor {
|
||||
|
||||
// Import skeletons and match them with atlases.
|
||||
bool abortSkeletonImport = false;
|
||||
foreach (string skeletonPath in skeletonPaths) {
|
||||
foreach (var skeletonPathEntry in skeletonPaths) {
|
||||
string skeletonPath = skeletonPathEntry.Key;
|
||||
var compatibilityProblems = skeletonPathEntry.Value;
|
||||
if (skeletonPath.StartsWith("Packages"))
|
||||
continue;
|
||||
if (!reimport && CheckForValidSkeletonData(skeletonPath)) {
|
||||
ReloadSkeletonData(skeletonPath);
|
||||
ReloadSkeletonData(skeletonPath, compatibilityProblems);
|
||||
continue;
|
||||
}
|
||||
|
||||
var loadedAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(skeletonPath);
|
||||
if (compatibilityProblems != null) {
|
||||
IngestIncompatibleSpineProject(loadedAsset, compatibilityProblems);
|
||||
continue;
|
||||
}
|
||||
|
||||
string dir = Path.GetDirectoryName(skeletonPath);
|
||||
|
||||
#if SPINE_TK2D
|
||||
IngestSpineProject(AssetDatabase.LoadAssetAtPath<TextAsset>(skeletonPath), null);
|
||||
IngestSpineProject(loadedAsset, compatibilityProblems, null);
|
||||
#else
|
||||
var localAtlases = FindAtlasesAtPath(dir);
|
||||
var requiredPaths = GetRequiredAtlasRegions(skeletonPath);
|
||||
var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases);
|
||||
if (atlasMatch != null || requiredPaths.Count == 0) {
|
||||
IngestSpineProject(AssetDatabase.LoadAssetAtPath<TextAsset>(skeletonPath), atlasMatch);
|
||||
IngestSpineProject(loadedAsset, atlasMatch);
|
||||
} else {
|
||||
SkeletonImportDialog(skeletonPath, localAtlases, requiredPaths, ref abortSkeletonImport);
|
||||
}
|
||||
@ -338,7 +350,7 @@ namespace Spine.Unity.Editor {
|
||||
}
|
||||
}
|
||||
|
||||
static void ReloadSkeletonData (string skeletonJSONPath) {
|
||||
static void ReloadSkeletonData (string skeletonJSONPath, CompatibilityProblemInfo compatibilityProblemInfo) {
|
||||
string dir = Path.GetDirectoryName(skeletonJSONPath);
|
||||
TextAsset textAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(skeletonJSONPath);
|
||||
DirectoryInfo dirInfo = new DirectoryInfo(dir);
|
||||
@ -353,6 +365,11 @@ namespace Spine.Unity.Editor {
|
||||
if (Selection.activeObject == skeletonDataAsset)
|
||||
Selection.activeObject = null;
|
||||
|
||||
if (compatibilityProblemInfo != null) {
|
||||
SkeletonDataCompatibility.DisplayCompatibilityProblem(compatibilityProblemInfo.DescriptionString(), textAsset);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.LogFormat("Changes to '{0}' detected. Clearing SkeletonDataAsset: {1}", skeletonJSONPath, localPath);
|
||||
skeletonDataAsset.Clear();
|
||||
|
||||
@ -545,10 +562,34 @@ namespace Spine.Unity.Editor {
|
||||
#endregion
|
||||
|
||||
#region Import SkeletonData (json or binary)
|
||||
internal static SkeletonDataAsset IngestSpineProject (TextAsset spineJson, params AtlasAssetBase[] atlasAssets) {
|
||||
internal static string GetSkeletonDataAssetFilePath(TextAsset spineJson) {
|
||||
string primaryName = Path.GetFileNameWithoutExtension(spineJson.name);
|
||||
string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson));
|
||||
string filePath = assetPath + "/" + primaryName + SkeletonDataSuffix + ".asset";
|
||||
return assetPath + "/" + primaryName + SkeletonDataSuffix + ".asset";
|
||||
}
|
||||
|
||||
internal static SkeletonDataAsset IngestIncompatibleSpineProject(TextAsset spineJson,
|
||||
CompatibilityProblemInfo compatibilityProblemInfo) {
|
||||
|
||||
string filePath = GetSkeletonDataAssetFilePath(spineJson);
|
||||
|
||||
if (spineJson == null)
|
||||
return null;
|
||||
|
||||
SkeletonDataAsset skeletonDataAsset = (SkeletonDataAsset)AssetDatabase.LoadAssetAtPath(filePath, typeof(SkeletonDataAsset));
|
||||
if (skeletonDataAsset == null) {
|
||||
skeletonDataAsset = SkeletonDataAsset.CreateInstance<SkeletonDataAsset>();
|
||||
skeletonDataAsset.skeletonJSON = spineJson;
|
||||
AssetDatabase.CreateAsset(skeletonDataAsset, filePath);
|
||||
}
|
||||
EditorUtility.SetDirty(skeletonDataAsset);
|
||||
|
||||
SkeletonDataCompatibility.DisplayCompatibilityProblem(compatibilityProblemInfo.DescriptionString(), spineJson);
|
||||
return skeletonDataAsset;
|
||||
}
|
||||
|
||||
internal static SkeletonDataAsset IngestSpineProject (TextAsset spineJson, params AtlasAssetBase[] atlasAssets) {
|
||||
string filePath = GetSkeletonDataAssetFilePath(spineJson);
|
||||
|
||||
#if SPINE_TK2D
|
||||
if (spineJson != null) {
|
||||
@ -622,76 +663,10 @@ namespace Spine.Unity.Editor {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsSpineData (TextAsset asset) {
|
||||
if (asset == null)
|
||||
return false;
|
||||
|
||||
bool isSpineData = false;
|
||||
string rawVersion = null;
|
||||
|
||||
int[][] compatibleVersions;
|
||||
if (asset.name.Contains(".skel")) {
|
||||
try {
|
||||
using (var memStream = new MemoryStream(asset.bytes)) {
|
||||
rawVersion = SkeletonBinary.GetVersionString(memStream);
|
||||
}
|
||||
isSpineData = !(string.IsNullOrEmpty(rawVersion));
|
||||
compatibleVersions = compatibleBinaryVersions;
|
||||
} catch (System.Exception e) {
|
||||
Debug.LogErrorFormat("Failed to read '{0}'. It is likely not a binary Spine SkeletonData file.\n{1}", asset.name, e);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
object obj = Json.Deserialize(new StringReader(asset.text));
|
||||
if (obj == null) {
|
||||
Debug.LogErrorFormat("'{0}' is not valid JSON.", asset.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
var root = obj as Dictionary<string, object>;
|
||||
if (root == null) {
|
||||
Debug.LogError("Parser returned an incorrect type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
isSpineData = root.ContainsKey("skeleton");
|
||||
if (isSpineData) {
|
||||
var skeletonInfo = (Dictionary<string, object>)root["skeleton"];
|
||||
object jv;
|
||||
skeletonInfo.TryGetValue("spine", out jv);
|
||||
rawVersion = jv as string;
|
||||
}
|
||||
|
||||
compatibleVersions = compatibleJsonVersions;
|
||||
}
|
||||
|
||||
// Version warning
|
||||
if (isSpineData) {
|
||||
string primaryRuntimeVersionDebugString = compatibleVersions[0][0] + "." + compatibleVersions[0][1];
|
||||
|
||||
if (string.IsNullOrEmpty(rawVersion)) {
|
||||
Debug.LogWarningFormat("Skeleton '{0}' has no version information. It may be incompatible with your runtime version: spine-unity v{1}", asset.name, primaryRuntimeVersionDebugString);
|
||||
} else {
|
||||
string[] versionSplit = rawVersion.Split('.');
|
||||
bool match = false;
|
||||
foreach (var version in compatibleVersions) {
|
||||
bool primaryMatch = version[0] == int.Parse(versionSplit[0], CultureInfo.InvariantCulture);
|
||||
bool secondaryMatch = version[1] == int.Parse(versionSplit[1], CultureInfo.InvariantCulture);
|
||||
|
||||
// if (isFixVersionRequired) secondaryMatch &= version[2] <= int.Parse(jsonVersionSplit[2], CultureInfo.InvariantCulture);
|
||||
|
||||
if (primaryMatch && secondaryMatch) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match)
|
||||
Debug.LogWarningFormat("Skeleton '{0}' (exported with Spine {1}) may be incompatible with your runtime version: spine-csharp v{2}", asset.name, rawVersion, primaryRuntimeVersionDebugString);
|
||||
}
|
||||
}
|
||||
|
||||
return isSpineData;
|
||||
public static bool IsSpineData (TextAsset asset, out CompatibilityProblemInfo compatibilityProblemInfo) {
|
||||
SkeletonDataCompatibility.VersionInfo fileVersion = SkeletonDataCompatibility.GetVersionInfo(asset);
|
||||
compatibilityProblemInfo = SkeletonDataCompatibility.GetCompatibilityProblemInfo(fileVersion);
|
||||
return fileVersion != null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
using Spine;
|
||||
using CompatibilityProblemInfo = Spine.Unity.SkeletonDataCompatibility.CompatibilityProblemInfo;
|
||||
|
||||
namespace Spine.Unity {
|
||||
|
||||
@ -114,26 +114,26 @@ namespace Spine.Unity {
|
||||
Clear();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Disabled to support attachmentless/skinless SkeletonData.
|
||||
// if (atlasAssets == null) {
|
||||
// atlasAssets = new AtlasAsset[0];
|
||||
// if (!quiet)
|
||||
// Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
|
||||
// Clear();
|
||||
// return null;
|
||||
// }
|
||||
// #if !SPINE_TK2D
|
||||
// if (atlasAssets.Length == 0) {
|
||||
// Clear();
|
||||
// return null;
|
||||
// }
|
||||
// #else
|
||||
// if (atlasAssets.Length == 0 && spriteCollection == null) {
|
||||
// Clear();
|
||||
// return null;
|
||||
// }
|
||||
// #endif
|
||||
// if (atlasAssets == null) {
|
||||
// atlasAssets = new AtlasAsset[0];
|
||||
// if (!quiet)
|
||||
// Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
|
||||
// Clear();
|
||||
// return null;
|
||||
// }
|
||||
// #if !SPINE_TK2D
|
||||
// if (atlasAssets.Length == 0) {
|
||||
// Clear();
|
||||
// return null;
|
||||
// }
|
||||
// #else
|
||||
// if (atlasAssets.Length == 0 && spriteCollection == null) {
|
||||
// Clear();
|
||||
// return null;
|
||||
// }
|
||||
// #endif
|
||||
|
||||
if (skeletonData != null)
|
||||
return skeletonData;
|
||||
@ -163,6 +163,17 @@ namespace Spine.Unity {
|
||||
bool isBinary = skeletonJSON.name.ToLower().Contains(".skel");
|
||||
SkeletonData loadedSkeletonData;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (skeletonJSON) {
|
||||
SkeletonDataCompatibility.VersionInfo fileVersion = SkeletonDataCompatibility.GetVersionInfo(skeletonJSON);
|
||||
CompatibilityProblemInfo compatibilityProblemInfo = SkeletonDataCompatibility.GetCompatibilityProblemInfo(fileVersion);
|
||||
if (compatibilityProblemInfo != null) {
|
||||
SkeletonDataCompatibility.DisplayCompatibilityProblem(compatibilityProblemInfo.DescriptionString(), skeletonJSON);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
try {
|
||||
if (isBinary)
|
||||
loadedSkeletonData = SkeletonDataAsset.ReadSkeletonData(skeletonJSON.bytes, attachmentLoader, skeletonDataScale);
|
||||
|
||||
@ -0,0 +1,160 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated May 1, 2019. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2019, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "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 LLC 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 System.IO;
|
||||
using UnityEngine;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Spine.Unity {
|
||||
|
||||
public static class SkeletonDataCompatibility {
|
||||
|
||||
static readonly int[][] compatibleBinaryVersions = { new[] { 3, 9, 0 }, new[] { 3, 8, 0 } };
|
||||
static readonly int[][] compatibleJsonVersions = { new[] { 3, 9, 0 }, new[] { 3, 8, 0 } };
|
||||
|
||||
static bool wasVersionDialogShown = false;
|
||||
|
||||
public enum SourceType {
|
||||
Json,
|
||||
Binary
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class VersionInfo {
|
||||
public string rawVersion = null;
|
||||
public int[] version = null;
|
||||
public SourceType sourceType;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class CompatibilityProblemInfo {
|
||||
public VersionInfo actualVersion;
|
||||
public int[][] compatibleVersions;
|
||||
|
||||
public string DescriptionString () {
|
||||
string compatibleVersionString = "";
|
||||
string optionalOr = null;
|
||||
foreach (int[] version in compatibleVersions) {
|
||||
compatibleVersionString += string.Format("{0}{1}.{2}", optionalOr, version[0], version[1]);
|
||||
optionalOr = " or ";
|
||||
}
|
||||
return string.Format("Skeleton data could not be loaded. Data version: {0}. Required version: {1}.\nPlease re-export skeleton data with Spine {1} or change runtime to version {2}.{3}.",
|
||||
actualVersion.rawVersion, compatibleVersionString, actualVersion.version[0], actualVersion.version[1]);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static VersionInfo GetVersionInfo (TextAsset asset) {
|
||||
if (asset == null)
|
||||
return null;
|
||||
|
||||
VersionInfo fileVersion = new VersionInfo();
|
||||
fileVersion.sourceType = asset.name.Contains(".skel") ? SourceType.Binary : SourceType.Json;
|
||||
|
||||
if (fileVersion.sourceType == SourceType.Binary) {
|
||||
try {
|
||||
using (var memStream = new MemoryStream(asset.bytes)) {
|
||||
fileVersion.rawVersion = SkeletonBinary.GetVersionString(memStream);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e) {
|
||||
Debug.LogErrorFormat("Failed to read '{0}'. It is likely not a binary Spine SkeletonData file.\n{1}", asset.name, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
object obj = Json.Deserialize(new StringReader(asset.text));
|
||||
if (obj == null) {
|
||||
Debug.LogErrorFormat("'{0}' is not valid JSON.", asset.name);
|
||||
return null;
|
||||
}
|
||||
|
||||
var root = obj as Dictionary<string, object>;
|
||||
if (root == null) {
|
||||
Debug.LogErrorFormat("'{0}' is not compatible JSON. Parser returned an incorrect type while parsing version info.", asset.name);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (root.ContainsKey("skeleton")) {
|
||||
var skeletonInfo = (Dictionary<string, object>)root["skeleton"];
|
||||
object jv;
|
||||
skeletonInfo.TryGetValue("spine", out jv);
|
||||
fileVersion.rawVersion = jv as string;
|
||||
}
|
||||
}
|
||||
|
||||
string primaryRuntimeVersionDebugString = compatibleBinaryVersions[0][0] + "." + compatibleBinaryVersions[0][1];
|
||||
if (string.IsNullOrEmpty(fileVersion.rawVersion)) {
|
||||
Debug.LogWarningFormat("Skeleton '{0}' has no version information. It is incompatible with your runtime version: spine-unity v{1}", asset.name, primaryRuntimeVersionDebugString);
|
||||
return null;
|
||||
}
|
||||
|
||||
var versionSplit = fileVersion.rawVersion.Split('.');
|
||||
try {
|
||||
fileVersion.version = new[]{ int.Parse(versionSplit[0], CultureInfo.InvariantCulture),
|
||||
int.Parse(versionSplit[1], CultureInfo.InvariantCulture) };
|
||||
}
|
||||
catch (System.Exception e) {
|
||||
Debug.LogErrorFormat("Failed to read version info at skeleton '{0}'. It is likely not a valid Spine SkeletonData file.\n{1}", asset.name, e);
|
||||
return null;
|
||||
}
|
||||
return fileVersion;
|
||||
}
|
||||
|
||||
public static CompatibilityProblemInfo GetCompatibilityProblemInfo (VersionInfo fileVersion) {
|
||||
CompatibilityProblemInfo info = new CompatibilityProblemInfo();
|
||||
info.actualVersion = fileVersion;
|
||||
info.compatibleVersions = (fileVersion.sourceType == SourceType.Binary) ? compatibleBinaryVersions
|
||||
: compatibleJsonVersions;
|
||||
|
||||
if (fileVersion == null)
|
||||
return info;
|
||||
|
||||
foreach (var compatibleVersion in info.compatibleVersions) {
|
||||
bool majorMatch = fileVersion.version[0] == compatibleVersion[0];
|
||||
bool minorMatch = fileVersion.version[1] == compatibleVersion[1];
|
||||
if (majorMatch && minorMatch) {
|
||||
return null; // is compatible, thus no problem info returned
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
public static void DisplayCompatibilityProblem (string descriptionString, TextAsset spineJson) {
|
||||
if (!wasVersionDialogShown) {
|
||||
wasVersionDialogShown = true;
|
||||
UnityEditor.EditorUtility.DisplayDialog("Version mismatch!", descriptionString, "OK");
|
||||
}
|
||||
Debug.LogError(string.Format("Error importing skeleton '{0}': {1}",
|
||||
spineJson.name, descriptionString), spineJson);
|
||||
}
|
||||
#endif // UNITY_EDITOR
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4224df6e20549f0449154531ae080201
|
||||
timeCreated: 1567002861
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
x
Reference in New Issue
Block a user