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 @@
+