diff --git a/pk3DS/Game/GameBackup.cs b/pk3DS/Game/GameBackup.cs new file mode 100644 index 0000000..e960444 --- /dev/null +++ b/pk3DS/Game/GameBackup.cs @@ -0,0 +1,224 @@ +using System; +using System.IO; +using System.Linq; + +namespace pk3DS +{ + public static class GameBackup + { + private const string bakpath = "backup"; + private const string bakexefs = "exefs"; + private const string baka = "a"; + private const string bakdll = "dll"; + + public static void backupFiles(this GameConfig config, bool overwrite = false) + { + // Users may use pk3DS for multiple games, and even the same game but from different paths. + // A simple way is to create a backup for each unique game, but... some carts may be pre-patched. + // Just save the backup based on the folder name, as the user may move that parent folder. + // Store a text file in each backup to keep track of its origin in case they rename the folder. + + if (!Directory.Exists(bakpath)) + Directory.CreateDirectory(bakpath); + + var gamePath = new DirectoryInfo(config.RomFS).Parent; + string gameFolder = gamePath.Name; + string gameBackup = Path.Combine(bakpath, gameFolder); + if (!Directory.Exists(gameBackup)) + Directory.CreateDirectory(gameBackup); + + string bak_exefs = Path.Combine(gameBackup, bakexefs); + string bak_a = Path.Combine(gameBackup, baka); + string bak_dll = Path.Combine(gameBackup, bakdll); + if (!Directory.Exists(bak_exefs)) + Directory.CreateDirectory(bak_exefs); + if (!Directory.Exists(bak_a)) + Directory.CreateDirectory(bak_a); + if (!Directory.Exists(bak_dll)) + Directory.CreateDirectory(bak_dll); + + // Backup files + if (config.ExeFS != null) // exefs + backupExeFS(config, overwrite, bak_exefs); + if (config.RomFS != null) // a + backupGARC(config, overwrite, bak_a); + if (config.RomFS != null) // dll + backupDLL(config, overwrite, bak_dll); + + File.WriteAllText(Path.Combine(gameBackup, "bakinfo.txt"), "Backup created from the following location:" + Environment.NewLine + gamePath.FullName); + } + private static void backupExeFS(GameConfig config, bool overwrite, string bak_exefs) + { + var files = Directory.GetFiles(config.ExeFS); + foreach (var f in files) + { + string dest = Path.Combine(bak_exefs, Path.GetFileName(f)); + if (overwrite || !File.Exists(dest)) + File.Copy(f, dest); + } + } + private static void backupGARC(GameConfig config, bool overwrite, string bak_a) + { + var files = config.Files.Select(file => file.Name); + foreach (var f in files) + { + string GARC = config.getGARCFileName(f); + string name = f + $" ({GARC.Replace(Path.DirectorySeparatorChar.ToString(), "")})"; + string src = Path.Combine(config.RomFS, GARC); + string dest = Path.Combine(bak_a, name); + if (overwrite || !File.Exists(dest)) + File.Copy(src, dest); + } + } + private static void backupDLL(GameConfig config, bool overwrite, string bak_dll) + { + string path = config.RomFS; + string[] files = Directory.GetFiles(path); + string[] CROs = files.Where(x => new FileInfo(x).Name.Contains("Dll")).ToArray(); + string[] CRSs = files.Where(x => new FileInfo(x).Extension.Contains("crs")).ToArray(); + string[] CRRs = Directory.Exists(Path.Combine(path, ".crr")) + ? Directory.GetFiles(Path.Combine(path, ".crr")) + : new string[0]; + + int count = CROs.Length + CRSs.Length + CRRs.Length; + if (count <= 0) + return; + + if (!Directory.Exists(bak_dll)) + Directory.CreateDirectory(bak_dll); + + foreach (string src in CROs.Concat(CRSs)) + { + string dest = Path.Combine(bak_dll, Path.GetFileName(src)); + if (overwrite || !File.Exists(dest)) + File.Copy(src, dest); + } + + if (CRRs.Length <= 0) + return; + + // Separate folder for the .crr + string CRRBAKPATH = Path.Combine(bak_dll, ".crr"); + if (!Directory.Exists(CRRBAKPATH)) + Directory.CreateDirectory(CRRBAKPATH); + + foreach (string src in CRRs) + { + string dest = Path.Combine(CRRBAKPATH, Path.GetFileName(src)); + if (overwrite || !File.Exists(dest)) + File.Copy(src, dest); + } + } + + public static string[] restoreFiles(this GameConfig config) + { + // Do the same process as backing up, but copy files in the opposite direction. + + string gameFolder = new DirectoryInfo(config.RomFS).Parent.Name; + string gameBackup = Path.Combine(bakpath, gameFolder); + if (!Directory.Exists(gameBackup)) + return new[] {"Unable to find the backup folder for this game.", $"Expected:\n{gameBackup}"}; + + string bak_exefs = Path.Combine(gameBackup, bakexefs); + string bak_a = Path.Combine(gameBackup, baka); + string bak_dll = Path.Combine(gameBackup, bakdll); + + int[] count = new int[3]; + + // restore exefs + if (Directory.Exists(bak_exefs)) + count[0] = restoreExeFS(config, bak_exefs); + if (Directory.Exists(bak_a)) + count[1] = restoreGARC(config, bak_a); + if (Directory.Exists(bak_dll)) + count[2] = restoreDLL(config, bak_dll); + + string[] sources = { "ExeFS", "'a'", "CRO" }; + var info = count.Select((c, i) => $"{sources[i]}: {c}"); + var result = string.Join(Environment.NewLine, info); + return new[] {result}; + } + private static int restoreExeFS(GameConfig config, string bak_exefs) + { + int count = 0; + var files = Directory.GetFiles(config.ExeFS); + foreach (var f in files) + { + string dest = Path.Combine(bak_exefs, Path.GetFileName(f)); + if (File.Exists(dest)) + { + File.Copy(dest, f); + count++; + } + else + Console.WriteLine("Unable to find backup: " + dest); + } + return count; + } + private static int restoreGARC(GameConfig config, string bak_a) + { + int count = 0; + var files = config.Files.Select(file => file.Name); + foreach (var f in files) + { + string GARC = config.getGARCFileName(f); + string name = f + $" ({GARC.Replace(Path.DirectorySeparatorChar.ToString(), "")})"; + string src = Path.Combine(config.RomFS, GARC); + string dest = Path.Combine(bak_a, name); + if (File.Exists(dest)) + { + File.Copy(dest, src); + count++; + } + else + Console.WriteLine("Unable to find backup: " + dest); + } + return count; + } + private static int restoreDLL(GameConfig config, string bak_dll) + { + int count = 0; + + string path = config.RomFS; + string[] files = Directory.GetFiles(path); + string[] CROs = files.Where(x => new FileInfo(x).Name.Contains("Dll")).ToArray(); + string[] CRSs = files.Where(x => new FileInfo(x).Extension.Contains("crs")).ToArray(); + string[] CRRs = Directory.Exists(Path.Combine(path, ".crr")) + ? Directory.GetFiles(Path.Combine(path, ".crr")) + : new string[0]; + + if (CROs.Length + CRSs.Length + CRRs.Length <= 0) + return 0; + + foreach (string src in CROs.Concat(CRSs)) + { + string dest = Path.Combine(bak_dll, Path.GetFileName(src)); + if (File.Exists(dest)) + { + File.Copy(dest, src); + count++; + } + else + Console.WriteLine("Unable to find backup: " + dest); + } + + if (CRRs.Length <= 0) + return count; + + // Separate folder for the .crr + string CRRBAKPATH = Path.Combine(bak_dll, ".crr"); + foreach (string src in CRRs) + { + string dest = Path.Combine(CRRBAKPATH, Path.GetFileName(src)); + if (File.Exists(dest)) + { + File.Copy(dest, src); + count++; + } + else + Console.WriteLine("Unable to find backup: " + dest); + } + return count; + } + } +} diff --git a/pk3DS/Game/GameConfig.cs b/pk3DS/Game/GameConfig.cs index 94c86d4..f29ec07 100644 --- a/pk3DS/Game/GameConfig.cs +++ b/pk3DS/Game/GameConfig.cs @@ -169,7 +169,7 @@ private GARC.lzGARC getlzGARC(string file) return new GARC.lzGARC(File.ReadAllBytes(getGARCPath(file))); } - private string RomFS, ExeFS; + public string RomFS, ExeFS; public GARCReference getGARCReference(string name) { return Files.FirstOrDefault(f => f.Name == name); } public TextVariableCode getVariableCode(string name) { return Variables.FirstOrDefault(v => v.Name == name); } diff --git a/pk3DS/Main.cs b/pk3DS/Main.cs index 574c48f..26e636e 100644 --- a/pk3DS/Main.cs +++ b/pk3DS/Main.cs @@ -70,21 +70,31 @@ private void L_About_Click(object sender, EventArgs e) } private void L_GARCInfo_Click(object sender, EventArgs e) { - if (RomFSPath != null) - { - string s = "Game Type: " + Config.Version + Environment.NewLine; - s = Config.Files.Select(file => file.Name).Aggregate(s, (current, t) => current + string.Format(Environment.NewLine + "{0} - {1}", t, Config.getGARCFileName(t))); + if (RomFSPath == null) + return; - if (DialogResult.Yes != Util.Prompt(MessageBoxButtons.YesNo, s, "Copy to Clipboard?")) return; + string s = "Game Type: " + Config.Version + Environment.NewLine; + s = Config.Files.Select(file => file.Name).Aggregate(s, (current, t) => current + string.Format(Environment.NewLine + "{0} - {1}", t, Config.getGARCFileName(t))); - try { Clipboard.SetText(s); } - catch { Util.Alert("Unable to copy to Clipboard."); } - } + if (DialogResult.Yes != Util.Prompt(MessageBoxButtons.YesNo, s, "Copy to Clipboard?")) return; + + try { Clipboard.SetText(s); } + catch { Util.Alert("Unable to copy to Clipboard."); } } private void L_Game_Click(object sender, EventArgs e) { - if (DialogResult.Yes == Util.Prompt(MessageBoxButtons.YesNo, "Restore Original Files?")) - restoreGARCs(Config.Files.Select(file => file.Name).ToArray()); + if (DialogResult.Yes != Util.Prompt(MessageBoxButtons.YesNo, "Restore Original Files?")) + return; + + string[] result = Config.restoreFiles(); + if (result.Length == 2) // error + { + Util.Alert(result); + return; + } + + Util.Alert("Restored files:", result[0], "The program will now close."); + Application.Exit(); // do not call closing events that repackage personal/gametext } private void B_Open_Click(object sender, EventArgs e) @@ -203,8 +213,7 @@ private void openQuick(string path) if (RTB_Status.Text.Length > 0) RTB_Status.Clear(); updateStatus("Data found! Loading persistent data for subforms...", false); Config.Initialize(RomFSPath, ExeFSPath, Language); - backupGARCs(false, Config.Files.Select(file => file.Name).ToArray()); - backupCROs(false, RomFSPath); + Config.backupFiles(); } // Enable Rebuilding options if all files have been found @@ -289,7 +298,6 @@ private static GameConfig checkGameType(string[] files) if (files.Length > 1000) return null; string[] fileArr = Directory.GetFiles(Path.Combine(Directory.GetParent(files[0]).FullName, "a"), "*", SearchOption.AllDirectories); - var afiles = fileArr.Where(file => Path.GetFileName(file)?.Length == 1).ToArray(); int fileCount = fileArr.Count(file => Path.GetFileName(file)?.Length == 1); return new GameConfig(fileCount); } @@ -781,7 +789,6 @@ private void B_TitleScreen_Click(object sender, EventArgs e) // RomFS File Requesting Method Wrapper private void fileGet(string[] files, bool skipDecompression = true, bool skipGet = false) { - if (ModifierKeys == (Keys.Control | Keys.Shift)) restoreGARCs(files.ToArray()); if (skipGet || skipBoth) return; foreach (string toEdit in files) { @@ -998,42 +1005,6 @@ private void B_Static_Click(object sender, EventArgs e) } new StaticEncounterEditor6().ShowDialog(); } - private void backupCROs(bool overwrite, string path) - { - if (!Directory.Exists(path)) - return; - - string[] files = Directory.GetFiles(path); - string[] CROs = files.Where(x => new FileInfo(x).Name.Contains("Dll")).ToArray(); - string[] CRSs = files.Where(x => new FileInfo(x).Extension.Contains("crs")).ToArray(); - string[] CRRs = Directory.Exists(Path.Combine(path, ".crr")) - ? Directory.GetFiles(Path.Combine(path, ".crr")) - : new string[0]; - - int count = CROs.Length + CRSs.Length + CRRs.Length; - if (count <= 0) - return; - - // Somewhat unique ID for the dlls to separate backup folders between versions - string CROBAKPATH = Path.Combine("backup", "DLL_" + count); - - if (!Directory.Exists(CROBAKPATH)) - Directory.CreateDirectory(CROBAKPATH); - - foreach (string file in CROs.Concat(CRSs).Where(file => overwrite || !File.Exists(Path.Combine(CROBAKPATH, Path.GetFileName(file))))) - File.Copy(file, Path.Combine(CROBAKPATH, Path.GetFileName(file))); - - if (CRRs.Length <= 0) - return; - - // Separate folder for the .crr - string CRRBAKPATH = Path.Combine(CROBAKPATH, ".crr"); - if (!Directory.Exists(CRRBAKPATH)) - Directory.CreateDirectory(CRRBAKPATH); - - foreach (string file in CRRs.Where(file => overwrite || !File.Exists(Path.Combine(CRRBAKPATH, Path.GetFileName(file))))) - File.Copy(file, Path.Combine(CRRBAKPATH, Path.GetFileName(file))); - } // 3DS Building private void B_Rebuild3DS_Click(object sender, EventArgs e) @@ -1185,32 +1156,6 @@ private void threadSet(string outfile, string infolder, int padBytes, bool PB = new Thread(() => setGARC(outfile, infolder, padBytes, PB)).Start(); } - private static void backupGARCs(bool overwrite, params string[] g) - { - if (!Directory.Exists("backup")) Directory.CreateDirectory("backup"); - foreach (string s in g) - { - string GARC = Config.getGARCFileName(s); - string dest = "backup" + Path.DirectorySeparatorChar + s + - $" ({GARC.Replace(Path.DirectorySeparatorChar.ToString(), "")})"; - if (overwrite || !File.Exists(dest)) - File.Copy(Path.Combine(RomFSPath, GARC), dest); - } - } - private static void restoreGARCs(params string[] g) - { - foreach (string s in g) - { - string dest = Path.Combine(RomFSPath, Config.getGARCFileName(s)); - string src = "backup" + Path.DirectorySeparatorChar + s + - $" ({Config.getGARCFileName(s).Replace(Path.DirectorySeparatorChar.ToString(), "")})"; - File.Copy(src, dest, true); - if (s == "personal" || s == "gametext") - Util.Alert("In order to restore " + s + ", restart the program. While exiting, hold the Control Key to prevent writebacks."); - } - Util.Alert(g.Length + " files restored."); - } - // Text Requests internal static string[] getText(TextName file) { diff --git a/pk3DS/pk3DS.csproj b/pk3DS/pk3DS.csproj index 1404eef..2f86c18 100644 --- a/pk3DS/pk3DS.csproj +++ b/pk3DS/pk3DS.csproj @@ -84,6 +84,7 @@ +