mirror of
https://github.com/kwsch/PKHeX
synced 2025-02-16 21:38:40 +00:00
Echoes of trash-test
Remove glyph remap for Switch gender symbols (none actually) Might be wise to convert StringConverter to singletons...
This commit is contained in:
parent
f80c2820f9
commit
671c3564ee
7 changed files with 214 additions and 10 deletions
|
@ -46,4 +46,46 @@ public sealed record EncounterStatic8U : EncounterStatic8Nest<EncounterStatic8U>
|
||||||
protected override bool IsMatchLocation(PKM pk) => Location == pk.Met_Location;
|
protected override bool IsMatchLocation(PKM pk) => Location == pk.Met_Location;
|
||||||
|
|
||||||
public bool IsShinyXorValid(ushort pkShinyXor) => pkShinyXor is > 15 or 1;
|
public bool IsShinyXorValid(ushort pkShinyXor) => pkShinyXor is > 15 or 1;
|
||||||
|
|
||||||
|
public bool ShouldHaveScientistTrash => !SpeciesCategory.IsLegendary(Species)
|
||||||
|
&& !SpeciesCategory.IsSubLegendary(Species);
|
||||||
|
|
||||||
|
protected override void FinishCorrelation(PK8 pk, ulong seed)
|
||||||
|
{
|
||||||
|
if (!ShouldHaveScientistTrash)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ApplyTrashBytes(pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyTrashBytes(PKM pk)
|
||||||
|
{
|
||||||
|
// Normally we would apply the trash before applying the OT, but we already did.
|
||||||
|
// Just add in the expected trash after the OT.
|
||||||
|
var ot = pk.OT_Trash;
|
||||||
|
var language = pk.Language;
|
||||||
|
var scientist = GetScientistName(language);
|
||||||
|
StringConverter8.ApplyTrashBytes(ot, scientist);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TrashMatch HasScientistTrash(PKM pk)
|
||||||
|
{
|
||||||
|
var language = pk.Language;
|
||||||
|
var name = GetScientistName(language);
|
||||||
|
return StringConverter8.GetTrashState(pk.OT_Trash, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReadOnlySpan<char> GetScientistName(int language) => language switch
|
||||||
|
{
|
||||||
|
(int)LanguageID.Japanese => "けんきゅういん",
|
||||||
|
(int)LanguageID.English => "Scientist",
|
||||||
|
(int)LanguageID.French => "Scientifique",
|
||||||
|
(int)LanguageID.Italian => "Scienziata",
|
||||||
|
(int)LanguageID.German => "Forscherin",
|
||||||
|
(int)LanguageID.Spanish => "Científica",
|
||||||
|
(int)LanguageID.Korean => "연구원",
|
||||||
|
(int)LanguageID.ChineseS => "研究员",
|
||||||
|
(int)LanguageID.ChineseT => "研究員",
|
||||||
|
_ => ReadOnlySpan<char>.Empty,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,14 @@ public static class StringConverter12
|
||||||
foreach (var c in data)
|
foreach (var c in data)
|
||||||
{
|
{
|
||||||
var b = table[c];
|
var b = table[c];
|
||||||
if (b == G1Terminator && c is not (G1TerminatorCode or 0))
|
if (b == G1Terminator && c is not (G1TerminatorCode or G1TerminatorZero))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public const byte G1TerminatorCode = 0x50;
|
public const byte G1TerminatorCode = 0x50;
|
||||||
|
public const byte G1TerminatorZero = 0x00;
|
||||||
public const char G1Terminator = '\0';
|
public const char G1Terminator = '\0';
|
||||||
public const byte G1TradeOTCode = 0x5D;
|
public const byte G1TradeOTCode = 0x5D;
|
||||||
public const char G1TradeOT = '*';
|
public const char G1TradeOT = '*';
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using static System.Buffers.Binary.BinaryPrimitives;
|
using static System.Buffers.Binary.BinaryPrimitives;
|
||||||
|
|
||||||
namespace PKHeX.Core;
|
namespace PKHeX.Core;
|
||||||
|
@ -33,7 +35,7 @@ public static class StringConverter8
|
||||||
var value = ReadUInt16LittleEndian(data[i..]);
|
var value = ReadUInt16LittleEndian(data[i..]);
|
||||||
if (value == TerminatorNull)
|
if (value == TerminatorNull)
|
||||||
break;
|
break;
|
||||||
result[i/2] = StringConverter.SanitizeChar((char)value);
|
result[i/2] = (char)value;
|
||||||
}
|
}
|
||||||
return i/2;
|
return i/2;
|
||||||
}
|
}
|
||||||
|
@ -53,14 +55,7 @@ public static class StringConverter8
|
||||||
if (option is StringConverterOption.ClearZero)
|
if (option is StringConverterOption.ClearZero)
|
||||||
destBuffer.Clear();
|
destBuffer.Clear();
|
||||||
|
|
||||||
bool isFullWidth = StringConverter.GetIsFullWidthString(value);
|
WriteCharacters(destBuffer, value);
|
||||||
for (int i = 0; i < value.Length; i++)
|
|
||||||
{
|
|
||||||
char c = value[i];
|
|
||||||
if (!isFullWidth)
|
|
||||||
c = StringConverter.UnSanitizeChar(c);
|
|
||||||
WriteUInt16LittleEndian(destBuffer[(i * 2)..], c);
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = value.Length * 2;
|
int count = value.Length * 2;
|
||||||
if (count == destBuffer.Length)
|
if (count == destBuffer.Length)
|
||||||
|
@ -68,4 +63,62 @@ public static class StringConverter8
|
||||||
WriteUInt16LittleEndian(destBuffer[count..], TerminatorNull);
|
WriteUInt16LittleEndian(destBuffer[count..], TerminatorNull);
|
||||||
return count + 2;
|
return count + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void WriteCharacters(Span<byte> destBuffer, ReadOnlySpan<char> value)
|
||||||
|
{
|
||||||
|
if (BitConverter.IsLittleEndian)
|
||||||
|
{
|
||||||
|
var u16 = MemoryMarshal.Cast<char, byte>(value);
|
||||||
|
u16.CopyTo(destBuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < value.Length; i++)
|
||||||
|
WriteUInt16LittleEndian(destBuffer[(i * 2)..], value[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the under string to the top string, if possible.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="top">Displayed string</param>
|
||||||
|
/// <param name="under">Previous string</param>
|
||||||
|
/// <returns>Indication of the under string's presence.</returns>
|
||||||
|
public static TrashMatch ApplyTrashBytes(Span<byte> top, ReadOnlySpan<char> under)
|
||||||
|
{
|
||||||
|
var index = TrashBytes.GetStringLength(top);
|
||||||
|
if (index == -1)
|
||||||
|
return TrashMatch.Skipped;
|
||||||
|
index++; // hop over the terminator
|
||||||
|
if (index >= under.Length) // Overlapping
|
||||||
|
return TrashMatch.TooLongToTell;
|
||||||
|
|
||||||
|
var src = under[index..];
|
||||||
|
var dest = top[(index * 2)..];
|
||||||
|
SetString(dest, src, src.Length, StringConverterOption.None);
|
||||||
|
return TrashMatch.Present;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks the displayed top string against the under string to see if the under is present.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="top">Displayed string</param>
|
||||||
|
/// <param name="under">Previous string</param>
|
||||||
|
/// <returns>Indication of the under string's presence.</returns>
|
||||||
|
public static TrashMatch GetTrashState(ReadOnlySpan<byte> top, ReadOnlySpan<char> under)
|
||||||
|
{
|
||||||
|
if (under.Length == 0)
|
||||||
|
return TrashMatch.Skipped;
|
||||||
|
|
||||||
|
var index = TrashBytes.GetStringLength(top);
|
||||||
|
if ((uint)index >= under.Length)
|
||||||
|
return TrashMatch.TooLongToTell;
|
||||||
|
index++; // hop over the terminator
|
||||||
|
|
||||||
|
// Adjust our spans to the relevant sections
|
||||||
|
under = under[index..];
|
||||||
|
var relevantSection = top[(index * 2)..];
|
||||||
|
Span<byte> expect = stackalloc byte[relevantSection.Length];
|
||||||
|
WriteCharacters(expect, under);
|
||||||
|
return relevantSection.SequenceEqual(expect) ? TrashMatch.Present : TrashMatch.NotPresent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
35
PKHeX.Core/PKM/Strings/Trash/TrashBytes.cs
Normal file
35
PKHeX.Core/PKM/Strings/Trash/TrashBytes.cs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace PKHeX.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 16-bit encoded string utility
|
||||||
|
/// </summary>
|
||||||
|
public static class TrashBytes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the length of the string based on the terminator.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Buffer to check the length of.</param>
|
||||||
|
/// <param name="terminator">String terminator to search for.</param>
|
||||||
|
/// <returns>Index of the terminator, or max length if not found.</returns>
|
||||||
|
public static int GetStringLength(ReadOnlySpan<byte> buffer, ushort terminator = 0)
|
||||||
|
{
|
||||||
|
int index = FindTerminatorIndex(buffer, terminator);
|
||||||
|
return index == -1 ? buffer.Length / 2 : index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a 16-bit aligned index of the terminator.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Backing buffer of the string.</param>
|
||||||
|
/// <param name="terminator">Terminator character to search for.</param>
|
||||||
|
/// <returns>Index of the terminator, or -1 if not found.</returns>
|
||||||
|
/// <remarks>When used on a raw string, returns the computed length of the string, assuming a terminator is present.</remarks>
|
||||||
|
public static int FindTerminatorIndex(ReadOnlySpan<byte> buffer, ushort terminator = 0)
|
||||||
|
{
|
||||||
|
var u16 = MemoryMarshal.Cast<byte, ushort>(buffer);
|
||||||
|
return u16.IndexOf(terminator);
|
||||||
|
}
|
||||||
|
}
|
24
PKHeX.Core/PKM/Strings/Trash/TrashBytes8.cs
Normal file
24
PKHeX.Core/PKM/Strings/Trash/TrashBytes8.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PKHeX.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generation 3 Encoding Utility
|
||||||
|
/// </summary>
|
||||||
|
public static class TrashBytes8
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="TrashBytes.GetStringLength"/>
|
||||||
|
public static int GetStringLength(ReadOnlySpan<byte> buffer)
|
||||||
|
{
|
||||||
|
int index = FindTerminatorIndex(buffer);
|
||||||
|
return index == -1 ? buffer.Length : index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a 16-bit aligned index of the terminator.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Backing buffer of the string.</param>
|
||||||
|
/// <returns>Index of the terminator, or -1 if not found.</returns>
|
||||||
|
public static int FindTerminatorIndex(ReadOnlySpan<byte> buffer)
|
||||||
|
=> buffer.IndexOf<byte>(0xFF);
|
||||||
|
}
|
25
PKHeX.Core/PKM/Strings/Trash/TrashBytesGB.cs
Normal file
25
PKHeX.Core/PKM/Strings/Trash/TrashBytesGB.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using static PKHeX.Core.StringConverter12;
|
||||||
|
|
||||||
|
namespace PKHeX.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generation 1 & 2 Encoding Utility
|
||||||
|
/// </summary>
|
||||||
|
public static class TrashBytesGB
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="TrashBytes.GetStringLength"/>
|
||||||
|
public static int GetStringLength(ReadOnlySpan<byte> buffer)
|
||||||
|
{
|
||||||
|
int index = FindTerminatorIndex(buffer);
|
||||||
|
return index == -1 ? buffer.Length : index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a 16-bit aligned index of the terminator.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Backing buffer of the string.</param>
|
||||||
|
/// <returns>Index of the terminator, or -1 if not found.</returns>
|
||||||
|
public static int FindTerminatorIndex(ReadOnlySpan<byte> buffer)
|
||||||
|
=> buffer.IndexOfAny(G1TerminatorZero, G1TerminatorCode);
|
||||||
|
}
|
24
PKHeX.Core/PKM/Strings/Trash/TrashMatch.cs
Normal file
24
PKHeX.Core/PKM/Strings/Trash/TrashMatch.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
namespace PKHeX.Core;
|
||||||
|
|
||||||
|
public enum TrashMatch
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Expected under-layer of trash was not found.
|
||||||
|
/// </summary>
|
||||||
|
NotPresent,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Expected under-layer of trash was found.
|
||||||
|
/// </summary>
|
||||||
|
Present,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Displayed string is too long, with all bytes covering the initial trash.
|
||||||
|
/// </summary>
|
||||||
|
TooLongToTell,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ignored due to other issues that would be flagged by other checks.
|
||||||
|
/// </summary>
|
||||||
|
Skipped,
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue