mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-03-21 17:48:28 -05:00
Extract logic from SaveUtil
BlankSaveFile -> creation of blank save files SaveFileType -> listing of all savefile types Blank save file arg passing is now clearer Instead of SaveFile? return, use TryGet pattern with nullable annotations to indicate success
This commit is contained in:
parent
d4bbb6dd02
commit
ff0f4727dd
|
|
@ -27,20 +27,13 @@ public void ReadArguments(IEnumerable<string> args)
|
|||
{
|
||||
var other = FileUtil.GetSupportedFile(path, SAV);
|
||||
if (other is SaveFile s)
|
||||
{
|
||||
s.Metadata.SetExtraInfo(path);
|
||||
SAV = s;
|
||||
}
|
||||
(SAV = s).Metadata.SetExtraInfo(path);
|
||||
else if (other is PKM pk)
|
||||
{
|
||||
Entity = pk;
|
||||
}
|
||||
else if (other is not null)
|
||||
{
|
||||
Extra.Add(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step 2: Reads settings config.
|
||||
|
|
@ -52,7 +45,7 @@ public void ReadSettings(IStartupSettings startup)
|
|||
|
||||
if (Entity is { } x)
|
||||
SAV = ReadSettingsDefinedPKM(startup, x) ?? GetBlank(x);
|
||||
else if (Extra.OfType<SAV3GCMemoryCard>().FirstOrDefault() is { } mc && SaveUtil.GetVariantSAV(mc) is { } mcSav)
|
||||
else if (Extra.OfType<SAV3GCMemoryCard>().FirstOrDefault() is { } mc && SaveUtil.TryGetSaveFile(mc, out var mcSav))
|
||||
SAV = mcSav;
|
||||
else
|
||||
SAV = ReadSettingsAnyPKM(startup) ?? GetBlankSaveFile(startup.DefaultSaveVersion, SAV);
|
||||
|
|
@ -96,19 +89,19 @@ private static SaveFile GetBlank(PKM pk)
|
|||
if (pk is { Format: 1, Japanese: true })
|
||||
version = GameVersion.BU;
|
||||
|
||||
return SaveUtil.GetBlankSAV(version, pk.OriginalTrainerName, (LanguageID)pk.Language);
|
||||
return BlankSaveFile.Get(version, pk.OriginalTrainerName, (LanguageID)pk.Language);
|
||||
}
|
||||
|
||||
private static SaveFile GetBlankSaveFile(GameVersion version, SaveFile? current)
|
||||
{
|
||||
var lang = SaveUtil.GetSafeLanguage(current);
|
||||
var tr = SaveUtil.GetSafeTrainerName(current, lang);
|
||||
var sav = SaveUtil.GetBlankSAV(version, tr, lang);
|
||||
var lang = BlankSaveFile.GetSafeLanguage(current);
|
||||
var tr = BlankSaveFile.GetSafeTrainerName(current, lang);
|
||||
var sav = BlankSaveFile.Get(version, tr, lang);
|
||||
if (sav.Version == GameVersion.Invalid) // will fail to load
|
||||
{
|
||||
var max = GameInfo.Sources.VersionDataSource.MaxBy(z => z.Value)!;
|
||||
var maxVer = (GameVersion)max.Value;
|
||||
sav = SaveUtil.GetBlankSAV(maxVer, tr, lang);
|
||||
sav = BlankSaveFile.Get(maxVer, tr, lang);
|
||||
}
|
||||
return sav;
|
||||
}
|
||||
|
|
@ -120,10 +113,7 @@ private static IEnumerable<SaveFile> GetMostRecentlyLoaded(IEnumerable<string> p
|
|||
if (!File.Exists(path))
|
||||
continue;
|
||||
|
||||
var sav = SaveUtil.GetVariantSAV(path);
|
||||
if (sav is null)
|
||||
continue;
|
||||
|
||||
if (SaveUtil.TryGetSaveFile(path, out var sav))
|
||||
yield return sav;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using static PKHeX.Core.EventWorkDiffCompatibility;
|
||||
using static PKHeX.Core.EventWorkDiffCompatibilityExtensions;
|
||||
|
|
@ -21,6 +22,17 @@ public sealed class EventBlockDiff<TSave, TWorkValue> : IEventWorkDiff
|
|||
|
||||
private const int MAX_SAVEFILE_SIZE = 0x10_0000; // 1 MB
|
||||
|
||||
private static bool TryGetSaveFile(string path, [NotNullWhen(true)] out TSave? sav, out GameVersion version)
|
||||
{
|
||||
version = default;
|
||||
sav = null;
|
||||
if (!SaveUtil.TryGetSaveFile(path, out var s) || s is not TSave b)
|
||||
return false;
|
||||
sav = b;
|
||||
version = s.Version;
|
||||
return true;
|
||||
}
|
||||
|
||||
public EventBlockDiff(TSave s1, TSave s2) => Diff(s1, s2);
|
||||
|
||||
public EventBlockDiff(string f1, string f2)
|
||||
|
|
@ -28,29 +40,19 @@ public EventBlockDiff(string f1, string f2)
|
|||
Message = SanityCheckFiles(f1, f2, MAX_SAVEFILE_SIZE);
|
||||
if (Message != Valid)
|
||||
return;
|
||||
var s1 = SaveUtil.GetVariantSAV(f1);
|
||||
var s2 = SaveUtil.GetVariantSAV(f2);
|
||||
if (s1 is null || s2 is null || s1.GetType() != s2.GetType() || GetBlock(s1) is not { } t1 || GetBlock(s2) is not { } t2)
|
||||
|
||||
if (!TryGetSaveFile(f1, out var s1, out var v1) || !TryGetSaveFile(f2, out var s2, out var v2))
|
||||
{
|
||||
Message = DifferentGameGroup;
|
||||
return;
|
||||
}
|
||||
if (s1.Version != s2.Version)
|
||||
if (v1 != v2)
|
||||
{
|
||||
Message = DifferentVersion;
|
||||
return;
|
||||
}
|
||||
|
||||
Diff(t1, t2);
|
||||
}
|
||||
|
||||
private static TSave? GetBlock(SaveFile s1)
|
||||
{
|
||||
if (s1 is TSave t1)
|
||||
return t1;
|
||||
if (s1 is IEventFlagProvider37 p1)
|
||||
return p1.EventWork as TSave;
|
||||
return null;
|
||||
Diff(s1, s2);
|
||||
}
|
||||
|
||||
private static EventWorkDiffCompatibility SanityCheckSaveInfo(TSave s1, TSave s2)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using static PKHeX.Core.EventWorkUtil;
|
||||
using static PKHeX.Core.EventWorkDiffCompatibility;
|
||||
|
|
@ -19,17 +20,24 @@ public sealed class EventWorkDiff7b : IEventWorkDiff
|
|||
|
||||
public EventWorkDiff7b(SAV7b s1, SAV7b s2) => Diff(s1, s2);
|
||||
|
||||
private static bool TryGetSaveFile(string path, [NotNullWhen(true)] out SAV7b? sav)
|
||||
{
|
||||
sav = null;
|
||||
if (!SaveUtil.TryGetSaveFile(path, out var s) || s is not SAV7b b)
|
||||
return false;
|
||||
sav = b;
|
||||
return true;
|
||||
}
|
||||
|
||||
public EventWorkDiff7b(string f1, string f2)
|
||||
{
|
||||
Message = SanityCheckFiles(f1, f2, MAX_SAVEFILE_SIZE);
|
||||
if (Message != Valid)
|
||||
return;
|
||||
|
||||
var s1 = SaveUtil.GetVariantSAV(f1);
|
||||
var s2 = SaveUtil.GetVariantSAV(f2);
|
||||
if (s1 is not SAV7b b1 || s2 is not SAV7b b2)
|
||||
if (!TryGetSaveFile(f1, out var b1) || !TryGetSaveFile(f2, out var b2))
|
||||
{
|
||||
Message = DifferentVersion;
|
||||
Message = DifferentGameGroup;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using static PKHeX.Core.EventWorkUtil;
|
||||
using static PKHeX.Core.EventWorkDiffCompatibility;
|
||||
|
|
@ -19,6 +20,15 @@ public sealed class EventWorkDiff8b : IEventWorkDiff
|
|||
|
||||
private const int MAX_SAVEFILE_SIZE = 0x10_0000; // 1 MB
|
||||
|
||||
private static bool TryGetSaveFile(string path, [NotNullWhen(true)] out SAV8BS? sav)
|
||||
{
|
||||
sav = null;
|
||||
if (!SaveUtil.TryGetSaveFile(path, out var s) || s is not SAV8BS b)
|
||||
return false;
|
||||
sav = b;
|
||||
return true;
|
||||
}
|
||||
|
||||
public EventWorkDiff8b(SAV8BS s1, SAV8BS s2) => Diff(s1, s2);
|
||||
|
||||
public EventWorkDiff8b(string f1, string f2)
|
||||
|
|
@ -26,9 +36,7 @@ public EventWorkDiff8b(string f1, string f2)
|
|||
Message = SanityCheckFiles(f1, f2, MAX_SAVEFILE_SIZE);
|
||||
if (Message != Valid)
|
||||
return;
|
||||
var s1 = SaveUtil.GetVariantSAV(f1);
|
||||
var s2 = SaveUtil.GetVariantSAV(f2);
|
||||
if (s1 is not SAV8BS b1 || s2 is not SAV8BS b2)
|
||||
if (!TryGetSaveFile(f1, out var b1) || !TryGetSaveFile(f2, out var b2))
|
||||
{
|
||||
Message = DifferentGameGroup;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -257,31 +257,31 @@ private MemoryCardSaveStatus AutoInferState()
|
|||
return MemoryCardSaveStatus.SaveGameRSBOX;
|
||||
}
|
||||
|
||||
public bool IsNoGameSelected => SelectedGameVersion == GameVersion.Any;
|
||||
public bool IsNoGameSelected => SelectedGameVersion == default;
|
||||
|
||||
public GameVersion SelectedGameVersion
|
||||
public SaveFileType SelectedGameVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
if (EntrySelected < 0)
|
||||
return GameVersion.Any;
|
||||
return SaveFileType.None;
|
||||
if (EntrySelected == EntryCOLO)
|
||||
return GameVersion.COLO;
|
||||
return SaveFileType.Colosseum;
|
||||
if (EntrySelected == EntryXD)
|
||||
return GameVersion.XD;
|
||||
return SaveFileType.XD;
|
||||
if (EntrySelected == EntryRSBOX)
|
||||
return GameVersion.RSBOX;
|
||||
return GameVersion.Any; //Default for no game selected
|
||||
return SaveFileType.RSBox;
|
||||
return default; //Default for no game selected
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectSaveGame(GameVersion Game)
|
||||
public void SelectSaveGame(SaveFileType Game)
|
||||
{
|
||||
switch (Game)
|
||||
{
|
||||
case GameVersion.COLO: if (HasCOLO) EntrySelected = EntryCOLO; break;
|
||||
case GameVersion.XD: if (HasXD) EntrySelected = EntryXD; break;
|
||||
case GameVersion.RSBOX: if (HasRSBOX) EntrySelected = EntryRSBOX; break;
|
||||
case SaveFileType.Colosseum: if (HasCOLO) EntrySelected = EntryCOLO; break;
|
||||
case SaveFileType.XD: if (HasXD) EntrySelected = EntryXD; break;
|
||||
case SaveFileType.RSBox: if (HasRSBOX) EntrySelected = EntryRSBOX; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,35 +35,33 @@ public sealed class SAV1 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWo
|
|||
|
||||
public override IReadOnlyList<string> PKMExtensions => EntityFileExtension.GetExtensionsAtOrBelow(2);
|
||||
|
||||
public SAV1(GameVersion version = GameVersion.RBY, LanguageID language = LanguageID.English) : base(SaveUtil.SIZE_G1RAW)
|
||||
public SAV1(LanguageID language = LanguageID.English, GameVersion version = default) : base(SaveUtil.SIZE_G1RAW)
|
||||
{
|
||||
Version = version;
|
||||
Version = version == default ? GameVersion.RBY : version;
|
||||
Japanese = language == LanguageID.Japanese;
|
||||
Language = (int)language;
|
||||
Offsets = Japanese ? SAV1Offsets.JPN : SAV1Offsets.INT;
|
||||
Personal = version == GameVersion.YW ? PersonalTable.Y : PersonalTable.RB;
|
||||
Initialize(version);
|
||||
Personal = Version == GameVersion.YW ? PersonalTable.Y : PersonalTable.RB;
|
||||
|
||||
Initialize();
|
||||
ClearBoxes();
|
||||
}
|
||||
|
||||
public SAV1(Memory<byte> data, GameVersion versionOverride = GameVersion.Any, LanguageID language = LanguageID.English) : base(data)
|
||||
public SAV1(Memory<byte> data, LanguageID language, GameVersion version = default) : base(data)
|
||||
{
|
||||
Japanese = SaveUtil.GetIsG1SAVJ(Data);
|
||||
Version = version == default ? GameVersion.RBY : version;
|
||||
Japanese = language == LanguageID.Japanese;
|
||||
Language = (int)language;
|
||||
Offsets = Japanese ? SAV1Offsets.JPN : SAV1Offsets.INT;
|
||||
|
||||
Version = versionOverride != GameVersion.Any ? versionOverride : SaveUtil.GetIsG1SAV(Data);
|
||||
Personal = Version == GameVersion.YW ? PersonalTable.Y : PersonalTable.RB;
|
||||
if (Version == GameVersion.Invalid)
|
||||
return;
|
||||
|
||||
Initialize(versionOverride);
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize(GameVersion versionOverride)
|
||||
private void Initialize()
|
||||
{
|
||||
// see if RBY can be differentiated
|
||||
if (versionOverride is not (GameVersion.RB or GameVersion.YW))
|
||||
// See if RBY can be differentiated
|
||||
if (Version is not (GameVersion.RB or GameVersion.YW))
|
||||
{
|
||||
if (Starter != 0) // Pikachu
|
||||
Version = Starter == 0x54 ? GameVersion.YW : GameVersion.RB;
|
||||
|
|
@ -217,7 +215,7 @@ private int GetBoxRawDataOffset(int box)
|
|||
}
|
||||
|
||||
// Configuration
|
||||
protected override SAV1 CloneInternal() => new(GetFinalData(), Version) { Language = Language };
|
||||
protected override SAV1 CloneInternal() => new(GetFinalData(), (LanguageID)Language, Version);
|
||||
|
||||
protected override int SIZE_STORED => Japanese ? PokeCrypto.SIZE_1JLIST : PokeCrypto.SIZE_1ULIST;
|
||||
protected override int SIZE_PARTY => SIZE_STORED;
|
||||
|
|
@ -591,4 +589,16 @@ public override int LoadString(ReadOnlySpan<byte> data, Span<char> destBuffer)
|
|||
=> StringConverter1.LoadString(data, destBuffer, Japanese);
|
||||
public override int SetString(Span<byte> destBuffer, ReadOnlySpan<char> value, int maxLength, StringConverterOption option)
|
||||
=> StringConverter1.SetString(destBuffer, value, maxLength, Japanese, option);
|
||||
|
||||
|
||||
public static bool IsYellow(ReadOnlySpan<byte> data, bool japanese) => japanese ? IsYellowJPN(data) : IsYellowINT(data);
|
||||
public static bool IsYellowINT(ReadOnlySpan<byte> data) => IsYellow(data[0x29C3], data[0x271C]);
|
||||
public static bool IsYellowJPN(ReadOnlySpan<byte> data) => IsYellow(data[0x29B9], data[0x2712]);
|
||||
|
||||
private static bool IsYellow(byte starter, byte friendship)
|
||||
{
|
||||
if (starter != 0)
|
||||
return starter == 0x54; // Pikachu
|
||||
return friendship != 0; // Initial Pikachu friendship is non-zero
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public sealed class SAV2 : SaveFile, ILangDeviantSave, IEventFlagArray, IEventWo
|
|||
public override IReadOnlyList<string> PKMExtensions => Korean ? ["pk2"]
|
||||
: EntityFileExtension.GetExtensionsAtOrBelow(2);
|
||||
|
||||
public SAV2(GameVersion version = GameVersion.C, LanguageID language = LanguageID.English) : base(SaveUtil.SIZE_G2RAW_J)
|
||||
public SAV2(LanguageID language = LanguageID.English, GameVersion version = GameVersion.C) : base(SaveUtil.SIZE_G2RAW_J)
|
||||
{
|
||||
Version = version;
|
||||
switch (language)
|
||||
|
|
@ -60,13 +60,12 @@ public SAV2(GameVersion version = GameVersion.C, LanguageID language = LanguageI
|
|||
ClearBoxes();
|
||||
}
|
||||
|
||||
public SAV2(Memory<byte> data, GameVersion versionOverride = GameVersion.Any) : base(data)
|
||||
public SAV2(Memory<byte> data, LanguageID language, GameVersion version) : base(data)
|
||||
{
|
||||
Version = versionOverride != GameVersion.Any ? versionOverride : SaveUtil.GetIsG2SAV(Data);
|
||||
Japanese = SaveUtil.GetIsG2SAVJ(Data) != GameVersion.Invalid;
|
||||
if (Version != GameVersion.C && !Japanese)
|
||||
Korean = SaveUtil.GetIsG2SAVK(Data) != GameVersion.Invalid;
|
||||
Language = Japanese ? 1 : Korean ? (int)LanguageID.Korean : -1;
|
||||
Version = version == GameVersion.C ? GameVersion.C : GameVersion.GS;
|
||||
Japanese = language == LanguageID.Japanese;
|
||||
Korean = language == LanguageID.Korean;
|
||||
Language = (int)language;
|
||||
|
||||
Offsets = new SAV2Offsets(this);
|
||||
Personal = Version == GameVersion.C ? PersonalTable.C : PersonalTable.GS;
|
||||
|
|
@ -243,7 +242,7 @@ private ushort GetKoreanChecksum()
|
|||
}
|
||||
|
||||
// Configuration
|
||||
protected override SAV2 CloneInternal() => new(GetFinalData(), Version) { Language = Language };
|
||||
protected override SAV2 CloneInternal() => new(GetFinalData(), (LanguageID)Language, Version);
|
||||
|
||||
protected override int SIZE_STORED => Japanese ? PokeCrypto.SIZE_2JLIST : PokeCrypto.SIZE_2ULIST;
|
||||
protected override int SIZE_PARTY => SIZE_STORED;
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ public override StorageSlotSource GetBoxSlotFlags(int index)
|
|||
#region Checksums
|
||||
|
||||
private const int HashLength = MD5.HashSizeInBytes;
|
||||
private const int HashOffset = SaveUtil.SIZE_G8BDSP - HashLength;
|
||||
private const int HashOffset = SaveUtil.SIZE_G8BDSP_0 - HashLength;
|
||||
private Span<byte> CurrentHash => Data.Slice(HashOffset, HashLength);
|
||||
|
||||
// Checksum is stored in the middle of the save file, and is zeroed before computing.
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public abstract class SAV_STADIUM : SaveFile, ILangDeviantSave
|
|||
protected SAV_STADIUM(Memory<byte> data, bool japanese, bool swap) : base(data)
|
||||
{
|
||||
Japanese = japanese;
|
||||
OT = SaveUtil.GetSafeTrainerName(this, (LanguageID)Language);
|
||||
OT = BlankSaveFile.GetSafeTrainerName(this, (LanguageID)Language);
|
||||
|
||||
if (!swap)
|
||||
return;
|
||||
|
|
@ -44,7 +44,7 @@ protected SAV_STADIUM(Memory<byte> data, bool japanese, bool swap) : base(data)
|
|||
protected SAV_STADIUM(bool japanese, [ConstantExpected] int size) : base(size)
|
||||
{
|
||||
Japanese = japanese;
|
||||
OT = SaveUtil.GetSafeTrainerName(this, (LanguageID)Language);
|
||||
OT = BlankSaveFile.GetSafeTrainerName(this, (LanguageID)Language);
|
||||
}
|
||||
|
||||
protected sealed override byte[] DecryptPKM(byte[] data) => data;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public enum Gem8Version
|
|||
/// <summary>
|
||||
/// Initial cartridge version shipped.
|
||||
/// </summary>
|
||||
/// <remarks><see cref="SaveUtil.SIZE_G8BDSP"/></remarks>
|
||||
/// <remarks><see cref="SaveUtil.SIZE_G8BDSP_0"/></remarks>
|
||||
V1_0 = 0x25, // 37
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
131
PKHeX.Core/Saves/Util/BlankSaveFile.cs
Normal file
131
PKHeX.Core/Saves/Util/BlankSaveFile.cs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
using System;
|
||||
using static PKHeX.Core.LanguageID;
|
||||
using static PKHeX.Core.SaveFileType;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Logic for blank save files or default values if not exposed via data.
|
||||
/// </summary>
|
||||
public static class BlankSaveFile
|
||||
{
|
||||
private const string DefaultTrainer = TrainerName.ProgramINT;
|
||||
private const LanguageID DefaultLanguage = English;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="LanguageID"/> that feels best for the save file's language.
|
||||
/// </summary>
|
||||
public static LanguageID GetSafeLanguage(SaveFile? sav) => sav switch
|
||||
{
|
||||
null => English,
|
||||
ILangDeviantSave s => s.Japanese ? Japanese : s.Korean ? Korean : English,
|
||||
_ => (uint)sav.Language <= Legal.GetMaxLanguageID(sav.Generation) ? (LanguageID)sav.Language : English,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Trainer Name that feels best for the save file's language.
|
||||
/// </summary>
|
||||
public static string GetSafeTrainerName(SaveFile? sav, LanguageID lang) => lang switch
|
||||
{
|
||||
Japanese => sav?.Generation >= 3 ? TrainerName.ProgramJPN : TrainerName.GameFreakJPN,
|
||||
_ => TrainerName.ProgramINT,
|
||||
};
|
||||
|
||||
/// <inheritdoc cref="Get(SaveFileType,LanguageID,GameVersion)"/>
|
||||
public static SaveFile Get(GameVersion game, string trainerName = DefaultTrainer, LanguageID language = DefaultLanguage)
|
||||
{
|
||||
var type = game.GetSaveFileType();
|
||||
return Get(type, game, trainerName, language);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of a SaveFile with a blank base.
|
||||
/// </summary>
|
||||
/// <param name="context">Context of the Save File.</param>
|
||||
/// <param name="trainerName">Trainer Name</param>
|
||||
/// <param name="language">Save file language to initialize for</param>
|
||||
/// <returns>Save File for that generation.</returns>
|
||||
public static SaveFile Get(EntityContext context, string trainerName = DefaultTrainer, LanguageID language = DefaultLanguage)
|
||||
{
|
||||
var version = context.GetSingleGameVersion();
|
||||
var type = version.GetSaveFileType();
|
||||
return Get(type, version, trainerName, language);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of a SaveFile with a blank base.
|
||||
/// </summary>
|
||||
/// <param name="type">Requested save file type.</param>
|
||||
/// <param name="game">Version to create the save file for.</param>
|
||||
/// <param name="trainerName">Trainer Name</param>
|
||||
/// <param name="language">Language to initialize with</param>
|
||||
/// <returns>Blank save file from the requested game, null if no game exists for that <see cref="GameVersion"/>.</returns>
|
||||
public static SaveFile Get(SaveFileType type, GameVersion game, string trainerName = DefaultTrainer, LanguageID language = DefaultLanguage)
|
||||
{
|
||||
var sav = Get(type, language, game);
|
||||
sav.Version = game;
|
||||
sav.OT = trainerName;
|
||||
if (sav.Generation >= 4)
|
||||
sav.Language = (int)language;
|
||||
|
||||
// Secondary Properties may not be used but can be filled in as template.
|
||||
(uint tid, uint sid) = sav.Generation >= 7 ? (123456u, 1234u) : (12345u, 54321u);
|
||||
sav.SetDisplayID(tid, sid);
|
||||
sav.Language = (int)language;
|
||||
|
||||
// Only set geolocation data for 3DS titles
|
||||
if (sav is IRegionOrigin o)
|
||||
o.SetDefaultRegionOrigins((int)language);
|
||||
|
||||
return sav;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of a SaveFile with a blank base.
|
||||
/// </summary>
|
||||
/// <param name="type">Requested save file type.</param>
|
||||
/// <param name="language">Save file language to initialize for</param>
|
||||
/// <param name="game">Version to create the save file for, if a specific version is requested within the <see cref="type"/>.</param>
|
||||
/// <returns>Blank save file from the requested game, null if no game exists for that <see cref="GameVersion"/>.</returns>
|
||||
private static SaveFile Get(SaveFileType type, LanguageID language, GameVersion game = default) => type switch
|
||||
{
|
||||
RBY => new SAV1(game == GameVersion.BU ? Japanese : language, version: game),
|
||||
Stadium1J => new SAV1StadiumJ(),
|
||||
Stadium1 => new SAV1Stadium(language == Japanese),
|
||||
|
||||
GSC => new SAV2(language, language == Korean ? GameVersion.GS : game),
|
||||
Stadium2 => new SAV2Stadium(language == Japanese),
|
||||
|
||||
RS => new SAV3RS(language == Japanese),
|
||||
Emerald => new SAV3E(language == Japanese),
|
||||
FRLG => new SAV3FRLG(language == Japanese),
|
||||
|
||||
Colosseum => new SAV3Colosseum(),
|
||||
XD => new SAV3XD(),
|
||||
RSBox => new SAV3RSBox(),
|
||||
|
||||
DP => new SAV4DP(),
|
||||
Pt => new SAV4Pt(),
|
||||
HGSS => new SAV4HGSS(),
|
||||
BattleRevolution => new SAV4BR(),
|
||||
|
||||
BW => new SAV5BW(),
|
||||
B2W2 => new SAV5B2W2(),
|
||||
|
||||
XY => new SAV6XY(),
|
||||
AODemo => new SAV6AODemo(),
|
||||
AO => new SAV6AO(),
|
||||
|
||||
SM => new SAV7SM(),
|
||||
USUM => new SAV7USUM(),
|
||||
LGPE => new SAV7b(),
|
||||
|
||||
SWSH => new SAV8SWSH(),
|
||||
BDSP => new SAV8BS(),
|
||||
LA => new SAV8LA(),
|
||||
|
||||
SV => new SAV9SV(),
|
||||
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null),
|
||||
};
|
||||
}
|
||||
106
PKHeX.Core/Saves/Util/SaveFileType.cs
Normal file
106
PKHeX.Core/Saves/Util/SaveFileType.cs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
using System;
|
||||
using static PKHeX.Core.SaveFileType;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the possible save file types that can be detected and loaded.
|
||||
/// </summary>
|
||||
public enum SaveFileType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Invalid or unrecognized save file type.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
// Main Games
|
||||
RBY,
|
||||
GSC,
|
||||
RS,
|
||||
Emerald,
|
||||
FRLG,
|
||||
DP,
|
||||
Pt,
|
||||
HGSS,
|
||||
BW,
|
||||
B2W2,
|
||||
XY,
|
||||
AO,
|
||||
AODemo,
|
||||
SM,
|
||||
USUM,
|
||||
LGPE,
|
||||
SWSH,
|
||||
BDSP,
|
||||
LA,
|
||||
SV,
|
||||
|
||||
// Side Games
|
||||
Colosseum,
|
||||
XD,
|
||||
RSBox,
|
||||
BattleRevolution,
|
||||
Ranch,
|
||||
Stadium1J,
|
||||
Stadium1,
|
||||
Stadium2,
|
||||
|
||||
// Bulk Storage
|
||||
Bulk3,
|
||||
Bulk4,
|
||||
Bulk7,
|
||||
}
|
||||
|
||||
public static class SaveFileTypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps a stored <see cref="GameVersion"/> to a <see cref="SaveFileType"/>.
|
||||
/// </summary>
|
||||
/// <param name="version">Actual game version to map</param>
|
||||
/// <returns>Corresponding <see cref="SaveFileType"/> for the given <paramref name="version"/>.</returns>
|
||||
public static SaveFileType GetSaveFileType(this GameVersion version) => version switch
|
||||
{
|
||||
> GameVersion.VL => 0,
|
||||
GameVersion.RD or GameVersion.GN or GameVersion.YW or GameVersion.BU => RBY,
|
||||
GameVersion.GD or GameVersion.SI or GameVersion.C => GSC,
|
||||
GameVersion.R or GameVersion.S => RS,
|
||||
GameVersion.E => Emerald,
|
||||
GameVersion.FR or GameVersion.LG => FRLG,
|
||||
GameVersion.CXD => XD,
|
||||
GameVersion.D or GameVersion.P => DP,
|
||||
GameVersion.Pt => Pt,
|
||||
GameVersion.HG or GameVersion.SS => HGSS,
|
||||
GameVersion.B or GameVersion.W => BW,
|
||||
GameVersion.B2 or GameVersion.W2 => B2W2,
|
||||
GameVersion.X or GameVersion.Y => XY,
|
||||
GameVersion.AS or GameVersion.OR => AO,
|
||||
GameVersion.SN or GameVersion.MN => SM,
|
||||
GameVersion.US or GameVersion.UM => USUM,
|
||||
GameVersion.GP or GameVersion.GE => LGPE,
|
||||
GameVersion.SW or GameVersion.SH => SWSH,
|
||||
GameVersion.BD or GameVersion.SP => BDSP,
|
||||
GameVersion.PLA => LA,
|
||||
GameVersion.SL or GameVersion.VL => SV,
|
||||
_ => None,
|
||||
};
|
||||
|
||||
public static byte GetGeneration(this SaveFileType type) => type switch
|
||||
{
|
||||
0 => 0,
|
||||
RBY or Stadium1J or Stadium1 => 1,
|
||||
GSC or Stadium2 => 2,
|
||||
RS or Emerald or FRLG => 3,
|
||||
DP or Pt or HGSS => 4,
|
||||
BW or B2W2 => 5,
|
||||
XY or AO or AODemo => 6,
|
||||
SM or USUM or LGPE => 7,
|
||||
SWSH or BDSP or LA => 8,
|
||||
SV => 9,
|
||||
Colosseum or XD or RSBox => 3,
|
||||
Ranch or BattleRevolution => 4,
|
||||
Bulk3 => 3,
|
||||
Bulk4 => 4,
|
||||
Bulk7 => 7,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
|
||||
};
|
||||
}
|
||||
|
|
@ -99,7 +99,7 @@ public static IEnumerable<string> GetSwitchBackupPaths(string root)
|
|||
|
||||
// return newest save file path that is valid
|
||||
var byMostRecent = possiblePaths.OrderByDescending(File.GetLastWriteTimeUtc);
|
||||
var saves = byMostRecent.Select(SaveUtil.GetVariantSAV);
|
||||
var saves = byMostRecent.Select(SaveUtil.GetSaveFile);
|
||||
return saves.FirstOrDefault(z => z?.ChecksumsValid == true);
|
||||
}
|
||||
|
||||
|
|
@ -122,8 +122,7 @@ public static IEnumerable<SaveFile> GetSaveFiles(IReadOnlyList<string> drives, b
|
|||
var byMostRecent = possiblePaths.OrderByDescending(File.GetLastWriteTimeUtc);
|
||||
foreach (var s in byMostRecent)
|
||||
{
|
||||
var sav = SaveUtil.GetVariantSAV(s);
|
||||
if (sav is not null)
|
||||
if (SaveUtil.TryGetSaveFile(s, out var sav))
|
||||
yield return sav;
|
||||
}
|
||||
}
|
||||
|
|
@ -176,13 +175,13 @@ private static bool GetSaveFilePathsFromFolders(IEnumerable<string> foldersToChe
|
|||
/// True if a valid save file was found, false otherwise.
|
||||
/// </returns>
|
||||
/// <inheritdoc cref="FindMostRecentSaveFile(IReadOnlyList{string},CancellationToken,string[])"/>
|
||||
public static bool TryDetectSaveFile(CancellationToken token, [NotNullWhen(true)] out SaveFile? sav) => TryDetectSaveFile(DriveList, token, out sav);
|
||||
public static bool TryDetectSaveFile(CancellationToken token, [NotNullWhen(true)] out SaveFile? result) => TryDetectSaveFile(DriveList, token, out result);
|
||||
|
||||
/// <inheritdoc cref="TryDetectSaveFile(CancellationToken, out SaveFile)"/>
|
||||
public static bool TryDetectSaveFile(IReadOnlyList<string> drives, CancellationToken token, [NotNullWhen(true)] out SaveFile? sav)
|
||||
public static bool TryDetectSaveFile(IReadOnlyList<string> drives, CancellationToken token, [NotNullWhen(true)] out SaveFile? result)
|
||||
{
|
||||
sav = FindMostRecentSaveFile(drives, CustomBackupPaths, token);
|
||||
var path = sav?.Metadata.FilePath;
|
||||
result = FindMostRecentSaveFile(drives, CustomBackupPaths, token);
|
||||
var path = result?.Metadata.FilePath;
|
||||
return File.Exists(path);
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -48,7 +48,7 @@ public static class FileUtil
|
|||
/// <returns>Supported file object reference, null if none found.</returns>
|
||||
public static object? GetSupportedFile(Memory<byte> data, ReadOnlySpan<char> ext, SaveFile? reference = null)
|
||||
{
|
||||
if (TryGetSAV(data, out var sav))
|
||||
if (SaveUtil.TryGetSaveFile(data, out var sav))
|
||||
return sav;
|
||||
if (TryGetMemoryCard(data, out var mc))
|
||||
return mc;
|
||||
|
|
@ -179,18 +179,6 @@ public static bool IsFileTooBig(long length)
|
|||
/// <param name="length">File size</param>
|
||||
public static bool IsFileTooSmall(long length) => length < 0x20; // bigger than PK1
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a <see cref="SaveFile"/> object from the input parameters.
|
||||
/// </summary>
|
||||
/// <param name="data">Binary data</param>
|
||||
/// <param name="sav">Output result</param>
|
||||
/// <returns>True if file object reference is valid, false if none found.</returns>
|
||||
public static bool TryGetSAV(Memory<byte> data, [NotNullWhen(true)] out SaveFile? sav)
|
||||
{
|
||||
sav = SaveUtil.GetVariantSAV(data);
|
||||
return sav is not null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a <see cref="SAV3GCMemoryCard"/> object from the input parameters.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -182,14 +182,14 @@ private void FormLoadInitialFiles(StartupArguments args)
|
|||
private void LoadBlankSaveFile(GameVersion version)
|
||||
{
|
||||
var current = C_SAV?.SAV;
|
||||
var lang = SaveUtil.GetSafeLanguage(current);
|
||||
var tr = SaveUtil.GetSafeTrainerName(current, lang);
|
||||
var sav = SaveUtil.GetBlankSAV(version, tr, lang);
|
||||
var lang = BlankSaveFile.GetSafeLanguage(current);
|
||||
var tr = BlankSaveFile.GetSafeTrainerName(current, lang);
|
||||
var sav = BlankSaveFile.Get(version, tr, lang);
|
||||
if (sav.Version == GameVersion.Invalid) // will fail to load
|
||||
{
|
||||
var max = GameInfo.Sources.VersionDataSource.MaxBy(z => z.Value) ?? throw new Exception();
|
||||
version = (GameVersion)max.Value;
|
||||
sav = SaveUtil.GetBlankSAV(version, tr, lang);
|
||||
sav = BlankSaveFile.Get(version, tr, lang);
|
||||
}
|
||||
OpenSAV(sav, string.Empty);
|
||||
C_SAV!.SAV.State.Edited = false; // Prevents form close warning from showing until changes are made
|
||||
|
|
@ -656,8 +656,7 @@ private bool LoadFile(object? input, string path)
|
|||
case SAV3GCMemoryCard gc:
|
||||
if (!CheckGCMemoryCard(gc, path))
|
||||
return true;
|
||||
var mcsav = SaveUtil.GetVariantSAV(gc);
|
||||
if (mcsav is null)
|
||||
if (!SaveUtil.TryGetSaveFile(gc, out var mcsav))
|
||||
return false;
|
||||
mcsav.Metadata.SetExtraInfo(path);
|
||||
return OpenSAV(mcsav, path);
|
||||
|
|
@ -729,7 +728,7 @@ private bool OpenPCBoxBin(ConcatenatedEntitySet pkms)
|
|||
return true;
|
||||
}
|
||||
|
||||
private static GameVersion SelectMemoryCardSaveGame(SAV3GCMemoryCard memCard)
|
||||
private static SaveFileType SelectMemoryCardSaveGame(SAV3GCMemoryCard memCard)
|
||||
{
|
||||
if (memCard.SaveGameCount == 1)
|
||||
return memCard.SelectedGameVersion;
|
||||
|
|
@ -737,15 +736,15 @@ private static GameVersion SelectMemoryCardSaveGame(SAV3GCMemoryCard memCard)
|
|||
var games = GetMemoryCardGameSelectionList(memCard);
|
||||
var dialog = new SAV_GameSelect(games, MsgFileLoadSaveMultiple, MsgFileLoadSaveSelectGame);
|
||||
dialog.ShowDialog();
|
||||
return dialog.Result;
|
||||
return (SaveFileType)dialog.Result;
|
||||
}
|
||||
|
||||
private static List<ComboItem> GetMemoryCardGameSelectionList(SAV3GCMemoryCard memCard)
|
||||
{
|
||||
var games = new List<ComboItem>();
|
||||
if (memCard.HasCOLO) games.Add(new ComboItem(MsgGameColosseum, (int)GameVersion.COLO));
|
||||
if (memCard.HasXD) games.Add(new ComboItem(MsgGameXD, (int)GameVersion.XD));
|
||||
if (memCard.HasRSBOX) games.Add(new ComboItem(MsgGameRSBOX, (int)GameVersion.RSBOX));
|
||||
if (memCard.HasCOLO) games.Add(new ComboItem(MsgGameColosseum, (int)SaveFileType.Colosseum));
|
||||
if (memCard.HasXD) games.Add(new ComboItem(MsgGameXD, (int)SaveFileType.XD));
|
||||
if (memCard.HasRSBOX) games.Add(new ComboItem(MsgGameRSBOX, (int)SaveFileType.RSBox));
|
||||
return games;
|
||||
}
|
||||
|
||||
|
|
@ -766,14 +765,14 @@ private static bool CheckGCMemoryCard(SAV3GCMemoryCard memCard, string path)
|
|||
|
||||
case MemoryCardSaveStatus.MultipleSaveGame:
|
||||
var game = SelectMemoryCardSaveGame(memCard);
|
||||
if (game == GameVersion.Invalid) //Cancel
|
||||
if (game == 0) // Cancel
|
||||
return false;
|
||||
memCard.SelectSaveGame(game);
|
||||
break;
|
||||
|
||||
case MemoryCardSaveStatus.SaveGameCOLO: memCard.SelectSaveGame(GameVersion.COLO); break;
|
||||
case MemoryCardSaveStatus.SaveGameXD: memCard.SelectSaveGame(GameVersion.XD); break;
|
||||
case MemoryCardSaveStatus.SaveGameRSBOX: memCard.SelectSaveGame(GameVersion.RSBOX); break;
|
||||
case MemoryCardSaveStatus.SaveGameCOLO: memCard.SelectSaveGame(SaveFileType.Colosseum); break;
|
||||
case MemoryCardSaveStatus.SaveGameXD: memCard.SelectSaveGame(SaveFileType.XD); break;
|
||||
case MemoryCardSaveStatus.SaveGameRSBOX: memCard.SelectSaveGame(SaveFileType.RSBox); break;
|
||||
|
||||
default:
|
||||
WinFormsUtil.Error(!SAV3GCMemoryCard.IsMemoryCardSize(memCard.Data.Length) ? MsgFileGameCubeBad : GetHintInvalidFile(memCard.Data, path), path);
|
||||
|
|
@ -964,13 +963,14 @@ private static bool SanityCheckSAV(ref SaveFile sav)
|
|||
var msg = string.Format(MsgFileLoadVersionDetect, $"3 ({s3.Version})");
|
||||
using var dialog = new SAV_GameSelect(games, msg, MsgFileLoadSaveSelectVersion);
|
||||
dialog.ShowDialog();
|
||||
if (dialog.Result is GameVersion.Invalid)
|
||||
if (dialog.Result is 0)
|
||||
return false;
|
||||
|
||||
var s = s3.ForceLoad(dialog.Result);
|
||||
var game = (GameVersion)dialog.Result;
|
||||
var s = s3.ForceLoad(game);
|
||||
if (s is SAV3FRLG frlg)
|
||||
{
|
||||
bool result = frlg.ResetPersonal(dialog.Result);
|
||||
bool result = frlg.ResetPersonal(game);
|
||||
if (!result)
|
||||
return false;
|
||||
}
|
||||
|
|
@ -988,7 +988,8 @@ private static bool SanityCheckSAV(ref SaveFile sav)
|
|||
var msg = string.Format(dual, "3", fr, lg);
|
||||
using var dialog = new SAV_GameSelect(games, msg, MsgFileLoadSaveSelectVersion);
|
||||
dialog.ShowDialog();
|
||||
bool result = frlg.ResetPersonal(dialog.Result);
|
||||
var game = (GameVersion)dialog.Result;
|
||||
bool result = frlg.ResetPersonal(game);
|
||||
if (!result)
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -455,17 +455,16 @@ private static List<SlotCache> LoadEntitiesFromFolder(string databaseFolder, Sav
|
|||
|
||||
private static void TryAddPKMsFromSaveFilePath(ConcurrentBag<SlotCache> dbTemp, string file)
|
||||
{
|
||||
var sav = SaveUtil.GetVariantSAV(file);
|
||||
if (sav is null)
|
||||
if (SaveUtil.TryGetSaveFile(file, out var sav))
|
||||
{
|
||||
SlotInfoLoader.AddFromSaveFile(sav, dbTemp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (FileUtil.TryGetMemoryCard(file, out var mc))
|
||||
TryAddPKMsFromMemoryCard(dbTemp, mc, file);
|
||||
else
|
||||
Debug.WriteLine($"Unable to load SaveFile: {file}");
|
||||
return;
|
||||
}
|
||||
|
||||
SlotInfoLoader.AddFromSaveFile(sav, dbTemp);
|
||||
}
|
||||
|
||||
private static void TryAddPKMsFromMemoryCard(ConcurrentBag<SlotCache> dbTemp, SAV3GCMemoryCard mc, string file)
|
||||
|
|
@ -475,17 +474,16 @@ private static void TryAddPKMsFromMemoryCard(ConcurrentBag<SlotCache> dbTemp, SA
|
|||
return;
|
||||
|
||||
if (mc.HasCOLO)
|
||||
TryAdd(dbTemp, mc, file, GameVersion.COLO);
|
||||
TryAdd(dbTemp, mc, file, SaveFileType.Colosseum);
|
||||
if (mc.HasXD)
|
||||
TryAdd(dbTemp, mc, file, GameVersion.XD);
|
||||
TryAdd(dbTemp, mc, file, SaveFileType.XD);
|
||||
if (mc.HasRSBOX)
|
||||
TryAdd(dbTemp, mc, file, GameVersion.RSBOX);
|
||||
TryAdd(dbTemp, mc, file, SaveFileType.RSBox);
|
||||
|
||||
static void TryAdd(ConcurrentBag<SlotCache> dbTemp, SAV3GCMemoryCard mc, string path, GameVersion game)
|
||||
static void TryAdd(ConcurrentBag<SlotCache> dbTemp, SAV3GCMemoryCard mc, string path, SaveFileType game)
|
||||
{
|
||||
mc.SelectSaveGame(game);
|
||||
var sav = SaveUtil.GetVariantSAV(mc);
|
||||
if (sav is null)
|
||||
if (!SaveUtil.TryGetSaveFile(mc, out var sav))
|
||||
return;
|
||||
sav.Metadata.SetExtraInfo(path);
|
||||
SlotInfoLoader.AddFromSaveFile(sav, dbTemp);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public SAV_FolderList(Action<SaveFile> openSaveFile)
|
|||
var recent = SaveFinder.GetSaveFiles(drives, false, extra, true, token).ToList();
|
||||
var loaded = Main.Settings.Startup.RecentlyLoaded
|
||||
.Where(z => recent.All(x => x.Metadata.FilePath != z))
|
||||
.Where(File.Exists).Select(SaveUtil.GetVariantSAV).OfType<SaveFile>();
|
||||
.Where(File.Exists).Select(SaveUtil.GetSaveFile).OfType<SaveFile>();
|
||||
|
||||
Recent = PopulateData(dgDataRecent, loaded.Concat(recent));
|
||||
Backup = PopulateData(dgDataBackup, backup);
|
||||
|
|
@ -276,7 +276,7 @@ public static void CleanBackups(string path, bool deleteNotSaves)
|
|||
foreach (var file in files)
|
||||
{
|
||||
var fi = new FileInfo(file);
|
||||
if (!SaveUtil.IsSizeValid(fi.Length) || SaveUtil.GetVariantSAV(file) is not { } sav)
|
||||
if (!SaveUtil.IsSizeValid(fi.Length) || !SaveUtil.TryGetSaveFile(file, out var sav))
|
||||
{
|
||||
if (deleteNotSaves)
|
||||
File.Delete(file);
|
||||
|
|
|
|||
|
|
@ -234,11 +234,9 @@ private void CompareSaves()
|
|||
if (!SaveUtil.IsSizeValid((int)f2.Length))
|
||||
return;
|
||||
|
||||
var s1 = SaveUtil.GetVariantSAV(p1);
|
||||
if (s1 is not ISCBlockArray w1)
|
||||
if (!SaveUtil.TryGetSaveFile(p1, out var s1) || s1 is not ISCBlockArray w1)
|
||||
return;
|
||||
var s2 = SaveUtil.GetVariantSAV(p2);
|
||||
if (s2 is not ISCBlockArray w2)
|
||||
if (!SaveUtil.TryGetSaveFile(p2, out var s2) || s2 is not ISCBlockArray w2)
|
||||
return;
|
||||
|
||||
// Get an external source of names if available.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace PKHeX.WinForms;
|
|||
|
||||
public partial class SAV_GameSelect : Form
|
||||
{
|
||||
public GameVersion Result = GameVersion.Invalid;
|
||||
public int Result { get; private set; }
|
||||
|
||||
public SAV_GameSelect(IEnumerable<ComboItem> items, params ReadOnlySpan<string?> lines)
|
||||
{
|
||||
|
|
@ -25,7 +25,7 @@ public SAV_GameSelect(IEnumerable<ComboItem> items, params ReadOnlySpan<string?>
|
|||
|
||||
private void B_OK_Click(object sender, EventArgs e)
|
||||
{
|
||||
Result = (GameVersion)WinFormsUtil.GetIndex(CB_Game);
|
||||
Result = WinFormsUtil.GetIndex(CB_Game);
|
||||
Close();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ public void SizeCheck()
|
|||
[Fact]
|
||||
public void CanMakeBlankSAV8()
|
||||
{
|
||||
var sav = SaveUtil.GetBlankSAV(GameVersion.SW, TrainerName.ProgramINT);
|
||||
var sav = BlankSaveFile.Get(SaveFileType.SWSH, GameVersion.SW);
|
||||
sav.Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user