From 4e92195b80f94acd3eeed4a75639191c40b73dab Mon Sep 17 00:00:00 2001 From: Kurt Date: Sat, 13 Feb 2021 01:53:38 -0800 Subject: [PATCH] Add custom save type loading (hacks) plugin adds a reader -> reader checks if it is a non-PKHeX.Core save type (they'd implement their own savefile/etc type) -> returns a matching save object if so basically bypasses the base PKHeX logic --- .../Saves/Util/Recognition/ISaveHandler.cs | 18 ++++++++++++ PKHeX.Core/Saves/Util/SaveUtil.cs | 29 +++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/PKHeX.Core/Saves/Util/Recognition/ISaveHandler.cs b/PKHeX.Core/Saves/Util/Recognition/ISaveHandler.cs index 3a94b65c2..a95697544 100644 --- a/PKHeX.Core/Saves/Util/Recognition/ISaveHandler.cs +++ b/PKHeX.Core/Saves/Util/Recognition/ISaveHandler.cs @@ -1,5 +1,6 @@ namespace PKHeX.Core { +#if !(EXCLUDE_EMULATOR_FORMATS && EXCLUDE_HACKS) /// /// Provides handling for recognizing atypical save file formats. /// @@ -19,4 +20,21 @@ public interface ISaveHandler /// Null if not a valid save file for this handler's format. Returns an object containing header, footer, and inner data references. SaveHandlerSplitResult? TrySplit(byte[] input); } +#endif + +#if !EXCLUDE_HACKS + /// + /// Provides handling for recognizing atypical save file formats. + /// + public interface ISaveReader : ISaveHandler + { + /// + /// Reads a save file from the + /// + /// Raw input data + /// Optional file path. + /// Save File object, or null if invalid. Check if it is compatible first. + SaveFile? ReadSaveFile(byte[] data, string? path = null); + } +#endif } diff --git a/PKHeX.Core/Saves/Util/SaveUtil.cs b/PKHeX.Core/Saves/Util/SaveUtil.cs index 8d1698a3b..6e607ab04 100644 --- a/PKHeX.Core/Saves/Util/SaveUtil.cs +++ b/PKHeX.Core/Saves/Util/SaveUtil.cs @@ -61,6 +61,15 @@ public static class SaveUtil private static readonly SaveHandlerGCI DolphinHandler = new(); +#if !EXCLUDE_HACKS + /// + /// Specialized readers for loading save files from non-standard games (e.g. hacks). + /// + // ReSharper disable once CollectionNeverUpdated.Global + public static readonly List CustomSaveReaders = new(); +#endif + +#if !EXCLUDE_EMULATOR_FORMATS /// /// Pre-formatters for loading save files from non-standard formats (e.g. emulators). /// @@ -70,6 +79,7 @@ public static class SaveUtil new SaveHandlerDeSmuME(), new SaveHandlerARDS(), }; +#endif internal static readonly HashSet SizesSWSH = new() { @@ -487,7 +497,7 @@ private static GameVersion GetIsG8SAV(byte[] data) public static SaveFile? GetVariantSAV(string path) { var data = File.ReadAllBytes(path); - var sav = GetVariantSAV(data); + var sav = GetVariantSAV(data, path); if (sav == null) return null; sav.Metadata.SetExtraInfo(path); @@ -496,13 +506,27 @@ private static GameVersion GetIsG8SAV(byte[] data) /// Creates an instance of a SaveFile using the given save data. /// Save data from which to create a SaveFile. + /// Optional save file path, may help initialize a non-standard save file format. /// An appropriate type of save file for the given data, or null if the save data is invalid. - public static SaveFile? GetVariantSAV(byte[] data) + public static SaveFile? GetVariantSAV(byte[] data, string? path = null) { +#if !EXCLUDE_HACKS + foreach (var h in CustomSaveReaders) + { + if (!h.IsRecognized(data.Length)) + continue; + + var custom = h.ReadSaveFile(data, path); + if (custom != null) + return custom; + } +#endif + var sav = GetVariantSAVInternal(data); if (sav != null) return sav; +#if !EXCLUDE_EMULATOR_FORMATS foreach (var h in Handlers) { if (!h.IsRecognized(data.Length)) @@ -519,6 +543,7 @@ private static GameVersion GetIsG8SAV(byte[] data) sav.Metadata.SetExtraInfo(split.Header, split.Footer); return sav; } +#endif // unrecognized. return null;