2023-08-12 23:01:16 +00:00
//#define SUPPRESS
2017-07-18 23:21:31 +00:00
using System ;
2016-03-25 07:10:11 +00:00
using System.Collections.Generic ;
2020-11-27 20:00:49 +00:00
using static PKHeX . Core . LegalityAnalyzers ;
2020-11-28 02:45:06 +00:00
using static PKHeX . Core . LegalityCheckStrings ;
2016-02-23 06:52:48 +00:00
2022-06-18 18:04:24 +00:00
namespace PKHeX.Core ;
/// <summary>
/// Legality Check object containing the <see cref="CheckResult"/> data and overview values from the parse.
/// </summary>
public sealed class LegalityAnalysis
2016-02-23 06:52:48 +00:00
{
2022-06-18 18:04:24 +00:00
/// <summary> The entity we are checking. </summary>
internal readonly PKM Entity ;
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
/// <summary> The entity's <see cref="IPersonalInfo"/>, which may have been sourced from the Save File it resides on. </summary>
2022-06-18 18:04:24 +00:00
/// <remarks>We store this rather than re-fetching, as some games that use the same <see cref="PKM"/> format have different values.</remarks>
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
internal readonly IPersonalInfo PersonalInfo ;
2022-06-18 18:04:24 +00:00
private readonly List < CheckResult > Parse = new ( 8 ) ;
/// <summary>
/// Parse result list allowing view of the legality parse.
/// </summary>
public IReadOnlyList < CheckResult > Results = > Parse ;
/// <summary>
/// Matched encounter data for the <see cref="Entity"/>.
/// </summary>
public IEncounterable EncounterMatch = > Info . EncounterMatch ;
/// <summary>
/// Original encounter data for the <see cref="Entity"/>.
/// </summary>
/// <remarks>
/// Generation 1/2 <see cref="Entity"/> that are transferred forward to Generation 7 are restricted to new encounter details.
/// By retaining their original match, more information can be provided by the parse.
/// </remarks>
public IEncounterable EncounterOriginal = > Info . EncounterOriginal ;
2022-08-05 18:23:28 +00:00
/// <summary>
/// Indicates where the <see cref="Entity"/> originated.
/// </summary>
2022-06-18 18:04:24 +00:00
public readonly SlotOrigin SlotOrigin ;
/// <summary>
/// Indicates if all checks ran to completion.
/// </summary>
/// <remarks>This value is false if any checks encountered an error.</remarks>
public readonly bool Parsed ;
/// <summary>
/// Indicates if all checks returned a <see cref="Severity.Valid"/> result.
/// </summary>
public readonly bool Valid ;
/// <summary>
/// Contains various data reused for multiple checks.
/// </summary>
public readonly LegalInfo Info ;
2017-10-24 06:12:58 +00:00
/// <summary>
2022-06-18 18:04:24 +00:00
/// Checks the input <see cref="PKM"/> data for legality. This is the best method for checking with context, as some games do not have all Alternate Form data available.
2017-10-24 06:12:58 +00:00
/// </summary>
2022-06-18 18:04:24 +00:00
/// <param name="pk">Input data to check</param>
/// <param name="table"><see cref="SaveFile"/> specific personal data</param>
/// <param name="source">Details about where the <see cref="Entity"/> originated from.</param>
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
public LegalityAnalysis ( PKM pk , IPersonalTable table , SlotOrigin source = SlotOrigin . Party ) : this ( pk , table . GetFormEntry ( pk . Species , pk . Form ) , source ) { }
2022-06-18 18:04:24 +00:00
/// <summary>
/// Checks the input <see cref="PKM"/> data for legality.
/// </summary>
/// <param name="pk">Input data to check</param>
/// <param name="source">Details about where the <see cref="Entity"/> originated from.</param>
public LegalityAnalysis ( PKM pk , SlotOrigin source = SlotOrigin . Party ) : this ( pk , pk . PersonalInfo , source ) { }
/// <summary>
/// Checks the input <see cref="PKM"/> data for legality.
/// </summary>
/// <param name="pk">Input data to check</param>
/// <param name="pi">Personal info to parse with</param>
/// <param name="source">Details about where the <see cref="Entity"/> originated from.</param>
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
public LegalityAnalysis ( PKM pk , IPersonalInfo pi , SlotOrigin source = SlotOrigin . Party )
2016-02-23 06:52:48 +00:00
{
2022-06-18 18:04:24 +00:00
Entity = pk ;
PersonalInfo = pi ;
SlotOrigin = source ;
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
2022-06-18 18:04:24 +00:00
Info = new LegalInfo ( pk , Parse ) ;
2017-07-18 23:21:31 +00:00
#if SUPPRESS
2022-06-18 18:04:24 +00:00
try
2017-07-18 23:21:31 +00:00
#endif
2022-06-18 18:04:24 +00:00
{
EncounterFinder . FindVerifiedEncounter ( pk , Info ) ;
if ( ! pk . IsOriginValid )
AddLine ( Severity . Invalid , LEncConditionBadSpecies , CheckIdentifier . GameOrigin ) ;
GetParseMethod ( ) ( ) ;
2017-02-14 06:49:32 +00:00
2022-06-18 18:04:24 +00:00
Valid = Parse . TrueForAll ( chk = > chk . Valid )
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
& & MoveResult . AllValid ( Info . Moves )
& & MoveResult . AllValid ( Info . Relearn ) ;
2016-11-15 00:27:15 +00:00
2022-06-18 18:04:24 +00:00
if ( ! Valid & & IsPotentiallyMysteryGift ( Info , pk ) )
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
AddLine ( Severity . Invalid , LFatefulGiftMissing , CheckIdentifier . Fateful ) ;
2022-06-18 18:04:24 +00:00
Parsed = true ;
}
2017-07-18 23:21:31 +00:00
#if SUPPRESS
2022-06-18 18:04:24 +00:00
// We want to swallow any error from malformed input data from the user. The Valid state is all that we really need.
catch ( Exception e )
{
System . Diagnostics . Debug . WriteLine ( e . Message ) ;
Valid = false ;
// Moves and Relearn arrays can potentially be empty on error.
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
var moves = Info . Moves ;
for ( var i = 0 ; i < moves . Length ; i + + )
2017-03-24 06:15:49 +00:00
{
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
ref var p = ref moves [ i ] ;
2022-06-18 18:04:24 +00:00
if ( ! p . IsParsed )
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
p = MoveResult . Unobtainable ( ) ;
2017-03-24 06:15:49 +00:00
}
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
moves = Info . Relearn ;
for ( var i = 0 ; i < moves . Length ; i + + )
2022-06-18 18:04:24 +00:00
{
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
ref var p = ref moves [ i ] ;
2022-06-18 18:04:24 +00:00
if ( ! p . IsParsed )
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
p = MoveResult . Unobtainable ( ) ;
2022-06-18 18:04:24 +00:00
}
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
2022-06-18 18:04:24 +00:00
AddLine ( Severity . Invalid , L_AError , CheckIdentifier . Misc ) ;
2016-10-23 19:48:49 +00:00
}
2022-06-18 18:04:24 +00:00
#endif
}
2018-07-27 02:34:27 +00:00
2022-06-18 18:04:24 +00:00
private static bool IsPotentiallyMysteryGift ( LegalInfo info , PKM pk )
{
if ( info . EncounterOriginal is not EncounterInvalid enc )
2021-08-06 00:16:13 +00:00
return false ;
2022-06-18 18:04:24 +00:00
if ( enc . Generation < = 3 )
return true ;
if ( ! pk . FatefulEncounter )
return false ;
if ( enc . Generation < 6 )
return true ;
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
if ( ! MoveResult . AllValid ( info . Relearn ) )
2022-06-18 18:04:24 +00:00
return true ;
return false ;
}
2018-07-27 02:34:27 +00:00
2022-06-18 18:04:24 +00:00
private Action GetParseMethod ( )
{
if ( Entity . Format < = 2 ) // prior to storing GameVersion
return ParsePK1 ;
2018-07-27 02:34:27 +00:00
2023-01-22 04:02:33 +00:00
var gen = GetParseFormat ( ) ;
2022-06-18 18:04:24 +00:00
return gen switch
2017-03-18 23:50:34 +00:00
{
2022-06-18 18:04:24 +00:00
3 = > ParsePK3 ,
4 = > ParsePK4 ,
5 = > ParsePK5 ,
6 = > ParsePK6 ,
2017-04-30 19:17:27 +00:00
2022-06-18 18:04:24 +00:00
1 = > ParsePK7 ,
2 = > ParsePK7 ,
7 = > ParsePK7 ,
2017-06-09 03:57:30 +00:00
2022-06-18 18:04:24 +00:00
8 = > ParsePK8 ,
2022-11-25 01:42:17 +00:00
9 = > ParsePK9 ,
2019-11-17 00:05:45 +00:00
2022-06-18 18:04:24 +00:00
_ = > throw new ArgumentOutOfRangeException ( nameof ( gen ) ) ,
} ;
}
2018-07-27 02:34:27 +00:00
2023-01-22 04:02:33 +00:00
private int GetParseFormat ( )
{
int gen = Entity . Generation ;
if ( gen > 0 )
return gen ;
if ( Entity is PK9 { IsUnhatchedEgg : true } )
return 9 ;
return Entity . Format ;
}
2022-06-18 18:04:24 +00:00
private void ParsePK1 ( )
{
Nickname . Verify ( this ) ;
Level . Verify ( this ) ;
Level . VerifyG1 ( this ) ;
Trainer . VerifyOTG1 ( this ) ;
MiscValues . VerifyMiscG1 ( this ) ;
if ( Entity . Format = = 2 )
Item . Verify ( this ) ;
}
2018-07-27 02:34:27 +00:00
2022-06-18 18:04:24 +00:00
private void ParsePK3 ( )
{
UpdateChecks ( ) ;
if ( Entity . Format > 3 )
Transfer . VerifyTransferLegalityG3 ( this ) ;
2018-07-27 02:34:27 +00:00
2022-06-18 18:04:24 +00:00
if ( Entity . Version = = ( int ) GameVersion . CXD )
CXD . Verify ( this ) ;
2018-07-27 02:34:27 +00:00
2022-06-18 18:04:24 +00:00
if ( Info . EncounterMatch is WC3 { NotDistributed : true } )
AddLine ( Severity . Invalid , LEncUnreleased , CheckIdentifier . Encounter ) ;
2016-03-14 03:19:04 +00:00
2022-06-18 18:04:24 +00:00
if ( Entity . Format > = 8 )
2019-11-28 19:51:23 +00:00
Transfer . VerifyTransferLegalityG8 ( this ) ;
2022-06-18 18:04:24 +00:00
}
2017-10-21 04:07:15 +00:00
2022-06-18 18:04:24 +00:00
private void ParsePK4 ( )
{
UpdateChecks ( ) ;
if ( Entity . Format > 4 )
Transfer . VerifyTransferLegalityG4 ( this ) ;
if ( Entity . Format > = 8 )
Transfer . VerifyTransferLegalityG8 ( this ) ;
}
2019-04-04 03:13:30 +00:00
2022-06-18 18:04:24 +00:00
private void ParsePK5 ( )
{
UpdateChecks ( ) ;
if ( Entity . Format > = 8 )
Transfer . VerifyTransferLegalityG8 ( this ) ;
}
2018-07-27 02:34:27 +00:00
2022-06-18 18:04:24 +00:00
private void ParsePK6 ( )
{
UpdateChecks ( ) ;
if ( Entity . Format > = 8 )
Transfer . VerifyTransferLegalityG8 ( this ) ;
}
2020-05-10 03:47:32 +00:00
2022-06-18 18:04:24 +00:00
private void ParsePK7 ( )
{
if ( Entity . VC )
UpdateVCTransferInfo ( ) ;
UpdateChecks ( ) ;
if ( Entity . Format > = 8 )
Transfer . VerifyTransferLegalityG8 ( this ) ;
2022-07-10 22:53:33 +00:00
else if ( Entity is PB7 )
Awakening . Verify ( this ) ;
2022-06-18 18:04:24 +00:00
}
2018-07-02 00:07:29 +00:00
2022-06-18 18:04:24 +00:00
private void ParsePK8 ( )
{
UpdateChecks ( ) ;
Transfer . VerifyTransferLegalityG8 ( this ) ;
}
2020-07-31 18:17:31 +00:00
2022-11-25 01:42:17 +00:00
private void ParsePK9 ( )
{
UpdateChecks ( ) ;
Transfer . VerifyTransferLegalityG9 ( this ) ;
}
2022-06-18 18:04:24 +00:00
/// <summary>
/// Adds a new Check parse value.
/// </summary>
/// <param name="s">Check severity</param>
/// <param name="c">Check comment</param>
/// <param name="i">Check type</param>
2023-04-23 23:04:04 +00:00
internal void AddLine ( Severity s , string c , CheckIdentifier i ) = > AddLine ( new CheckResult ( s , i , c ) ) ;
2020-08-05 05:56:55 +00:00
2022-06-18 18:04:24 +00:00
/// <summary>
/// Adds a new Check parse value.
/// </summary>
/// <param name="chk">Check result to add.</param>
internal void AddLine ( CheckResult chk ) = > Parse . Add ( chk ) ;
2018-07-02 00:07:29 +00:00
2022-06-18 18:04:24 +00:00
private void UpdateVCTransferInfo ( )
{
var enc = ( Info . EncounterOriginalGB = EncounterMatch ) ;
if ( enc is EncounterInvalid )
return ;
2023-01-22 04:02:33 +00:00
var vc = EncounterGenerator7 . GetVCStaticTransferEncounter ( Entity , enc . Species , Info . EvoChainsAllGens . Gen7 ) ;
2022-06-18 18:04:24 +00:00
Info . EncounterMatch = vc ;
2019-11-26 19:01:09 +00:00
Refactoring: Move Source (Legality) (#3560)
Rewrites a good amount of legality APIs pertaining to:
* Legal moves that can be learned
* Evolution chains & cross-generation paths
* Memory validation with forgotten moves
In generation 8, there are 3 separate contexts an entity can exist in: SW/SH, BD/SP, and LA. Not every entity can cross between them, and not every entity from generation 7 can exist in generation 8 (Gogoat, etc). By creating class models representing the restrictions to cross each boundary, we are able to better track and validate data.
The old implementation of validating moves was greedy: it would iterate for all generations and evolutions, and build a full list of every move that can be learned, storing it on the heap. Now, we check one game group at a time to see if the entity can learn a move that hasn't yet been validated. End result is an algorithm that requires 0 allocation, and a smaller/quicker search space.
The old implementation of storing move parses was inefficient; for each move that was parsed, a new object is created and adjusted depending on the parse. Now, move parse results are `struct` and store the move parse contiguously in memory. End result is faster parsing and 0 memory allocation.
* `PersonalTable` objects have been improved with new API methods to check if a species+form can exist in the game.
* `IEncounterTemplate` objects have been improved to indicate the `EntityContext` they originate in (similar to `Generation`).
* Some APIs have been extended to accept `Span<T>` instead of Array/IEnumerable
2022-08-03 23:15:27 +00:00
Transfer . VerifyVCEncounter ( Entity , enc , vc , this ) ;
2022-06-18 18:04:24 +00:00
Transfer . VerifyTransferLegalityG12 ( this ) ;
}
2020-04-06 23:32:23 +00:00
2022-06-18 18:04:24 +00:00
private void UpdateChecks ( )
{
PIDEC . Verify ( this ) ;
Nickname . Verify ( this ) ;
LanguageIndex . Verify ( this ) ;
Trainer . Verify ( this ) ;
TrainerID . Verify ( this ) ;
IVs . Verify ( this ) ;
EVs . Verify ( this ) ;
Level . Verify ( this ) ;
Ribbon . Verify ( this ) ;
AbilityValues . Verify ( this ) ;
BallIndex . Verify ( this ) ;
FormValues . Verify ( this ) ;
MiscValues . Verify ( this ) ;
GenderValues . Verify ( this ) ;
Item . Verify ( this ) ;
Contest . Verify ( this ) ;
Marking . Verify ( this ) ;
var format = Entity . Format ;
if ( format is 4 or 5 or 6 ) // Gen 6->7 transfer removes this property.
Gen4GroundTile . Verify ( this ) ;
if ( format < 6 )
return ;
History . Verify ( this ) ;
if ( format < 8 ) // Gen 7->8 transfer removes these properties.
ConsoleRegion . Verify ( this ) ;
if ( Entity is ITrainerMemories )
Memory . Verify ( this ) ;
if ( Entity is ISuperTrain )
Medal . Verify ( this ) ;
if ( format < 7 )
return ;
HyperTraining . Verify ( this ) ;
MiscValues . VerifyVersionEvolution ( this ) ;
if ( format < 8 )
return ;
Mark . Verify ( this ) ;
Arceus . Verify ( this ) ;
2016-02-23 06:52:48 +00:00
}
}