From 4f253a6da0a2c791aeed0f131607ffca3b821ad3 Mon Sep 17 00:00:00 2001 From: Kaphotics Date: Sat, 29 Oct 2016 21:11:52 -0700 Subject: [PATCH] Gen7 Config refactoring Old pk3DS only supported 0/1 for xy/oras; need to have a little more flexibility than that! --- pk3DS/Game/GARCReference.cs | 26 ++++++ pk3DS/Game/GameConfig.cs | 164 ++++++++++++++++++++++++++++++++++++ pk3DS/Game/GameVersion.cs | 48 +++++++++++ pk3DS/Main.cs | 92 ++++++++------------ pk3DS/pk3DS.csproj | 3 + 5 files changed, 276 insertions(+), 57 deletions(-) create mode 100644 pk3DS/Game/GARCReference.cs create mode 100644 pk3DS/Game/GameConfig.cs create mode 100644 pk3DS/Game/GameVersion.cs diff --git a/pk3DS/Game/GARCReference.cs b/pk3DS/Game/GARCReference.cs new file mode 100644 index 0000000..7503ee9 --- /dev/null +++ b/pk3DS/Game/GARCReference.cs @@ -0,0 +1,26 @@ +using System.IO; + +namespace pk3DS +{ + public class GARCReference + { + public readonly int FileNumber; + public readonly string Name; + private int A => (FileNumber / 100) % 10; + private int B => (FileNumber / 10) % 10; + private int C => (FileNumber / 1) % 10; + public readonly bool LanguageVariant; + public string Reference => Path.Combine("a", A.ToString(), B.ToString(), C.ToString()); + + public GARCReference(int file, string name, bool lv = false) + { + Name = name; + FileNumber = file; + LanguageVariant = lv; + } + public GARCReference getRelativeGARC(int offset, string name = "") + { + return new GARCReference(FileNumber + offset, name); + } + } +} diff --git a/pk3DS/Game/GameConfig.cs b/pk3DS/Game/GameConfig.cs new file mode 100644 index 0000000..a9760dd --- /dev/null +++ b/pk3DS/Game/GameConfig.cs @@ -0,0 +1,164 @@ +using System.Collections.Generic; +using System.Linq; + +namespace pk3DS +{ + public class GameConfig + { + private const int FILECOUNT_XY = 271; + private const int FILECOUNT_ORASDEMO = 301; + private const int FILECOUNT_ORAS = 299; + private const int FILECOUNT_SMDEMO = 238; + private const int FILECOUNT_SM = 1; + public readonly List Files = new List(); + public GARCReference getGARC(string name) { return Files.FirstOrDefault(file => file.Name == name); } + public bool XY => Version == GameVersion.XY; + public bool ORAS => Version == GameVersion.ORAS || Version == GameVersion.ORASDEMO; + public bool SM => Version == GameVersion.SM || Version == GameVersion.SMDEMO; + + private readonly GameVersion Version = GameVersion.Invalid; + public bool IsRebuildable(int fileCount) + { + switch (fileCount) + { + case FILECOUNT_XY: + return Version == GameVersion.XY; + case FILECOUNT_ORAS: + return Version == GameVersion.ORAS; + case FILECOUNT_ORASDEMO: + return Version == GameVersion.ORASDEMO; + case FILECOUNT_SMDEMO: + return Version == GameVersion.SMDEMO; + case FILECOUNT_SM: + return Version == GameVersion.SM; + } + return false; + } + + public GameConfig(int fileCount) + { + GameVersion game = GameVersion.Invalid; + switch (fileCount) + { + case FILECOUNT_XY: + game = GameVersion.XY; + break; + case FILECOUNT_ORAS: + case FILECOUNT_ORASDEMO: + game = GameVersion.ORAS; + break; + case FILECOUNT_SMDEMO: + case FILECOUNT_SM: + game = GameVersion.SM; + break; + } + if (game == GameVersion.Invalid) + return; + + Files.AddRange(getGameFiles(game)); + Version = game; + } + public GameConfig(GameVersion game) + { + Files.AddRange(getGameFiles(game)); + Version = game; + } + + private static IEnumerable getGameFiles(GameVersion game) + { + switch (game) + { + case GameVersion.XY: + return setupXY(); + case GameVersion.ORASDEMO: + case GameVersion.ORAS: + return setupORAS(); + case GameVersion.SMDEMO: + case GameVersion.SM: + return setupSM(); + default: + return null; + } + } + private static IEnumerable setupXY() + { + return new[] + { + new GARCReference(005,"movesprite"), + new GARCReference(012,"encdata"), + new GARCReference(038, "trdata"), + new GARCReference(040, "trpoke"), + new GARCReference(041, "mapGR"), + new GARCReference(042, "mapMatrix"), + new GARCReference(104, "wallpaper"), + new GARCReference(165, "titlescreen"), + new GARCReference(203, "maisonpkN"), + new GARCReference(204, "maisontrN"), + new GARCReference(205, "maisonpkS"), + new GARCReference(206, "maisontrS"), + new GARCReference(212, "move"), + new GARCReference(213, "eggmove"), + new GARCReference(214, "levelup"), + new GARCReference(215, "evolution"), + new GARCReference(216, "megaevo"), + new GARCReference(218, "personal"), + new GARCReference(220, "item"), + + // Varied + new GARCReference(072, "gametext", true), + new GARCReference(080, "storytext", true), + }; + } + private static IEnumerable setupORAS() + { + return new[] + { + new GARCReference(013, "encdata"), + new GARCReference(036, "trdata"), + new GARCReference(038, "trpoke"), + new GARCReference(039, "mapGR"), + new GARCReference(040, "mapMatrix"), + new GARCReference(103, "wallpaper"), + new GARCReference(152, "titlescreen"), + new GARCReference(182, "maisonpkN"), + new GARCReference(183, "maisontrN"), + new GARCReference(184, "maisonpkS"), + new GARCReference(185, "maisontrS"), + new GARCReference(189, "move"), + new GARCReference(190, "eggmove"), + new GARCReference(191, "levelup"), + new GARCReference(192, "evolution"), + new GARCReference(193, "megaevo"), + new GARCReference(195, "personal"), + new GARCReference(197, "item"), + + // Varied + new GARCReference(071, "gametext", true), + new GARCReference(079, "storytext", true), + }; + } + private static IEnumerable setupSM() + { + return new[] + { + new GARCReference(011, "move"), + new GARCReference(012, "eggmove"), + new GARCReference(013, "levelup"), + new GARCReference(014, "evolution"), + new GARCReference(015, "megaevo"), + new GARCReference(017, "personal"), + new GARCReference(019, "item"), + + new GARCReference(081, "encdata"), + + new GARCReference(101, "trclass"), + new GARCReference(102, "trdata"), + new GARCReference(013, "trpoke"), + + // Varied + new GARCReference(030, "gametext", true), + new GARCReference(040, "storytext", true), + }; + } + } +} diff --git a/pk3DS/Game/GameVersion.cs b/pk3DS/Game/GameVersion.cs new file mode 100644 index 0000000..d17f693 --- /dev/null +++ b/pk3DS/Game/GameVersion.cs @@ -0,0 +1,48 @@ +namespace pk3DS +{ + public enum GameVersion + { + // Not actually stored values, but assigned as properties. + XD = -11, + COLO = -10, + BATREV = -7, + RSBOX = -5, + GS = -4, + C = -3, + + // Indicators + Invalid = -2, + Any = -1, + Unknown = 0, + + // Version IDs, also stored in PKM structure + /*Gen3*/ + S = 1, R = 2, E = 3, FR = 4, LG = 5, CXD = 15, + /*Gen4*/ + D = 10, P = 11, Pt = 12, HG = 7, SS = 8, + /*Gen5*/ + W = 20, B = 21, W2 = 22, B2 = 23, + /*Gen6*/ + X = 24, Y = 25, AS = 26, OR = 27, + /*Gen7*/ + SN = 30, MN = 31, + + // Game Groupings (SaveFile type) + RBY = 98, + GSC = 99, + RS = 100, + FRLG = 101, + DP = 102, + HGSS = 103, + BW = 104, + B2W2 = 105, + XY = 106, + ORASDEMO = 107, + ORAS = 108, + SM = 109, + SMDEMO, + + // Extra Game Groupings (Generation) + Gen1, Gen2, Gen3, Gen4, Gen5, Gen6, Gen7 + } +} diff --git a/pk3DS/Main.cs b/pk3DS/Main.cs index 63f9a5e..49b1b84 100644 --- a/pk3DS/Main.cs +++ b/pk3DS/Main.cs @@ -123,13 +123,13 @@ private void changeLanguage(object sender, EventArgs e) while (threads > 0) Thread.Sleep(50); // Gather the Text Language Strings updateStatus($"GARC Get: {"gametext"} @ {getGARCFileName("gametext")}... "); - threadGet(RomFSPath + getGARCFileName("gametext"), "gametext", true, true); + threadGet(Path.Combine(RomFSPath, getGARCFileName("gametext")), "gametext", true, true); while (threads > 0) Thread.Sleep(50); if (!Directory.Exists("personal")) { updateStatus($"GARC Get: {"personal"} @ {getGARCFileName("personal")}... "); - threadGet(RomFSPath + getGARCFileName("personal"), "personal", true, true); + threadGet(Path.Combine(RomFSPath, getGARCFileName("personal")), "personal", true, true); } while (threads > 0) Thread.Sleep(50); // Refresh Personal Stats @@ -152,13 +152,13 @@ private void formClosing(object sender, FormClosingEventArgs e) // Set the GameText back as other forms may have edited it. updateStatus($"GARC Get: {"gametext"} @ {getGARCFileName("gametext")}... "); - threadSet(RomFSPath + getGARCFileName("gametext"), "gametext", false); + threadSet(Path.Combine(RomFSPath, getGARCFileName("gametext")), "gametext", false); while (threads > 0) Thread.Sleep(100); Thread.Sleep(200); // Small gap between beeps for faster computers. updateStatus($"GARC Get: {"personal"} @ {getGARCFileName("personal")}... "); - threadSet(RomFSPath + getGARCFileName("personal"), "personal", false); + threadSet(Path.Combine(RomFSPath, getGARCFileName("personal")), "personal", false); while (threads > 0) Thread.Sleep(100); if (Directory.Exists("gametext")) Directory.Delete("gametext", true); @@ -264,23 +264,18 @@ private void updateGameInfo() ? "pk3DS" // nothing else : "pk3DS - " + SMDH.AppInfo[AILang[Language]].ShortDescription; } - private int checkGameType(string[] files) + private static GameConfig checkGameType(string[] files) { try { if (files.Length > 1000) - return -1; - int aFiles = Directory.GetFiles(Path.Combine(Directory.GetParent(files[0]).FullName, "a"), - "*", SearchOption.AllDirectories).Length; - if (aFiles == 271) - return 0; // XY - if (aFiles == 299) - return 1; // ORAS - if (aFiles == 301) // rootFiles == meh - return 1; + return null; + string[] fileArr = Directory.GetFiles(Path.Combine(Directory.GetParent(files[0]).FullName, "a"), "*", SearchOption.AllDirectories); + int fileCount = fileArr.Count(file => Path.GetFileName(file)?.Length == 1); + return new GameConfig(fileCount); } catch { } - return -1; + return null; } private bool checkIfRomFS(string path) { @@ -289,17 +284,19 @@ private bool checkIfRomFS(string path) // Check to see if the folder is romfs if (fi.Name == "a") { - int game = checkGameType(Directory.GetFiles(path, "*", SearchOption.AllDirectories)); - if (game < 0) // Unknown + var cfg = checkGameType(Directory.GetFiles(path, "*", SearchOption.AllDirectories)); + + if (cfg == null || cfg.Files.Count == 0) { DialogResult dr = Util.Prompt(MessageBoxButtons.YesNoCancel, "Loading Override Options:", "Yes - OR/AS" + Environment.NewLine + "No - X/Y" + Environment.NewLine + "Cancel - Abort", "Path:" + Environment.NewLine + path); - if (dr == DialogResult.Yes) { oras = true; } - else if (dr == DialogResult.No) { oras = false; } + if (dr == DialogResult.Yes) { cfg = new GameConfig(GameVersion.ORAS); } + else if (dr == DialogResult.No) { cfg = new GameConfig(GameVersion.XY); } else { RomFSPath = null; oras = false; return false; } } - else - oras = game == 1; + RomFSPath = path; + Config = cfg; + oras = Config.ORAS; backupGARCs(false, allGARCs); backupCROs(false, RomFSPath); return true; @@ -589,7 +586,7 @@ private void fileGet(string[] files, bool skipDecompression = true, bool skipGet { string GARC = getGARCFileName(toEdit); updateStatus($"GARC Get: {toEdit} @ {GARC}... "); - threadGet(RomFSPath + GARC, toEdit, true, skipDecompression); + threadGet(Path.Combine(RomFSPath, GARC), toEdit, true, skipDecompression); while (threads > 0) Thread.Sleep(50); } } @@ -600,7 +597,7 @@ private void fileSet(IEnumerable files, bool keep = false) { string GARC = getGARCFileName(toEdit); updateStatus($"GARC Set: {toEdit} @ {GARC}... "); - threadSet(RomFSPath + GARC, toEdit); + threadSet(Path.Combine(RomFSPath, GARC), toEdit); while (threads > 0) Thread.Sleep(50); if (!keep && Directory.Exists(toEdit)) Directory.Delete(toEdit, true); } @@ -782,7 +779,8 @@ private void backupCROs(bool overwrite, string path) private void B_Rebuild3DS_Click(object sender, EventArgs e) { // Ensure that the romfs paths are valid - if (checkGameType(Directory.GetFiles(TB_Path.Text, "*", SearchOption.AllDirectories)) >= 0) + string[] files = Directory.GetFiles(TB_Path.Text, "*", SearchOption.AllDirectories); + if (!Config.IsRebuildable(files.Length)) { Util.Error("RomFS file count does not match the default game file count."); return; @@ -874,42 +872,22 @@ private void Menu_Shuffler_Click(object sender, EventArgs e) } // GARC Requests + internal static GameConfig Config; private string getGARCFileName(string requestedGARC) { - return getGARCFileName(requestedGARC, Language); + var garc = Config.getGARC(requestedGARC); + if (garc.LanguageVariant) + garc = garc.getRelativeGARC(Language); + + return garc.Reference; } internal static string getGARCFileName(string requestedGARC, int lang) { - string ans = ""; - switch (requestedGARC) - { - case "movesprite": ans = getGARCPath(0, 0, 5); break; - case "encdata": ans = oras ? getGARCPath(0, 1, 3) : getGARCPath(0, 1, 2); break; - case "trdata": ans = oras ? getGARCPath(0, 3, 6) : getGARCPath(0, 3, 8); break; - case "trpoke": ans = oras ? getGARCPath(0, 3, 8) : getGARCPath(0, 4, 0); break; - case "mapGR": ans = oras ? getGARCPath(0, 3, 9) : getGARCPath(0, 4, 1); break; - case "mapMatrix": ans = oras ? getGARCPath(0, 4, 0) : getGARCPath(0, 4, 2); break; - case "gametext": ans = oras ? getGARCPath(0, 7, 1 + lang) : getGARCPath(0, 7, 2 + lang); break; - case "storytext": ans = oras ? getGARCPath(0, 7 + (lang + 9) / 10, (10 + lang + 9) % 10) : getGARCPath(0, 8, lang); break; - case "wallpaper": ans = oras ? getGARCPath(1, 0, 3) : getGARCPath(1, 0, 4); break; - case "titlescreen": ans = oras ? getGARCPath(1, 5, 2) : getGARCPath(1, 6, 5); break; - case "maisonpkN": ans = oras ? getGARCPath(1, 8, 2) : getGARCPath(2, 0, 3); break; - case "maisontrN": ans = oras ? getGARCPath(1, 8, 3) : getGARCPath(2, 0, 4); break; - case "maisonpkS": ans = oras ? getGARCPath(1, 8, 4) : getGARCPath(2, 0, 5); break; - case "maisontrS": ans = oras ? getGARCPath(1, 8, 5) : getGARCPath(2, 0, 6); break; - case "move": ans = oras ? getGARCPath(1, 8, 9) : getGARCPath(2, 1, 2); break; - case "eggmove": ans = oras ? getGARCPath(1, 9, 0) : getGARCPath(2, 1, 3); break; - case "levelup": ans = oras ? getGARCPath(1, 9, 1) : getGARCPath(2, 1, 4); break; - case "evolution": ans = oras ? getGARCPath(1, 9, 2) : getGARCPath(2, 1, 5); break; - case "megaevo": ans = oras ? getGARCPath(1, 9, 3) : getGARCPath(2, 1, 6); break; - case "personal": ans = oras ? getGARCPath(1, 9, 5) : getGARCPath(2, 1, 8); break; - case "item": ans = oras ? getGARCPath(1, 9, 7) : getGARCPath(2, 2, 0); break; - } - return ans; - } - internal static string getGARCPath(int A, int B, int C) - { - return string.Format("{0}a{0}{1}{0}{2}{0}{3}", Path.DirectorySeparatorChar, A, B, C); + var garc = Config.getGARC(requestedGARC); + if (garc.LanguageVariant) + garc = garc.getRelativeGARC(lang); + + return garc.Reference; } public bool getGARC(string infile, string outfolder, bool PB, bool bypassExt = false) { @@ -963,7 +941,7 @@ public void backupGARCs(bool overwrite, params string[] g) string dest = "backup" + Path.DirectorySeparatorChar + s + $" ({GARC.Replace(Path.DirectorySeparatorChar.ToString(), "")})"; if (overwrite || !File.Exists(dest)) - File.Copy(RomFSPath + GARC, dest); + File.Copy(Path.Combine(RomFSPath, GARC), dest); } } public void restoreGARCs(bool oras_define, params string[] g) @@ -971,7 +949,7 @@ public void restoreGARCs(bool oras_define, params string[] g) oras = oras_define; foreach (string s in g) { - string dest = RomFSPath + getGARCFileName(s); + string dest = Path.Combine(RomFSPath, getGARCFileName(s)); string src = "backup" + Path.DirectorySeparatorChar + s + $" ({getGARCFileName(s).Replace(Path.DirectorySeparatorChar.ToString(), "")})"; File.Copy(src, dest, true); diff --git a/pk3DS/pk3DS.csproj b/pk3DS/pk3DS.csproj index 881fdbe..e3d419e 100644 --- a/pk3DS/pk3DS.csproj +++ b/pk3DS/pk3DS.csproj @@ -60,12 +60,15 @@ + + Form About.cs +