From e963283b70f8db8b394d378ed15909d60b696e88 Mon Sep 17 00:00:00 2001 From: Kurt Date: Sun, 20 Nov 2016 17:11:20 -0800 Subject: [PATCH] Refactoring Removes a bit of file r/w to the hard disk, speeds up subform opening times. Use the built in settings instead of config.ini / command line arguments --- pk3DS/3DS/GARC.cs | 182 ++++++++++++++++++++++++- pk3DS/Game/GARCFile.cs | 31 +++++ pk3DS/Game/GameConfig.cs | 75 ++++++++-- pk3DS/Main.cs | 167 +++++++++-------------- pk3DS/Properties/Settings.Designer.cs | 28 +++- pk3DS/Properties/Settings.settings | 17 ++- pk3DS/Subforms/Gen6/LevelUpEditor6.cs | 5 +- pk3DS/Subforms/Gen6/PersonalEditor6.cs | 58 +++----- pk3DS/Subforms/Gen7/PersonalEditor7.cs | 25 ++-- pk3DS/Subforms/TextEditor.cs | 38 +++--- pk3DS/Tools/TextFile.cs | 5 +- pk3DS/app.config | 18 +++ pk3DS/pk3DS.csproj | 2 + 13 files changed, 451 insertions(+), 200 deletions(-) create mode 100644 pk3DS/Game/GARCFile.cs create mode 100644 pk3DS/app.config diff --git a/pk3DS/3DS/GARC.cs b/pk3DS/3DS/GARC.cs index 5770e21..10a4c8d 100644 --- a/pk3DS/3DS/GARC.cs +++ b/pk3DS/3DS/GARC.cs @@ -506,10 +506,167 @@ private static GARCFile unpackGARC(Stream stream) return garc; } + public static MemGARC packGARC(byte[][] data, int version) + { + // Set Up the GARC template. + GARCFile garc = new GARCFile + { + ContentPadToNearest = 4, + fato = + { + // Magic = new[] { 'O', 'T', 'A', 'F' }, + Entries = new FATO_Entry[data.Length], + EntryCount = (ushort) data.Length, + HeaderSize = 0xC + data.Length*4, + Padding = 0xFFFF + }, + fatb = + { + // Magic = new[] { 'B', 'T', 'A', 'F' }, + Entries = new FATB_Entry[data.Length], + FileCount = data.Length + } + }; + + if (version == VER_6) + garc.ContentPadToNearest = 4; + + int op = 0; + int od = 0; + for (int i = 0; i < garc.fatb.Entries.Length; i++) + { + garc.fato.Entries[i].Offset = op; // FATO offset + garc.fatb.Entries[i].SubEntries = new FATB_SubEntry[32]; + op += 4; // Vector + garc.fatb.Entries[i].IsFolder = false; + garc.fatb.Entries[i].SubEntries[0].Exists = true; + + // Assemble Entry + int actualLength = data[i].Length%4 == 0 ? data[i].Length : data[i].Length + 4 - data[i].Length%4; + garc.fatb.Entries[i].SubEntries[0].Start = od; + garc.fatb.Entries[i].SubEntries[0].End = actualLength + garc.fatb.Entries[i].SubEntries[0].Start; + garc.fatb.Entries[i].SubEntries[0].Length = data[i].Length; + od += actualLength; + + op += 12; + garc.fatb.Entries[i].Vector = 1; + } + garc.fatb.HeaderSize = 0xC + op; + + // Set up the Header Info + using (MemoryStream newGARC = new MemoryStream()) + using (MemoryStream GARCdata = new MemoryStream()) + using (BinaryWriter gw = new BinaryWriter(newGARC)) + { + #region Write GARC Headers + + // Write GARC + gw.Write((uint) 0x47415243); // GARC + gw.Write((uint) (version == VER_6 ? 0x24 : 0x1C)); // Header Length + gw.Write((ushort) 0xFEFF); // Endianness BOM + gw.Write((ushort) version); // Version + gw.Write((uint) 0x00000004); // Section Count (4) + gw.Write((uint) 0x00000000); // Data Offset (temp) + gw.Write((uint) 0x00000000); // File Length (temp) + gw.Write((uint) 0x00000000); // Largest File Size (temp) + + if (version == VER_6) + { + gw.Write((uint) 0x0); + gw.Write((uint) 0x0); + } + + // Write FATO + gw.Write((uint) 0x4641544F); // FATO + gw.Write(garc.fato.HeaderSize); // Header Size + gw.Write(garc.fato.EntryCount); // Entry Count + gw.Write(garc.fato.Padding); // Padding + for (int i = 0; i < garc.fato.Entries.Length; i++) + gw.Write((uint) garc.fato.Entries[i].Offset); + + // Write FATB + gw.Write((uint) 0x46415442); // FATB + gw.Write(garc.fatb.HeaderSize); // Header Size + gw.Write(garc.fatb.FileCount); // File Count + foreach (var e in garc.fatb.Entries) + { + gw.Write(e.Vector); + foreach (var s in e.SubEntries.Where(s => s.Exists)) + { + gw.Write((uint) s.Start); + gw.Write((uint) s.End); + gw.Write((uint) s.Length); + } + } + + #endregion + + #region Write Files + + long largestSize = 0; // Required memory to allocate to handle the largest file + long largestPadded = 0; // Required memory to allocate to handle the largest PADDED file (Ver6 only) + foreach (byte[] e in data) + { + // Update largest file length if necessary + long len = e.Length; + bool largest = len > largestSize; + if (largest) + { + largestSize = len; + largestPadded = len; + } + + // Write to FIMB + using (var input = new MemoryStream(e)) + input.CopyTo(GARCdata); + + // While length is not divisible by 4, pad with FF (unused byte) + while (GARCdata.Length%garc.ContentPadToNearest != 0) + { + GARCdata.WriteByte(0xFF); + if (largest) + largestPadded++; + } + } + garc.ContentLargestUnpadded = (uint) largestSize; + garc.ContentLargestPadded = (uint) largestPadded; + + #endregion + + gw.Write((uint) 0x46494D42); // FIMB + gw.Write((uint) 0x0000000C); // Header Length + gw.Write((uint) GARCdata.Length); // Data Length + + gw.Seek(0x10, SeekOrigin.Begin); // Goto the start of the un-set 0 data we set earlier and set it. + gw.Write((uint) newGARC.Length); // Write Data Offset + gw.Write((uint) (newGARC.Length + GARCdata.Length)); // Write total GARC Length + + // Write Handling information + if (version == VER_4) + { + gw.Write(garc.ContentLargestUnpadded); // Write Largest File stat + } + else if (version == VER_6) + { + gw.Write(garc.ContentLargestPadded); // Write Largest With Padding + gw.Write(garc.ContentLargestUnpadded); // Write Largest Without Padding + gw.Write(garc.ContentPadToNearest); + } + + newGARC.Seek(0, SeekOrigin.End); // Goto the end so we can copy the filedata after the GARC headers. + + // Write in the data + GARCdata.Position = 0; + GARCdata.CopyTo(newGARC); // Copy the data. + // New File is ready to be saved (memstream newGARC) + return new MemGARC(newGARC.ToArray()); + } + } + public class MemGARC { private GARCFile garc; - private readonly byte[] Data; + internal byte[] Data; public int FileCount => garc.fato.EntryCount; public MemGARC(byte[] data) @@ -517,6 +674,8 @@ public MemGARC(byte[] data) Data = data; garc = unpackGARC(data); } + + // Returns an individual file public byte[] getFile(int file, int subfile = 0) { var Entry = garc.fatb.Entries[file]; @@ -528,6 +687,27 @@ public byte[] getFile(int file, int subfile = 0) Array.Copy(Data, offset, data, 0, data.Length); return data; } + + // Returns all files (excluding language vectorized) + public byte[][] Files + { + get + { + byte[][] data = new byte[FileCount][]; + for (int i = 0; i < data.Length; i++) + data[i] = getFile(i); + return data; + } + set + { + if (value == null || value.Length != FileCount) + throw new ArgumentException(); + + var ng = packGARC(value, garc.Version); + garc = ng.garc; + Data = ng.Data; + } + } } public struct GARCFile diff --git a/pk3DS/Game/GARCFile.cs b/pk3DS/Game/GARCFile.cs new file mode 100644 index 0000000..85b2eb2 --- /dev/null +++ b/pk3DS/Game/GARCFile.cs @@ -0,0 +1,31 @@ +using System; +using System.IO; +using CTR; + +namespace pk3DS +{ + public class GARCFile + { + private readonly GARC.MemGARC GARC; + private readonly GARCReference Reference; + private readonly string Path; + + public GARCFile(GARC.MemGARC g, GARCReference r, string p) + { + GARC = g; + Reference = r; + Path = p; + } + + // Shorthand Alias + public byte[] getFile(int file, int subfile = 0) { return GARC.getFile(file, subfile); } + public byte[][] Files { get { return GARC.Files; } set { GARC.Files = value; } } + public int FileCount => GARC.FileCount; + + public void Save() + { + File.WriteAllBytes(Path, GARC.Data); + Console.WriteLine($"Wrote {Reference.Name} to {Reference.Reference}"); + } + } +} diff --git a/pk3DS/Game/GameConfig.cs b/pk3DS/Game/GameConfig.cs index e41f08f..84fff6e 100644 --- a/pk3DS/Game/GameConfig.cs +++ b/pk3DS/Game/GameConfig.cs @@ -87,30 +87,81 @@ public void Initialize(string romFSpath, string exeFSpath, int lang) ExeFS = exeFSpath; Language = lang; getGameData(Version); + InitializeAll(); + } + public void InitializeAll() + { + InitializePersonal(); + InitializeLearnset(); + InitializeGameText(); + InitializeMoves(); } - public void InitializePersonal() { - var pG = getROMFSFile("personal"); - Personal = new PersonalTable(pG.getFile(pG.FileCount - 1), Version); + GARCPersonal = getGARCData("personal"); + Personal = new PersonalTable(GARCPersonal.getFile(GARCPersonal.FileCount - 1), Version); + } + public void InitializeLearnset() + { + GARCLearnsets = getGARCData("levelup"); + switch (Generation) + { + case 6: + Learnsets = GARCLearnsets.Files.Select(file => new Learnset6(file)).ToArray(); + break; + case 7: + Learnsets = GARCLearnsets.Files.Select(file => new Learnset7(file)).ToArray(); + break; + } + } + public void InitializeGameText() + { + GARCGameText = getGARCData("gametext"); + GameTextStrings = GARCGameText.Files.Select(file => new TextFile(file).Lines).ToArray(); + } + public void InitializeMoves() + { + GARCMoves = getGARCData("move"); + switch (Generation) + { + case 6: + if (XY) + Moves = GARCMoves.Files.Select(file => new Move(file)).ToArray(); + if (ORAS) + Moves = mini.unpackMini(GARCMoves.getFile(0), "WD").Select(file => new Move(file)).ToArray(); + break; + case 7: + Moves = mini.unpackMini(GARCMoves.getFile(0), "WD").Select(file => new Move(file)).ToArray(); + break; + } + } + public GARCFile getGARCData(string file) + { + return new GARCFile(getMemGARC(file), getGARCReference(file), getGARCPath(file)); + } + private string getGARCPath(string file) + { + var gr = getGARCReference(file); + gr = gr.LanguageVariant ? gr.getRelativeGARC(Language, gr.Name) : gr; + string subloc = gr.Reference; + return Path.Combine(RomFS, subloc); } - private GARC.MemGARC getROMFSFile(string file) + private GARC.MemGARC getMemGARC(string file) { - string path = Path.Combine(RomFS, getGARC(file).Reference); - return new GARC.MemGARC(File.ReadAllBytes(path)); + return new GARC.MemGARC(File.ReadAllBytes(getGARCPath(file))); } private string RomFS, ExeFS; - public GARCReference getGARC(string name) { return Files.FirstOrDefault(f => f.Name == name); } + public GARCReference getGARCReference(string name) { return Files.FirstOrDefault(f => f.Name == name); } public TextVariableCode getVariableCode(string name) { return Variables.FirstOrDefault(v => v.Name == name); } public TextVariableCode getVariableName(int value) { return Variables.FirstOrDefault(v => v.Code == value); } public TextReference getGameText(TextName name) { return GameText.FirstOrDefault(f => f.Name == name); } public string getGARCFileName(string requestedGARC) { - var garc = getGARC(requestedGARC); + var garc = getGARCReference(requestedGARC); if (garc.LanguageVariant) garc = garc.getRelativeGARC(Language); @@ -118,7 +169,13 @@ public string getGARCFileName(string requestedGARC) } public int Language { get; set; } - public PersonalTable Personal; + + public GARCFile GARCPersonal, GARCLearnsets, GARCMoves, GARCGameText; + public PersonalTable Personal { get; private set; } + public Learnset[] Learnsets { get; private set; } + public string[][] GameTextStrings { get; private set; } + public Move[] Moves { get; private set; } + public bool XY => Version == GameVersion.XY; public bool ORAS => Version == GameVersion.ORAS || Version == GameVersion.ORASDEMO; public bool SM => Version == GameVersion.SM || Version == GameVersion.SMDEMO; diff --git a/pk3DS/Main.cs b/pk3DS/Main.cs index 04738c3..99ed495 100644 --- a/pk3DS/Main.cs +++ b/pk3DS/Main.cs @@ -29,9 +29,6 @@ public Main() // Initialize the Main Form InitializeComponent(); - // Set the Current Language to English - CB_Lang.SelectedIndex = 2; - // Prepare DragDrop Functionality AllowDrop = TB_Path.AllowDrop = true; DragEnter += tabMain_DragEnter; @@ -45,29 +42,14 @@ public Main() t.DragDrop += tabMain_DragDrop; } - // Load with special arguments if supplied via command line - string[] args = Environment.GetCommandLineArgs(); - if (args.Length > 1) - { - int lang; - if (args.Length > 2 && int.TryParse(args[2], out lang)) - CB_Lang.SelectedIndex = lang; - - string path = args[1]; - if (path.Length > 0) openQuick(path); - } // Reload Previous Editing Files if the file exists - else if (File.Exists("config.ini")) - { - string[] lines = File.ReadAllLines("config.ini"); - string path = lines[0]; - int lang; - if (lines.Length > 1 && int.TryParse(lines[1], out lang)) - CB_Lang.SelectedIndex = lang; - if (Directory.Exists("personal") && !skipBoth) { Directory.Delete("personal", true); } // Clear data on form load. - if (path.Length > 0) openQuick(path); - } - string filename = Path.GetFileNameWithoutExtension(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName); + + CB_Lang.SelectedIndex = Properties.Settings.Default.Language; + if (!string.IsNullOrWhiteSpace(Properties.Settings.Default.GamePath)) + openQuick(Properties.Settings.Default.GamePath); + + string[] args = Environment.GetCommandLineArgs(); + string filename = args.Length > 0 ? Path.GetFileNameWithoutExtension(args[0])?.ToLower() : ""; skipBoth = filename.IndexOf("3DSkip", StringComparison.Ordinal) >= 0; } internal static GameConfig Config; @@ -132,26 +114,9 @@ private void changeLanguage(object sender, EventArgs e) } updateGameInfo(); - new Thread(() => - { - // Let all other operations finish first (ie, if the user quickly switches languages on load) - while (threads > 0) Thread.Sleep(50); - // Gather the Text Language Strings - updateStatus($"GARC Get: {"gametext"} @ {Config.getGARCFileName("gametext")}... "); - threadGet(Path.Combine(RomFSPath, Config.getGARCFileName("gametext")), "gametext", true, true); - - while (threads > 0) Thread.Sleep(50); - if (!Directory.Exists("personal")) - { - updateStatus($"GARC Get: {"personal"} @ {Config.getGARCFileName("personal")}... "); - threadGet(Path.Combine(RomFSPath, Config.getGARCFileName("personal")), "personal", true, true); - } - while (threads > 0) Thread.Sleep(50); - // Refresh Personal Stats - Config.InitializePersonal(); - resetStatus(); - - }).Start(); + Config.InitializeGameText(); + Properties.Settings.Default.Language = Language; + Properties.Settings.Default.Save(); } private void Menu_Exit_Click(object sender, EventArgs e) { @@ -159,30 +124,13 @@ private void Menu_Exit_Click(object sender, EventArgs e) } private void formClosing(object sender, FormClosingEventArgs e) { - while (threads > 0) { Util.Alert("Please wait for all operations to finish first."); } - - updateStatus(Environment.NewLine + Environment.NewLine + "Saving data and closing the program..."); - try - { - if (TB_Path.Text.Length > 0) File.WriteAllLines("config.ini", new[] { TB_Path.Text, CB_Lang.SelectedIndex.ToString() }); - if (!Tab_RomFS.Enabled || skipBoth) return; // No data/threads need to be addressed if we haven't loaded anything. - - // Set the GameText back as other forms may have edited it. - updateStatus($"GARC Get: {"gametext"} @ {Config.getGARCFileName("gametext")}... "); - threadSet(Path.Combine(RomFSPath, Config.getGARCFileName("gametext")), "gametext", false); - while (threads > 0) Thread.Sleep(100); - - Thread.Sleep(200); // Small gap between beeps for faster computers. - - updateStatus($"GARC Get: {"personal"} @ {Config.getGARCFileName("personal")}... "); - threadSet(Path.Combine(RomFSPath, Config.getGARCFileName("personal")), "personal", false); - while (threads > 0) Thread.Sleep(100); - - if (Directory.Exists("gametext")) Directory.Delete("gametext", true); - if (Directory.Exists("personal")) Directory.Delete("personal", true); - } - catch { } + var g = Config.GARCGameText; + string[][] files = Config.GameTextStrings; + Invoke((Action)(() => new TextEditor(files, "gametext").ShowDialog())); + g.Files = files.Select(TextFile.getBytes).ToArray(); + g.Save(); } + private void openQuick(string path) { if (threadActive()) return; @@ -257,7 +205,6 @@ private void openQuick(string path) Config.Initialize(RomFSPath, ExeFSPath, Language); backupGARCs(false, Config.Files.Select(file => file.Name).ToArray()); backupCROs(false, RomFSPath); - changeLanguage(null, null); } // Enable Rebuilding options if all files have been found @@ -276,6 +223,9 @@ private void openQuick(string path) TB_Path.Select(TB_Path.TextLength, 0); // Method finished. System.Media.SystemSounds.Asterisk.Play(); + resetStatus(); + Properties.Settings.Default.GamePath = path; + Properties.Settings.Default.Save(); } } @@ -468,10 +418,11 @@ private void B_GameText_Click(object sender, EventArgs e) if (threadActive()) return; new Thread(() => { - string[] files = { "gametext" }; - fileGet(files, false, true); - Invoke((Action)(() => new TextEditor(Directory.GetFiles("gametext")).ShowDialog())); - fileSet(files, true); + var g = Config.GARCGameText; + string[][] files = Config.GameTextStrings; + Invoke((Action)(() => new TextEditor(files, "gametext").ShowDialog())); + g.Files = files.Select(TextFile.getBytes).ToArray(); + Config.GARCGameText.Save(); }).Start(); } private void B_StoryText_Click(object sender, EventArgs e) @@ -479,10 +430,11 @@ private void B_StoryText_Click(object sender, EventArgs e) if (threadActive()) return; new Thread(() => { - string[] files = { "storytext" }; - fileGet(files); - Invoke((Action)(() => new TextEditor(Directory.GetFiles("storytext")).ShowDialog())); - fileSet(files); + var g = Config.getGARCData("storytext"); + string[][] files = g.Files.Select(file => new TextFile(file).Lines).ToArray(); + Invoke((Action)(() => new TextEditor(files, "storytext").ShowDialog())); + g.Files = files.Select(TextFile.getBytes).ToArray(); + g.Save(); }).Start(); } private void B_Maison_Click(object sender, EventArgs e) @@ -505,21 +457,22 @@ private void B_Personal_Click(object sender, EventArgs e) if (threadActive()) return; new Thread(() => { - string[] files = { "personal" }; - fileGet(files, false, true); + byte[][] d = Config.GARCPersonal.Files; switch (Config.Generation) { case 6: - Invoke((Action)(() => new PersonalEditor6().ShowDialog())); + Invoke((Action)(() => new PersonalEditor6(d).ShowDialog())); break; case 7: - Invoke((Action)(() => new PersonalEditor7().ShowDialog())); + Invoke((Action)(() => new PersonalEditor7(d).ShowDialog())); break; } - - // Refresh Personal Stats + // Set Master Table back + for (int i = 0; i < d.Length - 1; i++) + d[i].CopyTo(d[d.Length-1], i * d[i].Length); + Config.GARCPersonal.Save(); Config.InitializePersonal(); - fileSet(files, true); + }).Start(); } private void B_Trainer_Click(object sender, EventArgs e) @@ -567,22 +520,29 @@ private void B_Wild_Click(object sender, EventArgs e) } private void B_OWSE_Click(object sender, EventArgs e) { - bool reload = (ModifierKeys == Keys.Control) || ModifierKeys == (Keys.Alt | Keys.Control); - string[] files = { "encdata", "storytext", "mapGR", "mapMatrix" }; - if (reload || files.Sum(t => Directory.Exists(t) ? 0 : 1) != 0) // Dev bypass if all exist already - fileGet(files, false); - - // Only want to set back encdata. - files = new[] { "encdata" }; - Invoke((MethodInvoker)delegate { Enabled = false; }); + if (threadActive()) return; + new Thread(() => { - Invoke((Action)(() => new TextEditor(Directory.GetFiles("storytext")).Show())); - Invoke((Action)(() => new OWSE().Show())); - while (Application.OpenForms.Count > 1) - Thread.Sleep(200); - } - Invoke((MethodInvoker)delegate { Enabled = true; }); - fileSet(files); + bool reload = (ModifierKeys == Keys.Control) || ModifierKeys == (Keys.Alt | Keys.Control); + string[] files = {"encdata", "storytext", "mapGR", "mapMatrix"}; + if (reload || files.Sum(t => Directory.Exists(t) ? 0 : 1) != 0) // Dev bypass if all exist already + fileGet(files, false); + + // Only want to set back encdata. + files = new[] {"encdata"}; + Invoke((MethodInvoker) delegate { Enabled = false; }); + { + var g = Config.getGARCData("storytext"); + string[][] tfiles = g.Files.Select(file => new TextFile(file).Lines).ToArray(); + Invoke((Action)(() => new TextEditor(tfiles, "storytext").ShowDialog())); + while (Application.OpenForms.Count > 1) + Thread.Sleep(200); + g.Files = tfiles.Select(TextFile.getBytes).ToArray(); + g.Save(); + } + Invoke((MethodInvoker) delegate { Enabled = true; }); + fileSet(files); + }).Start(); } private void B_Evolution_Click(object sender, EventArgs e) { @@ -1029,7 +989,7 @@ private void Menu_Shuffler_Click(object sender, EventArgs e) // GARC Requests internal static string getGARCFileName(string requestedGARC, int lang) { - var garc = Config.getGARC(requestedGARC); + var garc = Config.getGARCReference(requestedGARC); if (garc.LanguageVariant) garc = garc.getRelativeGARC(lang); @@ -1109,14 +1069,11 @@ private static void restoreGARCs(params string[] g) // Text Requests internal static string[] getText(TextName file) { - string path = Path.Combine("gametext", $"{Config.getGameText(file).Index.ToString("000")}.bin"); - return TextFile.getStrings(path); + return Config.GameTextStrings[Config.getGameText(file).Index]; } internal static bool setText(TextName file, string[] strings) { - byte[] data = TextFile.getBytes(strings); - string path = Path.Combine("gametext", $"{Config.getGameText(file).Index.ToString("000")}.bin"); - File.WriteAllBytes(path, data); + Config.GameTextStrings[Config.getGameText(file).Index] = strings; return true; } diff --git a/pk3DS/Properties/Settings.Designer.cs b/pk3DS/Properties/Settings.Designer.cs index 101382a..b53e019 100644 --- a/pk3DS/Properties/Settings.Designer.cs +++ b/pk3DS/Properties/Settings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.17929 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -12,7 +12,7 @@ namespace pk3DS.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -22,5 +22,29 @@ internal sealed partial class Settings : global::System.Configuration.Applicatio return defaultInstance; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("2")] + public int Language { + get { + return ((int)(this["Language"])); + } + set { + this["Language"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string GamePath { + get { + return ((string)(this["GamePath"])); + } + set { + this["GamePath"] = value; + } + } } } diff --git a/pk3DS/Properties/Settings.settings b/pk3DS/Properties/Settings.settings index 3964565..5e4c305 100644 --- a/pk3DS/Properties/Settings.settings +++ b/pk3DS/Properties/Settings.settings @@ -1,7 +1,12 @@  - - - - - - + + + + + 2 + + + + + + \ No newline at end of file diff --git a/pk3DS/Subforms/Gen6/LevelUpEditor6.cs b/pk3DS/Subforms/Gen6/LevelUpEditor6.cs index e09ead3..dc87fda 100644 --- a/pk3DS/Subforms/Gen6/LevelUpEditor6.cs +++ b/pk3DS/Subforms/Gen6/LevelUpEditor6.cs @@ -15,7 +15,10 @@ public partial class LevelUpEditor6 : Form public LevelUpEditor6() { InitializeComponent(); - string[] specieslist = PersonalEditor6.getSpeciesIndexStrings(Main.Config.ORAS); + string[] species = Main.getText(TextName.SpeciesNames); + string[][] AltForms = Main.Config.Personal.getFormList(species, Main.Config.MaxSpeciesID); + int[] baseForm, formVal; + string[] specieslist = Main.Config.Personal.getPersonalEntryList(AltForms, species, Main.Config.MaxSpeciesID, out baseForm, out formVal); specieslist[0] = movelist[0] = ""; string[] sortedspecies = (string[])specieslist.Clone(); diff --git a/pk3DS/Subforms/Gen6/PersonalEditor6.cs b/pk3DS/Subforms/Gen6/PersonalEditor6.cs index 79efec3..fdc8624 100644 --- a/pk3DS/Subforms/Gen6/PersonalEditor6.cs +++ b/pk3DS/Subforms/Gen6/PersonalEditor6.cs @@ -1,7 +1,6 @@ using System; using System.Drawing; using System.IO; -using System.Linq; using System.Media; using System.Text; using System.Windows.Forms; @@ -11,7 +10,7 @@ namespace pk3DS { public partial class PersonalEditor6 : Form { - public PersonalEditor6() + public PersonalEditor6(byte[][] infiles) { InitializeComponent(); helditem_boxes = new[] { CB_HeldItem1, CB_HeldItem2, CB_HeldItem3 }; @@ -21,22 +20,29 @@ public PersonalEditor6() byte_boxes = new[] { TB_BaseHP, TB_BaseATK, TB_BaseDEF, TB_BaseSPA, TB_BaseSPD, TB_BaseSPE, TB_Gender, TB_HatchCycles, TB_Friendship, TB_CatchRate }; ev_boxes = new[] { TB_HPEVs, TB_ATKEVs, TB_DEFEVs, TB_SPEEVs, TB_SPAEVs, TB_SPDEVs }; rstat_boxes = new[] { CHK_rHP, CHK_rATK, CHK_rDEF, CHK_rSPA, CHK_rSPD, CHK_rSPE }; + files = infiles; + + abilities = Main.getText(TextName.AbilityNames); + moves = Main.getText(TextName.MoveNames); + items = Main.getText(TextName.ItemNames); + species = Main.getText(TextName.SpeciesNames); + types = Main.getText(TextName.Types); + species[0] = "---"; + abilities[0] = items[0] = moves[0] = ""; + string[][] AltForms = Main.Config.Personal.getFormList(species, Main.Config.MaxSpeciesID); + species = Main.Config.Personal.getPersonalEntryList(AltForms, species, Main.Config.MaxSpeciesID, out baseForms, out formVal); - data = File.ReadAllBytes(paths.Last()); // Load last to data. Setup(); //Turn string resources into arrays CB_Species.SelectedIndex = 1; } #region Global Variables - private readonly string[] paths = Directory.GetFiles("personal", "*.*", SearchOption.TopDirectoryOnly); private readonly string mode = Main.Config.ORAS ? "ORAS" : "XY"; + private readonly byte[][] files; private string[] items = { }; private string[] moves = { }; private string[] species = { }; private string[] abilities = { }; - private string[] forms = { }; - - private readonly byte[] data = { }; private readonly ComboBox[] helditem_boxes; private readonly ComboBox[] ability_boxes; @@ -66,23 +72,11 @@ public PersonalEditor6() public ushort[] tutor3 = { 20, 173, 282, 235, 257, 272, 215, 366, 143, 220, 202, 409, 314, 264, 351, 352 }; public ushort[] tutor4 = { 380, 388, 180, 495, 270, 271, 478, 472, 283, 200, 278, 289, 446, 214, 285 }; - private string[][] AltForms; - int entrysize = Main.Config.ORAS ? 0x50 : 0x40; + private readonly int[] baseForms, formVal; int entry = -1; #endregion private void Setup() { - abilities = Main.getText(TextName.AbilityNames); - moves = Main.getText(TextName.MoveNames); - items = Main.getText(TextName.ItemNames); - species = Main.getText(TextName.SpeciesNames); - types = Main.getText(TextName.Types); - forms = Main.getText(TextName.Forms); - species[0] = "---"; - abilities[0] = items[0] = moves[0] = ""; - AltForms = getFormList(data, Main.Config.ORAS, species, forms, types, items); - species = getPersonalEntryList(data, Main.Config.ORAS, AltForms, species); - ushort[] TMs = new ushort[0]; ushort[] HMs = new ushort[0]; TMHMEditor6.getTMHMList(Main.Config.ORAS, ref TMs, ref HMs); @@ -255,7 +249,11 @@ private void readEntry() readInfo(); if (dumping) return; - int[] specForm = getSpecies(data, Main.Config.ORAS, CB_Species.SelectedIndex); + int s = baseForms[entry]; + int f = formVal[entry]; + if (entry <= Main.Config.MaxSpeciesID) + s = entry; + int[] specForm = { s, f }; string filename = "_" + specForm[0] + (CB_Species.SelectedIndex > 721 ? "_" + (specForm[1] + 1) : ""); Bitmap rawImg = (Bitmap)Resources.ResourceManager.GetObject(filename); Bitmap bigImg = new Bitmap(rawImg.Width * 2, rawImg.Height * 2); @@ -334,9 +332,7 @@ private void saveEntry() { savePersonal(); byte[] edits = pkm.Write(); - File.WriteAllBytes(paths[entry], edits); - Array.Copy(edits, 0, data, entry * edits.Length, edits.Length); - File.WriteAllBytes(paths[paths.Length - 1], data); + files[entry] = edits; } private void B_Randomize_Click(object sender, EventArgs e) @@ -608,19 +604,5 @@ internal static void setForms(int species, ComboBox cb, string[][] AltForms) } cb.SelectedIndex = 0; } - - internal static string[] getSpeciesIndexStrings(bool oras) - { - string[] items = Main.getText(TextName.ItemNames); - string[] species = Main.getText(TextName.SpeciesNames); - string[] types = Main.getText(TextName.Types); - string[] forms = Main.getText(TextName.Forms); - species[0] = "---"; - byte[] data = File.ReadAllBytes(Directory.GetFiles("personal").Last()); - string[][] AltForms = getFormList(data, Main.Config.ORAS, species, forms, types, items); - species = getPersonalEntryList(data, Main.Config.ORAS, AltForms, species); - Array.Resize(ref species, oras ? species.Length : 799); - return species; - } } } \ No newline at end of file diff --git a/pk3DS/Subforms/Gen7/PersonalEditor7.cs b/pk3DS/Subforms/Gen7/PersonalEditor7.cs index 11f3483..5f6aaff 100644 --- a/pk3DS/Subforms/Gen7/PersonalEditor7.cs +++ b/pk3DS/Subforms/Gen7/PersonalEditor7.cs @@ -1,7 +1,6 @@ using System; using System.Drawing; using System.IO; -using System.Linq; using System.Media; using System.Text; using System.Windows.Forms; @@ -11,7 +10,7 @@ namespace pk3DS { public partial class PersonalEditor7 : Form { - public PersonalEditor7() + public PersonalEditor7(byte[][] infiles) { InitializeComponent(); helditem_boxes = new[] { CB_HeldItem1, CB_HeldItem2, CB_HeldItem3 }; @@ -21,19 +20,18 @@ public PersonalEditor7() byte_boxes = new[] { TB_BaseHP, TB_BaseATK, TB_BaseDEF, TB_BaseSPA, TB_BaseSPD, TB_BaseSPE, TB_Gender, TB_HatchCycles, TB_Friendship, TB_CatchRate }; ev_boxes = new[] { TB_HPEVs, TB_ATKEVs, TB_DEFEVs, TB_SPEEVs, TB_SPAEVs, TB_SPDEVs }; rstat_boxes = new[] { CHK_rHP, CHK_rATK, CHK_rDEF, CHK_rSPA, CHK_rSPD, CHK_rSPE }; - - data = File.ReadAllBytes(paths.Last()); // Load last to data. - Personal = new PersonalTable(data, GameVersion.SM); + files = infiles; + species[0] = "---"; abilities[0] = items[0] = moves[0] = ""; - AltForms = Personal.getFormList(species, Main.Config.MaxSpeciesID); - entryNames = Personal.getPersonalEntryList(AltForms, species, Main.Config.MaxSpeciesID, out baseForms, out formVal); + var altForms = Main.Config.Personal.getFormList(species, Main.Config.MaxSpeciesID); + entryNames = Main.Config.Personal.getPersonalEntryList(altForms, species, Main.Config.MaxSpeciesID, out baseForms, out formVal); Setup(); CB_Species.SelectedIndex = 1; } #region Global Variables - private readonly string[] paths = Directory.GetFiles("personal", "*.*", SearchOption.TopDirectoryOnly); + private readonly byte[][] files; private readonly string[] items = Main.getText(TextName.ItemNames); private readonly string[] moves = Main.getText(TextName.MoveNames); @@ -41,8 +39,7 @@ public PersonalEditor7() private readonly string[] abilities = Main.getText(TextName.AbilityNames); private readonly string[] forms = Main.getText(TextName.Forms); private readonly string[] types = Main.getText(TextName.Types); - - private readonly byte[] data; + private readonly string[] entryNames; private readonly ComboBox[] helditem_boxes; @@ -59,9 +56,7 @@ public PersonalEditor7() private readonly string[] colors = { "Red", "Blue", "Yellow", "Green", "Black", "Brown", "Purple", "Gray", "White", "Pink" }; private readonly ushort[] tutormoves = { 338, 307, 308, 520, 519, 518, 434, 620 }; - private readonly PersonalTable Personal; - private string[][] AltForms; - private int[] baseForms, formVal; + private readonly int[] baseForms, formVal; int entry = -1; #endregion private void Setup() @@ -264,9 +259,7 @@ private void saveEntry() { savePersonal(); byte[] edits = pkm.Write(); - File.WriteAllBytes(paths[entry], edits); - Array.Copy(edits, 0, data, entry * edits.Length, edits.Length); - File.WriteAllBytes(paths[paths.Length - 1], data); + files[entry] = edits; } private void B_Randomize_Click(object sender, EventArgs e) diff --git a/pk3DS/Subforms/TextEditor.cs b/pk3DS/Subforms/TextEditor.cs index 6dd5b2b..995621f 100644 --- a/pk3DS/Subforms/TextEditor.cs +++ b/pk3DS/Subforms/TextEditor.cs @@ -9,16 +9,19 @@ namespace pk3DS { public partial class TextEditor : Form { - public TextEditor(string[] infiles) + public TextEditor(string[][] infiles, string mode) { InitializeComponent(); files = infiles; + Mode = mode; for (int i = 0; i < files.Length; i++) CB_Entry.Items.Add(i.ToString()); CB_Entry.SelectedIndex = 0; } - private readonly string[] files; + private readonly string[][] files; + private readonly string Mode; private int entry = -1; + // IO private void B_Export_Click(object sender, EventArgs e) { @@ -54,7 +57,7 @@ private void exportTextFile(string fileName, bool newline) for (int i = 0; i < files.Length; i++) { // Get Strings for the File - string[] data = TextFile.getStrings(files[i]); + string[] data = files[i]; // Append the File Header tw.WriteLine("~~~~~~~~~~~~~~~"); tw.WriteLine("Text File : " + i); @@ -117,7 +120,7 @@ private bool importTextFile(string fileName) // All Text Lines received. Store all back. for (int i = 0; i < files.Length; i++) - try { File.WriteAllBytes(files[i], TextFile.getBytes(textLines[i])); } + try { files[i] = textLines[i]; } catch (Exception e) { Util.Error($"The input Text File (# {i}) failed to convert:", e.ToString()); return false; } return true; } @@ -128,18 +131,16 @@ private void changeEntry(object sender, EventArgs e) { try { - byte[] bin = TextFile.getBytes(getCurrentDGLines()); - File.WriteAllBytes(files[entry], bin); + files[entry] = getCurrentDGLines(); } catch (Exception ex) { Util.Error(ex.ToString()); } } // Reset entry = CB_Entry.SelectedIndex; - string file = files[entry]; - string[] data = TextFile.getStrings(file); - setStringsDataGridView(data); + setStringsDataGridView(files[entry]); } + // Main Handling private void setStringsDataGridView(string[] textArray) { @@ -229,14 +230,13 @@ private void B_RemoveLine_Click(object sender, EventArgs e) private void xytext_FormClosing(object sender, FormClosingEventArgs e) { // Save All the old text - if (entry > -1) File.WriteAllBytes(files[entry], TextFile.getBytes(getCurrentDGLines())); + if (entry > -1) files[entry] = getCurrentDGLines(); } private void B_Randomize_Click(object sender, EventArgs e) { // gametext can be horribly broken if randomized - string dirname = Directory.GetParent(files[entry]).Name; - if (dirname == "gametext" && DialogResult.Yes != + if (Mode == "gametext" && DialogResult.Yes != Util.Prompt(MessageBoxButtons.YesNo, "Randomizing Game Text is dangerous?", "Continue?")) return; @@ -258,7 +258,8 @@ private void B_Randomize_Click(object sender, EventArgs e) bool smart = drs == DialogResult.Yes; // save current - if (entry > -1) File.WriteAllBytes(files[entry], TextFile.getBytes(getCurrentDGLines())); + if (entry > -1) + files[entry] = getCurrentDGLines(); // single-entire looping int start = all ? 0 : entry; @@ -268,7 +269,7 @@ private void B_Randomize_Click(object sender, EventArgs e) List strings = new List(); for (int i = start; i <= end; i++) { - string[] data = TextFile.getStrings(files[i]); + string[] data = files[i]; strings.AddRange(smart ? data.Where(line => !line.Contains("[")) : data); @@ -282,18 +283,17 @@ private void B_Randomize_Click(object sender, EventArgs e) int ctr = 0; for (int i = start; i <= end; i++) { - string[] data = TextFile.getStrings(files[i]); + string[] data = files[i]; for (int j = 0; j < data.Length; j++) // apply lines if (!smart || !data[j].Contains("[")) data[j] = pool[ctr++]; - - byte[] file = TextFile.getBytes(data); - File.WriteAllBytes(files[i], file); + + files[i] = data; } // Load current text file - setStringsDataGridView(TextFile.getStrings(files[entry])); + setStringsDataGridView(files[entry]); Util.Alert("Strings randomized!"); } diff --git a/pk3DS/Tools/TextFile.cs b/pk3DS/Tools/TextFile.cs index 099a148..0c02a6f 100644 --- a/pk3DS/Tools/TextFile.cs +++ b/pk3DS/Tools/TextFile.cs @@ -46,7 +46,7 @@ private LineInfo[] LineOffsets result[i] = new LineInfo { Offset = BitConverter.ToInt32(Data, i * 8 + sdo + 4) + sdo, - Length = BitConverter.ToInt32(Data, i * 8 + sdo + 8) + Length = BitConverter.ToInt16(Data, i * 8 + sdo + 8) }; return result; } @@ -319,9 +319,8 @@ private static string getVariableString(ushort variable) } // Exposed Methods - internal static string[] getStrings(string path) + internal static string[] getStrings(byte[] data) { - byte[] data = File.ReadAllBytes(path); TextFile t; try { t = new TextFile(data); } catch { return null; } return t.Lines; diff --git a/pk3DS/app.config b/pk3DS/app.config new file mode 100644 index 0000000..18caac5 --- /dev/null +++ b/pk3DS/app.config @@ -0,0 +1,18 @@ + + + + +
+ + + + + + 2 + + + + + + + \ No newline at end of file diff --git a/pk3DS/pk3DS.csproj b/pk3DS/pk3DS.csproj index 41500ef..fb24a78 100644 --- a/pk3DS/pk3DS.csproj +++ b/pk3DS/pk3DS.csproj @@ -62,6 +62,7 @@ + @@ -482,6 +483,7 @@ ToolsUI.cs + SettingsSingleFileGenerator Settings.Designer.cs