From f7f7211ca25e9c08dead2ed068b1fd6b967f0636 Mon Sep 17 00:00:00 2001 From: ww-rm Date: Thu, 20 Mar 2025 14:04:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8=E7=89=88?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SpineViewer/Spine/Spine.cs | 71 +++++++++++++++++++++++++++++++++++- SpineViewer/Spine/Version.cs | 1 + 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/SpineViewer/Spine/Spine.cs b/SpineViewer/Spine/Spine.cs index 2c11dae..2b03a84 100644 --- a/SpineViewer/Spine/Spine.cs +++ b/SpineViewer/Spine/Spine.cs @@ -14,6 +14,7 @@ using System.ComponentModel; using System.Reflection; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Text.Json.Nodes; namespace SpineViewer.Spine { @@ -106,11 +107,79 @@ namespace SpineViewer.Spine } } + /// + /// 尝试检测骨骼文件版本 + /// + public static Version? GetVersion(string skelPath) + { + string versionString = null; + Version? version = null; + using var input = File.OpenRead(skelPath); + var reader = new SkeletonConverter.BinaryReader(input); + + // try json format + try + { + if (JsonNode.Parse(input) is JsonObject root && root.TryGetPropertyValue("spine", out var node)) + versionString = (string)node; + } + catch { } + + // try v4 binary format + if (versionString is null) + { + try + { + input.Position = 0; + var hash = reader.ReadLong(); + var versionPosition = input.Position; + var versionByteCount = reader.ReadVarInt(); + input.Position = versionPosition; + if (versionByteCount <= 13) + versionString = reader.ReadString(); + } + catch { } + } + + // try v3 binary format + if (versionString is null) + { + try + { + input.Position = 0; + var hash = reader.ReadString(); + versionString = reader.ReadString(); + } + catch { } + } + + if (versionString is not null) + { + if (versionString.StartsWith("2.1.")) version = Version.V21; + else if (versionString.StartsWith("3.6.")) version = Version.V36; + else if (versionString.StartsWith("3.7.")) version = Version.V37; + else if (versionString.StartsWith("3.8.")) version = Version.V38; + else if (versionString.StartsWith("4.0.")) version = Version.V40; + else if (versionString.StartsWith("4.1.")) version = Version.V41; + else if (versionString.StartsWith("4.2.")) version = Version.V42; + else if (versionString.StartsWith("4.3.")) version = Version.V43; + } + + return version; + } + /// /// 创建特定版本的 Spine /// public static Spine New(Version version, string skelPath, string? atlasPath = null) { + if (version == Version.Auto) + { + if (GetVersion(skelPath) is Version detectedVersion) + version = detectedVersion; + else + throw new InvalidDataException($"Auto version detection failed for {skelPath}, try to use a specific version"); + } if (!ImplementationTypes.TryGetValue(version, out var spineType)) { throw new NotImplementedException($"Not implemented version: {version}"); @@ -133,7 +202,7 @@ namespace SpineViewer.Spine var attr = type.GetCustomAttribute(); if (attr is null) { - throw new InvalidOperationException($"Class {type.Name} has no SpineImplementationAttribute."); + throw new InvalidOperationException($"Class {type.Name} has no SpineImplementationAttribute"); } atlasPath ??= Path.ChangeExtension(skelPath, ".atlas"); diff --git a/SpineViewer/Spine/Version.cs b/SpineViewer/Spine/Version.cs index 298e96a..eb93c09 100644 --- a/SpineViewer/Spine/Version.cs +++ b/SpineViewer/Spine/Version.cs @@ -40,6 +40,7 @@ namespace SpineViewer.Spine /// public enum Version { + [Description("")] Auto = 0x0000, [Description("2.1.x")] V21 = 0x0201, [Description("3.6.x")] V36 = 0x0306, [Description("3.7.x")] V37 = 0x0307,