using System; using System.Collections.Generic; using System.Collections.Frozen; using System.Collections.Immutable; using System.Linq; using System.Text; using System.Threading.Tasks; using Spine.Utils; using Spine.SpineWrappers; using Spine.SpineWrappers.Attachments; using SpineRuntime37; using Spine.Implementations.SpineWrappers.V37.Attachments; namespace Spine.Implementations.SpineWrappers.V37 { [SpineImplementation(3, 7)] internal sealed class SpineObjectData37 : SpineObjectData { private readonly Atlas _atlas; private readonly SkeletonData _skeletonData; private readonly AnimationStateData _animationStateData; private readonly ImmutableArray _skins; private readonly FrozenDictionary _skinsByName; private readonly FrozenDictionary> _slotAttachments; private readonly ImmutableArray _animations; private readonly FrozenDictionary _animationsByName; public SpineObjectData37(string skelPath, string atlasPath, Spine.SpineWrappers.TextureLoader textureLoader) : base(skelPath, atlasPath, textureLoader) { // 加载 atlas try { _atlas = new Atlas(atlasPath, textureLoader); } catch (Exception ex) { _logger.Trace(ex.ToString()); throw new InvalidDataException($"Failed to load atlas '{atlasPath}'"); } try { if (Utf8Validator.IsUtf8(skelPath)) { try { _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } catch (Exception ex) { _logger.Trace(ex.ToString()); _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } } else { try { _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } catch (Exception ex) { _logger.Trace(ex.ToString()); _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); } } } catch (Exception ex) { _atlas.Dispose(); _logger.Trace(ex.ToString()); throw new InvalidDataException($"Failed to load skeleton file {skelPath}"); } // 加载动画数据 _animationStateData = new AnimationStateData(_skeletonData); // 整理皮肤和附件 Dictionary> slotAttachments = []; List skins = []; Dictionary skinsByName = []; foreach (var s in _skeletonData.Skins) { var skin = new Skin37(s); skins.Add(skin); skinsByName[s.Name] = skin; foreach (var (k, att) in s.Attachments) { var slotName = _skeletonData.Slots.Items[k.slotIndex].Name; if (!slotAttachments.TryGetValue(slotName, out var attachments)) slotAttachments[slotName] = attachments = []; attachments[att.Name] = att switch { RegionAttachment regionAtt => new RegionAttachment37(regionAtt), MeshAttachment meshAtt => new MeshAttachment37(meshAtt), ClippingAttachment clipAtt => new ClippingAttachment37(clipAtt), BoundingBoxAttachment bbAtt => new BoundingBoxAttachment37(bbAtt), PathAttachment pathAtt => new PathAttachment37(pathAtt), PointAttachment ptAtt => new PointAttachment37(ptAtt), _ => throw new InvalidOperationException($"Unrecognized attachment type {att.GetType().FullName}") }; } } _slotAttachments = slotAttachments.ToFrozenDictionary(it => it.Key, it => it.Value.ToFrozenDictionary()); _skins = skins.ToImmutableArray(); _skinsByName = skinsByName.ToFrozenDictionary(); // 整理所有动画数据 List animations = []; Dictionary animationsByName = []; foreach (var a in _skeletonData.Animations) { var anime = new Animation37(a); animations.Add(anime); animationsByName[anime.Name] = anime; } _animations = animations.ToImmutableArray(); _animationsByName = animationsByName.ToFrozenDictionary(); } public override string SkeletonVersion => _skeletonData.Version; public override ImmutableArray Skins => _skins; public override FrozenDictionary SkinsByName => _skinsByName; public override FrozenDictionary> SlotAttachments => _slotAttachments; public override float DefaultMix { get => _animationStateData.DefaultMix; set => _animationStateData.DefaultMix = value; } public override ImmutableArray Animations => _animations; public override FrozenDictionary AnimationsByName => _animationsByName; protected override void DisposeAtlas() => _atlas.Dispose(); public override ISkeleton CreateSkeleton() => new Skeleton37(new(_skeletonData), this); public override IAnimationState CreateAnimationState() => new AnimationState37(new(_animationStateData), this); public override ISkeletonClipping CreateSkeletonClipping() => new SkeletonClipping37(); public override ISkin CreateSkin(string name) => new Skin37(name); } }