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 SpineRuntime40; using Spine.Implementations.SpineWrappers.V40.Attachments; namespace Spine.Implementations.SpineWrappers.V40 { [SpineImplementation(4, 0)] internal sealed class SpineObjectData40 : 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 SpineObjectData40(string skelPath, string atlasPath) : base(skelPath, atlasPath) { // 加载 atlas try { _atlas = new Atlas(atlasPath, _textureLoader); } catch (Exception ex) { throw new InvalidDataException($"Failed to load atlas '{atlasPath}'", ex); } // 加载 skel try { if (Utf8Validator.IsUtf8(skelPath)) _skeletonData = new SkeletonJson(_atlas).ReadSkeletonData(skelPath); else _skeletonData = new SkeletonBinary(_atlas).ReadSkeletonData(skelPath); } catch (Exception ex) { _atlas.Dispose(); throw new InvalidDataException($"Failed to load skeleton file {skelPath}", ex); } // 加载动画数据 _animationStateData = new AnimationStateData(_skeletonData); // 整理皮肤和附件 Dictionary> slotAttachments = []; List skins = []; Dictionary skinsByName = []; foreach (var s in _skeletonData.Skins) { var skin = new Skin40(s); skins.Add(skin); skinsByName[s.Name] = skin; foreach (var entry in s.Attachments) { var att = entry.Attachment; var slotName = _skeletonData.Slots.Items[entry.SlotIndex].Name; if (!slotAttachments.TryGetValue(slotName, out var attachments)) slotAttachments[slotName] = attachments = []; attachments[att.Name] = att switch { RegionAttachment regionAtt => new RegionAttachment40(regionAtt), MeshAttachment meshAtt => new MeshAttachment40(meshAtt), ClippingAttachment clipAtt => new ClippingAttachment40(clipAtt), BoundingBoxAttachment bbAtt => new BoundingBoxAttachment40(bbAtt), PathAttachment pathAtt => new PathAttachment40(pathAtt), PointAttachment ptAtt => new PointAttachment40(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 Animation40(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 Skeleton40(new(_skeletonData), this); public override IAnimationState CreateAnimationState() => new AnimationState40(new(_animationStateData), this); public override ISkeletonClipping CreateSkeletonClipping() => new SkeletonClipping40(); public override ISkin CreateSkin(string name) => new Skin40(name); } }