Add version hints to filter name checks

Extract result valid check to less-wide style, add extra sanity checks for Gen3 typed saves.
This commit is contained in:
Kurt 2024-05-15 23:29:27 -05:00
parent a4a0337162
commit 99857540ae

View file

@ -63,11 +63,20 @@ public static class SaveLanguage
if (sav.Metadata.FileName is not { } x)
return GetFallback(sav);
var result = InferFrom1(x);
if (result != default && sav.Japanese == (result.Language == Japanese))
return result;
var result = InferFrom1(x, sav.Version);
if (!IsResultValid(result, sav))
return GetFallback(sav);
return GetFallback(sav);
return result;
}
private static bool IsResultValid(in SaveLanguageResult result, SAV1 sav)
{
if (result == default)
return false;
if (sav.Japanese)
return result.Language == Japanese;
return result.Language is not Japanese;
}
/// <inheritdoc cref="InferFrom(SAV1)"/>
@ -76,11 +85,22 @@ public static class SaveLanguage
if (sav.Metadata.FileName is not { } x)
return GetFallback(sav);
var result = InferFrom2(x);
if (result != default && (sav.Japanese == (result.Language == Japanese)) && (sav.Korean == (result.Language == Korean)))
return result;
var result = InferFrom2(x, sav.Version);
if (!IsResultValid(result, sav))
return GetFallback(sav);
return GetFallback(sav);
return result;
}
private static bool IsResultValid(in SaveLanguageResult result, SAV2 sav)
{
if (result == default)
return false;
if (sav.Japanese)
return result.Language == Japanese;
if (sav.Korean)
return result.Language == Korean;
return result.Language is not (Japanese or Korean);
}
/// <inheritdoc cref="InferFrom(SAV1)"/>
@ -89,151 +109,197 @@ public static class SaveLanguage
if (sav.Metadata.FileName is not { } x)
return GetFallback(sav);
var result = InferFrom3(x);
if (result != default && sav.Japanese == (result.Language == Japanese))
return result;
var result = InferFrom3(x, sav.Version);
if (!IsResultValid(result, sav))
return GetFallback(sav);
return GetFallback(sav);
return result;
}
private static bool IsResultValid(in SaveLanguageResult result, SAV3 sav)
{
if (result == default)
return false;
if (sav.Japanese != (result.Language == Japanese))
return false;
return sav switch
{
SAV3RS => result.Version is R or S,
SAV3E => result.Version is E,
SAV3FRLG => result.Version is FR or LG,
_ => false,
};
}
private static bool Contains(ReadOnlySpan<char> span, ReadOnlySpan<char> value)
=> span.Contains(value, StringComparison.OrdinalIgnoreCase);
/// <inheritdoc cref="InferFrom(SAV1)"/>
public static SaveLanguageResult InferFrom1(ReadOnlySpan<char> name)
public static SaveLanguageResult InferFrom1(ReadOnlySpan<char> name, GameVersion hint = Any)
{
// Red
if (Contains(name, "red")) return (English, RD);
if (Contains(name, "roug")) return (French, RD);
if (Contains(name, "rot")) return (German, RD);
if (Contains(name, "ross")) return (Italian, RD);
if (Contains(name, "rojo")) return (Spanish, RD);
if (MaybeRD(hint)) {
if (Contains(name, "red")) return (English, RD);
if (Contains(name, "roug")) return (French, RD);
if (Contains(name, "rot")) return (German, RD);
if (Contains(name, "ross")) return (Italian, RD);
if (Contains(name, "rojo")) return (Spanish, RD);
// Blue
if (Contains(name, "blue")) return (English, GN);
if (Contains(name, "bleu")) return (French, GN);
if (Contains(name, "blau")) return (German, GN);
if (Contains(name, "blu")) return (Italian, GN);
if (Contains(name, "azul")) return (Spanish, GN);
if (Contains(name, "赤")) return (Japanese, RD);
if (Contains(name, "aka")) return (Japanese, RD);
}
if (MaybeGN(hint)) {
if (Contains(name, "blue")) return (English, GN);
if (Contains(name, "bleu")) return (French, GN);
if (Contains(name, "blau")) return (German, GN);
if (Contains(name, "blu")) return (Italian, GN);
if (Contains(name, "azul")) return (Spanish, GN);
// Yellow
if (Contains(name, "yell")) return (English, YW);
if (Contains(name, "jaun")) return (French, YW);
if (Contains(name, "gelb")) return (German, YW);
if (Contains(name, "gial")) return (Italian, YW);
if (Contains(name, "amar")) return (Spanish, YW);
// Japanese
if (Contains(name, "赤")) return (Japanese, RD);
if (Contains(name, "緑")) return (Japanese, GN);
if (Contains(name, "青")) return (Japanese, BU);
if (Contains(name, "ピ")) return (Japanese, YW);
if (Contains(name, "黄")) return (Japanese, YW);
if (Contains(name, "aka")) return (Japanese, RD);
if (Contains(name, "ao")) return (Japanese, BU);
if (Contains(name, "mid")) return (Japanese, GN);
if (Contains(name, "pika")) return (Japanese, YW);
if (Contains(name, "緑")) return (Japanese, GN);
if (Contains(name, "mid")) return (Japanese, GN);
}
if (MaybeYW(hint)) {
if (Contains(name, "yell")) return (English, YW);
if (Contains(name, "jaun")) return (French, YW);
if (Contains(name, "gelb")) return (German, YW);
if (Contains(name, "gial")) return (Italian, YW);
if (Contains(name, "amar")) return (Spanish, YW);
if (Contains(name, "ピ")) return (Japanese, YW);
if (Contains(name, "黄")) return (Japanese, YW);
if (Contains(name, "pika")) return (Japanese, YW);
}
if (MaybeBU(hint)) {
if (Contains(name, "青")) return (Japanese, BU);
if (Contains(name, "ao")) return (Japanese, BU);
}
return default;
static bool MaybeRD(GameVersion game) => game is RD or RB or RBY or Any;
static bool MaybeGN(GameVersion game) => game is GN or RB or RBY or Any;
static bool MaybeBU(GameVersion game) => game is BU or RBY or Any;
static bool MaybeYW(GameVersion game) => game is YW or RBY or Any;
}
/// <inheritdoc cref="InferFrom(SAV1)"/>
public static SaveLanguageResult InferFrom2(ReadOnlySpan<char> name)
public static SaveLanguageResult InferFrom2(ReadOnlySpan<char> name, GameVersion hint = Any)
{
// Gold
if (Contains(name, "golde")) return (German, GD);
if (Contains(name, "gold")) return (English, GD);
if (Contains(name, "e oro")) return (Italian, GD);
if (Contains(name, "oro")) return (Spanish, GD);
if (Contains(name, "n or")) return (French, GD);
if (Contains(name, "金")) return (Japanese, GD);
if (Contains(name, "금")) return (Korean, GD);
if (MaybeGD(hint)) {
if (Contains(name, "golde")) return (German, GD);
if (Contains(name, "gold")) return (English, GD);
if (Contains(name, "e oro")) return (Italian, GD);
if (Contains(name, "oro")) return (Spanish, GD);
if (Contains(name, "n or")) return (French, GD);
if (Contains(name, "金")) return (Japanese, GD);
if (Contains(name, "금")) return (Korean, GD);
// Silver
if (Contains(name, "silv")) return (English, SI);
if (Contains(name, "silb")) return (German, SI);
if (Contains(name, "plat")) return (Spanish, SI);
if (Contains(name, "e arg")) return (Italian, SI);
if (Contains(name, "arge")) return (French, SI);
if (Contains(name, "銀")) return (Japanese, SI);
if (Contains(name, "은")) return (Korean, SI);
if (Contains(name, "kin")) return (Japanese, GD);
if (Contains(name, "geum")) return (Korean, GD);
}
if (MaybeSI(hint)) {
if (Contains(name, "silv")) return (English, SI);
if (Contains(name, "silb")) return (German, SI);
if (Contains(name, "plat")) return (Spanish, SI);
if (Contains(name, "e arg")) return (Italian, SI);
if (Contains(name, "arge")) return (French, SI);
if (Contains(name, "銀")) return (Japanese, SI);
if (Contains(name, "은")) return (Korean, SI);
// Crystal
if (Contains(name, "cry")) return (English, C);
if (Contains(name, "kri")) return (German, C);
if (Contains(name, "cristall")) return (Italian, C);
if (Contains(name, "on cri")) return (French, C);
if (Contains(name, "ón crist")) return (Spanish, C);
if (Contains(name, "クリ")) return (Japanese, C);
if (Contains(name, "kin")) return (Japanese, GD);
if (Contains(name, "gin")) return (Japanese, SI);
if (Contains(name, "geum")) return (Korean, GD);
if (Contains(name, "eun")) return (Korean, SI);
if (Contains(name, "gin")) return (Japanese, SI);
if (Contains(name, "eun")) return (Korean, SI);
}
if (MaybeC(hint)) {
if (Contains(name, "cry")) return (English, C);
if (Contains(name, "kri")) return (German, C);
if (Contains(name, "cristall")) return (Italian, C);
if (Contains(name, "on cri")) return (French, C);
if (Contains(name, "ón crist")) return (Spanish, C);
if (Contains(name, "クリ")) return (Japanese, C);
}
// Codes
if (Contains(name, "gd")) return (OverrideLanguageGen2, GD);
if (Contains(name, "si")) return (OverrideLanguageGen2, SI);
if (MaybeGD(hint) && Contains(name, "gd")) return (OverrideLanguageGen2, GD);
if (MaybeSI(hint) && Contains(name, "si")) return (OverrideLanguageGen2, SI);
return default;
static bool MaybeGD(GameVersion game) => game is GD or GS or Any;
static bool MaybeSI(GameVersion game) => game is SI or GS or Any;
static bool MaybeC(GameVersion game) => game is C or Any;
}
/// <inheritdoc cref="InferFrom(SAV1)"/>
public static SaveLanguageResult InferFrom3(ReadOnlySpan<char> name)
public static SaveLanguageResult InferFrom3(ReadOnlySpan<char> name, GameVersion hint = Any)
{
// FireRed
if (Contains(name, "fir")) return (English, FR);
if (Contains(name, "feu")) return (French, FR);
if (Contains(name, "feuer")) return (German, FR);
if (Contains(name, "fuoco")) return (Italian, FR);
if (Contains(name, "fueg")) return (Spanish, FR);
if (Contains(name, "ファイアレッド")) return (Japanese, FR);
// LeafGreen
if (Contains(name, "lea")) return (English, LG);
if (Contains(name, "vert")) return (French, LG);
if (Contains(name, "blatt")) return (German, LG);
if (Contains(name, "fogli")) return (Italian, LG);
if (Contains(name, "hoja")) return (Spanish, LG);
if (Contains(name, "リーフグリーン")) return (Japanese, LG);
// Ruby
if (Contains(name, "ruby")) return (English, R);
if (Contains(name, "rubí")) return (Spanish, R);
if (Contains(name, "rubino")) return (Italian, R);
if (Contains(name, "rubis")) return (French, R);
if (Contains(name, "rubin")) return (German, R);
if (Contains(name, "ルビー")) return (Japanese, R);
// Sapphire
if (Contains(name, "sapp")) return (English, S);
if (Contains(name, "saphir")) return (French, S);
if (Contains(name, "safir")) return (German, S);
if (Contains(name, "zafir")) return (Spanish, S);
if (Contains(name, "zaffiro")) return (Italian, S);
if (Contains(name, "サファ")) return (Japanese, S);
// Emerald
if (Contains(name, "esm")) return (Spanish, E);
if (Contains(name, "smar")) return (German, E);
if (Contains(name, "smer")) return (Italian, E);
if (Contains(name, "éme") || Contains(name, "n eme")) return (French, E);
if (Contains(name, "emer")) return (English, E);
if (Contains(name, "エメ")) return (Japanese, E);
if (MaybeFR(hint)) {
if (Contains(name, "fir")) return (English, FR);
if (Contains(name, "feu")) return (French, FR);
if (Contains(name, "feuer")) return (German, FR);
if (Contains(name, "fuoco")) return (Italian, FR);
if (Contains(name, "fueg")) return (Spanish, FR);
if (Contains(name, "ファイアレッド")) return (Japanese, FR);
}
if (MaybeLG(hint)) {
if (Contains(name, "lea")) return (English, LG);
if (Contains(name, "vert")) return (French, LG);
if (Contains(name, "blatt")) return (German, LG);
if (Contains(name, "fogli")) return (Italian, LG);
if (Contains(name, "hoja")) return (Spanish, LG);
if (Contains(name, "リーフグリーン")) return (Japanese, LG);
}
if (MaybeR(hint)) {
if (Contains(name, "ruby")) return (English, R);
if (Contains(name, "rubí")) return (Spanish, R);
if (Contains(name, "rubino")) return (Italian, R);
if (Contains(name, "rubis")) return (French, R);
if (Contains(name, "rubin")) return (German, R);
if (Contains(name, "ルビー")) return (Japanese, R);
}
if (MaybeS(hint)) {
if (Contains(name, "sapp")) return (English, S);
if (Contains(name, "saphir")) return (French, S);
if (Contains(name, "safir")) return (German, S);
if (Contains(name, "zafir")) return (Spanish, S);
if (Contains(name, "zaffiro")) return (Italian, S);
if (Contains(name, "サファ")) return (Japanese, S);
}
if (MaybeE(hint)) {
if (Contains(name, "esm")) return (Spanish, E);
if (Contains(name, "smar")) return (German, E);
if (Contains(name, "smer")) return (Italian, E);
if (Contains(name, "éme") || Contains(name, "n eme")) return (French, E);
if (Contains(name, "emer")) return (English, E);
if (Contains(name, "エメ")) return (Japanese, E);
}
// Codes
if (Contains(name, "axpj")) return (Japanese, S);
if (Contains(name, "axp")) return (OverrideLanguageGen3RS, S);
if (Contains(name, "axvj")) return (Japanese, R);
if (Contains(name, "axv")) return (OverrideLanguageGen3RS, R);
if (Contains(name, "bpej")) return (Japanese, E);
if (Contains(name, "bpe")) return (OverrideLanguageGen3RS, E);
if (Contains(name, "bprj")) return (Japanese, FR);
if (Contains(name, "bpr") || Contains(name, "fr") || Contains(name, "fire")) return (OverrideLanguageGen3FRLG, FR);
if (Contains(name, "bpgj")) return (Japanese, LG);
if (Contains(name, "bpg") || Contains(name, "lg") || Contains(name, "leaf")) return (OverrideLanguageGen3FRLG, LG);
if (MaybeS(hint)) {
if (Contains(name, "axpj")) return (Japanese, S);
if (Contains(name, "axp")) return (OverrideLanguageGen3RS, S);
}
if (MaybeR(hint)) {
if (Contains(name, "axvj")) return (Japanese, R);
if (Contains(name, "axv")) return (OverrideLanguageGen3RS, R);
}
if (MaybeE(hint)) {
if (Contains(name, "bpej")) return (Japanese, E);
if (Contains(name, "bpe")) return (OverrideLanguageGen3RS, E);
}
if (MaybeFR(hint)) {
if (Contains(name, "bprj")) return (Japanese, FR);
if (Contains(name, "bpr") || Contains(name, "fr") || Contains(name, "fire")) return (OverrideLanguageGen3FRLG, FR);
}
if (MaybeLG(hint)) {
if (Contains(name, "bpgj")) return (Japanese, LG);
if (Contains(name, "bpg") || Contains(name, "lg") || Contains(name, "leaf")) return (OverrideLanguageGen3FRLG, LG);
}
return default;
static bool MaybeFR(GameVersion game) => game is FR or FRLG or Any;
static bool MaybeLG(GameVersion game) => game is LG or FRLG or Any;
static bool MaybeR(GameVersion game) => game is R or RS or Any;
static bool MaybeS(GameVersion game) => game is S or RS or Any;
static bool MaybeE(GameVersion game) => game is E or RS or Any;
}
/// <summary>