2016-07-09 22:30:12 +00:00
using System ;
using System.Collections.Generic ;
2017-07-02 02:43:51 +00:00
using System.Diagnostics ;
2017-10-23 18:18:44 +00:00
using System.IO ;
2016-07-09 22:30:12 +00:00
using System.Linq ;
2017-05-12 04:34:18 +00:00
using System.Reflection ;
2016-07-09 22:30:12 +00:00
2017-01-08 07:54:09 +00:00
namespace PKHeX.Core
2016-07-09 22:30:12 +00:00
{
2018-05-12 19:28:48 +00:00
public static partial class Util
2016-07-09 22:30:12 +00:00
{
2017-03-24 17:59:45 +00:00
private const string TranslationSplitter = " = " ;
2017-11-03 03:39:38 +00:00
private static readonly Assembly thisAssembly = typeof ( Util ) . GetTypeInfo ( ) . Assembly ;
private static readonly string [ ] manifestResourceNames = thisAssembly . GetManifestResourceNames ( ) ;
private static readonly Dictionary < string , string > resourceNameMap = new Dictionary < string , string > ( ) ;
private static readonly Dictionary < string , string [ ] > stringListCache = new Dictionary < string , string [ ] > ( ) ;
2017-03-24 17:59:45 +00:00
2019-02-04 04:28:03 +00:00
private static readonly object getStringListLoadLock = new object ( ) ;
2018-11-06 23:25:35 +00:00
2018-05-12 19:28:48 +00:00
#region String Lists
2016-10-06 04:06:24 +00:00
2016-08-08 20:11:02 +00:00
/// <summary>
/// Gets a list of all Pokémon species names.
/// </summary>
/// <param name="language">Language of the Pokémon species names to select (e.g. "en", "fr", "jp", etc.)</param>
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon species name.</returns>
2017-10-12 03:00:18 +00:00
public static string [ ] GetSpeciesList ( string language ) = > GetStringList ( "species" , language ) ;
2016-08-08 20:11:02 +00:00
/// <summary>
/// Gets a list of all move names.
/// </summary>
/// <param name="language">Language of the move names to select (e.g. "en", "fr", "jp", etc.)</param>
/// <returns>An array of strings whose indexes correspond to the IDs of each move name.</returns>
2017-10-12 03:00:18 +00:00
public static string [ ] GetMovesList ( string language ) = > GetStringList ( "moves" , language ) ;
2016-08-08 20:11:02 +00:00
/// <summary>
/// Gets a list of all Pokémon ability names.
/// </summary>
/// <param name="language">Language of the Pokémon ability names to select (e.g. "en", "fr", "jp", etc.)</param>
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon ability name.</returns>
2017-10-12 03:00:18 +00:00
public static string [ ] GetAbilitiesList ( string language ) = > GetStringList ( "abilities" , language ) ;
2016-08-08 20:11:02 +00:00
2016-10-06 04:06:24 +00:00
/// <summary>
/// Gets a list of all Pokémon nature names.
/// </summary>
/// <param name="language">Language of the Pokémon nature names to select (e.g. "en", "fr", "jp", etc.)</param>
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon nature name.</returns>
2017-10-12 03:00:18 +00:00
public static string [ ] GetNaturesList ( string language ) = > GetStringList ( "natures" , language ) ;
2016-10-06 04:06:24 +00:00
/// <summary>
/// Gets a list of all Pokémon form names.
/// </summary>
/// <param name="language">Language of the Pokémon form names to select (e.g. "en", "fr", "jp", etc.)</param>
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon form name.</returns>
2017-10-12 03:00:18 +00:00
public static string [ ] GetFormsList ( string language ) = > GetStringList ( "forms" , language ) ;
2016-10-06 04:06:24 +00:00
/// <summary>
/// Gets a list of all Pokémon type names.
/// </summary>
/// <param name="language">Language of the Pokémon type names to select (e.g. "en", "fr", "jp", etc.)</param>
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon type name.</returns>
2017-10-12 03:00:18 +00:00
public static string [ ] GetTypesList ( string language ) = > GetStringList ( "types" , language ) ;
2016-10-06 04:06:24 +00:00
/// <summary>
/// Gets a list of all Pokémon characteristic.
/// </summary>
/// <param name="language">Language of the Pokémon characteristic to select (e.g. "en", "fr", "jp", etc.)</param>
/// <returns>An array of strings whose indexes correspond to the IDs of each Pokémon characteristic.</returns>
2017-10-12 03:00:18 +00:00
public static string [ ] GetCharacteristicsList ( string language ) = > GetStringList ( "character" , language ) ;
2016-10-06 04:06:24 +00:00
/// <summary>
/// Gets a list of all items.
/// </summary>
/// <param name="language">Language of the items to select (e.g. "en", "fr", "jp", etc.)</param>
/// <returns>An array of strings whose indexes correspond to the IDs of each item.</returns>
2017-10-12 03:00:18 +00:00
public static string [ ] GetItemsList ( string language ) = > GetStringList ( "items" , language ) ;
2016-10-06 04:06:24 +00:00
2019-09-12 05:06:24 +00:00
public static string [ ] [ ] GetLanguageStrings7 ( string fileName )
{
return new [ ]
{
Array . Empty < string > ( ) , // 0 - None
GetStringList ( fileName , "ja" ) , // 1
GetStringList ( fileName , "en" ) , // 2
GetStringList ( fileName , "fr" ) , // 3
GetStringList ( fileName , "it" ) , // 4
GetStringList ( fileName , "de" ) , // 5
Array . Empty < string > ( ) , // 6 - None
GetStringList ( fileName , "es" ) , // 7
} ;
}
public static string [ ] [ ] GetLanguageStrings8 ( string fileName )
{
return new [ ]
{
Array . Empty < string > ( ) , // 0 - None
GetStringList ( fileName , "ja" ) , // 1
GetStringList ( fileName , "en" ) , // 2
GetStringList ( fileName , "fr" ) , // 3
GetStringList ( fileName , "it" ) , // 4
GetStringList ( fileName , "de" ) , // 5
Array . Empty < string > ( ) , // 6 - None
GetStringList ( fileName , "es" ) , // 7
GetStringList ( fileName , "ko" ) , // 8
} ;
}
public static string [ ] [ ] GetLanguageStrings10 ( string fileName )
{
return new [ ]
{
Array . Empty < string > ( ) , // 0 - None
GetStringList ( fileName , "ja" ) , // 1
GetStringList ( fileName , "en" ) , // 2
GetStringList ( fileName , "fr" ) , // 3
GetStringList ( fileName , "it" ) , // 4
GetStringList ( fileName , "de" ) , // 5
Array . Empty < string > ( ) , // 6 - None
GetStringList ( fileName , "es" ) , // 7
GetStringList ( fileName , "ko" ) , // 8
GetStringList ( fileName , "zh" ) , // 9
GetStringList ( fileName , "zh" ) , // 10
} ;
}
2016-10-06 04:06:24 +00:00
#endregion
2020-01-03 23:53:48 +00:00
public static string [ ] GetStringList ( string fileName )
{
if ( IsStringListCached ( fileName , out var result ) )
return result ;
var txt = GetStringResource ( fileName ) ; // Fetch File, \n to list.
return LoadStringList ( fileName , txt ) ;
}
public static bool IsStringListCached ( string fileName , out string [ ] result )
2016-07-09 22:30:12 +00:00
{
2019-03-19 04:34:21 +00:00
lock ( getStringListLoadLock ) // Make sure only one thread can read the cache
2020-01-03 23:53:48 +00:00
return stringListCache . TryGetValue ( fileName , out result ) ;
}
2017-11-02 02:34:01 +00:00
2020-01-03 23:53:48 +00:00
public static string [ ] LoadStringList ( string file , string? txt )
{
2019-02-15 19:47:35 +00:00
if ( txt = = null )
return Array . Empty < string > ( ) ;
2017-09-30 05:58:25 +00:00
string [ ] rawlist = txt . Split ( '\n' ) ;
2016-07-09 22:30:12 +00:00
for ( int i = 0 ; i < rawlist . Length ; i + + )
2018-05-25 04:16:55 +00:00
rawlist [ i ] = rawlist [ i ] . TrimEnd ( '\r' ) ;
2018-11-06 23:25:35 +00:00
lock ( getStringListLoadLock ) // Make sure only one thread can write to the cache
2019-02-02 07:08:03 +00:00
{
2020-01-03 23:53:48 +00:00
if ( ! stringListCache . ContainsKey ( file ) ) // Check cache again in case of race condition
stringListCache . Add ( file , rawlist ) ;
2018-11-06 23:25:35 +00:00
}
2017-11-08 01:12:04 +00:00
return ( string [ ] ) rawlist . Clone ( ) ;
2016-07-09 22:30:12 +00:00
}
2018-07-29 20:27:48 +00:00
2020-01-03 23:53:48 +00:00
public static string [ ] GetStringList ( string fileName , string lang2char , string type = "text" ) = > GetStringList ( $"{type}_{fileName}_{lang2char}" ) ;
2018-07-29 20:27:48 +00:00
2017-06-18 01:37:19 +00:00
public static byte [ ] GetBinaryResource ( string name )
2017-05-12 04:34:18 +00:00
{
2019-10-08 01:40:09 +00:00
using var resource = thisAssembly . GetManifestResourceStream ( $"PKHeX.Core.Resources.byte.{name}" ) ;
var buffer = new byte [ resource . Length ] ;
resource . Read ( buffer , 0 , ( int ) resource . Length ) ;
return buffer ;
2017-10-23 18:18:44 +00:00
}
PKHeX.Core Nullable cleanup (#2401)
* Handle some nullable cases
Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data)
Make some classes have explicit constructors instead of { } initialization
* Handle bits more obviously without null
* Make SaveFile.BAK explicitly readonly again
* merge constructor methods to have readonly fields
* Inline some properties
* More nullable handling
* Rearrange box actions
define straightforward classes to not have any null properties
* Make extrabyte reference array immutable
* Move tooltip creation to designer
* Rearrange some logic to reduce nesting
* Cache generated fonts
* Split mystery gift album purpose
* Handle more tooltips
* Disallow null setters
* Don't capture RNG object, only type enum
* Unify learnset objects
Now have readonly properties which are never null
don't new() empty learnsets (>800 Learnset objects no longer created,
total of 2400 objects since we also new() a move & level array)
optimize g1/2 reader for early abort case
* Access rewrite
Initialize blocks in a separate object, and get via that object
removes a couple hundred "might be null" warnings since blocks are now readonly getters
some block references have been relocated, but interfaces should expose all that's needed
put HoF6 controls in a groupbox, and disable
* Readonly personal data
* IVs non nullable for mystery gift
* Explicitly initialize forced encounter moves
* Make shadow objects readonly & non-null
Put murkrow fix in binary data resource, instead of on startup
* Assign dex form fetch on constructor
Fixes legality parsing edge cases
also handle cxd parse for valid; exit before exception is thrown in FrameGenerator
* Remove unnecessary null checks
* Keep empty value until init
SetPouch sets the value to an actual one during load, but whatever
* Readonly team lock data
* Readonly locks
Put locked encounters at bottom (favor unlocked)
* Mail readonly data / offset
Rearrange some call flow and pass defaults
Add fake classes for SaveDataEditor mocking
Always party size, no need to check twice in stat editor
use a fake save file as initial data for savedata editor, and for
gamedata (wow i found a usage)
constrain eventwork editor to struct variable types (uint, int, etc),
thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
public static string? GetStringResource ( string name )
2017-10-23 18:18:44 +00:00
{
2019-09-11 05:07:50 +00:00
if ( ! resourceNameMap . TryGetValue ( name , out var resname ) )
2018-05-12 19:28:48 +00:00
{
bool Match ( string x ) = > x . StartsWith ( "PKHeX.Core.Resources.text." ) & & x . EndsWith ( $"{name}.txt" , StringComparison . OrdinalIgnoreCase ) ;
2019-09-11 05:07:50 +00:00
resname = Array . Find ( manifestResourceNames , Match ) ;
if ( resname = = null )
return null ;
2018-05-12 19:28:48 +00:00
resourceNameMap . Add ( name , resname ) ;
}
2017-11-02 02:44:35 +00:00
2019-10-08 01:40:09 +00:00
using var resource = thisAssembly . GetManifestResourceStream ( resname ) ;
PKHeX.Core Nullable cleanup (#2401)
* Handle some nullable cases
Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data)
Make some classes have explicit constructors instead of { } initialization
* Handle bits more obviously without null
* Make SaveFile.BAK explicitly readonly again
* merge constructor methods to have readonly fields
* Inline some properties
* More nullable handling
* Rearrange box actions
define straightforward classes to not have any null properties
* Make extrabyte reference array immutable
* Move tooltip creation to designer
* Rearrange some logic to reduce nesting
* Cache generated fonts
* Split mystery gift album purpose
* Handle more tooltips
* Disallow null setters
* Don't capture RNG object, only type enum
* Unify learnset objects
Now have readonly properties which are never null
don't new() empty learnsets (>800 Learnset objects no longer created,
total of 2400 objects since we also new() a move & level array)
optimize g1/2 reader for early abort case
* Access rewrite
Initialize blocks in a separate object, and get via that object
removes a couple hundred "might be null" warnings since blocks are now readonly getters
some block references have been relocated, but interfaces should expose all that's needed
put HoF6 controls in a groupbox, and disable
* Readonly personal data
* IVs non nullable for mystery gift
* Explicitly initialize forced encounter moves
* Make shadow objects readonly & non-null
Put murkrow fix in binary data resource, instead of on startup
* Assign dex form fetch on constructor
Fixes legality parsing edge cases
also handle cxd parse for valid; exit before exception is thrown in FrameGenerator
* Remove unnecessary null checks
* Keep empty value until init
SetPouch sets the value to an actual one during load, but whatever
* Readonly team lock data
* Readonly locks
Put locked encounters at bottom (favor unlocked)
* Mail readonly data / offset
Rearrange some call flow and pass defaults
Add fake classes for SaveDataEditor mocking
Always party size, no need to check twice in stat editor
use a fake save file as initial data for savedata editor, and for
gamedata (wow i found a usage)
constrain eventwork editor to struct variable types (uint, int, etc),
thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
if ( resource = = null )
return null ;
2019-10-08 01:40:09 +00:00
using var reader = new StreamReader ( resource ) ;
return reader . ReadToEnd ( ) ;
2017-05-12 04:34:18 +00:00
}
2017-03-25 01:23:39 +00:00
#region Non - Form Translation
2017-03-24 17:59:45 +00:00
/// <summary>
/// Gets the names of the properties defined in the given input
/// </summary>
/// <param name="input">Enumerable of translation definitions in the form "Property = Value".</param>
2017-06-18 01:37:19 +00:00
private static string [ ] GetProperties ( IEnumerable < string > input )
2017-03-24 17:59:45 +00:00
{
return input . Select ( l = > l . Substring ( 0 , l . IndexOf ( TranslationSplitter , StringComparison . Ordinal ) ) ) . ToArray ( ) ;
}
private static IEnumerable < string > DumpStrings ( Type t )
{
2019-02-08 05:40:20 +00:00
var props = ReflectUtil . GetPropertiesStartWithPrefix ( t , string . Empty ) ;
2018-05-12 19:28:48 +00:00
return props . Select ( p = > $"{p}{TranslationSplitter}{ReflectUtil.GetValue(t, p)}" ) ;
2017-03-24 17:59:45 +00:00
}
PKHeX.Core Nullable cleanup (#2401)
* Handle some nullable cases
Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data)
Make some classes have explicit constructors instead of { } initialization
* Handle bits more obviously without null
* Make SaveFile.BAK explicitly readonly again
* merge constructor methods to have readonly fields
* Inline some properties
* More nullable handling
* Rearrange box actions
define straightforward classes to not have any null properties
* Make extrabyte reference array immutable
* Move tooltip creation to designer
* Rearrange some logic to reduce nesting
* Cache generated fonts
* Split mystery gift album purpose
* Handle more tooltips
* Disallow null setters
* Don't capture RNG object, only type enum
* Unify learnset objects
Now have readonly properties which are never null
don't new() empty learnsets (>800 Learnset objects no longer created,
total of 2400 objects since we also new() a move & level array)
optimize g1/2 reader for early abort case
* Access rewrite
Initialize blocks in a separate object, and get via that object
removes a couple hundred "might be null" warnings since blocks are now readonly getters
some block references have been relocated, but interfaces should expose all that's needed
put HoF6 controls in a groupbox, and disable
* Readonly personal data
* IVs non nullable for mystery gift
* Explicitly initialize forced encounter moves
* Make shadow objects readonly & non-null
Put murkrow fix in binary data resource, instead of on startup
* Assign dex form fetch on constructor
Fixes legality parsing edge cases
also handle cxd parse for valid; exit before exception is thrown in FrameGenerator
* Remove unnecessary null checks
* Keep empty value until init
SetPouch sets the value to an actual one during load, but whatever
* Readonly team lock data
* Readonly locks
Put locked encounters at bottom (favor unlocked)
* Mail readonly data / offset
Rearrange some call flow and pass defaults
Add fake classes for SaveDataEditor mocking
Always party size, no need to check twice in stat editor
use a fake save file as initial data for savedata editor, and for
gamedata (wow i found a usage)
constrain eventwork editor to struct variable types (uint, int, etc),
thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
/// <summary>
/// Gets the current localization in a static class containing language-specific strings
/// </summary>
/// <param name="t"></param>
public static string [ ] GetLocalization ( Type t ) = > DumpStrings ( t ) . ToArray ( ) ;
2017-03-24 17:59:45 +00:00
/// <summary>
/// Gets the current localization in a static class containing language-specific strings
/// </summary>
2018-05-12 19:28:48 +00:00
/// <param name="t"></param>
/// <param name="existingLines">Existing localization lines (if provided)</param>
PKHeX.Core Nullable cleanup (#2401)
* Handle some nullable cases
Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data)
Make some classes have explicit constructors instead of { } initialization
* Handle bits more obviously without null
* Make SaveFile.BAK explicitly readonly again
* merge constructor methods to have readonly fields
* Inline some properties
* More nullable handling
* Rearrange box actions
define straightforward classes to not have any null properties
* Make extrabyte reference array immutable
* Move tooltip creation to designer
* Rearrange some logic to reduce nesting
* Cache generated fonts
* Split mystery gift album purpose
* Handle more tooltips
* Disallow null setters
* Don't capture RNG object, only type enum
* Unify learnset objects
Now have readonly properties which are never null
don't new() empty learnsets (>800 Learnset objects no longer created,
total of 2400 objects since we also new() a move & level array)
optimize g1/2 reader for early abort case
* Access rewrite
Initialize blocks in a separate object, and get via that object
removes a couple hundred "might be null" warnings since blocks are now readonly getters
some block references have been relocated, but interfaces should expose all that's needed
put HoF6 controls in a groupbox, and disable
* Readonly personal data
* IVs non nullable for mystery gift
* Explicitly initialize forced encounter moves
* Make shadow objects readonly & non-null
Put murkrow fix in binary data resource, instead of on startup
* Assign dex form fetch on constructor
Fixes legality parsing edge cases
also handle cxd parse for valid; exit before exception is thrown in FrameGenerator
* Remove unnecessary null checks
* Keep empty value until init
SetPouch sets the value to an actual one during load, but whatever
* Readonly team lock data
* Readonly locks
Put locked encounters at bottom (favor unlocked)
* Mail readonly data / offset
Rearrange some call flow and pass defaults
Add fake classes for SaveDataEditor mocking
Always party size, no need to check twice in stat editor
use a fake save file as initial data for savedata editor, and for
gamedata (wow i found a usage)
constrain eventwork editor to struct variable types (uint, int, etc),
thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
public static string [ ] GetLocalization ( Type t , string [ ] existingLines )
2017-03-24 17:59:45 +00:00
{
PKHeX.Core Nullable cleanup (#2401)
* Handle some nullable cases
Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data)
Make some classes have explicit constructors instead of { } initialization
* Handle bits more obviously without null
* Make SaveFile.BAK explicitly readonly again
* merge constructor methods to have readonly fields
* Inline some properties
* More nullable handling
* Rearrange box actions
define straightforward classes to not have any null properties
* Make extrabyte reference array immutable
* Move tooltip creation to designer
* Rearrange some logic to reduce nesting
* Cache generated fonts
* Split mystery gift album purpose
* Handle more tooltips
* Disallow null setters
* Don't capture RNG object, only type enum
* Unify learnset objects
Now have readonly properties which are never null
don't new() empty learnsets (>800 Learnset objects no longer created,
total of 2400 objects since we also new() a move & level array)
optimize g1/2 reader for early abort case
* Access rewrite
Initialize blocks in a separate object, and get via that object
removes a couple hundred "might be null" warnings since blocks are now readonly getters
some block references have been relocated, but interfaces should expose all that's needed
put HoF6 controls in a groupbox, and disable
* Readonly personal data
* IVs non nullable for mystery gift
* Explicitly initialize forced encounter moves
* Make shadow objects readonly & non-null
Put murkrow fix in binary data resource, instead of on startup
* Assign dex form fetch on constructor
Fixes legality parsing edge cases
also handle cxd parse for valid; exit before exception is thrown in FrameGenerator
* Remove unnecessary null checks
* Keep empty value until init
SetPouch sets the value to an actual one during load, but whatever
* Readonly team lock data
* Readonly locks
Put locked encounters at bottom (favor unlocked)
* Mail readonly data / offset
Rearrange some call flow and pass defaults
Add fake classes for SaveDataEditor mocking
Always party size, no need to check twice in stat editor
use a fake save file as initial data for savedata editor, and for
gamedata (wow i found a usage)
constrain eventwork editor to struct variable types (uint, int, etc),
thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
var currentLines = GetLocalization ( t ) ;
2017-06-18 01:37:19 +00:00
var existing = GetProperties ( existingLines ) ;
var current = GetProperties ( currentLines ) ;
2017-03-24 17:59:45 +00:00
var result = new string [ currentLines . Length ] ;
for ( int i = 0 ; i < current . Length ; i + + )
{
int index = Array . IndexOf ( existing , current [ i ] ) ;
result [ i ] = index < 0 ? currentLines [ i ] : existingLines [ index ] ;
}
return result ;
}
/// <summary>
/// Applies localization to a static class containing language-specific strings.
/// </summary>
2017-03-25 01:23:39 +00:00
/// <param name="t">Type of the static class containing the desired strings.</param>
2017-03-24 17:59:45 +00:00
/// <param name="lines">Lines containing the localized strings</param>
2017-06-18 01:37:19 +00:00
private static void SetLocalization ( Type t , IEnumerable < string > lines )
2018-05-12 15:13:39 +00:00
{
2017-03-24 17:59:45 +00:00
if ( lines = = null )
return ;
foreach ( var line in lines . Where ( l = > l ! = null ) )
{
var index = line . IndexOf ( TranslationSplitter , StringComparison . Ordinal ) ;
if ( index < 0 )
continue ;
var prop = line . Substring ( 0 , index ) ;
var value = line . Substring ( index + TranslationSplitter . Length ) ;
try
{
2018-04-08 16:19:19 +00:00
ReflectUtil . SetValue ( t , prop , value ) ;
2017-03-24 17:59:45 +00:00
}
2019-02-15 19:47:35 +00:00
catch ( Exception e )
2017-03-24 17:59:45 +00:00
{
2017-07-02 02:43:51 +00:00
Debug . WriteLine ( $"Property not present: {prop} || Value written: {value}" ) ;
2019-02-15 19:47:35 +00:00
Debug . WriteLine ( e . Message ) ;
2017-03-24 17:59:45 +00:00
}
}
}
/// <summary>
/// Applies localization to a static class containing language-specific strings.
/// </summary>
2017-03-25 01:23:39 +00:00
/// <param name="t">Type of the static class containing the desired strings.</param>
2017-03-24 17:59:45 +00:00
/// <param name="languageFilePrefix">Prefix of the language file to use. Example: if the target is legality_en.txt, <paramref name="languageFilePrefix"/> should be "legality".</param>
2017-05-12 16:33:12 +00:00
/// <param name="currentCultureCode">Culture information</param>
2017-06-18 01:37:19 +00:00
private static void SetLocalization ( Type t , string languageFilePrefix , string currentCultureCode )
2017-03-24 17:59:45 +00:00
{
2017-06-18 01:37:19 +00:00
SetLocalization ( t , GetStringList ( $"{languageFilePrefix}_{currentCultureCode}" ) ) ;
2017-03-24 17:59:45 +00:00
}
/// <summary>
/// Applies localization to a static class containing language-specific strings.
/// </summary>
2017-03-25 01:23:39 +00:00
/// <param name="t">Type of the static class containing the desired strings.</param>
2017-03-24 17:59:45 +00:00
/// <remarks>The values used to translate the given static class are retrieved from [TypeName]_[CurrentLangCode2].txt in the resource manager of PKHeX.Core.</remarks>
2017-05-12 16:33:12 +00:00
/// <param name="currentCultureCode">Culture information</param>
2017-06-18 01:37:19 +00:00
public static void SetLocalization ( Type t , string currentCultureCode )
2017-03-24 17:59:45 +00:00
{
2017-06-18 01:37:19 +00:00
SetLocalization ( t , t . Name , currentCultureCode ) ;
2017-03-24 17:59:45 +00:00
}
2017-03-25 01:23:39 +00:00
#endregion
2017-03-24 17:59:45 +00:00
2016-10-06 04:06:24 +00:00
#region DataSource Providing
2019-04-30 04:55:43 +00:00
2019-06-22 17:50:32 +00:00
private static readonly string [ ] CountryRegionLanguages = { "ja" , "en" , "fr" , "de" , "it" , "es" , "zh" , "ko" } ;
2019-04-30 04:55:43 +00:00
2019-02-15 19:47:35 +00:00
public static List < ComboItem > GetCountryRegionList ( string textfile , string lang )
2016-07-09 22:30:12 +00:00
{
2017-06-18 01:37:19 +00:00
string [ ] inputCSV = GetStringList ( textfile ) ;
2019-04-30 04:55:43 +00:00
int index = Array . IndexOf ( CountryRegionLanguages , lang ) ;
return GetCBListCSVSorted ( inputCSV , index ) ;
}
2016-07-09 22:30:12 +00:00
2019-04-30 04:55:43 +00:00
private static List < ComboItem > GetCBListCSVSorted ( string [ ] inputCSV , int index = 0 )
{
var list = GetCBListFromCSV ( inputCSV , index ) ;
list . Sort ( Comparer ) ;
return list ;
2017-09-30 08:07:30 +00:00
}
2018-07-29 20:27:48 +00:00
2019-04-30 04:55:43 +00:00
public static List < ComboItem > GetCSVUnsortedCBList ( string textfile )
2017-09-30 08:07:30 +00:00
{
string [ ] inputCSV = GetStringList ( textfile ) ;
2019-04-30 04:55:43 +00:00
return GetCBListFromCSV ( inputCSV , 0 ) ;
}
private static List < ComboItem > GetCBListFromCSV ( IReadOnlyList < string > inputCSV , int index )
{
var arr = new List < ComboItem > ( inputCSV . Count - 1 ) ; // skip header
index + + ;
for ( int i = 1 ; i < inputCSV . Count ; i + + )
{
var line = inputCSV [ i ] ;
var zeroth = line . IndexOf ( ',' ) ;
var val = line . Substring ( 0 , zeroth ) ;
2020-01-02 03:07:21 +00:00
var text = StringUtil . GetNthEntry ( line , index , zeroth ) ;
2019-06-02 02:12:41 +00:00
var item = new ComboItem ( text , Convert . ToInt32 ( val ) ) ;
2019-04-30 04:55:43 +00:00
arr . Add ( item ) ;
}
return arr ;
}
2019-03-19 04:55:33 +00:00
public static List < ComboItem > GetCBList ( IReadOnlyList < string > inStrings )
2019-11-19 16:48:44 +00:00
{
var list = GetCBListUnsorted ( inStrings ) ;
list . Sort ( Comparer ) ;
return list ;
}
public static List < ComboItem > GetCBListUnsorted ( IReadOnlyList < string > inStrings )
2016-07-09 22:30:12 +00:00
{
2019-03-19 04:55:33 +00:00
var list = new List < ComboItem > ( inStrings . Count ) ;
2019-04-30 04:55:43 +00:00
for ( int i = 0 ; i < inStrings . Count ; i + + )
2019-06-02 02:12:41 +00:00
list . Add ( new ComboItem ( inStrings [ i ] , i ) ) ;
2019-04-30 04:55:43 +00:00
return list ;
}
public static List < ComboItem > GetCBList ( IReadOnlyList < string > inStrings , int index , int offset = 0 )
{
var list = new List < ComboItem > ( ) ;
AddCBWithOffset ( list , inStrings , offset , index ) ;
2019-03-19 04:55:33 +00:00
return list ;
}
2016-07-09 22:30:12 +00:00
2019-03-19 04:55:33 +00:00
public static List < ComboItem > GetCBList ( IReadOnlyList < string > inStrings , params int [ ] [ ] allowed )
{
var count = allowed . Sum ( z = > z . Length ) ;
var list = new List < ComboItem > ( count ) ;
foreach ( var arr in allowed )
2019-04-30 04:55:43 +00:00
AddCB ( list , inStrings , arr ) ;
2019-03-19 04:55:33 +00:00
return list ;
2016-07-09 22:30:12 +00:00
}
2018-07-29 20:27:48 +00:00
2019-04-30 04:55:43 +00:00
public static void AddCBWithOffset ( List < ComboItem > list , IReadOnlyList < string > inStrings , int offset , int index )
2016-07-09 22:30:12 +00:00
{
2019-06-02 02:12:41 +00:00
var item = new ComboItem ( inStrings [ index - offset ] , index ) ;
2019-04-30 04:55:43 +00:00
list . Add ( item ) ;
}
2016-07-09 22:30:12 +00:00
2019-04-30 04:55:43 +00:00
public static void AddCBWithOffset ( List < ComboItem > cbList , IReadOnlyList < string > inStrings , int offset , params int [ ] allowed )
{
int beginCount = cbList . Count ;
2019-09-11 05:07:50 +00:00
foreach ( var index in allowed )
2019-04-30 04:55:43 +00:00
{
2019-06-02 02:12:41 +00:00
var item = new ComboItem ( inStrings [ index - offset ] , index ) ;
2019-04-30 04:55:43 +00:00
cbList . Add ( item ) ;
}
cbList . Sort ( beginCount , allowed . Length , Comparer ) ;
}
public static void AddCB ( List < ComboItem > cbList , IReadOnlyList < string > inStrings , int [ ] allowed )
{
int beginCount = cbList . Count ;
2019-09-11 05:07:50 +00:00
foreach ( var index in allowed )
2019-04-30 04:55:43 +00:00
{
2019-06-02 02:12:41 +00:00
var item = new ComboItem ( inStrings [ index ] , index ) ;
2019-04-30 04:55:43 +00:00
cbList . Add ( item ) ;
}
cbList . Sort ( beginCount , allowed . Length , Comparer ) ;
2016-07-09 22:30:12 +00:00
}
2018-07-29 20:27:48 +00:00
2017-09-30 08:07:30 +00:00
public static List < ComboItem > GetVariedCBListBall ( string [ ] inStrings , int [ ] stringNum , int [ ] stringVal )
2016-07-09 22:30:12 +00:00
{
2019-04-30 04:55:43 +00:00
const int forcedTop = 3 ; // 3 Balls are preferentially first
var list = new List < ComboItem > ( forcedTop + stringNum . Length )
2018-09-02 02:55:08 +00:00
{
2019-06-02 02:12:41 +00:00
new ComboItem ( inStrings [ 4 ] , ( int ) Ball . Poke ) ,
new ComboItem ( inStrings [ 3 ] , ( int ) Ball . Great ) ,
new ComboItem ( inStrings [ 2 ] , ( int ) Ball . Ultra ) ,
2018-09-02 02:55:08 +00:00
} ;
2016-07-09 22:30:12 +00:00
2019-04-30 04:55:43 +00:00
for ( int i = 0 ; i < stringNum . Length ; i + + )
{
int index = stringNum [ i ] ;
var val = stringVal [ i ] ;
var txt = inStrings [ index ] ;
2019-06-02 02:12:41 +00:00
list . Add ( new ComboItem ( txt , val ) ) ;
2019-04-30 04:55:43 +00:00
}
list . Sort ( forcedTop , stringNum . Length , Comparer ) ;
return list
;
}
private static readonly FunctorComparer < ComboItem > Comparer =
2019-06-02 02:12:41 +00:00
new FunctorComparer < ComboItem > ( ( a , b ) = > string . CompareOrdinal ( a . Text , b . Text ) ) ;
2019-04-30 04:55:43 +00:00
private sealed class FunctorComparer < T > : IComparer < T >
{
private readonly Comparison < T > Comparison ;
public FunctorComparer ( Comparison < T > comparison ) = > Comparison = comparison ;
public int Compare ( T x , T y ) = > Comparison ( x , y ) ;
2016-07-09 22:30:12 +00:00
}
2016-10-06 04:06:24 +00:00
#endregion
2016-07-09 22:30:12 +00:00
}
}