diff --git a/PKHeX.Core/Editing/Saves/Editors/SaveDataEditor.cs b/PKHeX.Core/Editing/Saves/Editors/SaveDataEditor.cs
index e629f2814..9481b86ba 100644
--- a/PKHeX.Core/Editing/Saves/Editors/SaveDataEditor.cs
+++ b/PKHeX.Core/Editing/Saves/Editors/SaveDataEditor.cs
@@ -50,9 +50,8 @@ public sealed class FakePKMEditor : IPKMView
public sealed class FakeSaveFile : SaveFile
{
public static readonly FakeSaveFile Default = new FakeSaveFile();
- protected override string BAKText => "Fake Save File";
- public override SaveFile Clone() => this;
- public override string Filter => string.Empty;
+ protected internal override string ShortSummary => "Fake Save File";
+ protected override SaveFile CloneInternal() => this;
public override string Extension => string.Empty;
public override bool ChecksumsValid => true;
public override string ChecksumInfo => string.Empty;
diff --git a/PKHeX.Core/Editing/Saves/Management/INamedFolderPath.cs b/PKHeX.Core/Editing/Saves/Management/INamedFolderPath.cs
new file mode 100644
index 000000000..3803c188a
--- /dev/null
+++ b/PKHeX.Core/Editing/Saves/Management/INamedFolderPath.cs
@@ -0,0 +1,9 @@
+namespace PKHeX.Core
+{
+ public interface INamedFolderPath
+ {
+ string Path { get; }
+ string DisplayText { get; }
+ bool Custom { get; }
+ }
+}
diff --git a/PKHeX.Core/Editing/Saves/Management/SavePreview.cs b/PKHeX.Core/Editing/Saves/Management/SavePreview.cs
new file mode 100644
index 000000000..3b2838683
--- /dev/null
+++ b/PKHeX.Core/Editing/Saves/Management/SavePreview.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using System.IO;
+
+namespace PKHeX.Core
+{
+ ///
+ /// Bindable Summary of a for use in a sortable table.
+ ///
+ public sealed class SavePreview
+ {
+ public readonly SaveFile Save;
+ public readonly string FilePath;
+
+ public SavePreview(SaveFile sav, string parent, string path)
+ {
+ Save = sav;
+ Folder = parent;
+ FilePath = path;
+ }
+
+ public SavePreview(SaveFile sav, List paths)
+ {
+ var meta = sav.Metadata;
+ var dir = meta.FileFolder;
+ const string notFound = "???";
+ var parent = dir == null ? notFound : paths.Find(z => dir.StartsWith(z.Path))?.DisplayText ?? notFound;
+
+ Save = sav;
+ Folder = parent;
+ FilePath = meta.FilePath ?? notFound;
+ }
+
+ public string OT => Save.OT;
+ public int G => Save.Generation;
+ public GameVersion Game => Save.Version;
+
+ public string Played => Save.PlayTimeString.PadLeft(9, '0');
+ public string FileTime => File.GetLastWriteTimeUtc(FilePath).ToString("yyyy.MM.dd:hh:mm:ss");
+
+ public string TID => Save.Generation >= 7 ? Save.TrainerID7.ToString("000000") : Save.TID.ToString("00000");
+ public string SID => Save.Generation >= 7 ? Save.TrainerSID7.ToString("0000") : Save.SID.ToString("00000");
+
+ // ReSharper disable once MemberCanBePrivate.Local
+ // ReSharper disable once UnusedAutoPropertyAccessor.Local
+ public string Folder { get; }
+
+ public string Name => Path.GetFileName(FilePath);
+ }
+}
diff --git a/PKHeX.Core/Legality/Verifiers/ParseSettings.cs b/PKHeX.Core/Legality/Verifiers/ParseSettings.cs
index d82bdb2e4..434edfd42 100644
--- a/PKHeX.Core/Legality/Verifiers/ParseSettings.cs
+++ b/PKHeX.Core/Legality/Verifiers/ParseSettings.cs
@@ -74,7 +74,7 @@ public static bool InitFromSaveFileData(SaveFile sav)
ActiveTrainer = sav;
if (sav.Generation >= 3)
return AllowGBCartEra = false;
- bool vc = !sav.Exportable || (sav.FileName?.EndsWith("dat") ?? false); // default to true for non-exportable
+ bool vc = !sav.State.Exportable || (sav.Metadata.FileName?.EndsWith("dat") ?? false); // default to true for non-exportable
return AllowGBCartEra = !vc; // physical cart selected
}
}
diff --git a/PKHeX.Core/Saves/SAV1.cs b/PKHeX.Core/Saves/SAV1.cs
index c06e69dcd..baae3435c 100644
--- a/PKHeX.Core/Saves/SAV1.cs
+++ b/PKHeX.Core/Saves/SAV1.cs
@@ -9,8 +9,7 @@ namespace PKHeX.Core
///
public sealed class SAV1 : SaveFile, ILangDeviantSave
{
- protected override string BAKText => $"{OT} ({Version}) - {PlayTimeString}";
- public override string Filter => "SAV File|*.sav|All Files|*.*";
+ protected internal override string ShortSummary => $"{OT} ({Version}) - {PlayTimeString}";
public override string Extension => ".sav";
public int SaveRevision => Japanese ? 0 : 1;
@@ -184,7 +183,7 @@ private int GetBoxRawDataOffset(int i)
}
// Configuration
- public override SaveFile Clone() => new SAV1(Write(), Version);
+ protected override SaveFile CloneInternal() => new SAV1(Write(), Version);
protected override int SIZE_STORED => Japanese ? PokeCrypto.SIZE_1JLIST : PokeCrypto.SIZE_1ULIST;
protected override int SIZE_PARTY => Japanese ? PokeCrypto.SIZE_1JLIST : PokeCrypto.SIZE_1ULIST;
diff --git a/PKHeX.Core/Saves/SAV1Stadium.cs b/PKHeX.Core/Saves/SAV1Stadium.cs
index 97f98022a..1f9af6abe 100644
--- a/PKHeX.Core/Saves/SAV1Stadium.cs
+++ b/PKHeX.Core/Saves/SAV1Stadium.cs
@@ -16,7 +16,7 @@ public sealed class SAV1Stadium : SAV_STADIUM
public override IReadOnlyList HeldItems => Array.Empty();
public override GameVersion Version { get; protected set; } = GameVersion.Stadium;
- public override SaveFile Clone() => new SAV1Stadium((byte[])Data.Clone(), Japanese);
+ protected override SaveFile CloneInternal() => new SAV1Stadium((byte[])Data.Clone(), Japanese);
public override int Generation => 1;
private int StringLength => Japanese ? StringLengthJ : StringLengthU;
diff --git a/PKHeX.Core/Saves/SAV1StadiumJ.cs b/PKHeX.Core/Saves/SAV1StadiumJ.cs
index f6a3f250c..32a93a528 100644
--- a/PKHeX.Core/Saves/SAV1StadiumJ.cs
+++ b/PKHeX.Core/Saves/SAV1StadiumJ.cs
@@ -17,7 +17,7 @@ public sealed class SAV1StadiumJ : SAV_STADIUM
public override IReadOnlyList HeldItems => Array.Empty();
public override GameVersion Version { get; protected set; } = GameVersion.StadiumJ;
- public override SaveFile Clone() => new SAV1StadiumJ((byte[])Data.Clone());
+ protected override SaveFile CloneInternal() => new SAV1StadiumJ((byte[])Data.Clone());
public override int Generation => 1;
private const int StringLength = 6; // Japanese Only
diff --git a/PKHeX.Core/Saves/SAV2.cs b/PKHeX.Core/Saves/SAV2.cs
index b30e9f7dd..a2a8e5ae5 100644
--- a/PKHeX.Core/Saves/SAV2.cs
+++ b/PKHeX.Core/Saves/SAV2.cs
@@ -9,8 +9,7 @@ namespace PKHeX.Core
///
public sealed class SAV2 : SaveFile, ILangDeviantSave
{
- protected override string BAKText => $"{OT} ({Version}) - {PlayTimeString}";
- public override string Filter => "SAV File|*.sav|All Files|*.*";
+ protected internal override string ShortSummary => $"{OT} ({Version}) - {PlayTimeString}";
public override string Extension => ".sav";
public int SaveRevision => Japanese ? 0 : !Korean ? 1 : 2;
@@ -247,7 +246,7 @@ protected override byte[] GetFinalData()
}
// Configuration
- public override SaveFile Clone() => new SAV2(Write(), Version);
+ protected override SaveFile CloneInternal() => new SAV2(Write(), Version);
protected override int SIZE_STORED => Japanese ? PokeCrypto.SIZE_2JLIST : PokeCrypto.SIZE_2ULIST;
protected override int SIZE_PARTY => Japanese ? PokeCrypto.SIZE_2JLIST : PokeCrypto.SIZE_2ULIST;
diff --git a/PKHeX.Core/Saves/SAV2Stadium.cs b/PKHeX.Core/Saves/SAV2Stadium.cs
index 95ec8b045..87efac0bb 100644
--- a/PKHeX.Core/Saves/SAV2Stadium.cs
+++ b/PKHeX.Core/Saves/SAV2Stadium.cs
@@ -16,7 +16,7 @@ public sealed class SAV2Stadium : SAV_STADIUM
public override IReadOnlyList HeldItems => Legal.HeldItems_GSC;
public override GameVersion Version { get; protected set; } = GameVersion.Stadium2;
- public override SaveFile Clone() => new SAV1Stadium((byte[])Data.Clone(), Japanese);
+ protected override SaveFile CloneInternal() => new SAV1Stadium((byte[])Data.Clone(), Japanese);
public override int Generation => 2;
private const int StringLength = 12;
diff --git a/PKHeX.Core/Saves/SAV3.cs b/PKHeX.Core/Saves/SAV3.cs
index dd22663ec..67d5424d8 100644
--- a/PKHeX.Core/Saves/SAV3.cs
+++ b/PKHeX.Core/Saves/SAV3.cs
@@ -9,8 +9,7 @@ namespace PKHeX.Core
///
public sealed class SAV3 : SaveFile, ILangDeviantSave
{
- protected override string BAKText => $"{OT} ({Version}) - {PlayTimeString}";
- public override string Filter => "SAV File|*.sav|All Files|*.*";
+ protected internal override string ShortSummary => $"{OT} ({Version}) - {PlayTimeString}";
public override string Extension => ".sav";
public int SaveRevision => Japanese ? 0 : 1;
@@ -285,7 +284,7 @@ protected override byte[] GetFinalData()
public int GetBlockOffset(int block) => BlockOfs[block];
// Configuration
- public override SaveFile Clone() => new SAV3(Write(), Version);
+ protected override SaveFile CloneInternal() => new SAV3(Write(), Version);
protected override int SIZE_STORED => PokeCrypto.SIZE_3STORED;
protected override int SIZE_PARTY => PokeCrypto.SIZE_3PARTY;
@@ -331,7 +330,7 @@ protected override void SetChecksums()
BitConverter.GetBytes(chk).CopyTo(Data, ofs + 0xFF6);
}
- if (BAK.Length < SaveUtil.SIZE_G3RAW) // don't update HoF for half-sizes
+ if (State.BAK.Length < SaveUtil.SIZE_G3RAW) // don't update HoF for half-sizes
return;
// Hall of Fame Checksums
@@ -355,7 +354,7 @@ public override bool ChecksumsValid
return false;
}
- if (BAK.Length < SaveUtil.SIZE_G3RAW) // don't check HoF for half-sizes
+ if (State.BAK.Length < SaveUtil.SIZE_G3RAW) // don't check HoF for half-sizes
return true;
if (!IsChunkValidHoF(0x1C000))
@@ -391,7 +390,7 @@ public override string ChecksumInfo
list.Add($"Block {BlockOrder[i]:00} @ {i*SIZE_BLOCK:X5} invalid.");
}
- if (BAK.Length > SaveUtil.SIZE_G3RAW) // don't check HoF for half-sizes
+ if (State.BAK.Length > SaveUtil.SIZE_G3RAW) // don't check HoF for half-sizes
{
if (!IsChunkValidHoF(0x1C000))
list.Add("HoF Block 1 invalid.");
diff --git a/PKHeX.Core/Saves/SAV3Colosseum.cs b/PKHeX.Core/Saves/SAV3Colosseum.cs
index 80b68da28..9b5244be2 100644
--- a/PKHeX.Core/Saves/SAV3Colosseum.cs
+++ b/PKHeX.Core/Saves/SAV3Colosseum.cs
@@ -10,8 +10,7 @@ namespace PKHeX.Core
///
public sealed class SAV3Colosseum : SaveFile, IDisposable, IGCSaveFile
{
- protected override string BAKText => $"{OT} ({Version}) - {PlayTimeString}";
- public override string Filter => this.GCFilter();
+ protected internal override string ShortSummary => $"{OT} ({Version}) - {PlayTimeString}";
public override string Extension => this.GCExtension();
public override PersonalTable Personal => PersonalTable.RS;
public override IReadOnlyList HeldItems => Legal.HeldItems_COLO;
@@ -120,17 +119,16 @@ private byte[] GetInnerData()
byte[] newSAV = EncryptColosseum(Data, digest);
// Put save slot back in original save data
- byte[] newFile = MC != null ? MC.SelectedSaveData : (byte[])BAK.Clone();
+ byte[] newFile = MC != null ? MC.SelectedSaveData : (byte[]) State.BAK.Clone();
Array.Copy(newSAV, 0, newFile, SLOT_START + (SaveIndex * SLOT_SIZE), newSAV.Length);
return newFile;
}
// Configuration
- public override SaveFile Clone()
+ protected override SaveFile CloneInternal()
{
var data = GetInnerData();
var sav = IsMemoryCardSave ? new SAV3Colosseum(data, MC!) : new SAV3Colosseum(data);
- sav.Header = (byte[])Header.Clone();
return sav;
}
diff --git a/PKHeX.Core/Saves/SAV3RSBox.cs b/PKHeX.Core/Saves/SAV3RSBox.cs
index 46c3a16b5..8a097d723 100644
--- a/PKHeX.Core/Saves/SAV3RSBox.cs
+++ b/PKHeX.Core/Saves/SAV3RSBox.cs
@@ -9,8 +9,7 @@ namespace PKHeX.Core
///
public sealed class SAV3RSBox : SaveFile, IGCSaveFile
{
- protected override string BAKText => $"{Version} #{SaveCount:0000}";
- public override string Filter => this.GCFilter();
+ protected internal override string ShortSummary => $"{Version} #{SaveCount:0000}";
public override string Extension => this.GCExtension();
public override PersonalTable Personal => PersonalTable.RS;
public override IReadOnlyList HeldItems => Legal.HeldItems_RS;
@@ -95,11 +94,10 @@ private byte[] GetInnerData()
}
// Configuration
- public override SaveFile Clone()
+ protected override SaveFile CloneInternal()
{
var data = GetInnerData();
var sav = IsMemoryCardSave ? new SAV3RSBox(data, MC!) : new SAV3RSBox(data);
- sav.Header = (byte[])Header.Clone();
return sav;
}
diff --git a/PKHeX.Core/Saves/SAV3XD.cs b/PKHeX.Core/Saves/SAV3XD.cs
index 1aa99771b..2600bef99 100644
--- a/PKHeX.Core/Saves/SAV3XD.cs
+++ b/PKHeX.Core/Saves/SAV3XD.cs
@@ -9,8 +9,7 @@ namespace PKHeX.Core
///
public sealed class SAV3XD : SaveFile, IGCSaveFile
{
- protected override string BAKText => $"{OT} ({Version}) #{SaveCount:0000}";
- public override string Filter => this.GCFilter();
+ protected internal override string ShortSummary => $"{OT} ({Version}) #{SaveCount:0000}";
public override string Extension => this.GCExtension();
public bool IsMemoryCardSave => MC != null;
private readonly SAV3GCMemoryCard? MC;
@@ -144,17 +143,16 @@ private byte[] GetInnerData()
byte[] newSAV = GCSaveUtil.Encrypt(Data, 0x10, 0x27FD8, keys);
// Put save slot back in original save data
- byte[] newFile = MC != null ? MC.SelectedSaveData : (byte[])BAK.Clone();
+ byte[] newFile = MC != null ? MC.SelectedSaveData : (byte[]) State.BAK.Clone();
Array.Copy(newSAV, 0, newFile, SLOT_START + (SaveIndex * SLOT_SIZE), newSAV.Length);
return newFile;
}
// Configuration
- public override SaveFile Clone()
+ protected override SaveFile CloneInternal()
{
var data = GetInnerData();
var sav = IsMemoryCardSave ? new SAV3XD(data, MC!) : new SAV3XD(data);
- sav.Header = (byte[]) Header.Clone();
return sav;
}
diff --git a/PKHeX.Core/Saves/SAV4.cs b/PKHeX.Core/Saves/SAV4.cs
index 46a99fbd6..a78408875 100644
--- a/PKHeX.Core/Saves/SAV4.cs
+++ b/PKHeX.Core/Saves/SAV4.cs
@@ -12,8 +12,7 @@ namespace PKHeX.Core
///
public abstract class SAV4 : SaveFile
{
- protected override string BAKText => $"{OT} ({Version}) - {PlayTimeString}";
- public override string Filter => (Footer.Length > 0 ? "DeSmuME DSV|*.dsv|" : string.Empty) + "SAV File|*.sav|All Files|*.*";
+ protected internal override string ShortSummary => $"{OT} ({Version}) - {PlayTimeString}";
public override string Extension => ".sav";
// Blocks & Offsets
@@ -59,16 +58,15 @@ protected SAV4(byte[] data) : base(data)
}
// Configuration
- public override SaveFile Clone()
+ protected override SaveFile CloneInternal()
{
- var sav = CloneInternal();
+ var sav = CloneInternal4();
SetData(sav.General, General, 0);
SetData(sav.Storage, Storage, 0);
- sav.Footer = (byte[])Footer.Clone();
return sav;
}
- protected abstract SAV4 CloneInternal();
+ protected abstract SAV4 CloneInternal4();
public override void CopyChangesFrom(SaveFile sav)
{
diff --git a/PKHeX.Core/Saves/SAV4BR.cs b/PKHeX.Core/Saves/SAV4BR.cs
index 9b9418ad3..781443e93 100644
--- a/PKHeX.Core/Saves/SAV4BR.cs
+++ b/PKHeX.Core/Saves/SAV4BR.cs
@@ -10,8 +10,7 @@ namespace PKHeX.Core
///
public sealed class SAV4BR : SaveFile
{
- protected override string BAKText => $"{Version} #{SaveCount:0000}";
- public override string Filter => "PbrSaveData|*";
+ protected internal override string ShortSummary => $"{Version} #{SaveCount:0000}";
public override string Extension => string.Empty;
public override PersonalTable Personal => PersonalTable.DP;
public override IReadOnlyList HeldItems => Legal.HeldItems_DP;
@@ -67,7 +66,7 @@ protected override byte[] GetFinalData()
}
// Configuration
- public override SaveFile Clone() => new SAV4BR(Write());
+ protected override SaveFile CloneInternal() => new SAV4BR(Write());
public readonly List SaveSlots = new List(SAVE_COUNT);
public readonly List SaveNames = new List(SAVE_COUNT);
diff --git a/PKHeX.Core/Saves/SAV4DP.cs b/PKHeX.Core/Saves/SAV4DP.cs
index ba824925d..5a00a0af8 100644
--- a/PKHeX.Core/Saves/SAV4DP.cs
+++ b/PKHeX.Core/Saves/SAV4DP.cs
@@ -10,7 +10,7 @@ public sealed class SAV4DP : SAV4Sinnoh
{
public SAV4DP() => Initialize();
public SAV4DP(byte[] data) : base(data) => Initialize();
- protected override SAV4 CloneInternal() => Exportable ? new SAV4DP(Data) : new SAV4DP();
+ protected override SAV4 CloneInternal4() => State.Exportable ? new SAV4DP(Data) : new SAV4DP();
public override PersonalTable Personal => PersonalTable.DP;
public override IReadOnlyList HeldItems => Legal.HeldItems_DP;
diff --git a/PKHeX.Core/Saves/SAV4HGSS.cs b/PKHeX.Core/Saves/SAV4HGSS.cs
index 6330f1d70..eecd7c8e3 100644
--- a/PKHeX.Core/Saves/SAV4HGSS.cs
+++ b/PKHeX.Core/Saves/SAV4HGSS.cs
@@ -10,7 +10,7 @@ public sealed class SAV4HGSS : SAV4
{
public SAV4HGSS() => Initialize();
public SAV4HGSS(byte[] data) : base(data) => Initialize();
- protected override SAV4 CloneInternal() => Exportable ? new SAV4HGSS(Data) : new SAV4HGSS();
+ protected override SAV4 CloneInternal4() => State.Exportable ? new SAV4HGSS(Data) : new SAV4HGSS();
public override PersonalTable Personal => PersonalTable.HGSS;
public override IReadOnlyList HeldItems => Legal.HeldItems_HGSS;
diff --git a/PKHeX.Core/Saves/SAV4Pt.cs b/PKHeX.Core/Saves/SAV4Pt.cs
index 859284ba3..ab53d4d88 100644
--- a/PKHeX.Core/Saves/SAV4Pt.cs
+++ b/PKHeX.Core/Saves/SAV4Pt.cs
@@ -9,7 +9,7 @@ public sealed class SAV4Pt : SAV4Sinnoh
{
public SAV4Pt() => Initialize();
public SAV4Pt(byte[] data) : base(data) => Initialize();
- protected override SAV4 CloneInternal() => Exportable ? new SAV4Pt(Data) : new SAV4Pt();
+ protected override SAV4 CloneInternal4() => State.Exportable ? new SAV4Pt(Data) : new SAV4Pt();
public override PersonalTable Personal => PersonalTable.Pt;
public override IReadOnlyList HeldItems => Legal.HeldItems_Pt;
diff --git a/PKHeX.Core/Saves/SAV5.cs b/PKHeX.Core/Saves/SAV5.cs
index a39d03516..19fcfa891 100644
--- a/PKHeX.Core/Saves/SAV5.cs
+++ b/PKHeX.Core/Saves/SAV5.cs
@@ -11,8 +11,7 @@ public abstract class SAV5 : SaveFile, ISaveBlock5BW
protected override PKM GetPKM(byte[] data) => new PK5(data);
protected override byte[] DecryptPKM(byte[] data) => PokeCrypto.DecryptArray45(data);
- protected override string BAKText => $"{OT} ({(GameVersion)Game}) - {PlayTimeString}";
- public override string Filter => (Footer.Length != 0 ? "DeSmuME DSV|*.dsv|" : string.Empty) + "SAV File|*.sav|All Files|*.*";
+ protected internal override string ShortSummary => $"{OT} ({(GameVersion)Game}) - {PlayTimeString}";
public override string Extension => ".sav";
public override IReadOnlyList HeldItems => Legal.HeldItems_BW;
@@ -185,7 +184,7 @@ public byte[] CGearSkinData
chkbytes.CopyTo(Data, CGearSkinInfoOffset);
CGearSkinPresent = true;
- Edited = true;
+ State.Edited = true;
}
}
diff --git a/PKHeX.Core/Saves/SAV5B2W2.cs b/PKHeX.Core/Saves/SAV5B2W2.cs
index 0f6e1bd84..d974d0966 100644
--- a/PKHeX.Core/Saves/SAV5B2W2.cs
+++ b/PKHeX.Core/Saves/SAV5B2W2.cs
@@ -18,7 +18,7 @@ public SAV5B2W2(byte[] data) : base(data)
public override PersonalTable Personal => PersonalTable.B2W2;
public SaveBlockAccessor5B2W2 Blocks { get; }
- public override SaveFile Clone() => new SAV5B2W2((byte[])Data.Clone()) { Footer = (byte[])Footer.Clone() };
+ protected override SaveFile CloneInternal() => new SAV5B2W2((byte[]) Data.Clone());
protected override int EventConstMax => 0x1AF; // this doesn't seem right?
protected override int EventFlagMax => 0xBF8;
public override int MaxItemID => Legal.MaxItemID_5_B2W2;
diff --git a/PKHeX.Core/Saves/SAV5BW.cs b/PKHeX.Core/Saves/SAV5BW.cs
index 0714b8832..ceba12ea5 100644
--- a/PKHeX.Core/Saves/SAV5BW.cs
+++ b/PKHeX.Core/Saves/SAV5BW.cs
@@ -18,7 +18,7 @@ public SAV5BW(byte[] data) : base(data)
public override PersonalTable Personal => PersonalTable.BW;
public SaveBlockAccessor5BW Blocks { get; }
- public override SaveFile Clone() => new SAV5BW((byte[])Data.Clone()) { Footer = (byte[])Footer.Clone() };
+ protected override SaveFile CloneInternal() => new SAV5BW((byte[])Data.Clone());
protected override int EventConstMax => 0x13E;
protected override int EventFlagMax => 0xB60;
public override int MaxItemID => Legal.MaxItemID_5_BW;
diff --git a/PKHeX.Core/Saves/SAV6.cs b/PKHeX.Core/Saves/SAV6.cs
index c68dcb3a8..d0e46b3f6 100644
--- a/PKHeX.Core/Saves/SAV6.cs
+++ b/PKHeX.Core/Saves/SAV6.cs
@@ -8,8 +8,7 @@ namespace PKHeX.Core
public abstract class SAV6 : SAV_BEEF, ITrainerStatRecord, ISaveBlock6Core, IRegionOrigin, IGameSync
{
// Save Data Attributes
- protected override string BAKText => $"{OT} ({Version}) - {Played.LastSavedTime}";
- public override string Filter => "Main SAV|*.*";
+ protected internal override string ShortSummary => $"{OT} ({Version}) - {Played.LastSavedTime}";
public override string Extension => string.Empty;
protected SAV6(byte[] data, int biOffset) : base(data, biOffset) { }
diff --git a/PKHeX.Core/Saves/SAV6AO.cs b/PKHeX.Core/Saves/SAV6AO.cs
index 6db65058b..ca4585870 100644
--- a/PKHeX.Core/Saves/SAV6AO.cs
+++ b/PKHeX.Core/Saves/SAV6AO.cs
@@ -27,7 +27,7 @@ public SAV6AO() : base(SaveUtil.SIZE_G6ORAS, SaveBlockAccessor6AO.boAO)
public override PersonalTable Personal => PersonalTable.AO;
public override IReadOnlyList HeldItems => Legal.HeldItem_AO;
public SaveBlockAccessor6AO Blocks { get; }
- public override SaveFile Clone() => new SAV6AO((byte[])Data.Clone());
+ protected override SaveFile CloneInternal() => new SAV6AO((byte[])Data.Clone());
public override int MaxMoveID => Legal.MaxMoveID_6_AO;
public override int MaxItemID => Legal.MaxItemID_6_AO;
public override int MaxAbilityID => Legal.MaxAbilityID_6_AO;
diff --git a/PKHeX.Core/Saves/SAV6AODemo.cs b/PKHeX.Core/Saves/SAV6AODemo.cs
index 7b8bc7847..d62a8bebd 100644
--- a/PKHeX.Core/Saves/SAV6AODemo.cs
+++ b/PKHeX.Core/Saves/SAV6AODemo.cs
@@ -22,7 +22,7 @@ public SAV6AODemo() : base(SaveUtil.SIZE_G6ORASDEMO, SaveBlockAccessor6AODemo.bo
public override PersonalTable Personal => PersonalTable.AO;
public override IReadOnlyList HeldItems => Legal.HeldItem_AO;
- public override SaveFile Clone() => new SAV6AODemo((byte[])Data.Clone());
+ protected override SaveFile CloneInternal() => new SAV6AODemo((byte[])Data.Clone());
public override int MaxMoveID => Legal.MaxMoveID_6_AO;
public override int MaxItemID => Legal.MaxItemID_6_AO;
public override int MaxAbilityID => Legal.MaxAbilityID_6_AO;
diff --git a/PKHeX.Core/Saves/SAV6XY.cs b/PKHeX.Core/Saves/SAV6XY.cs
index bae0a0e70..681e9475d 100644
--- a/PKHeX.Core/Saves/SAV6XY.cs
+++ b/PKHeX.Core/Saves/SAV6XY.cs
@@ -27,7 +27,7 @@ public SAV6XY() : base(SaveUtil.SIZE_G6XY, SaveBlockAccessor6XY.boXY)
public override PersonalTable Personal => PersonalTable.XY;
public override IReadOnlyList HeldItems => Legal.HeldItem_XY;
public SaveBlockAccessor6XY Blocks { get; }
- public override SaveFile Clone() => new SAV6XY((byte[])Data.Clone());
+ protected override SaveFile CloneInternal() => new SAV6XY((byte[])Data.Clone());
public override int MaxMoveID => Legal.MaxMoveID_6_XY;
public override int MaxItemID => Legal.MaxItemID_6_XY;
public override int MaxAbilityID => Legal.MaxAbilityID_6_XY;
@@ -133,7 +133,8 @@ public void UnlockAllFriendSafariSlots()
if (Data[ofs] != 0) // no friend data == 0x00
Data[ofs] = 0x3D;
}
- Edited = true;
+
+ State.Edited = true;
}
public override GameVersion Version
diff --git a/PKHeX.Core/Saves/SAV7.cs b/PKHeX.Core/Saves/SAV7.cs
index f77a7a748..df148d3f8 100644
--- a/PKHeX.Core/Saves/SAV7.cs
+++ b/PKHeX.Core/Saves/SAV7.cs
@@ -11,8 +11,7 @@ namespace PKHeX.Core
public abstract class SAV7 : SAV_BEEF, ITrainerStatRecord, ISaveBlock7Main, IRegionOrigin
{
// Save Data Attributes
- protected override string BAKText => $"{OT} ({Version}) - {Played.LastSavedTime}";
- public override string Filter => "Main SAV|*.*";
+ protected internal override string ShortSummary => $"{OT} ({Version}) - {Played.LastSavedTime}";
public override string Extension => string.Empty;
public override IReadOnlyList PKMExtensions => PKM.Extensions.Where(f =>
@@ -32,7 +31,7 @@ protected SAV7(int size, int biOffset) : base(size, biOffset)
protected void ReloadBattleTeams()
{
var demo = this is SAV7SM && Data.IsRangeAll((byte)0, BoxLayout.Offset, 0x4C4); // up to Battle Box values
- if (demo || !Exportable)
+ if (demo || !State.Exportable)
{
BoxLayout.ClearBattleTeams();
}
diff --git a/PKHeX.Core/Saves/SAV7SM.cs b/PKHeX.Core/Saves/SAV7SM.cs
index d4e2a40f5..adb6cf8eb 100644
--- a/PKHeX.Core/Saves/SAV7SM.cs
+++ b/PKHeX.Core/Saves/SAV7SM.cs
@@ -37,7 +37,7 @@ private void Initialize()
public override PersonalTable Personal => PersonalTable.SM;
public override IReadOnlyList HeldItems => Legal.HeldItems_SM;
- public override SaveFile Clone() => new SAV7SM((byte[])Data.Clone());
+ protected override SaveFile CloneInternal() => new SAV7SM((byte[])Data.Clone());
#region Blocks
public SaveBlockAccessor7SM Blocks { get; }
diff --git a/PKHeX.Core/Saves/SAV7USUM.cs b/PKHeX.Core/Saves/SAV7USUM.cs
index 3cc1446c8..84da88a37 100644
--- a/PKHeX.Core/Saves/SAV7USUM.cs
+++ b/PKHeX.Core/Saves/SAV7USUM.cs
@@ -35,7 +35,7 @@ private void Initialize()
public override PersonalTable Personal => PersonalTable.USUM;
public override IReadOnlyList HeldItems => Legal.HeldItems_USUM;
- public override SaveFile Clone() => new SAV7USUM((byte[])Data.Clone());
+ protected override SaveFile CloneInternal() => new SAV7USUM((byte[])Data.Clone());
protected override int EventFlagMax => 4928;
public override int MaxMoveID => Legal.MaxMoveID_7_USUM;
public override int MaxSpeciesID => Legal.MaxSpeciesID_7_USUM;
diff --git a/PKHeX.Core/Saves/SAV7b.cs b/PKHeX.Core/Saves/SAV7b.cs
index 962289f6a..05769cc7c 100644
--- a/PKHeX.Core/Saves/SAV7b.cs
+++ b/PKHeX.Core/Saves/SAV7b.cs
@@ -9,8 +9,7 @@ namespace PKHeX.Core
///
public sealed class SAV7b : SAV_BEEF, IGameSync
{
- protected override string BAKText => $"{OT} ({Version}) - {Blocks.Played.LastSavedTime}";
- public override string Filter => "savedata|*.bin";
+ protected internal override string ShortSummary => $"{OT} ({Version}) - {Blocks.Played.LastSavedTime}";
public override string Extension => ".bin";
public override IReadOnlyList PKMExtensions => PKM.Extensions.Where(f => f[1] == 'b' && f[f.Length - 1] == '7').ToArray();
@@ -24,7 +23,7 @@ public sealed class SAV7b : SAV_BEEF, IGameSync
public override PersonalTable Personal => PersonalTable.GG;
public override IReadOnlyList HeldItems => Legal.HeldItems_GG;
- public override SaveFile Clone() => new SAV7b((byte[])Data.Clone());
+ protected override SaveFile CloneInternal() => new SAV7b((byte[])Data.Clone());
public SaveBlockAccessor7b Blocks { get; }
public override IReadOnlyList AllBlocks => Blocks.BlockInfo;
diff --git a/PKHeX.Core/Saves/SAV8.cs b/PKHeX.Core/Saves/SAV8.cs
index 3daca725e..dc74d7c6a 100644
--- a/PKHeX.Core/Saves/SAV8.cs
+++ b/PKHeX.Core/Saves/SAV8.cs
@@ -10,8 +10,7 @@ namespace PKHeX.Core
public abstract class SAV8 : SaveFile, ISaveBlock8Main
{
// Save Data Attributes
- protected override string BAKText => $"{OT} ({Version}) - {Played.LastSavedTime}";
- public override string Filter => "Main SAV|*.*";
+ protected internal override string ShortSummary => $"{OT} ({Version}) - {Played.LastSavedTime}";
public override string Extension => string.Empty;
public override IReadOnlyList PKMExtensions => PKM.Extensions.Where(f =>
diff --git a/PKHeX.Core/Saves/SAV8SWSH.cs b/PKHeX.Core/Saves/SAV8SWSH.cs
index c374116ac..640333a9a 100644
--- a/PKHeX.Core/Saves/SAV8SWSH.cs
+++ b/PKHeX.Core/Saves/SAV8SWSH.cs
@@ -39,7 +39,7 @@ public override void CopyChangesFrom(SaveFile sav)
var newB = z.AllBlocks;
for (int i = 0; i < mine.Count; i++)
newB[i].Data.CopyTo(mine[i].Data, 0);
- Edited = true;
+ State.Edited = true;
}
public int SaveRevision { get; }
@@ -83,7 +83,7 @@ public override void CopyChangesFrom(SaveFile sav)
public T GetValue(uint key) where T : struct
{
- if (!Exportable)
+ if (!State.Exportable)
return default;
var value = Blocks.GetBlockValue(key);
if (value is T v)
@@ -93,13 +93,13 @@ public override void CopyChangesFrom(SaveFile sav)
public void SetValue(uint key, T value) where T : struct
{
- if (!Exportable)
+ if (!State.Exportable)
return;
Blocks.SetBlockValue(key, value);
}
#endregion
- public override SaveFile Clone() => new SAV8SWSH(BAK, AllBlocks.Select(z => z.Clone()).ToArray());
+ protected override SaveFile CloneInternal() => new SAV8SWSH(State.BAK, AllBlocks.Select(z => z.Clone()).ToArray());
private int m_spec, m_item, m_move, m_abil;
public override int MaxMoveID => m_move;
diff --git a/PKHeX.Core/Saves/SAV_STADIUM.cs b/PKHeX.Core/Saves/SAV_STADIUM.cs
index 7b21f179f..0745d4831 100644
--- a/PKHeX.Core/Saves/SAV_STADIUM.cs
+++ b/PKHeX.Core/Saves/SAV_STADIUM.cs
@@ -5,8 +5,7 @@
///
public abstract class SAV_STADIUM : SaveFile, ILangDeviantSave
{
- protected sealed override string BAKText => $"{OT} ({Version})";
- public sealed override string Filter => "SAV File|*.sav|All Files|*.*";
+ protected internal sealed override string ShortSummary => $"{OT} ({Version})";
public sealed override string Extension => ".sav";
public abstract int SaveRevision { get; }
diff --git a/PKHeX.Core/Saves/SaveFile.cs b/PKHeX.Core/Saves/SaveFile.cs
index 2de7c40a2..7edf99df7 100644
--- a/PKHeX.Core/Saves/SaveFile.cs
+++ b/PKHeX.Core/Saves/SaveFile.cs
@@ -5,6 +5,19 @@
namespace PKHeX.Core
{
+ public class SaveFileState
+ {
+ public bool Edited { get; set; }
+ public readonly bool Exportable;
+ public readonly byte[] BAK;
+
+ public SaveFileState(byte[] bak, bool exportable = true)
+ {
+ BAK = bak;
+ Exportable = exportable;
+ }
+ }
+
///
/// Base Class for Save Files
///
@@ -12,42 +25,42 @@ public abstract class SaveFile : ITrainerInfo, IGameValueLimit, IBoxDetailWallpa
{
// General Object Properties
public byte[] Data;
- public bool Edited;
- public readonly bool Exportable;
- public readonly byte[] BAK;
+
+ public SaveFileState State { get; }
+ public SaveFileMetadata Metadata { get; private set; }
protected SaveFile(byte[] data, byte[] bak, bool exportable = true)
{
Data = data;
- BAK = bak;
- Exportable = exportable;
+ State = new SaveFileState(bak, exportable);
+ Metadata = new SaveFileMetadata(this);
}
- protected SaveFile(byte[] data, bool exportable = true) : this(data, (byte[])data.Clone(), exportable) { }
-
- protected SaveFile()
+ protected SaveFile(byte[] data, bool exportable = true) : this(data, (byte[])data.Clone(), exportable)
{
- Data = BAK = Array.Empty();
- Exportable = false;
}
- protected SaveFile(int size)
+ protected SaveFile(int size = 0)
{
- Data = new byte[size];
- BAK = Data;
- Exportable = false;
+ Data = size == 0 ? Array.Empty() : new byte[size];
+ State = new SaveFileState(Array.Empty(), false);
+ Metadata = new SaveFileMetadata(this);
}
- public string? FileName, FilePath, FileFolder;
- public string BAKName => $"{FileName} [{BAKText}].bak";
- protected abstract string BAKText { get; }
- public abstract SaveFile Clone();
- public abstract string Filter { get; }
- public byte[] Footer { protected get; set; } = Array.Empty(); // .dsv
- public byte[] Header { protected get; set; } = Array.Empty(); // .gci
- public virtual string PlayTimeString => $"{PlayedHours}ː{PlayedMinutes:00}ː{PlayedSeconds:00}"; // not :
+ protected internal abstract string ShortSummary { get; }
public abstract string Extension { get; }
+ protected abstract SaveFile CloneInternal();
+
+ public SaveFile Clone()
+ {
+ var sav = CloneInternal();
+ sav.Metadata = Metadata;
+ return sav;
+ }
+
+ public virtual string PlayTimeString => $"{PlayedHours}ː{PlayedMinutes:00}ː{PlayedSeconds:00}"; // not :
+
public virtual IReadOnlyList PKMExtensions => PKM.Extensions.Where(f =>
{
int gen = f.Last() - 0x30;
@@ -58,11 +71,7 @@ protected SaveFile(int size)
public byte[] Write(ExportFlags flags = ExportFlags.None)
{
byte[] data = GetFinalData();
- if (Footer.Length > 0 && flags.HasFlagFast(ExportFlags.IncludeFooter))
- return data.Concat(Footer).ToArray();
- if (Header.Length > 0 && flags.HasFlagFast(ExportFlags.IncludeHeader))
- return Header.Concat(data).ToArray();
- return data;
+ return Metadata.Finalize(data, flags);
}
protected virtual byte[] GetFinalData()
@@ -87,7 +96,7 @@ protected virtual byte[] GetFinalData()
public void SetData(byte[] dest, byte[] input, int offset)
{
input.CopyTo(dest, offset);
- Edited = true;
+ State.Edited = true;
}
public abstract string GetString(byte[] data, int offset, int length);
diff --git a/PKHeX.Core/Saves/SaveFileMetadata.cs b/PKHeX.Core/Saves/SaveFileMetadata.cs
new file mode 100644
index 000000000..3e51d7fb9
--- /dev/null
+++ b/PKHeX.Core/Saves/SaveFileMetadata.cs
@@ -0,0 +1,78 @@
+using System;
+using System.IO;
+using System.Linq;
+
+namespace PKHeX.Core
+{
+ public class SaveFileMetadata
+ {
+ private readonly SaveFile SAV;
+
+ public string? FileName;
+ public string? FilePath;
+ public string? FileFolder;
+ private byte[] Footer = Array.Empty(); // .dsv
+ private byte[] Header = Array.Empty(); // .gci
+
+ public string BAKName => $"{FileName} [{SAV.ShortSummary}].bak";
+
+ public SaveFileMetadata(SaveFile sav) => SAV = sav;
+
+ public bool HasHeader => Header.Length != 0;
+ public bool HasFooter => Footer.Length != 0;
+ public string Filter => $"{SAV.GetType().Name}|{GetSuggestedExtension()}|All Files|*.*";
+
+ public byte[] Finalize(byte[] data, ExportFlags flags)
+ {
+ if (Footer.Length > 0 && flags.HasFlagFast(ExportFlags.IncludeFooter))
+ return data.Concat(Footer).ToArray();
+ if (Header.Length > 0 && flags.HasFlagFast(ExportFlags.IncludeHeader))
+ return Header.Concat(data).ToArray();
+ return data;
+ }
+
+ ///
+ /// Sets the details of any trimmed header and footer arrays to a object.
+ ///
+ public void SetExtraInfo(byte[] header, byte[] footer)
+ {
+ Header = header;
+ Footer = footer;
+ }
+
+ ///
+ /// Sets the details of a path to a object.
+ ///
+ /// Full Path of the file
+ public void SetExtraInfo(string path)
+ {
+ var sav = SAV;
+ if (!sav.State.Exportable) // Blank save file
+ {
+ sav.Metadata.FileFolder = sav.Metadata.FilePath = string.Empty;
+ sav.Metadata.FileName = "Blank Save File";
+ return;
+ }
+
+ sav.Metadata.FilePath = path;
+ sav.Metadata.FileFolder = Path.GetDirectoryName(path);
+ sav.Metadata.FileName = string.Empty;
+ var bakName = Util.CleanFileName(sav.Metadata.BAKName);
+ sav.Metadata.FileName = Path.GetFileName(path);
+ if (sav.Metadata.FileName?.EndsWith(bakName) == true)
+ sav.Metadata.FileName = sav.Metadata.FileName.Substring(0, sav.Metadata.FileName.Length - bakName.Length);
+ }
+
+ public string GetSuggestedExtension()
+ {
+ var sav = SAV;
+ var fn = sav.Metadata.FileName;
+ if (fn != null)
+ return Path.GetExtension(fn);
+
+ if ((sav.Generation == 4 || sav.Generation == 5) && sav.Metadata.HasFooter)
+ return ".dsv";
+ return sav.Extension;
+ }
+ }
+}
\ No newline at end of file
diff --git a/PKHeX.Core/Saves/Storage/Bank3.cs b/PKHeX.Core/Saves/Storage/Bank3.cs
index 78c68d51e..35b4424f3 100644
--- a/PKHeX.Core/Saves/Storage/Bank3.cs
+++ b/PKHeX.Core/Saves/Storage/Bank3.cs
@@ -11,11 +11,10 @@ public sealed class Bank3 : BulkStorage
public override PersonalTable Personal => PersonalTable.RS;
public override IReadOnlyList HeldItems => Legal.HeldItems_RS;
- public override SaveFile Clone() => new Bank3((byte[])Data.Clone());
+ protected override SaveFile CloneInternal() => new Bank3((byte[])Data.Clone());
public override string PlayTimeString => Checksums.CRC16(Data, 0, Data.Length).ToString("X4");
- protected override string BAKText => PlayTimeString;
+ protected internal override string ShortSummary => PlayTimeString;
public override string Extension => ".gst";
- public override string Filter { get; } = "PokeStock G3 Storage|*.gst*";
public override int BoxCount => 64;
private const int BoxNameSize = 9;
diff --git a/PKHeX.Core/Saves/Storage/Bank4.cs b/PKHeX.Core/Saves/Storage/Bank4.cs
index c17f8fc81..4abd7bafd 100644
--- a/PKHeX.Core/Saves/Storage/Bank4.cs
+++ b/PKHeX.Core/Saves/Storage/Bank4.cs
@@ -11,11 +11,10 @@ public sealed class Bank4 : BulkStorage
public override PersonalTable Personal => PersonalTable.HGSS;
public override IReadOnlyList HeldItems => Legal.HeldItems_HGSS;
- public override SaveFile Clone() => new Bank4((byte[])Data.Clone());
+ protected override SaveFile CloneInternal() => new Bank4((byte[])Data.Clone());
public override string PlayTimeString => Checksums.CRC16(Data, 0, Data.Length).ToString("X4");
- protected override string BAKText => PlayTimeString;
+ protected internal override string ShortSummary => PlayTimeString;
public override string Extension => ".stk";
- public override string Filter { get; } = "PokeStock G4 Storage|*.stk*";
public override int BoxCount => 64;
private const int BoxNameSize = 0x18;
diff --git a/PKHeX.Core/Saves/Storage/Bank7.cs b/PKHeX.Core/Saves/Storage/Bank7.cs
index 623315003..5a73ec2db 100644
--- a/PKHeX.Core/Saves/Storage/Bank7.cs
+++ b/PKHeX.Core/Saves/Storage/Bank7.cs
@@ -12,9 +12,9 @@ public sealed class Bank7 : BulkStorage
public override PersonalTable Personal => PersonalTable.USUM;
public override IReadOnlyList HeldItems => Legal.HeldItems_SM;
- public override SaveFile Clone() => new Bank7((byte[])Data.Clone(), PKMType, BoxStart, SlotsPerBox);
+ protected override SaveFile CloneInternal() => new Bank7((byte[])Data.Clone(), PKMType, BoxStart, SlotsPerBox);
public override string PlayTimeString => $"{Year:00}{Month:00}{Day:00}_{Hours:00}ː{Minutes:00}";
- protected override string BAKText => PlayTimeString;
+ protected internal override string ShortSummary => PlayTimeString;
private const int GroupNameSize = 0x20;
private const int BankNameSize = 0x24;
private const int GroupNameSpacing = GroupNameSize + 2;
diff --git a/PKHeX.Core/Saves/Storage/BulkStorage.cs b/PKHeX.Core/Saves/Storage/BulkStorage.cs
index f62997473..780fa64b3 100644
--- a/PKHeX.Core/Saves/Storage/BulkStorage.cs
+++ b/PKHeX.Core/Saves/Storage/BulkStorage.cs
@@ -21,11 +21,10 @@ protected BulkStorage(byte[] data, Type t, int start, int slotsPerBox = 30) : ba
protected readonly int SlotsPerBox;
- protected override string BAKText => $"{Checksums.CRC16(Data, Box, Data.Length - Box):X4}";
- public override string Filter { get; } = "All Files|*.*";
- public override string Extension { get; } = ".bin";
- public sealed override bool ChecksumsValid { get; } = true;
- public sealed override string ChecksumInfo { get; } = "No Info.";
+ protected internal override string ShortSummary => $"{Checksums.CRC16(Data, Box, Data.Length - Box):X4}";
+ public override string Extension => ".bin";
+ public sealed override bool ChecksumsValid => true;
+ public sealed override string ChecksumInfo => "No Info.";
private readonly PKM blank;
public sealed override Type PKMType => blank.GetType();
diff --git a/PKHeX.Core/Saves/Storage/SAV4Ranch.cs b/PKHeX.Core/Saves/Storage/SAV4Ranch.cs
index 3be060565..5d91ec61c 100644
--- a/PKHeX.Core/Saves/Storage/SAV4Ranch.cs
+++ b/PKHeX.Core/Saves/Storage/SAV4Ranch.cs
@@ -21,11 +21,10 @@ public sealed class SAV4Ranch : BulkStorage, ISaveFileRevision
public override PersonalTable Personal => PersonalTable.Pt;
public override IReadOnlyList HeldItems => Legal.HeldItems_Pt;
- public override SaveFile Clone() => new SAV4Ranch((byte[])Data.Clone());
+ protected override SaveFile CloneInternal() => new SAV4Ranch((byte[])Data.Clone());
public override string PlayTimeString => Checksums.CRC16(Data, 0, Data.Length).ToString("X4");
- protected override string BAKText => $"{OT} {PlayTimeString}";
+ protected internal override string ShortSummary => $"{OT} {PlayTimeString}";
public override string Extension => ".bin";
- public override string Filter { get; } = "Ranch G4 Storage|*.bin*";
protected override PKM GetPKM(byte[] data) => new PK4(data);
protected override byte[] DecryptPKM(byte[] data) => PokeCrypto.DecryptArray45(data);
diff --git a/PKHeX.Core/Saves/Substructures/Gen6/MysteryBlock6.cs b/PKHeX.Core/Saves/Substructures/Gen6/MysteryBlock6.cs
index 49b152e2a..29c8ba2e2 100644
--- a/PKHeX.Core/Saves/Substructures/Gen6/MysteryBlock6.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen6/MysteryBlock6.cs
@@ -20,7 +20,7 @@ public void SetReceivedFlags(bool[] value)
if (value.Length != MaxReceivedFlag)
return;
ArrayUtil.SetBitFlagArray(Data, Offset + FlagStart, value);
- SAV.Edited = true;
+ SAV.State.Edited = true;
}
public DataMysteryGift[] GetGifts()
diff --git a/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs b/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs
index 9dffcf0d6..addd06f02 100644
--- a/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs
@@ -22,7 +22,7 @@ public bool[] MysteryGiftReceivedFlags
if (value.Length != MaxReceivedFlag)
return;
ArrayUtil.SetBitFlagArray(Data, Offset + FlagStart, value);
- SAV.Edited = true;
+ SAV.State.Edited = true;
}
}
diff --git a/PKHeX.Core/Saves/Substructures/Gen7/PokeListHeader.cs b/PKHeX.Core/Saves/Substructures/Gen7/PokeListHeader.cs
index 8aa316564..7462208f4 100644
--- a/PKHeX.Core/Saves/Substructures/Gen7/PokeListHeader.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen7/PokeListHeader.cs
@@ -30,7 +30,7 @@ public PokeListHeader(SAV7b sav, int offset) : base(sav)
{
Offset = offset;
PokeListInfo = LoadPointerData();
- if (!sav.Exportable)
+ if (!sav.State.Exportable)
{
for (int i = 0; i < COUNT; i++)
PokeListInfo[i] = SLOT_EMPTY;
diff --git a/PKHeX.Core/Saves/Substructures/Gen8/MyStatus8.cs b/PKHeX.Core/Saves/Substructures/Gen8/MyStatus8.cs
index 021310808..103f65555 100644
--- a/PKHeX.Core/Saves/Substructures/Gen8/MyStatus8.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen8/MyStatus8.cs
@@ -16,7 +16,7 @@ public string Number
{
for (int i = 0; i < 3; i++)
Data[0x01 + i] = (byte)(value.Length > i ? value[i] : '\0');
- SAV.Edited = true;
+ SAV.State.Edited = true;
}
}
diff --git a/PKHeX.Core/Saves/Substructures/Gen8/TeamIndexes8.cs b/PKHeX.Core/Saves/Substructures/Gen8/TeamIndexes8.cs
index 9b3c5e5ba..9da5ea9e2 100644
--- a/PKHeX.Core/Saves/Substructures/Gen8/TeamIndexes8.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen8/TeamIndexes8.cs
@@ -12,7 +12,7 @@ public sealed class TeamIndexes8 : SaveBlock, ITeamIndexSet
public void LoadBattleTeams()
{
- if (!SAV.Exportable)
+ if (!SAV.State.Exportable)
{
ClearBattleTeams();
return;
diff --git a/PKHeX.Core/Saves/Substructures/Gen8/TrainerCard8.cs b/PKHeX.Core/Saves/Substructures/Gen8/TrainerCard8.cs
index 74e6911e2..bb49a6ab5 100644
--- a/PKHeX.Core/Saves/Substructures/Gen8/TrainerCard8.cs
+++ b/PKHeX.Core/Saves/Substructures/Gen8/TrainerCard8.cs
@@ -117,7 +117,7 @@ public string Number
{
for (int i = 0; i < 3; i++)
Data[0x39 + i] = (byte) (value.Length > i ? value[i] : '\0');
- SAV.Edited = true;
+ SAV.State.Edited = true;
}
}
diff --git a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7.cs b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7.cs
index 05beec857..7ec259c7f 100644
--- a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7.cs
+++ b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7.cs
@@ -32,7 +32,7 @@ private Zukan7(SaveFile sav, int dex, int langflag, Func for
{
DexFormIndexFetcher = form;
FormBaseSpecies = GetFormIndexBaseSpeciesList();
- Debug.Assert(!SAV.Exportable || BitConverter.ToUInt32(SAV.Data, PokeDex) == MAGIC);
+ Debug.Assert(!SAV.State.Exportable || BitConverter.ToUInt32(SAV.Data, PokeDex) == MAGIC);
}
public Func DexFormIndexFetcher { get; }
diff --git a/PKHeX.Core/Saves/Util/BoxUtil.cs b/PKHeX.Core/Saves/Util/BoxUtil.cs
index 344a1b975..025ef6d77 100644
--- a/PKHeX.Core/Saves/Util/BoxUtil.cs
+++ b/PKHeX.Core/Saves/Util/BoxUtil.cs
@@ -212,7 +212,7 @@ public static string[] GetBoxNames(SaveFile sav)
{
int count = sav.BoxCount;
var result = new string[count];
- if (!sav.Exportable)
+ if (!sav.State.Exportable)
{
for (int i = 0; i < count; i++)
result[i] = $"Box {i + 1}";
diff --git a/PKHeX.Core/Saves/Util/SaveExtensions.cs b/PKHeX.Core/Saves/Util/SaveExtensions.cs
index 627084656..2b53b6f0f 100644
--- a/PKHeX.Core/Saves/Util/SaveExtensions.cs
+++ b/PKHeX.Core/Saves/Util/SaveExtensions.cs
@@ -22,30 +22,7 @@ public static class SaveExtensions
/// PKM input that is to be injected into the Save File.
/// Indication whether or not the PKM is compatible.
public static bool IsPKMCompatibleWithModifications(this SaveFile sav, PKM pk) => PKMConverter.IsPKMCompatibleWithModifications(pk, sav);
-
- ///
- /// Sets the details of a path to a object.
- ///
- /// Save File to set path details to.
- /// Full Path of the file
- public static void SetFileInfo(this SaveFile sav, string path)
- {
- if (!sav.Exportable) // Blank save file
- {
- sav.FileFolder = sav.FilePath = string.Empty;
- sav.FileName = "Blank Save File";
- return;
- }
-
- sav.FilePath = path;
- sav.FileFolder = Path.GetDirectoryName(path);
- sav.FileName = string.Empty;
- var bakName = Util.CleanFileName(sav.BAKName);
- sav.FileName = Path.GetFileName(path);
- if (sav.FileName?.EndsWith(bakName) == true)
- sav.FileName = sav.FileName.Substring(0, sav.FileName.Length - bakName.Length);
- }
-
+
///
/// Gets suggested export options for the save file.
///
diff --git a/PKHeX.Core/Saves/Util/SaveFinder.cs b/PKHeX.Core/Saves/Util/SaveFinder.cs
index 1e72becf7..7c110873d 100644
--- a/PKHeX.Core/Saves/Util/SaveFinder.cs
+++ b/PKHeX.Core/Saves/Util/SaveFinder.cs
@@ -173,7 +173,7 @@ public static bool DetectSaveFile(out string path, out SaveFile? sav, IReadOnlyL
return false;
}
- path = result.FilePath!;
+ path = result.Metadata.FilePath!;
sav = result;
return File.Exists(path);
}
diff --git a/PKHeX.Core/Saves/Util/SaveUtil.cs b/PKHeX.Core/Saves/Util/SaveUtil.cs
index b2c47b7bd..1f02ef0fd 100644
--- a/PKHeX.Core/Saves/Util/SaveUtil.cs
+++ b/PKHeX.Core/Saves/Util/SaveUtil.cs
@@ -487,7 +487,7 @@ private static GameVersion GetIsG8SAV(byte[] data)
var sav = GetVariantSAV(data);
if (sav == null)
return null;
- sav.SetFileInfo(path);
+ sav.Metadata.SetExtraInfo(path);
return sav;
}
@@ -501,8 +501,8 @@ private static GameVersion GetIsG8SAV(byte[] data)
var sav = GetVariantSAVInternal(data);
if (sav == null)
return null;
- sav.Header = header;
- sav.Footer = footer;
+
+ sav.Metadata.SetExtraInfo(header, footer);
return sav;
}
@@ -569,8 +569,8 @@ private static GameVersion GetIsG8SAV(byte[] data)
// No pattern matched
default: return null;
}
- sav.Header = header;
- sav.Footer = footer;
+
+ sav.Metadata.SetExtraInfo(header, footer);
return sav;
}
@@ -780,12 +780,9 @@ private static void CheckHeaderFooter(ref byte[] input, out byte[] header, out b
input = input.SliceEnd(0xA4);
return;
}
- int start = input.Length - FOOTER_DSV.Length;
- for (int i = 0; i < FOOTER_DSV.Length; i++)
- {
- if (FOOTER_DSV[i] != input[start + i])
- return;
- }
+
+ if (!GetHasFooterDSV(input))
+ return;
footer = input.SliceEnd(SIZE_G4RAW);
input = input.Slice(0, SIZE_G4RAW);
@@ -814,6 +811,24 @@ private static void CheckHeaderFooter(ref byte[] input, out byte[] header, out b
static bool IsGameMatchHeader(IEnumerable headers, byte[] data) => headers.Contains(Encoding.ASCII.GetString(data, 0, 4));
}
+ private static bool GetHasFooterDSV(byte[] input)
+ {
+ var signature = FOOTER_DSV;
+ if (!GetHasSignature(input, signature, input.Length - signature.Length))
+ return false;
+ return true;
+ }
+
+ private static bool GetHasSignature(byte[] input, byte[] signature, int start)
+ {
+ for (int i = 0; i < signature.Length; i++)
+ {
+ if (signature[i] != input[start + i])
+ return false;
+ }
+ return true;
+ }
+
///
/// Force loads the provided to the requested .
///
@@ -824,13 +839,13 @@ public static SAV3 GetG3SaveOverride(SaveFile sav, GameVersion ver)
{
return ver switch // Reset save file info
{
- R => new SAV3(sav.BAK, RS),
- S => new SAV3(sav.BAK, RS),
- RS => new SAV3(sav.BAK, RS),
- E => new SAV3(sav.BAK, E),
- FRLG => new SAV3(sav.BAK, FRLG),
- FR => new SAV3(sav.BAK, FRLG),
- LG => new SAV3(sav.BAK, FRLG),
+ R => new SAV3(sav.State.BAK, RS),
+ S => new SAV3(sav.State.BAK, RS),
+ RS => new SAV3(sav.State.BAK, RS),
+ E => new SAV3(sav.State.BAK, E),
+ FRLG => new SAV3(sav.State.BAK, FRLG),
+ FR => new SAV3(sav.State.BAK, FRLG),
+ LG => new SAV3(sav.State.BAK, FRLG),
_ => throw new ArgumentException(nameof(ver))
};
}
diff --git a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs
index fcc0f16ab..92360a2c5 100644
--- a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs
+++ b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs
@@ -456,13 +456,13 @@ private void UpdateStringSeed(object sender, EventArgs e)
{
var value = filterText.PadLeft(SAV.DaycareSeedSize, '0');
SAV.SetDaycareRNGSeed(SAV.DaycareIndex, value);
- SAV.Edited = true;
+ SAV.State.Edited = true;
}
else if (tb == TB_GameSync && SAV is IGameSync sync)
{
var value = filterText.PadLeft(sync.GameSyncIDSize, '0');
sync.GameSyncID = value;
- SAV.Edited = true;
+ SAV.State.Edited = true;
}
else if (SAV is ISecureValueStorage s)
{
@@ -471,7 +471,7 @@ private void UpdateStringSeed(object sender, EventArgs e)
s.TimeStampCurrent = value;
else if (tb == TB_Secure2)
s.TimeStampPrevious = value;
- SAV.Edited = true;
+ SAV.State.Edited = true;
}
}
@@ -728,7 +728,7 @@ private void ClickVerifyCHK(object sender, EventArgs e)
return;
}
- if (SAV.Edited)
+ if (SAV.State.Edited)
{
WinFormsUtil.Alert(MsgSaveChecksumFailEdited);
return;
@@ -775,14 +775,14 @@ public bool ExportSaveFile()
public bool ExportBackup()
{
- if (!SAV.Exportable)
+ if (!SAV.State.Exportable)
return false;
- using var sfd = new SaveFileDialog {FileName = Util.CleanFileName(SAV.BAKName)};
+ using var sfd = new SaveFileDialog {FileName = Util.CleanFileName(SAV.Metadata.BAKName)};
if (sfd.ShowDialog() != DialogResult.OK)
return false;
string path = sfd.FileName;
- File.WriteAllBytes(path, SAV.BAK);
+ File.WriteAllBytes(path, SAV.State.BAK);
WinFormsUtil.Alert(MsgSaveBackup, path);
return true;
@@ -1009,7 +1009,7 @@ private bool ToggleViewBox(SaveFile sav)
private bool ToggleViewParty(SaveFile sav, int BoxTab)
{
- if (!sav.HasParty || !sav.Exportable)
+ if (!sav.HasParty || !sav.State.Exportable)
{
if (tabBoxMulti.TabPages.Contains(Tab_PartyBattle))
tabBoxMulti.TabPages.Remove(Tab_PartyBattle);
@@ -1028,7 +1028,7 @@ private bool ToggleViewParty(SaveFile sav, int BoxTab)
private bool ToggleViewDaycare(SaveFile sav, int BoxTab, int PartyTab)
{
- if ((!sav.HasDaycare && SL_Extra.SlotCount == 0) || !sav.Exportable)
+ if ((!sav.HasDaycare && SL_Extra.SlotCount == 0) || !sav.State.Exportable)
{
if (tabBoxMulti.TabPages.Contains(Tab_Other))
tabBoxMulti.TabPages.Remove(Tab_Other);
@@ -1050,7 +1050,7 @@ private bool ToggleViewDaycare(SaveFile sav, int BoxTab, int PartyTab)
private void ToggleViewSubEditors(SaveFile sav)
{
- if (!sav.Exportable || sav is BulkStorage)
+ if (!sav.State.Exportable || sav is BulkStorage)
{
GB_SAVtools.Visible = false;
B_JPEG.Visible = false;
@@ -1093,7 +1093,7 @@ private void ToggleViewSubEditors(SaveFile sav)
SL_Extra.SAV = sav;
SL_Extra.Initialize(sav.GetExtraSlots(HaX), InitializeDragDrop);
}
- GB_SAVtools.Visible = sav.Exportable && FLP_SAVtools.Controls.OfType().Any(c => c.Enabled);
+ GB_SAVtools.Visible = sav.State.Exportable && FLP_SAVtools.Controls.OfType().Any(c => c.Enabled);
foreach (Control c in FLP_SAVtools.Controls.OfType())
c.Visible = c.Enabled;
var list = FLP_SAVtools.Controls.OfType().ToArray();
@@ -1106,7 +1106,7 @@ private void ToggleViewMisc(SaveFile sav)
{
// Generational Interface
ToggleSecrets(sav, HideSecretDetails);
- B_VerifyCHK.Enabled = SAV.Exportable;
+ B_VerifyCHK.Enabled = SAV.State.Exportable;
if (sav is SAV4BR br)
{
@@ -1138,7 +1138,7 @@ private void ToggleViewMisc(SaveFile sav)
private void ToggleSecrets(SaveFile sav, bool hide)
{
- var shouldShow = sav.Exportable && !hide;
+ var shouldShow = sav.State.Exportable && !hide;
TB_Secure1.Visible = TB_Secure2.Visible = L_Secure1.Visible = L_Secure2.Visible = shouldShow && sav is ISecureValueStorage;
TB_GameSync.Visible = L_GameSync.Visible = shouldShow && sav is IGameSync;
}
diff --git a/PKHeX.WinForms/MainWindow/Main.cs b/PKHeX.WinForms/MainWindow/Main.cs
index fdb2fe058..e0a808369 100644
--- a/PKHeX.WinForms/MainWindow/Main.cs
+++ b/PKHeX.WinForms/MainWindow/Main.cs
@@ -226,7 +226,7 @@ private void LoadBlankSaveFile(GameVersion ver)
if (sav.Version == GameVersion.Invalid) // will fail to load
sav = SaveUtil.GetBlankSAV((GameVersion)GameInfo.VersionDataSource.Max(z => z.Value), tr, lang);
OpenSAV(sav, string.Empty);
- C_SAV!.SAV.Edited = false; // Prevents form close warning from showing until changes are made
+ C_SAV!.SAV.State.Edited = false; // Prevents form close warning from showing until changes are made
}
private void FormLoadCheckForUpdates()
@@ -486,7 +486,7 @@ private void MainMenuFolder(object sender, EventArgs e)
{
if (this.OpenWindowExists())
return;
- var form = new SAV_FolderList(s => OpenSAV(SaveUtil.GetVariantSAV(s.FilePath!), s.FilePath!));
+ var form = new SAV_FolderList(s => OpenSAV(SaveUtil.GetVariantSAV(s.Metadata.FilePath!), s.Metadata.FilePath!));
form.Show();
}
@@ -729,11 +729,11 @@ private bool OpenSAV(SaveFile? sav, string path)
return true;
}
- sav.SetFileInfo(path);
+ sav.Metadata.SetExtraInfo(path);
if (!SanityCheckSAV(ref sav))
return true;
- if (C_SAV.SAV.Edited && Settings.Default.ModifyUnset)
+ if (C_SAV.SAV.State.Edited && Settings.Default.ModifyUnset)
{
var prompt = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgProgramCloseUnsaved, MsgProgramSaveFileConfirm);
if (prompt != DialogResult.Yes)
@@ -747,7 +747,7 @@ private bool OpenSAV(SaveFile? sav, string path)
dragout.Size = new Size(SpriteUtil.Spriter.Width, SpriteUtil.Spriter.Height);
// clean fields
- Menu_ExportSAV.Enabled = sav.Exportable;
+ Menu_ExportSAV.Enabled = sav.State.Exportable;
// No changes made yet
Menu_Undo.Enabled = false;
@@ -807,7 +807,7 @@ private void ResetSAVPKMEditors(SaveFile sav)
PKME_Tabs.FlickerInterface();
foreach (var p in Plugins)
p.NotifySaveLoaded();
- sav.Edited = false;
+ sav.State.Edited = false;
}
private static string GetProgramTitle()
@@ -830,9 +830,9 @@ private static string GetProgramTitle(SaveFile sav)
var ver = GameInfo.GetVersionName(sav.Version);
if (Settings.Default.HideSAVDetails)
return title + $"[{ver}]";
- if (!sav.Exportable) // Blank save file
- return title + $"{sav.FileName} [{sav.OT} ({ver})]";
- return title + Path.GetFileNameWithoutExtension(Util.CleanFileName(sav.BAKName)); // more descriptive
+ if (!sav.State.Exportable) // Blank save file
+ return title + $"{sav.Metadata.FileName} [{sav.OT} ({ver})]";
+ return title + Path.GetFileNameWithoutExtension(Util.CleanFileName(sav.Metadata.BAKName)); // more descriptive
}
private static bool TryBackupExportCheck(SaveFile sav, string path)
@@ -841,9 +841,9 @@ private static bool TryBackupExportCheck(SaveFile sav, string path)
return false;
// If backup folder exists, save a backup.
- string backupName = Path.Combine(BackupPath, Util.CleanFileName(sav.BAKName));
- if (sav.Exportable && Directory.Exists(BackupPath) && !File.Exists(backupName))
- File.WriteAllBytes(backupName, sav.BAK);
+ string backupName = Path.Combine(BackupPath, Util.CleanFileName(sav.Metadata.BAKName));
+ if (sav.State.Exportable && Directory.Exists(BackupPath) && !File.Exists(backupName))
+ File.WriteAllBytes(backupName, sav.State.BAK);
if (!FileUtil.IsFileLocked(path))
return true;
@@ -856,7 +856,7 @@ private static bool SanityCheckSAV(ref SaveFile sav)
{
ParseSettings.InitFromSaveFileData(sav); // physical GB, no longer used in logic
- if (sav.Exportable && sav is SAV3 s3)
+ if (sav.State.Exportable && sav is SAV3 s3)
{
if (s3.IndeterminateGame || ModifierKeys == Keys.Control)
{
@@ -1156,7 +1156,7 @@ private void DragoutDrop(object sender, DragEventArgs e)
private void Main_FormClosing(object sender, FormClosingEventArgs e)
{
- if (C_SAV.SAV.Edited || PKME_Tabs.PKMIsUnsaved)
+ if (C_SAV.SAV.State.Edited || PKME_Tabs.PKMIsUnsaved)
{
var prompt = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgProgramCloseUnsaved, MsgProgramCloseConfirm);
if (prompt != DialogResult.Yes)
diff --git a/PKHeX.WinForms/Subforms/SAV_FolderList.cs b/PKHeX.WinForms/Subforms/SAV_FolderList.cs
index bac14a2ce..d0b6a4ed6 100644
--- a/PKHeX.WinForms/Subforms/SAV_FolderList.cs
+++ b/PKHeX.WinForms/Subforms/SAV_FolderList.cs
@@ -15,7 +15,7 @@ namespace PKHeX.WinForms
public partial class SAV_FolderList : Form
{
private readonly Action OpenSaveFile;
- private readonly List Paths;
+ private readonly List Paths;
private readonly SortableBindingList Recent;
private readonly SortableBindingList Backup;
private readonly List