From a22665283737543f51131a2d1b13ff7c930102af Mon Sep 17 00:00:00 2001
From: 1987kostya <ivaninvideorec@gmail.com>
Date: Tue, 12 Jan 2021 12:03:07 +0600
Subject: [PATCH] Added SE-style image dumping

---
 CTFAK/CTFAK.csproj                            |   7 +-
 CTFAK/GUI/MainForm.Designer.cs                |  23 +++-
 CTFAK/GUI/MainForm.cs                         |  19 ++-
 CTFAK/MMFParser/EXE/ChunkList.cs              |  13 +-
 .../MMFParser/EXE/Loaders/Banks/ImageBank.cs  |   8 +-
 .../EXE/Loaders/Objects/ObjectCommon.cs       | 117 ++++++++++--------
 CTFAK/MMFParser/Translation/PAME2MFA.cs       |  15 +--
 CTFAK/Program.cs                              |   4 +-
 CTFAK/Utils/Decryption.cs                     |  22 ++--
 CTFAK/Utils/ImageDumper.cs                    |  47 +++++--
 10 files changed, 175 insertions(+), 100 deletions(-)

diff --git a/CTFAK/CTFAK.csproj b/CTFAK/CTFAK.csproj
index bd2803d..eb6c87c 100644
--- a/CTFAK/CTFAK.csproj
+++ b/CTFAK/CTFAK.csproj
@@ -8,7 +8,7 @@
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
     <ProjectGuid>{86D99F9E-98FB-4E50-AB68-F5C115850C33}</ProjectGuid>
-    <OutputType>Exe</OutputType>
+    <OutputType>WinExe</OutputType>
     <RootNamespace>CTFAK</RootNamespace>
     <AssemblyName>CTFAK</AssemblyName>
     <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
@@ -65,8 +65,8 @@
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
     <OutputPath>bin\x64\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <Optimize>true</Optimize>
+    <DefineConstants>WIN64</DefineConstants>
+    <Optimize>false</Optimize>
     <DebugType>pdbonly</DebugType>
     <PlatformTarget>x64</PlatformTarget>
     <LangVersion>7.3</LangVersion>
@@ -80,6 +80,7 @@
     <PlatformTarget>x86</PlatformTarget>
     <DebugSymbols>true</DebugSymbols>
     <DebugType>pdbonly</DebugType>
+    <DefineConstants>WIN32</DefineConstants>
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="Be.Windows.Forms.HexBox, Version=1.6.1.0, Culture=neutral, PublicKeyToken=null">
diff --git a/CTFAK/GUI/MainForm.Designer.cs b/CTFAK/GUI/MainForm.Designer.cs
index 3ada21c..e1fe2d3 100644
--- a/CTFAK/GUI/MainForm.Designer.cs
+++ b/CTFAK/GUI/MainForm.Designer.cs
@@ -85,6 +85,7 @@
             this.updateSettings = new System.Windows.Forms.Button();
             this.colorBox = new System.Windows.Forms.TextBox();
             this.packDataDialog = new System.Windows.Forms.SaveFileDialog();
+            this.dumpSelectedBtn = new System.Windows.Forms.Button();
             this.ChunkCombo.SuspendLayout();
             this.tabControl1.SuspendLayout();
             this.mainTab.SuspendLayout();
@@ -114,9 +115,7 @@
             // 
             // openFileDialog1
             // 
-            this.openFileDialog1.FileName = "fnaf3.exe";
             this.openFileDialog1.Filter = "CTF Executable|*.exe";
-            this.openFileDialog1.InitialDirectory = "E:\\";
             this.openFileDialog1.FileOk += new System.ComponentModel.CancelEventHandler(this.openFileDialog1_FileOk);
             // 
             // treeView1
@@ -523,6 +522,7 @@
             // objViewerTab
             // 
             this.objViewerTab.BackColor = System.Drawing.Color.Black;
+            this.objViewerTab.Controls.Add(this.dumpSelectedBtn);
             this.objViewerTab.Controls.Add(this.objViewerInfo);
             this.objViewerTab.Controls.Add(this.imageViewerPlayAnim);
             this.objViewerTab.Controls.Add(this.imageViewPictureBox);
@@ -550,9 +550,10 @@
             // imageViewerPlayAnim
             // 
             this.imageViewerPlayAnim.Dock = System.Windows.Forms.DockStyle.Bottom;
-            this.imageViewerPlayAnim.Location = new System.Drawing.Point(201, 441);
+            this.imageViewerPlayAnim.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.imageViewerPlayAnim.Location = new System.Drawing.Point(201, 451);
             this.imageViewerPlayAnim.Name = "imageViewerPlayAnim";
-            this.imageViewerPlayAnim.Size = new System.Drawing.Size(731, 35);
+            this.imageViewerPlayAnim.Size = new System.Drawing.Size(731, 25);
             this.imageViewerPlayAnim.TabIndex = 2;
             this.imageViewerPlayAnim.Text = "Play Animation";
             this.imageViewerPlayAnim.UseVisualStyleBackColor = true;
@@ -785,6 +786,18 @@
             // 
             this.packDataDialog.FileOk += new System.ComponentModel.CancelEventHandler(this.packDataDialog_FileOk);
             // 
+            // dumpSelectedBtn
+            // 
+            this.dumpSelectedBtn.Dock = System.Windows.Forms.DockStyle.Bottom;
+            this.dumpSelectedBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.dumpSelectedBtn.Location = new System.Drawing.Point(201, 426);
+            this.dumpSelectedBtn.Name = "dumpSelectedBtn";
+            this.dumpSelectedBtn.Size = new System.Drawing.Size(731, 25);
+            this.dumpSelectedBtn.TabIndex = 4;
+            this.dumpSelectedBtn.Text = "Dump Selected";
+            this.dumpSelectedBtn.UseVisualStyleBackColor = true;
+            this.dumpSelectedBtn.MouseClick += dumpSelectedBtn_Click;
+            // 
             // MainForm
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -816,6 +829,8 @@
             this.ResumeLayout(false);
         }
 
+        private System.Windows.Forms.Button dumpSelectedBtn;
+
         private System.Windows.Forms.ComboBox langComboBox;
 
         private System.Windows.Forms.Label langLabel;
diff --git a/CTFAK/GUI/MainForm.cs b/CTFAK/GUI/MainForm.cs
index 75ccada..07db838 100644
--- a/CTFAK/GUI/MainForm.cs
+++ b/CTFAK/GUI/MainForm.cs
@@ -44,13 +44,17 @@ namespace CTFAK.GUI
         private bool _isAudioPlaying;
         private SoundPlayer _soundPlayer;
         public Label ObjectViewerLabel;
+        public TreeNode LastSelected;
 
 
         public MainForm(Color color)
         {
             //Buttons
             InitializeComponent();
-            Thread.CurrentThread.CurrentUICulture=new CultureInfo(LoadableSettings.instance["lang"].ToString());
+            if (LoadableSettings.instance["lang"]?.ToString()?.Length > 0)
+            {
+                Thread.CurrentThread.CurrentUICulture=new CultureInfo(LoadableSettings.instance["lang"].ToString());
+            }
             
             ColorTheme = color;
             foreach (Control item in Controls)
@@ -785,6 +789,7 @@ namespace CTFAK.GUI
         private void advancedTreeView_AfterSelect(object sender, TreeViewEventArgs e)
         {
             ObjectViewerLabel?.Dispose();
+            LastSelected = objTreeView.SelectedNode;
             var node = e.Node;
             var loader = ((ChunkNode) node).loader;
             string text=String.Empty;
@@ -952,5 +957,17 @@ namespace CTFAK.GUI
         {
             LoadableSettings.instance["lang"] = langComboBox.SelectedItem;
         }
+
+        
+
+        private void dumpSelectedBtn_Click(object sender, EventArgs e)
+        {
+            Logger.Log("Dumping");
+            var node = (ChunkNode) LastSelected;
+            var path =
+                $"{Settings.ImagePath}\\{Helper.GetTreePath(objTreeView, (ChunkNode) objTreeView.SelectedNode)}";
+            if (node == null) return;
+            ImageDumper.SaveFromNode(node);
+        }
     }
 }
\ No newline at end of file
diff --git a/CTFAK/MMFParser/EXE/ChunkList.cs b/CTFAK/MMFParser/EXE/ChunkList.cs
index 2dee7e0..37bcc4d 100644
--- a/CTFAK/MMFParser/EXE/ChunkList.cs
+++ b/CTFAK/MMFParser/EXE/ChunkList.cs
@@ -142,8 +142,17 @@ namespace CTFAK.MMFParser.EXE
                 Settings.Copyright = _chunkList.GetChunk<Copyright>()?.Value??"";
                 Settings.ProjectPath = _chunkList.GetChunk<EditorFilename>()?.Value??"";
 
-                if (Exe.Instance.GameData.ProductBuild > 284)Decryption.MakeKey(Settings.AppName,Settings.Copyright,Settings.ProjectPath);
-                else Decryption.MakeKey(Settings.ProjectPath, Settings.AppName, Settings.Copyright);
+                if (Settings.Build > 284)
+                {
+                    Logger.Log("Using New Key");
+                    Decryption.MakeKey(Settings.AppName,Settings.Copyright,Settings.ProjectPath);
+                }
+                else
+                {
+                    Logger.Log("Using Old Key");
+                    Decryption.MakeKey(Settings.ProjectPath, Settings.AppName, Settings.Copyright);
+                }
+                // Decryption.MakeKey(Settings.ProjectPath, Settings.AppName, Settings.Copyright);
             }
         }
 
diff --git a/CTFAK/MMFParser/EXE/Loaders/Banks/ImageBank.cs b/CTFAK/MMFParser/EXE/Loaders/Banks/ImageBank.cs
index 49efbdd..6cb8545 100644
--- a/CTFAK/MMFParser/EXE/Loaders/Banks/ImageBank.cs
+++ b/CTFAK/MMFParser/EXE/Loaders/Banks/ImageBank.cs
@@ -101,8 +101,8 @@ namespace CTFAK.MMFParser.EXE.Loaders.Banks
 
 
 
-                if (Settings.Build >= 284)
-                    item.Handle -= 1;
+                //if (Settings.Build >= 284)
+                //    item.Handle -= 1;
 
                 //images[item.handle] = item;
             }
@@ -156,7 +156,7 @@ namespace CTFAK.MMFParser.EXE.Loaders.Banks
         public void Read(bool load)
         {
             Handle = Reader.ReadInt32();
-            if (Exe.Instance.GameData.ProductVersion != Constants.Products.MMF15) Handle -= 1;
+            if (Exe.Instance.GameData.ProductVersion != Constants.Products.MMF15&&Settings.Build>=284) Handle -= 1;
             Position = (int) Reader.Tell();
             if (load) Load();
             else Preload();
@@ -165,7 +165,7 @@ namespace CTFAK.MMFParser.EXE.Loaders.Banks
         public override void Read()
         {
             Handle = Reader.ReadInt32();
-            if (Exe.Instance.GameData.ProductVersion != Constants.Products.MMF15) Handle -= 1;
+            if (Exe.Instance.GameData.ProductVersion != Constants.Products.MMF15&&Settings.Build>=284) Handle -= 1;
             Position = (int) Reader.Tell();
             Load();
         }
diff --git a/CTFAK/MMFParser/EXE/Loaders/Objects/ObjectCommon.cs b/CTFAK/MMFParser/EXE/Loaders/Objects/ObjectCommon.cs
index 3d50987..2c08ae6 100644
--- a/CTFAK/MMFParser/EXE/Loaders/Objects/ObjectCommon.cs
+++ b/CTFAK/MMFParser/EXE/Loaders/Objects/ObjectCommon.cs
@@ -1,4 +1,6 @@
 using System;
+using System.Collections.Generic;
+using System.Diagnostics;
 using System.Drawing;
 using CTFAK.Utils;
 
@@ -8,7 +10,6 @@ namespace CTFAK.MMFParser.EXE.Loaders.Objects
     {
         private ushort _valuesOffset;
         private ushort _stringsOffset;
-        private int Identifier;
         private uint _fadeinOffset;
         private uint _fadeoutOffset;
         private ushort _movementsOffset;
@@ -16,6 +17,8 @@ namespace CTFAK.MMFParser.EXE.Loaders.Objects
         private ushort _systemObjectOffset;
         public ushort _counterOffset;
         public ushort _extensionOffset;
+        private int Identifier;
+        
         public Animations Animations;
         private long _end;
 
@@ -83,7 +86,7 @@ namespace CTFAK.MMFParser.EXE.Loaders.Objects
         public AlterableValues Values;
         public AlterableStrings Strings;
         public Movements Movements;
-        private ushort _unk;
+        private ushort _zeroUnk;
         public Text Text;
 
 
@@ -101,58 +104,46 @@ namespace CTFAK.MMFParser.EXE.Loaders.Objects
 
         public override void Read()
         {
-            //if(Parent.ObjectType!=2)return;
             var currentPosition = Reader.Tell();
             var size = Reader.ReadInt32();
             if (Settings.Build >= 284)
             {
                 _animationsOffset = Reader.ReadUInt16();
                 _movementsOffset = Reader.ReadUInt16();
-                var version = Reader.ReadUInt16();
-                _unk = Reader.ReadUInt16();
-                _extensionOffset = Reader.ReadUInt16();
-                _counterOffset = Reader.ReadUInt16();
-                Flags.flag = Reader.ReadUInt16();
-                _end = Reader.Tell() + (8+1) * 2;
-                
-                Reader.Seek(_end);
-                _systemObjectOffset = Reader.ReadUInt16();
-                
-
-                _valuesOffset = Reader.ReadUInt16();
-                _stringsOffset = Reader.ReadUInt16();
-                NewFlags.flag = Reader.ReadUInt16();
-                preferences.flag = Reader.ReadUInt16();
-                Identifier = Reader.ReadInt32();
-                BackColor = Reader.ReadColor();
-                _fadeinOffset = Reader.ReadUInt32();
-                _fadeoutOffset = Reader.ReadUInt32();
             }
             else
             {
                 _movementsOffset = Reader.ReadUInt16();
                 _animationsOffset = Reader.ReadUInt16();
-                var version = Reader.ReadUInt16();
-                //_unk = Reader.ReadUInt16();
-                _extensionOffset = Reader.ReadUInt16();
-                _counterOffset = Reader.ReadUInt16();
-                Flags.flag = Reader.ReadUInt16();
-                _end = Reader.Tell() + (8+1) * 2;
-                
-                Reader.Seek(_end);
-                _systemObjectOffset = Reader.ReadUInt16();
-                
-
-                _valuesOffset = Reader.ReadUInt16();
-                _stringsOffset = Reader.ReadUInt16();
-                NewFlags.flag = Reader.ReadUInt16();
-                preferences.flag = Reader.ReadUInt16();
-                Identifier = Reader.ReadInt32();
-                BackColor = Reader.ReadColor();
-                _fadeinOffset = Reader.ReadUInt32();
-                _fadeoutOffset = Reader.ReadUInt32();
             }
-
+            _zeroUnk = Reader.ReadUInt16();
+            
+            if(_zeroUnk!=0) throw new NotImplementedException("Unknown value is not zero");
+            var version = Reader.ReadUInt16();
+
+            _extensionOffset = Reader.ReadUInt16();
+            _counterOffset = Reader.ReadUInt16();
+            Flags.flag = Reader.ReadUInt16();
+            var end = Reader.Tell()+(8+1)*2;
+            List<Int16> qualifiers = new List<Int16>();
+            while(true)
+            {
+                // break;
+                var value = Reader.ReadInt16();
+                if(value!=-1) qualifiers.Add(value);
+                else break;
+            }
+            Reader.Seek(end);
+            _systemObjectOffset = Reader.ReadUInt16();
+            
+            _valuesOffset = Reader.ReadUInt16();
+            _stringsOffset = Reader.ReadUInt16();
+            NewFlags.flag = Reader.ReadUInt16();
+            preferences.flag = Reader.ReadUInt16();
+            Identifier = Reader.ReadInt32();
+            BackColor = Reader.ReadColor();
+            _fadeinOffset = Reader.ReadUInt32();
+            _fadeoutOffset = Reader.ReadUInt32();
             if (_animationsOffset > 0)
             {
                 Reader.Seek(currentPosition+_animationsOffset);
@@ -160,23 +151,45 @@ namespace CTFAK.MMFParser.EXE.Loaders.Objects
                 Animations.Read();
             }
             
+            if (_movementsOffset > 0)
+            {
+                Reader.Seek(currentPosition+_movementsOffset);
+                Movements=new Movements(Reader);
+                Movements.Read();
+            }
+            
             if (_systemObjectOffset > 0)
             {
                 Reader.Seek(currentPosition+_systemObjectOffset);
-                if (Parent.ObjectType == 7) //Counter
+                switch (Parent.ObjectType)
                 {
-          
-                    Counters=new Counters(Reader);
-                    Counters.Read();
+                    //Text
+                    case 3:
+                        Text = new Text(Reader);
+                        Text.Read();
+                        break;
+                    //Counter
+                    case 7:
+                        Counters=new Counters(Reader);
+                        Counters.Read();
+                        break;
+                    
                 }
-                else if(Parent.ObjectType==3)//Text
+            }
+
+            if (_extensionOffset > 0)
+            {
+                Reader.Seek(currentPosition + _extensionOffset);
+
+                var dataSize = Reader.ReadInt32() - 20;
+                Reader.Skip(4); //maxSize;
+                ExtensionVersion = Reader.ReadInt32();
+                ExtensionId = Reader.ReadInt32();
+                ExtensionPrivate = Reader.ReadInt32();
+                if (dataSize != 0)
                 {
-        
-                    Text = new Text(Reader);
-                    Text.Read();
-                    
+                    ExtensionData = Reader.ReadBytes(dataSize);
                 }
-                
             }
 
             // Logger.Log("anims: "+_animationsOffset);
diff --git a/CTFAK/MMFParser/Translation/PAME2MFA.cs b/CTFAK/MMFParser/Translation/PAME2MFA.cs
index 73fdeb6..ce80e64 100644
--- a/CTFAK/MMFParser/Translation/PAME2MFA.cs
+++ b/CTFAK/MMFParser/Translation/PAME2MFA.cs
@@ -26,23 +26,23 @@ namespace CTFAK.MMFParser.Translation
             Message("Running Pame2MFA");
             Message("Original MFA Build: "+mfa.BuildVersion);
             Message("");
-            //mfa.MfaBuild = 4;
-            //mfa.Product = (int) game.ProductVersion;
-            //mfa.BuildVersion = 283;
+            // mfa.MfaBuild = 4;
+            // mfa.Product = (int) game.ProductVersion;
+            // mfa.BuildVersion = 283;
             mfa.Name = game.Name;
             mfa.LangId = 8192;
             mfa.Description = "";
             mfa.Path = game.EditorFilename;
             
             //mfa.Stamp = wtf;
-            if (game.Fonts != null) mfa.Fonts = game.Fonts;
+            //if (game.Fonts != null) mfa.Fonts = game.Fonts;
             
             //mfa.Sounds = game.Sounds;
             //foreach (var item in mfa.Sounds.Items)
             //{
             //    item.IsCompressed = false;
             //}
-            mfa.Music = game.Music;
+            //mfa.Music = game.Music;
             mfa.Images.Items = game.Images.Images;
             foreach (var key in mfa.Images.Items.Keys)
             {
@@ -73,6 +73,7 @@ namespace CTFAK.MMFParser.Translation
             mfa.Aboutbox = game.AboutText?.Length > 0
                 ? game?.AboutText
                 : "";
+            //TODO: Controls
             
             //Object Section
             FrameItems = new Dictionary<int,FrameItem>();
@@ -83,14 +84,14 @@ namespace CTFAK.MMFParser.Translation
                 if (item.ObjectType != 2) continue;
                 var newItem = new FrameItem(null);
                 newItem.Name = item.Name;
-                newItem.ObjectType = item.ObjectType;
+                newItem.ObjectType = 2;//item.ObjectType;
                 newItem.Handle = item.Handle;
                 newItem.Transparent = item.Transparent ? 1:0;
                 newItem.InkEffect = item.InkEffect;
                 newItem.InkEffectParameter = item.InkEffectValue;
                 newItem.AntiAliasing = item.Antialias ? 1 : 0;
                 newItem.Flags = (int) item.Flags; //32 TODO:Fix this 
-                newItem.IconHandle = 12;
+                newItem.IconHandle = 10;
                 newItem.Chunks = new ChunkList(null);
                 var itemLoader = (ObjectCommon)item.Properties.Loader;
                 //Only actives
diff --git a/CTFAK/Program.cs b/CTFAK/Program.cs
index 456a2bc..4125de5 100644
--- a/CTFAK/Program.cs
+++ b/CTFAK/Program.cs
@@ -34,14 +34,14 @@ namespace CTFAK
             
             // MFAGenerator.ReadTestMFA();
             // Environment.Exit(0);
-            /*AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
+            AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
             {
                 
                 if (eventArgs.Exception is ThreadAbortException) return;
                 var ex = (Exception) eventArgs.Exception;
                 Logger.Log("ERROR: ");
                 Logger.Log(ex.ToString());
-            };*/
+            };
             
             Settings.UseGUI = true;
             
diff --git a/CTFAK/Utils/Decryption.cs b/CTFAK/Utils/Decryption.cs
index 86caa8b..4c25d6b 100644
--- a/CTFAK/Utils/Decryption.cs
+++ b/CTFAK/Utils/Decryption.cs
@@ -9,20 +9,9 @@ namespace CTFAK.Utils
     static class Decryption
     {
         private static byte[] _decryptionKey;
-        public static byte MagicChar = 0;
-
-        public static byte[] FixString(byte[] bytes)
-        {
-            List<byte> newBytes = new List<byte>();
-            foreach (byte b in bytes)
-            {
-                if(b!=0) newBytes.Add(b);
-            }
-
-            return bytes; //newBytes.ToArray();
-
-        }
+        public static byte MagicChar = 54;
 
+        
         public static void MakeKey(string data1, string data2, string data3)
         {
             
@@ -95,9 +84,14 @@ namespace CTFAK.Utils
 
             return decodedChunk;
         }
+        
 
+        #if WIN64
         private const string _dllPath = "x64\\Decrypter-x64.dll";
-        //private const string _dllPath = "x86\\Decrypter-x86.dll";
+        #else
+        private const string _dllPath = "x86\\Decrypter-x86.dll";
+        #endif
+        
         [DllImport(_dllPath, EntryPoint = "decode_chunk", CharSet = CharSet.Auto)]
         public static extern IntPtr decode_chunk(IntPtr chunkData, int chunkSize, byte magicChar, IntPtr wrapperKey);
 
diff --git a/CTFAK/Utils/ImageDumper.cs b/CTFAK/Utils/ImageDumper.cs
index c7a4565..6da5cb5 100644
--- a/CTFAK/Utils/ImageDumper.cs
+++ b/CTFAK/Utils/ImageDumper.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
+using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using CTFAK.GUI;
@@ -16,6 +17,8 @@ namespace CTFAK.Utils
     {
         public static void SaveFromNode(ChunkNode node)
         {
+            var timer = new Stopwatch();
+            timer.Start();
             var bank = Exe.Instance.GameData.GameChunks.GetChunk<ImageBank>();
             var fullPath = $"{Settings.ImagePath}\\Sorted\\{node.FullPath}";
             if (fullPath == null) return;
@@ -39,14 +42,25 @@ namespace CTFAK.Utils
                 SaveInstance(instance,bank,fullPath);
             }
             else if(node.loader is Backdrop) Console.WriteLine("Dumping Backdrop");
-            else if(node.loader is Frame) Console.WriteLine("Dumping Frame");
-            
-            
-            
+            else if(node.loader is Frame frame)
+            {
+                SaveFrame(frame,bank,fullPath);
+            }
             
+            else Console.WriteLine("Unknown: "+node.loader.GetType().Name);
+            timer.Stop();
+            Logger.Log("Done in "+timer.Elapsed.ToString("g"));
             
+        }
 
-            else Console.WriteLine("Unknown: "+node.loader.GetType().Name);
+        public static void SaveFrame(Frame frame, ImageBank bank, string fullPath)
+        {
+            foreach (var inst in frame.Objects.Items)
+            {
+                var path = $"{fullPath}\\{Helper.CleanInput(inst.FrameItem.Name)}";
+                Logger.Log("Saving Object to "+path);
+                SaveInstance(inst,bank,path);
+            }
             
         }
 
@@ -63,6 +77,7 @@ namespace CTFAK.Utils
             if (inst.FrameItem.Properties.IsCommon)
             {
                 var common = ((ObjectCommon)inst.FrameItem.Properties.Loader);
+                Directory.CreateDirectory(fullPath);
                 switch (common.Parent.ObjectType)
                 {
                     case 2:
@@ -72,7 +87,9 @@ namespace CTFAK.Utils
                         }
                         break;
                     case 7:
-                        foreach (int frame in common.Counters.Frames)
+                        if (common?.Counters?.Frames.Count == 0) return;
+                        if (common?.Counters?.Frames == null) return;
+                        foreach (int frame in common?.Counters?.Frames)
                         {
                             var img = bank.FromHandle(frame);
                             img.Save(fullPath+$"\\{frame}.png");
@@ -101,12 +118,20 @@ namespace CTFAK.Utils
             }
             else
             {
-                for (int i = 0; i < anim.DirectionDict[0].Frames.Count; i++)
+                foreach (var dir in anim.DirectionDict.Values)
                 {
-                    Directory.CreateDirectory(fullPath);
-                    var frame = anim.DirectionDict[0].Frames[i];
-                    bank.Images[frame].Save($"{fullPath}\\{i}.png");
-                } 
+                    for (int i = 0; i < dir.Frames.Count; i++)
+                    {
+                        Directory.CreateDirectory(fullPath);
+                        var frame = dir.Frames[i];
+                        bank.Images.TryGetValue(frame, out var img);
+                        img?.Save($"{fullPath}\\{i}.png");
+                    }
+
+                    break;
+                }
+                
+                
             }
             
         }