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 @@ Debug AnyCPU {86D99F9E-98FB-4E50-AB68-F5C115850C33} - Exe + WinExe CTFAK CTFAK v4.7.2 @@ -65,8 +65,8 @@ bin\x64\Release\ - TRACE - true + WIN64 + false pdbonly x64 7.3 @@ -80,6 +80,7 @@ x86 true pdbonly + WIN32 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()?.Value??""; Settings.ProjectPath = _chunkList.GetChunk()?.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 qualifiers = new List(); + 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(); @@ -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 newBytes = new List(); - 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(); 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; + } + + } }