using System; using System.Collections.Generic; using System.Linq; using System.Threading; using pkNX.Containers; using pkNX.Structures; namespace pkNX.Game { /// /// Handles file retrieval and lifetime management for a 's data. /// public class GameFileMapping { private readonly Dictionary Cache = new Dictionary(); private readonly IReadOnlyCollection FileMap; public readonly ContainerHandler ProgressTracker = new ContainerHandler(); public readonly CancellationTokenSource TokenSource = new CancellationTokenSource(); private readonly GameLocation ROM; public GameFileMapping(GameLocation rom) => FileMap = GetMapping((ROM = rom).Game); internal IFileContainer GetFile(GameFile file, int language) { if (file == GameFile.GameText || file == GameFile.StoryText) file += language; // shift to localized language if (Cache.TryGetValue(file, out var container)) return container; var info = FileMap.FirstOrDefault(f => f.File == file); if (info == null) throw new ArgumentException($"Unknown {nameof(GameFile)} provided.", file.ToString()); var basePath = info.Parent == ContainerParent.ExeFS ? ROM.ExeFS : ROM.RomFS; container = info.Get(basePath); Cache.Add(file, container); return container; } internal void SaveAll() { foreach (var container in Cache) { var c = container.Value; c.SaveAs(c.FilePath, ProgressTracker, TokenSource.Token); Cache.Remove(container.Key); } } public static IReadOnlyCollection GetMapping(GameVersion game) { switch (game) { case GameVersion.SN: return SN; case GameVersion.MN: return MN; case GameVersion.US: return US; case GameVersion.UM: return UM; case GameVersion.XY: return XY; case GameVersion.GG: return GG; case GameVersion.ORASDEMO: case GameVersion.ORAS: return AO; case GameVersion.SMDEMO: return SMDEMO; } return null; } #region Games private static readonly GameFileReference[] XY = { new GameFileReference(005, GameFile.MoveSprites), new GameFileReference(012, GameFile.Encounters), new GameFileReference(038, GameFile.TrainerData), new GameFileReference(039, GameFile.TrainerClass), new GameFileReference(040, GameFile.TrainerPoke), new GameFileReference(041, GameFile.MapGameRegion), new GameFileReference(042, GameFile.MapMatrix), new GameFileReference(072, GameFile.GameText0), new GameFileReference(073, GameFile.GameText1), new GameFileReference(074, GameFile.GameText2), new GameFileReference(075, GameFile.GameText3), new GameFileReference(076, GameFile.GameText4), new GameFileReference(077, GameFile.GameText5), new GameFileReference(078, GameFile.GameText6), new GameFileReference(079, GameFile.GameText7), new GameFileReference(080, GameFile.StoryText0), new GameFileReference(081, GameFile.StoryText1), new GameFileReference(082, GameFile.StoryText2), new GameFileReference(083, GameFile.StoryText3), new GameFileReference(084, GameFile.StoryText4), new GameFileReference(085, GameFile.StoryText5), new GameFileReference(086, GameFile.StoryText6), new GameFileReference(087, GameFile.StoryText7), new GameFileReference(104, GameFile.Wallpaper), new GameFileReference(165, GameFile.TitleScreen), new GameFileReference(203, GameFile.FacilityPokeNormal), new GameFileReference(204, GameFile.FacilityTrainerNormal), new GameFileReference(205, GameFile.FacilityPokeSuper), new GameFileReference(206, GameFile.FacilityTrainerSuper), new GameFileReference(212, GameFile.MoveStats), new GameFileReference(213, GameFile.EggMoves), new GameFileReference(214, GameFile.Learnsets), new GameFileReference(215, GameFile.Evolutions), new GameFileReference(216, GameFile.MegaEvolutions), new GameFileReference(218, GameFile.PersonalStats), new GameFileReference(220, GameFile.ItemStats), }; private static readonly GameFileReference[] AO = { new GameFileReference(013, GameFile.Encounters), new GameFileReference(036, GameFile.TrainerData), new GameFileReference(037, GameFile.TrainerClass), new GameFileReference(038, GameFile.TrainerPoke), new GameFileReference(039, GameFile.MapGameRegion), new GameFileReference(040, GameFile.MapMatrix), new GameFileReference(071, GameFile.GameText0), new GameFileReference(072, GameFile.GameText1), new GameFileReference(073, GameFile.GameText2), new GameFileReference(074, GameFile.GameText3), new GameFileReference(075, GameFile.GameText4), new GameFileReference(076, GameFile.GameText5), new GameFileReference(077, GameFile.GameText6), new GameFileReference(078, GameFile.GameText7), new GameFileReference(079, GameFile.StoryText0), new GameFileReference(080, GameFile.StoryText1), new GameFileReference(081, GameFile.StoryText2), new GameFileReference(082, GameFile.StoryText3), new GameFileReference(083, GameFile.StoryText4), new GameFileReference(084, GameFile.StoryText5), new GameFileReference(085, GameFile.StoryText6), new GameFileReference(086, GameFile.StoryText7), new GameFileReference(103, GameFile.Wallpaper), new GameFileReference(152, GameFile.TitleScreen), new GameFileReference(182, GameFile.FacilityPokeNormal), new GameFileReference(183, GameFile.FacilityTrainerNormal), new GameFileReference(184, GameFile.FacilityPokeSuper), new GameFileReference(185, GameFile.FacilityTrainerSuper), new GameFileReference(189, GameFile.MoveStats), new GameFileReference(190, GameFile.EggMoves), new GameFileReference(191, GameFile.Learnsets), new GameFileReference(192, GameFile.Evolutions), new GameFileReference(193, GameFile.MegaEvolutions), new GameFileReference(195, GameFile.PersonalStats), new GameFileReference(197, GameFile.ItemStats), }; #endregion #region Gen7 private static readonly GameFileReference[] SMDEMO = { new GameFileReference(011, GameFile.MoveStats), new GameFileReference(012, GameFile.EggMoves), new GameFileReference(013, GameFile.Learnsets), new GameFileReference(014, GameFile.Evolutions), new GameFileReference(015, GameFile.MegaEvolutions), new GameFileReference(017, GameFile.PersonalStats), new GameFileReference(019, GameFile.ItemStats), new GameFileReference(030, GameFile.GameText0), new GameFileReference(031, GameFile.GameText1), new GameFileReference(032, GameFile.GameText2), new GameFileReference(033, GameFile.GameText3), new GameFileReference(034, GameFile.GameText4), new GameFileReference(035, GameFile.GameText5), new GameFileReference(036, GameFile.GameText6), new GameFileReference(037, GameFile.GameText7), new GameFileReference(038, GameFile.GameText8), new GameFileReference(039, GameFile.GameText9), new GameFileReference(040, GameFile.StoryText0), new GameFileReference(041, GameFile.StoryText1), new GameFileReference(042, GameFile.StoryText2), new GameFileReference(043, GameFile.StoryText3), new GameFileReference(044, GameFile.StoryText4), new GameFileReference(045, GameFile.StoryText5), new GameFileReference(046, GameFile.StoryText6), new GameFileReference(047, GameFile.StoryText7), new GameFileReference(048, GameFile.StoryText8), new GameFileReference(049, GameFile.StoryText9), new GameFileReference(076, GameFile.ZoneData), new GameFileReference(091, GameFile.WorldData), new GameFileReference(101, GameFile.TrainerClass), new GameFileReference(102, GameFile.TrainerData), new GameFileReference(103, GameFile.TrainerPoke), }; private static readonly GameFileReference[] SM = { new GameFileReference(011, GameFile.MoveStats), new GameFileReference(012, GameFile.EggMoves), new GameFileReference(013, GameFile.Learnsets), new GameFileReference(014, GameFile.Evolutions), new GameFileReference(015, GameFile.MegaEvolutions), new GameFileReference(017, GameFile.PersonalStats), new GameFileReference(019, GameFile.ItemStats), new GameFileReference(030, GameFile.GameText0), new GameFileReference(031, GameFile.GameText1), new GameFileReference(032, GameFile.GameText2), new GameFileReference(033, GameFile.GameText3), new GameFileReference(034, GameFile.GameText4), new GameFileReference(035, GameFile.GameText5), new GameFileReference(036, GameFile.GameText6), new GameFileReference(037, GameFile.GameText7), new GameFileReference(038, GameFile.GameText8), new GameFileReference(039, GameFile.GameText9), new GameFileReference(040, GameFile.StoryText0), new GameFileReference(041, GameFile.StoryText1), new GameFileReference(042, GameFile.StoryText2), new GameFileReference(043, GameFile.StoryText3), new GameFileReference(044, GameFile.StoryText4), new GameFileReference(045, GameFile.StoryText5), new GameFileReference(046, GameFile.StoryText6), new GameFileReference(047, GameFile.StoryText7), new GameFileReference(048, GameFile.StoryText8), new GameFileReference(049, GameFile.StoryText9), new GameFileReference(077, GameFile.ZoneData), new GameFileReference(091, GameFile.WorldData), new GameFileReference(104, GameFile.TrainerClass), new GameFileReference(105, GameFile.TrainerData), new GameFileReference(106, GameFile.TrainerPoke), new GameFileReference(155, GameFile.EncounterStatic), new GameFileReference(267, GameFile.Pickup), new GameFileReference(277, GameFile.FacilityPokeNormal), new GameFileReference(278, GameFile.FacilityTrainerNormal), new GameFileReference(279, GameFile.FacilityPokeSuper), new GameFileReference(280, GameFile.FacilityTrainerSuper), }; /// /// Ultra Sun & Ultra Moon /// private static readonly GameFileReference[] UU = { new GameFileReference(011, GameFile.MoveStats), new GameFileReference(012, GameFile.EggMoves), new GameFileReference(013, GameFile.Learnsets), new GameFileReference(014, GameFile.Evolutions), new GameFileReference(015, GameFile.MegaEvolutions), new GameFileReference(017, GameFile.PersonalStats), new GameFileReference(019, GameFile.ItemStats), new GameFileReference(030, GameFile.GameText0), new GameFileReference(031, GameFile.GameText1), new GameFileReference(032, GameFile.GameText2), new GameFileReference(033, GameFile.GameText3), new GameFileReference(034, GameFile.GameText4), new GameFileReference(035, GameFile.GameText5), new GameFileReference(036, GameFile.GameText6), new GameFileReference(037, GameFile.GameText7), new GameFileReference(038, GameFile.GameText8), new GameFileReference(039, GameFile.GameText9), new GameFileReference(040, GameFile.StoryText0), new GameFileReference(041, GameFile.StoryText1), new GameFileReference(042, GameFile.StoryText2), new GameFileReference(043, GameFile.StoryText3), new GameFileReference(044, GameFile.StoryText4), new GameFileReference(045, GameFile.StoryText5), new GameFileReference(046, GameFile.StoryText6), new GameFileReference(047, GameFile.StoryText7), new GameFileReference(048, GameFile.StoryText8), new GameFileReference(049, GameFile.StoryText9), new GameFileReference(077, GameFile.ZoneData), new GameFileReference(091, GameFile.WorldData), new GameFileReference(105, GameFile.TrainerClass), new GameFileReference(106, GameFile.TrainerData), new GameFileReference(107, GameFile.TrainerPoke), new GameFileReference(159, GameFile.EncounterStatic), new GameFileReference(271, GameFile.Pickup), new GameFileReference(281, GameFile.FacilityPokeNormal), new GameFileReference(282, GameFile.FacilityTrainerNormal), new GameFileReference(283, GameFile.FacilityPokeSuper), new GameFileReference(284, GameFile.FacilityTrainerSuper), }; /// /// Let's Go Pikachu & Let's Go Eevee /// private static readonly GameFileReference[] GG = { }; #endregion #region Split Versions private static readonly GameFileReference[] SN = SM.Concat(new[] {new GameFileReference(082, GameFile.Encounters)}).ToArray(); private static readonly GameFileReference[] MN = SM.Concat(new[] {new GameFileReference(083, GameFile.Encounters)}).ToArray(); private static readonly GameFileReference[] US = UU.Concat(new[] {new GameFileReference(082, GameFile.Encounters)}).ToArray(); private static readonly GameFileReference[] UM = UU.Concat(new[] {new GameFileReference(083, GameFile.Encounters)}).ToArray(); #endregion } }