private void animationsList_SelectedIndexChanged(object sender, EventArgs e) { if (animationTimer != null) { StopAnimation(); } object item = animationsList.SelectedItem; if (item is TkSpriteAnimationClip anim) { framesList.Items.Clear(); foreach (TkSpriteFrame frame in anim.frames) { if (frame.spriteId < frame.collection.sprites.Count) { framesList.Items.Add(frame.collection.sprites[frame.spriteId]); } else { framesList.Items.Add("[nonexistant sprite]"); } } frameSlider.Minimum = 0; frameSlider.Maximum = anim.frames.Count - 1; frameSlider.Enabled = true; frameInfo.Text = $"{anim.name} at {anim.fps} fps"; activeAnimation = anim; } else { object colItem = spriteCollectionsList.SelectedItem; if (colItem is TkSpriteCollection col) { if (col.baseTexture == null) { col.baseTexture = GetTexture(col.textureExts[0]); } List <TkSpriteAnimationClip> colAnis = animationClips.Where(a => a.parent.parents.Contains(col)).ToList(); framesList.Items.Clear(); framesList.Items.AddRange(col.sprites.OrderBy(s => s.name).ToArray()); pictureBox.Image = col.baseTexture; } frameSlider.Enabled = false; frameInfo.Text = "nothing playing"; activeAnimation = null; } activeFrame = 0; if (framesList.Items.Count > 0) { framesList.SelectedIndex = 0; } if (frameSlider.Maximum > 0) { frameSlider.Value = 0; } }
private void GetTk2dSprites(AssetsFileInstance inst) { collections = new List <TkSpriteCollection>(); animations = new List <TkSpriteAnimation>(); animationClips = new List <TkSpriteAnimationClip>(); List <TkSpriteFrame> sprFrames = new List <TkSpriteFrame>(); string managedPath = Path.Combine(Path.GetDirectoryName(inst.path), "Managed"); Dictionary <AssetID, TkSpriteCollection> collectionLookup = new Dictionary <AssetID, TkSpriteCollection>(); int tk2dSCid = -1; int tk2dSAid = -1; foreach (AssetFileInfoEx mbInf in inst.table.GetAssetsOfType(0x72)) { string scriptName = null; ushort scriptIndex = AssetHelper.GetScriptIndex(inst.file, mbInf); if (tk2dSCid != -1 && scriptIndex == tk2dSCid) { scriptName = "tk2dSpriteCollectionData"; } else if (tk2dSAid != -1 && scriptIndex == tk2dSAid) { scriptName = "tk2dSpriteAnimation"; } if (tk2dSCid == -1 || tk2dSAid == -1) //still looking for script ids { AssetTypeValueField mbBase = am.GetATI(inst.file, mbInf).GetBaseField(); AssetTypeValueField scBase = am.GetExtAsset(inst, mbBase.Get("m_Script")).instance.GetBaseField(); scriptName = scBase.Get("m_Name").GetValue().AsString(); if (scriptName == "tk2dSpriteCollectionData") { tk2dSCid = scriptIndex; } else if (scriptName == "tk2dSpriteAnimation") { tk2dSAid = scriptIndex; } else { continue; //nope, nobody cares } } if (scriptName == null) { continue; } AssetTypeValueField mbSerialBase = am.GetMonoBaseFieldCached(inst, mbInf, managedPath); if (scriptName == "tk2dSpriteCollectionData") { AssetTypeValueField textures = mbSerialBase.Get("textures"); List <AssetExternal> textureExts = new List <AssetExternal>(); List <int> textureWidths = new List <int>(); List <int> textureHeights = new List <int>(); for (int i = 0; i < textures.childrenCount; i++) { AssetExternal textureExt = am.GetExtAsset(inst, mbSerialBase.Get("textures")[i], true); if (textureExt.info.curFileSize > 100000) { //bad news, unity probably stored the entire image into an array which is gonna //take up too much memory when we decode it, so we'll change the data to a byte array ClassDatabaseType textureType = AssetHelper.FindAssetClassByID(am.classFile, textureExt.info.curFileType); AssetTypeTemplateField textureTemp = new AssetTypeTemplateField(); textureTemp.FromClassDatabase(am.classFile, textureType, 0); AssetTypeTemplateField image_data = textureTemp.children[textureTemp.childrenCount - 1]; image_data.valueType = EnumValueTypes.ByteArray; //convert array to bytearray, much better AssetTypeInstance textureTypeInstance = new AssetTypeInstance(new[] { textureTemp }, inst.file.reader, textureExt.info.absoluteFilePos); AssetTypeValueField textureBase = textureTypeInstance.GetBaseField(); textureExt.instance = textureTypeInstance; textureExts.Add(textureExt); textureWidths.Add(textureBase.Get("m_Width").GetValue().AsInt()); textureHeights.Add(textureBase.Get("m_Height").GetValue().AsInt()); } else { textureExt = am.GetExtAsset(inst, mbSerialBase.Get("textures")[i]); AssetTypeValueField textureBase = textureExt.instance.GetBaseField(); textureExts.Add(textureExt); textureWidths.Add(textureBase.Get("m_Width").GetValue().AsInt()); textureHeights.Add(textureBase.Get("m_Height").GetValue().AsInt()); } } TkSpriteCollection collection = new TkSpriteCollection() { name = mbSerialBase.Get("spriteCollectionName").GetValue().AsString(), version = mbSerialBase.Get("version").GetValue().AsInt(), baseTexture = null, //do later textures = new Dictionary <int, Bitmap>(), //same textureExts = textureExts, sprites = new List <TkSpriteDefinition>() }; collectionLookup[new AssetID(inst.name, mbInf.index)] = collection; AssetTypeValueField spriteDefinitions = mbSerialBase.Get("spriteDefinitions"); foreach (AssetTypeValueField def in spriteDefinitions.children) { bool flipped = def.Get("flipped").GetValue().AsInt() == 1; int materialId = def.Get("materialId").GetValue().AsInt(); int textureWidth = textureWidths[materialId]; int textureHeight = textureHeights[materialId]; double uxn = double.MaxValue; double uxp = 0; double uyn = double.MaxValue; double uyp = 0; double pxn = double.MaxValue; double pyn = double.MaxValue; AssetTypeValueField positions = def.Get("positions"); AssetTypeValueField uvs = def.Get("uvs"); for (int i = 0; i < 4; i++) { AssetTypeValueField pos = positions[i]; AssetTypeValueField uv = uvs[i]; double posX = pos.Get("x").GetValue().AsFloat(); double posY = pos.Get("y").GetValue().AsFloat(); double uvX = Math.Round(uv.Get("x").GetValue().AsFloat() * textureWidth); double uvY = textureHeight - Math.Round(uv.Get("y").GetValue().AsFloat() * textureHeight); if (posX < pxn) { pxn = posX; } if (posY < pyn) { pyn = posY; } if (uvX < uxn) { uxn = uvX; } if (uvX > uxp) { uxp = uvX; } if (uvY < uyn) { uyn = uvY; } if (uvY > uyp) { uyp = uvY; } } int spriteX = (int)uxn; int spriteY = (int)uyn; int spriteWidth = (int)(uxp - uxn); int spriteHeight = (int)(uyp - uyn); AssetTypeValueField boundsData = def.Get("boundsData"); AssetTypeValueField untrimmedBoundsData = def.Get("untrimmedBoundsData"); AssetTypeValueField texelSize = def.Get("texelSize"); float texelX = texelSize.Get("x").GetValue().AsFloat(); float texelY = texelSize.Get("y").GetValue().AsFloat(); float realX = ((float)pxn) / texelX; float realY = -((flipped ? spriteWidth : spriteHeight) + ((float)pyn) / texelY); TkSpriteDefinition sprite = new TkSpriteDefinition() { parent = collection, name = def.Get("name").GetValue().AsString(), x = spriteX, y = spriteY, width = spriteWidth, height = spriteHeight, xOff = realX, yOff = realY, materialId = materialId, fullWidth = untrimmedBoundsData[1].Get("x").GetValue().AsFloat() / texelX, fullHeight = untrimmedBoundsData[1].Get("y").GetValue().AsFloat() / texelY, flipped = flipped }; collection.sprites.Add(sprite); } collections.Add(collection); } else if (scriptName == "tk2dSpriteAnimation") { AssetFileInfoEx gameObjectInfo = inst.table.GetAssetInfo(mbSerialBase.Get("m_GameObject").Get("m_PathID").GetValue().AsInt64()); TkSpriteAnimation animation = new TkSpriteAnimation() { parents = new List <TkSpriteCollection>(), //do later parentIds = new List <AssetID>(), gameObjectName = AssetHelper.GetAssetNameFast(inst.file, am.classFile, gameObjectInfo), clips = new List <TkSpriteAnimationClip>() }; AssetTypeValueField clips = mbSerialBase.Get("clips"); foreach (AssetTypeValueField clip in clips.children) { TkSpriteAnimationClip aniClip = new TkSpriteAnimationClip() { parent = animation, name = clip.Get("name").GetValue().AsString(), fps = clip.Get("fps").GetValue().AsFloat(), loopStart = clip.Get("loopStart").GetValue().AsInt(), wrapMode = (WrapMode)clip.Get("wrapMode").GetValue().AsInt(), frames = new List <TkSpriteFrame>() }; animation.clips.Add(aniClip); animationClips.Add(aniClip); AssetTypeValueField frames = clip.Get("frames"); foreach (AssetTypeValueField frame in frames.children) { AssetExternal collectionExt = am.GetExtAsset(inst, frame.Get("spriteCollection")); AssetID collectionId = new AssetID(collectionExt.file.name, collectionExt.info.index); if (!animation.parentIds.Contains(collectionId)) { animation.parentIds.Add(collectionId); } TkSpriteFrame sprFrame = new TkSpriteFrame() { collection = null, //do later collectionId = collectionId, spriteId = frame.Get("spriteId").GetValue().AsInt() }; sprFrames.Add(sprFrame); aniClip.frames.Add(sprFrame); } } animations.Add(animation); } } foreach (TkSpriteAnimation animation in animations) { foreach (AssetID parentId in animation.parentIds) { if (collectionLookup.ContainsKey(parentId)) { animation.parents.Add(collectionLookup[parentId]); } } } foreach (TkSpriteFrame frame in sprFrames) { if (collectionLookup.ContainsKey(frame.collectionId)) { frame.collection = collectionLookup[frame.collectionId]; } } }