2022-08-05 23:18:42 +00:00
using System.Collections.Generic ;
2017-02-04 22:58:30 +00:00
using System.IO ;
using System.Linq ;
2018-07-21 04:32:33 +00:00
2018-04-07 04:23:09 +00:00
using static PKHeX . Core . MessageStrings ;
2017-02-04 22:58:30 +00:00
2022-06-18 18:04:24 +00:00
namespace PKHeX.Core ;
/// <summary>
/// Contains extension methods for use with a <see cref="SaveFile"/>.
/// </summary>
public static class BoxUtil
2017-02-04 22:58:30 +00:00
{
/// <summary>
2022-06-18 18:04:24 +00:00
/// Dumps a folder of files to the <see cref="SaveFile"/>.
2017-02-04 22:58:30 +00:00
/// </summary>
2022-06-18 18:04:24 +00:00
/// <param name="sav"><see cref="SaveFile"/> that is being dumped from.</param>
/// <param name="path">Folder to store <see cref="PKM"/> files.</param>
/// <param name="boxFolders">Option to save in child folders with the Box Name as the folder name.</param>
/// <returns>-1 if aborted, otherwise the amount of files dumped.</returns>
public static int DumpBoxes ( this SaveFile sav , string path , bool boxFolders = false )
2017-02-04 22:58:30 +00:00
{
2022-06-18 18:04:24 +00:00
if ( ! sav . HasBox )
return - 1 ;
2017-02-04 22:58:30 +00:00
2022-06-18 18:04:24 +00:00
var boxData = sav . BoxData ;
int boxSlotCount = sav . BoxSlotCount ;
var ctr = 0 ;
for ( var slot = 0 ; slot < boxData . Count ; slot + + )
2017-03-21 07:21:03 +00:00
{
2022-06-18 18:04:24 +00:00
var pk = boxData [ slot ] ;
var box = slot / boxSlotCount ;
if ( pk . Species = = 0 | | ! pk . Valid )
continue ;
2017-03-21 07:21:03 +00:00
2022-06-18 18:04:24 +00:00
var boxFolder = path ;
if ( boxFolders )
2017-03-21 07:21:03 +00:00
{
2022-06-18 18:04:24 +00:00
var boxName = Util . CleanFileName ( sav . GetBoxName ( box ) ) ;
boxFolder = Path . Combine ( path , boxName ) ;
Directory . CreateDirectory ( boxFolder ) ;
}
2017-03-21 07:21:03 +00:00
2022-06-18 18:04:24 +00:00
var fileName = Util . CleanFileName ( pk . FileName ) ;
var fn = Path . Combine ( boxFolder , fileName ) ;
if ( File . Exists ( fn ) )
continue ;
2019-02-23 22:58:48 +00:00
2022-06-18 18:04:24 +00:00
File . WriteAllBytes ( fn , pk . DecryptedPartyData ) ;
ctr + + ;
2017-03-21 07:21:03 +00:00
}
2022-06-18 18:04:24 +00:00
return ctr ;
}
2017-03-21 07:21:03 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Dumps the <see cref="SaveFile.BoxData"/> to a folder with individual decrypted files.
/// </summary>
/// <param name="sav"><see cref="SaveFile"/> that is being dumped from.</param>
/// <param name="path">Folder to store <see cref="PKM"/> files.</param>
/// <param name="currentBox">Box contents to be dumped.</param>
/// <returns>-1 if aborted, otherwise the amount of files dumped.</returns>
public static int DumpBox ( this SaveFile sav , string path , int currentBox )
{
if ( ! sav . HasBox )
return - 1 ;
var boxData = sav . BoxData ;
int boxSlotCount = sav . BoxSlotCount ;
var ctr = 0 ;
for ( var slot = 0 ; slot < boxData . Count ; slot + + )
2017-02-04 22:58:30 +00:00
{
2022-06-18 18:04:24 +00:00
var pk = boxData [ slot ] ;
var box = slot / boxSlotCount ;
if ( pk . Species = = 0 | | ! pk . Valid | | box ! = currentBox )
continue ;
2018-02-01 07:37:01 +00:00
2022-06-18 18:04:24 +00:00
var fileName = Path . Combine ( path , Util . CleanFileName ( pk . FileName ) ) ;
if ( File . Exists ( fileName ) )
continue ;
2018-07-29 20:27:48 +00:00
2022-06-18 18:04:24 +00:00
File . WriteAllBytes ( fileName , pk . DecryptedPartyData ) ;
ctr + + ;
2018-02-01 07:37:01 +00:00
}
2022-06-18 18:04:24 +00:00
return ctr ;
}
2018-07-29 20:27:48 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Loads a folder of files to the <see cref="SaveFile"/>.
/// </summary>
/// <param name="sav"><see cref="SaveFile"/> to load folder to.</param>
/// <param name="path">Folder to load <see cref="PKM"/> files from. Files are only loaded from the top directory.</param>
/// <param name="result">Result message from the method.</param>
/// <param name="boxStart">First box to start loading to. All prior boxes are not modified.</param>
/// <param name="boxClear">Instruction to clear boxes after the starting box.</param>
/// <param name="overwrite">Overwrite existing full slots. If true, will only overwrite empty slots.</param>
/// <param name="noSetb">Bypass option to not modify <see cref="PKM"/> properties when setting to Save File.</param>
/// <param name="all">Enumerate all files even in sub-folders.</param>
/// <returns>Count of files imported.</returns>
public static int LoadBoxes ( this SaveFile sav , string path , out string result , int boxStart = 0 , bool boxClear = false , bool overwrite = false , PKMImportSetting noSetb = PKMImportSetting . UseDefault , bool all = false )
{
if ( string . IsNullOrWhiteSpace ( path ) | | ! Directory . Exists ( path ) )
{ result = MsgSaveBoxExportPathInvalid ; return - 1 ; }
2018-07-29 20:27:48 +00:00
2022-06-18 18:04:24 +00:00
var option = all ? SearchOption . AllDirectories : SearchOption . TopDirectoryOnly ;
var files = Directory . EnumerateFiles ( path , "*.*" , option ) ;
return sav . LoadBoxes ( files , out result , boxStart , boxClear , overwrite , noSetb ) ;
}
2018-02-01 07:37:01 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Loads a folder of files to the <see cref="SaveFile"/>.
/// </summary>
/// <param name="sav"><see cref="SaveFile"/> to load folder to.</param>
/// <param name="files">Files to load <see cref="PKM"/> files from.</param>
/// <param name="result">Result message from the method.</param>
/// <param name="boxStart">First box to start loading to. All prior boxes are not modified.</param>
/// <param name="boxClear">Instruction to clear boxes after the starting box.</param>
/// <param name="overwrite">Overwrite existing full slots. If true, will only overwrite empty slots.</param>
/// <param name="noSetb">Bypass option to not modify <see cref="PKM"/> properties when setting to Save File.</param>
/// <returns>Count of files imported.</returns>
public static int LoadBoxes ( this SaveFile sav , IEnumerable < string > files , out string result , int boxStart = 0 , bool boxClear = false , bool overwrite = false , PKMImportSetting noSetb = PKMImportSetting . UseDefault )
{
var pks = GetPossiblePKMsFromPaths ( sav , files ) ;
return sav . LoadBoxes ( pks , out result , boxStart , boxClear , overwrite , noSetb ) ;
}
2017-02-04 22:58:30 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Loads a folder of files to the <see cref="SaveFile"/>.
/// </summary>
/// <param name="sav"><see cref="SaveFile"/> to load folder to.</param>
/// <param name="encounters">Encounters to create <see cref="PKM"/> files from.</param>
/// <param name="result">Result message from the method.</param>
/// <param name="boxStart">First box to start loading to. All prior boxes are not modified.</param>
/// <param name="boxClear">Instruction to clear boxes after the starting box.</param>
/// <param name="overwrite">Overwrite existing full slots. If true, will only overwrite empty slots.</param>
/// <param name="noSetb">Bypass option to not modify <see cref="PKM"/> properties when setting to Save File.</param>
/// <returns>Count of files imported.</returns>
public static int LoadBoxes ( this SaveFile sav , IEnumerable < IEncounterConvertible > encounters , out string result , int boxStart = 0 , bool boxClear = false , bool overwrite = false , PKMImportSetting noSetb = PKMImportSetting . UseDefault )
{
var pks = encounters . Select ( z = > z . ConvertToPKM ( sav ) ) ;
return sav . LoadBoxes ( pks , out result , boxStart , boxClear , overwrite , noSetb ) ;
}
2017-02-04 22:58:30 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Loads a folder of files to the <see cref="SaveFile"/>.
/// </summary>
/// <param name="sav"><see cref="SaveFile"/> to load folder to.</param>
/// <param name="pks">Unconverted <see cref="PKM"/> objects to load.</param>
/// <param name="result">Result message from the method.</param>
/// <param name="boxStart">First box to start loading to. All prior boxes are not modified.</param>
/// <param name="boxClear">Instruction to clear boxes after the starting box.</param>
/// <param name="overwrite">Overwrite existing full slots. If true, will only overwrite empty slots.</param>
/// <param name="noSetb">Bypass option to not modify <see cref="PKM"/> properties when setting to Save File.</param>
/// <returns>True if any files are imported.</returns>
public static int LoadBoxes ( this SaveFile sav , IEnumerable < PKM > pks , out string result , int boxStart = 0 , bool boxClear = false , bool overwrite = false , PKMImportSetting noSetb = PKMImportSetting . UseDefault )
{
if ( ! sav . HasBox )
{ result = MsgSaveBoxFailNone ; return - 1 ; }
var compat = sav . GetCompatible ( pks ) ;
if ( boxClear )
sav . ClearBoxes ( boxStart ) ;
2017-02-04 22:58:30 +00:00
2022-06-18 18:04:24 +00:00
int ctr = sav . ImportPKMs ( compat , overwrite , boxStart , noSetb ) ;
if ( ctr < = 0 )
2018-02-01 07:37:01 +00:00
{
2022-06-18 18:04:24 +00:00
result = MsgSaveBoxImportNoFiles ;
return - 1 ;
2018-02-01 07:37:01 +00:00
}
2018-11-23 20:22:51 +00:00
2022-06-18 18:04:24 +00:00
result = string . Format ( MsgSaveBoxImportSuccess , ctr ) ;
return ctr ;
}
public static IEnumerable < PKM > GetPKMsFromPaths ( IEnumerable < string > files , EntityContext generation )
{
foreach ( var f in files )
2018-11-23 20:22:51 +00:00
{
2022-06-18 18:04:24 +00:00
var fi = new FileInfo ( f ) ;
if ( ! fi . Exists )
continue ;
if ( ! EntityDetection . IsSizePlausible ( fi . Length ) )
continue ;
var data = File . ReadAllBytes ( f ) ;
var prefer = EntityFileExtension . GetContextFromExtension ( fi . Extension , generation ) ;
var pk = EntityFormat . GetFromBytes ( data , prefer ) ;
if ( pk ? . Species is > 0 )
yield return pk ;
2018-11-23 20:22:51 +00:00
}
2022-06-18 18:04:24 +00:00
}
2020-09-19 05:11:13 +00:00
2022-06-18 18:04:24 +00:00
private static IEnumerable < PKM > GetPossiblePKMsFromPaths ( SaveFile sav , IEnumerable < string > files )
{
foreach ( var f in files )
2020-09-19 05:11:13 +00:00
{
2022-06-18 18:04:24 +00:00
var obj = FileUtil . GetSupportedFile ( f , sav ) ;
switch ( obj )
2020-09-19 05:11:13 +00:00
{
2022-06-18 18:04:24 +00:00
case PKM pk :
yield return pk ;
break ;
case MysteryGift { IsEntity : true } g :
yield return g . ConvertToPKM ( sav ) ;
break ;
2022-08-05 23:18:42 +00:00
case IEncounterInfo g when g . Species ! = 0 :
yield return g . ConvertToPKM ( sav ) ;
2022-06-18 18:04:24 +00:00
break ;
case IPokeGroup g :
foreach ( var p in g . Contents )
yield return p ;
break ;
2022-08-05 23:18:42 +00:00
case IEnumerable < PKM > contents :
foreach ( var pk in contents )
yield return pk ;
break ;
2020-09-19 05:11:13 +00:00
}
2022-06-18 18:04:24 +00:00
}
}
2020-09-19 05:11:13 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Gets box names for all boxes in the save file.
/// </summary>
/// <param name="sav"><see cref="SaveFile"/> that box names are being dumped for.</param>
/// <returns>Returns default English box names in the event the save file does not have names (not exportable), or fails to return a box name.</returns>
public static string [ ] GetBoxNames ( SaveFile sav )
{
int count = sav . BoxCount ;
var result = new string [ count ] ;
if ( ! sav . State . Exportable )
{
2020-09-19 05:11:13 +00:00
for ( int i = 0 ; i < count ; i + + )
2022-06-18 18:04:24 +00:00
result [ i ] = $"Box {i + 1}" ;
2020-09-19 05:11:13 +00:00
return result ;
}
2022-06-18 18:04:24 +00:00
for ( int i = 0 ; i < count ; i + + )
{
try { result [ i ] = sav . GetBoxName ( i ) ; }
catch { result [ i ] = $"Box {i + 1}" ; }
}
return result ;
2017-02-04 22:58:30 +00:00
}
}