Minor tweaks

ShowdownSet: Lessen allocation
MoveTutor: Remove boxing by calling the generic method instead of object method
Xoro8b: Add more xmldoc, use positive constant instead of inverse negative for parity
StadiumUtil: Use built-in endianness reversal methods
This commit is contained in:
Kurt
2022-05-14 08:28:13 -07:00
parent c113ded3b7
commit a5b46d80f5
4 changed files with 130 additions and 106 deletions

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using static PKHeX.Core.Species;
namespace PKHeX.Core
@@ -97,9 +96,6 @@ public sealed class ShowdownSet : IBattleTemplate
private void LoadLines(IEnumerable<string> lines)
{
lines = lines.Select(z => z.Replace('\'', '').Replace('', '-').Trim()); // Sanitize apostrophes & dashes
lines = lines.Where(z => z.Length > 2);
ParseLines(lines);
FormName = ShowdownParsing.SetShowdownFormName(Species, FormName, Ability);
@@ -110,6 +106,23 @@ private void LoadLines(IEnumerable<string> lines)
ReviseGenderedForms();
}
private static IEnumerable<string> GetSanitizedLines(IEnumerable<string> lines)
{
foreach (var line in lines)
{
var trim = line.Trim();
if (trim.Length <= 2)
continue;
// Sanitize apostrophes & dashes
if (trim.IndexOf('\'') != -1)
trim = trim.Replace('\'', '');
if (trim.IndexOf('') != -1)
trim = trim.Replace('', '-');
yield return trim;
}
}
private void ReviseGenderedForms()
{
if (Gender == 1) // Recognized with (F)
@@ -128,6 +141,7 @@ private void ReviseGenderedForms()
private void ParseLines(IEnumerable<string> lines)
{
lines = GetSanitizedLines(lines);
using var e = lines.GetEnumerator();
if (!e.MoveNext())
return;
@@ -146,7 +160,7 @@ private void ParseLines(IEnumerable<string> lines)
int move = StringUtil.FindIndexIgnoreCase(Strings.movelist, moveString);
if (move < 0)
InvalidLines.Add($"Unknown Move: {moveString}");
else if (Moves.Contains(move))
else if (Array.IndexOf(Moves, move) != -1)
InvalidLines.Add($"Duplicate Move: {moveString}");
else
Moves[movectr++] = move;
@@ -325,15 +339,19 @@ private static IList<string> GetStringStats(ReadOnlySpan<int> stats, int ignore)
private IEnumerable<string> GetStringMoves()
{
foreach (int move in Moves.Where(move => move != 0 && move < Strings.Move.Count))
var moves = Strings.Move;
foreach (int move in Moves)
{
if ((uint)move >= moves.Count)
continue;
if (move == 237) // Hidden Power
{
yield return $"- {Strings.Move[move]} [{Strings.Types[1 + HiddenPowerType]}]";
yield return $"- {moves[move]} [{Strings.Types[1 + HiddenPowerType]}]";
continue;
}
yield return $"- {Strings.Move[move]}";
yield return $"- {moves[move]}";
}
}
@@ -431,7 +449,7 @@ private void ParseFirstLineNoItem(string line)
}
// Nickname Detection
if (line.Contains('(') && line.Contains(')'))
if (line.IndexOf('(') != -1 && line.IndexOf(')') != -1)
ParseSpeciesNickname(line);
else
ParseSpeciesForm(line);
@@ -535,7 +553,7 @@ private string ParseLineMove(string line)
int hpVal = StringUtil.FindIndexIgnoreCase(Strings.types, type) - 1; // Get HP Type
HiddenPowerType = hpVal;
if (IVs.Any(z => z != 31))
if (!Array.TrueForAll(IVs, z => z == 31))
{
if (!HiddenPower.SetIVsForType(hpVal, IVs, Format))
InvalidLines.Add($"Invalid IVs for Hidden Power Type: {type}");
@@ -585,7 +603,19 @@ private void ParseLineIVs(string line)
IVs = IVsSpeedFirst;
}
private static string RemoveAll(string original, char[] remove) => string.Concat(original.Where(z => !remove.Contains(z)));
private static string RemoveAll(string original, char[] remove)
{
Span<char> result = stackalloc char[original.Length];
int ctr = 0;
foreach (var c in original)
{
if (Array.IndexOf(remove, c) == -1)
result[ctr++] = c;
}
if (ctr == original.Length)
return original;
return new string(result[..ctr].ToArray());
}
private static string[] SplitLineStats(string line)
{

View File

@@ -158,7 +158,7 @@ private static GameVersion GetIsTutor8(PKM pkm, int species, int form, bool spec
var pi = (PersonalInfoLA)PersonalTable.LA.GetFormEntry(species, form);
if (!pi.IsPresentInGame)
return NONE;
var index = Array.IndexOf(MoveShop8_LA, move);
var index = Array.IndexOf(MoveShop8_LA, (ushort)move);
if (index != -1 && pi.SpecialTutors[0][index])
return GameVersion.PLA;

View File

@@ -1,100 +1,98 @@
using System.Runtime.CompilerServices;
namespace PKHeX.Core
namespace PKHeX.Core;
/// <summary>
/// Self-modifying RNG structure that implements xoroshiro128+ which split-mixes the initial seed to populate all 128-bits of the initial state, rather than using a fixed 64-bit half.
/// </summary>
/// <remarks>https://en.wikipedia.org/wiki/Xoroshiro128%2B</remarks>
/// <seealso cref="Xoroshiro128Plus"/>
/// <remarks>Used by the Brilliant Diamond &amp; Shining Pearl games; differs in how values are yielded by Next calls.</remarks>
public ref struct Xoroshiro128Plus8b
{
/// <summary>
/// Self-modifying RNG structure that implements xoroshiro128+ which split-mixes the initial seed to populate all 128-bits of the initial state, rather than using a fixed 64-bit half.
/// </summary>
/// <remarks>https://en.wikipedia.org/wiki/Xoroshiro128%2B</remarks>
/// <seealso cref="Xoroshiro128Plus"/>
public ref struct Xoroshiro128Plus8b
private ulong s0, s1;
public Xoroshiro128Plus8b(ulong seed)
{
private ulong s0, s1;
s0 = SplitMix64(seed + 0x9E3779B97F4A7C15);
s1 = SplitMix64(seed + 0x3C6EF372FE94F82A);
}
public Xoroshiro128Plus8b(ulong seed)
{
var _s0 = seed - 0x61C8864680B583EB;
var _s1 = seed + 0x3C6EF372FE94F82A;
private static ulong SplitMix64(ulong seed)
{
seed = 0xBF58476D1CE4E5B9 * (seed ^ (seed >> 30));
seed = 0x94D049BB133111EB * (seed ^ (seed >> 27));
return seed ^ (seed >> 31);
}
_s0 = 0xBF58476D1CE4E5B9 * (_s0 ^ (_s0 >> 30));
_s1 = 0xBF58476D1CE4E5B9 * (_s1 ^ (_s1 >> 30));
public Xoroshiro128Plus8b(ulong s0, ulong s1)
{
this.s0 = s0;
this.s1 = s1;
}
_s0 = 0x94D049BB133111EB * (_s0 ^ (_s0 >> 27));
_s1 = 0x94D049BB133111EB * (_s1 ^ (_s1 >> 27));
public (ulong s0, ulong s1) GetState() => (s0, s1);
public string FullState => $"{s1:X16}{s0:X16}";
s0 = _s0 ^ (_s0 >> 31);
s1 = _s1 ^ (_s1 >> 31);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong RotateLeft(ulong x, int k)
{
return (x << k) | (x >> (64 - k));
}
public Xoroshiro128Plus8b(ulong s0, ulong s1)
{
this.s0 = s0;
this.s1 = s1;
}
/// <summary>
/// Gets the next random <see cref="ulong"/>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong Next()
{
var _s0 = s0;
var _s1 = s1;
ulong result = _s0 + _s1;
public (ulong s0, ulong s1) GetState() => (s0, s1);
public string FullState => $"{s1:X16}{s0:X16}";
_s1 ^= _s0;
// Final calculations and store back to fields
s0 = RotateLeft(_s0, 24) ^ _s1 ^ (_s1 << 16);
s1 = RotateLeft(_s1, 37);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong RotateLeft(ulong x, int k)
{
return (x << k) | (x >> (64 - k));
}
return result;
}
/// <summary>
/// Gets the next random <see cref="ulong"/>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong Next()
{
var _s0 = s0;
var _s1 = s1;
ulong result = _s0 + _s1;
/// <summary>
/// Gets the next previous <see cref="ulong"/>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong Prev()
{
var _s0 = s0;
var _s1 = s1;
_s1 = RotateLeft(_s1, 27);
_s0 = _s0 ^ _s1 ^ (_s1 << 16);
_s0 = RotateLeft(_s0, 40);
_s1 ^= _s0;
ulong result = _s0 + _s1;
_s1 ^= _s0;
// Final calculations and store back to fields
s0 = RotateLeft(_s0, 24) ^ _s1 ^ (_s1 << 16);
s1 = RotateLeft(_s1, 37);
s0 = _s0;
s1 = _s1;
return result;
}
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool NextBool() => (Next() >> 63) != 0;
/// <summary>
/// Gets the next previous <see cref="ulong"/>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong Prev()
{
var _s0 = s0;
var _s1 = s1;
_s1 = RotateLeft(_s1, 27);
_s0 = _s0 ^ _s1 ^ (_s1 << 16);
_s0 = RotateLeft(_s0, 40);
_s1 ^= _s0;
ulong result = _s0 + _s1;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte NextByte() => (byte)(Next() >> 56);
s0 = _s0;
s1 = _s1;
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ushort UShort() => (ushort)(Next() >> 48);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool NextBool() => (Next() >> 63) != 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint NextUInt() => (uint)(Next() >> 32);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte NextByte() => (byte)(Next() >> 56);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ushort UShort() => (ushort)(Next() >> 48);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint NextUInt() => (uint)(Next() >> 32);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint NextUInt(uint max)
{
var rnd = NextUInt();
return rnd - ((rnd / max) * max);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint NextUInt(uint max)
{
var rnd = NextUInt();
return rnd - ((rnd / max) * max);
}
}

View File

@@ -43,17 +43,16 @@ public static bool IsMagicPresent(ReadOnlySpan<byte> data, int size, uint magic)
public static bool IsMagicPresentSwap(ReadOnlySpan<byte> data, int size, uint magic)
{
// Check footers of first few teams to see if the magic value is there.
var left = (ushort)magic;
var right = (ushort)(magic >> 16);
left = (ushort)((left >> 8) | (left << 8));
right = (ushort)((right >> 8) | (right << 8));
var right = ReverseEndianness((ushort)(magic >> 16));
var left = ReverseEndianness((ushort)magic);
for (int i = 0; i < 10; i++)
{
var ofs = size - 6 + (i * size);
if (ReadUInt16LittleEndian(data[(ofs - 2)..]) != left) // OP
var offset = size - 6 + (i * size);
if (ReadUInt16LittleEndian(data[(offset + 4)..]) != right) // EK
return false;
if (ReadUInt16LittleEndian(data[(ofs + 4)..]) != right) // EK
if (ReadUInt16LittleEndian(data[(offset - 2)..]) != left) // OP
return false;
}
return true;
@@ -65,15 +64,12 @@ public static bool IsMagicPresentAbsolute(ReadOnlySpan<byte> data, int offset, u
if (actual == magic) // POKE
return true;
var left = (ushort)magic;
var right = (ushort)(magic >> 16);
left = (ushort)((left >> 8) | (left << 8));
right = (ushort)((right >> 8) | (right << 8));
if (ReadUInt16LittleEndian(data[(offset - 2)..]) != left) // OP
return false;
var right = ReverseEndianness((ushort)(magic >> 16));
if (ReadUInt16LittleEndian(data[(offset + 4)..]) != right) // EK
return false;
var left = ReverseEndianness((ushort)magic);
if (ReadUInt16LittleEndian(data[(offset - 2)..]) != left) // OP
return false;
return true;
}