Use range/index

More in line with modernizing the codebase with latest c# syntax

improve web-qr decode speed slightly (no linq skiptake)
get money/coin mask without a temporary string (lol performance)
This commit is contained in:
Kurt 2021-05-14 15:30:55 -07:00
parent 871f9b0627
commit 50b15cd740
54 changed files with 130 additions and 155 deletions

View file

@ -57,7 +57,7 @@ namespace PKHeX.Core
var p1 = new string[Types.Length + 2][];
Array.Copy(p, 0, p1, 1, p.Length);
p1[0] = any;
p1[p1.Length - 1] = all;
p1[^1] = all;
return p1;
}
@ -513,7 +513,7 @@ namespace PKHeX.Core
default:
return ModifyResult.Error;
}
static byte[] ConvertToBytes(string str) => str.Substring(CONST_BYTES.Length).Split(',').Select(z => Convert.ToByte(z.Trim(), 16)).ToArray();
static byte[] ConvertToBytes(string str) => str[CONST_BYTES.Length..].Split(',').Select(z => Convert.ToByte(z.Trim(), 16)).ToArray();
}
/// <summary>

View file

@ -55,7 +55,7 @@ namespace PKHeX.Core
public void SetRandRange(string pv)
{
string str = pv.Substring(1);
string str = pv[1..];
var split = str.Split(SplitRange);
int.TryParse(split[0], out RandomMinimum);
int.TryParse(split[1], out RandomMaximum);
@ -76,14 +76,14 @@ namespace PKHeX.Core
var raw = GetRelevantStrings(lines, Exclude, Require);
return from line in raw
let eval = line[0] == Require
let split = line.Substring(1).Split(SplitInstruction)
let split = line[1..].Split(SplitInstruction)
where split.Length == 2 && !string.IsNullOrWhiteSpace(split[0])
select new StringInstruction(split[0], split[1]) { Evaluator = eval };
}
public static IEnumerable<StringInstruction> GetInstructions(IEnumerable<string> lines)
{
var raw = GetRelevantStrings(lines, Apply).Select(line => line.Substring(1));
var raw = GetRelevantStrings(lines, Apply).Select(line => line[1..]);
return from line in raw
select line.Split(SplitInstruction) into split
where split.Length == 2

View file

@ -91,7 +91,7 @@ namespace PKHeX.Core
{
if (!flag.StartsWith("0x"))
return Convert.ToInt16(flag);
flag = flag.Substring(2);
flag = flag[2..];
return Convert.ToInt16(flag, 16);
}
@ -99,7 +99,7 @@ namespace PKHeX.Core
{
if (!c.StartsWith("0x40"))
return Convert.ToInt16(c);
c = c.Substring(4);
c = c[4..];
return Convert.ToInt16(c, 16);
}
}

View file

@ -28,7 +28,7 @@ namespace PKHeX.Core
return false;
}
var indexString = l.Substring(1);
var indexString = l[1..];
if (int.TryParse(indexString, out index))
return true;

View file

@ -361,7 +361,7 @@ namespace PKHeX.Core
if (first.Contains(" @ "))
{
string[] pieces = first.Split(ItemSplit, StringSplitOptions.None);
string itemName = pieces[pieces.Length - 1].Trim();
string itemName = pieces[^1].Trim();
ParseItemName(itemName);
ParseFirstLineNoItem(pieces[0]);
@ -399,8 +399,8 @@ namespace PKHeX.Core
// Gender Detection
if (line.EndsWith("(M)") || line.EndsWith("(F)"))
{
Gender = line[line.Length - 2].ToString();
line = line.Substring(0, line.Length - 3);
Gender = line[^2].ToString();
line = line[0..^3];
}
else // Meowstic Edge Case with no gender provided
{
@ -424,7 +424,7 @@ namespace PKHeX.Core
if (speciesLine.EndsWith(Gmax))
{
CanGigantamax = true;
speciesLine = speciesLine.Substring(0, speciesLine.Length - Gmax.Length);
speciesLine = speciesLine[..^Gmax.Length];
}
if ((Species = StringUtil.FindIndexIgnoreCase(Strings.specieslist, speciesLine)) >= 0) // success, nothing else!
@ -435,8 +435,8 @@ namespace PKHeX.Core
if (end < 0)
return false;
Species = StringUtil.FindIndexIgnoreCase(Strings.specieslist, speciesLine.Substring(0, end));
FormName = speciesLine.Substring(end + 1);
Species = StringUtil.FindIndexIgnoreCase(Strings.specieslist, speciesLine[..end]);
FormName = speciesLine[(end + 1)..];
if (Species >= 0)
return true;
@ -448,7 +448,7 @@ namespace PKHeX.Core
if (!speciesLine.StartsWith(sn.Replace("♂", "-M").Replace("♀", "-F")))
continue;
Species = e;
FormName = speciesLine.Substring(sn.Length);
FormName = speciesLine[sn.Length..];
return true;
}
@ -456,8 +456,8 @@ namespace PKHeX.Core
end = speciesLine.LastIndexOf('-', Math.Max(0, end - 1));
if (end < 0)
return false;
Species = StringUtil.FindIndexIgnoreCase(Strings.specieslist, speciesLine.Substring(0, end));
FormName = speciesLine.Substring(end + 1);
Species = StringUtil.FindIndexIgnoreCase(Strings.specieslist, speciesLine[..end]);
FormName = speciesLine[(end + 1)..];
return Species >= 0;
}
@ -468,15 +468,15 @@ namespace PKHeX.Core
string n1, n2;
if (index > 1) // correct format
{
n1 = line.Substring(0, index).Trim();
n2 = line.Substring(index).Trim();
n1 = line[..index].Trim();
n2 = line[index..].Trim();
n2 = RemoveAll(n2, ParenJunk); // Trim out excess data
}
else // nickname first (manually created set, incorrect)
{
int end = line.IndexOf(')');
n2 = line.Substring(index + 1, end - 1);
n1 = end < line.Length - 2 ? line.Substring(end + 2) : n2;
n1 = end < line.Length - 2 ? line[(end + 2)..] : n2;
}
if (ParseSpeciesForm(n2))
@ -493,7 +493,7 @@ namespace PKHeX.Core
private string ParseLineMove(string line)
{
const int hiddenPower = 237;
string moveString = line.Substring(line[1] == ' ' ? 2 : 1).Split('/')[0].Trim();
string moveString = line[(line[1] == ' ' ? 2 : 1)..].Split('/')[0].Trim();
if (!moveString.StartsWith(Strings.Move[hiddenPower])) // Hidden Power
return moveString; // regular move
@ -501,7 +501,7 @@ namespace PKHeX.Core
return Strings.Move[hiddenPower];
// Defined Hidden Power
string type = moveString.Substring(13);
string type = moveString[13..];
type = RemoveAll(type, ParenJunk); // Trim out excess data
int hpVal = StringUtil.FindIndexIgnoreCase(Strings.types, type) - 1; // Get HP Type

View file

@ -183,7 +183,7 @@ namespace PKHeX.Core
{
// Fix Item Names (Duplicate entries)
var HM06 = itemlist[425];
var HM0 = HM06.Substring(0, HM06.Length - 1); // language ambiguous!
var HM0 = HM06[..^1]; // language ambiguous!
itemlist[426] = $"{HM0}7 (G4)";
itemlist[427] = $"{HM0}8 (G4)";
itemlist[456] += " (HG/SS)"; // S.S. Ticket

View file

@ -30,7 +30,7 @@ namespace PKHeX.Core
private static string[][] UnpackList(string[] input)
{
var last = GetEntry(input[input.Length - 1], out var lastIndex);
var last = GetEntry(input[^1], out var lastIndex);
var list = new string[lastIndex+1][];
list[lastIndex] = last;
for (int i = 1; i < input.Length - 1; i++)

View file

@ -14,7 +14,7 @@ namespace PKHeX.Core
var result = new EncounterArea6XY[input.Length + 1];
for (int i = 0; i < input.Length; i++)
result[i] = new EncounterArea6XY(input[i], game);
result[result.Length - 1] = safari;
result[^1] = safari;
return result;
}

View file

@ -36,7 +36,7 @@ namespace PKHeX.Core
if (((EncounterArea8)Area).PermitCrossover)
return MustHave; // symbol walking overworld
bool curry = pk is IRibbonSetMark8 {RibbonMarkCurry: true} || pk.Species == (int)Core.Species.Shedinja && pk is PK8 {AffixedRibbon:(int)RibbonIndex.MarkCurry};
bool curry = pk is IRibbonSetMark8 {RibbonMarkCurry: true} || (pk.Species == (int)Core.Species.Shedinja && pk is PK8 {AffixedRibbon:(int)RibbonIndex.MarkCurry});
if (curry)
return MustNotHave;

View file

@ -28,9 +28,9 @@ namespace PKHeX.Core
// Gen2 was before split-breed species existed; try to ensure that the egg we try and match to can actually originate in the game.
// Species must be < 251
// Form must be 0 (Unown cannot breed).
var baseID = chain[chain.Count - 1];
var baseID = chain[^1];
if ((baseID.Species >= Legal.MaxSpeciesID_2 || baseID.Form != 0) && chain.Count != 1)
baseID = chain[chain.Count - 2];
baseID = chain[^2];
if (baseID.Form != 0)
yield break; // Forms don't exist in Gen2, besides Unown (which can't breed). Nothing can form-change.

View file

@ -270,7 +270,7 @@ namespace PKHeX.Core
if (reset != 0)
generations = generations.Where(z => z >= reset).ToArray();
int lastgen = generations.Length == 0 ? 0 : generations[generations.Length - 1];
int lastgen = generations.Length == 0 ? 0 : generations[^1];
foreach (var gen in generations)
{
ParseMovesByGeneration(pkm, res, gen, info, moveInfo, lastgen);

View file

@ -212,7 +212,7 @@ namespace PKHeX.Core
private static void CheckLastEncounterRemoval(IEncounterable enc, IReadOnlyList<EvoCriteria> chain)
{
// Last entry from chain is removed, turn next entry into the encountered Pokémon
var last = chain[chain.Count - 1];
var last = chain[^1];
last.MinLevel = enc.LevelMin;
last.RequiresLvlUp = false;

View file

@ -351,12 +351,12 @@ namespace PKHeX.Core
}
// Remove future gen pre-evolutions; no Munchlax from a Gen3 Snorlax, no Pichu from a Gen1-only Raichu, etc
var last = dl[dl.Count - 1];
var last = dl[^1];
if (last.Species > maxSpeciesOrigin && dl.Any(d => d.Species <= maxSpeciesOrigin))
dl.RemoveAt(dl.Count - 1);
// Last species is the wild/hatched species, the minimum level is 1 because it has not evolved from previous species
last = dl[dl.Count - 1];
last = dl[^1];
last.MinLevel = 1;
last.RequiresLvlUp = false;
return dl;
@ -364,7 +364,7 @@ namespace PKHeX.Core
private static void UpdateMinValues(IReadOnlyList<EvoCriteria> dl, EvolutionMethod evo)
{
var last = dl[dl.Count - 1];
var last = dl[^1];
if (!evo.RequiresLevelUp)
{
// Evolutions like elemental stones, trade, etc

View file

@ -107,12 +107,12 @@ namespace PKHeX.Core
var moves = info.Moves;
if (count == -1)
return moves[moves.Length - 1] != 0;
return moves[^1] != 0;
var baseMoves = info.Learnset.GetBaseEggMoves(info.Level);
if (baseMoves.Length < count)
return false;
if (moves[moves.Length - 1] == 0 && count != baseMoves.Length)
if (moves[^1] == 0 && count != baseMoves.Length)
return false;
for (int i = count - 1, b = baseMoves.Length - 1; i >= 0; i--, b--)

View file

@ -103,12 +103,12 @@ namespace PKHeX.Core
var moves = info.Moves;
if (count == -1)
return moves[moves.Length - 1] != 0;
return moves[^1] != 0;
var baseMoves = info.Learnset.GetBaseEggMoves(info.Level);
if (baseMoves.Length < count)
return false;
if (moves[moves.Length - 1] == 0 && count != baseMoves.Length)
if (moves[^1] == 0 && count != baseMoves.Length)
return false;
for (int i = count - 1, b = baseMoves.Length - 1; i >= 0; i--, b--)

View file

@ -104,12 +104,12 @@ namespace PKHeX.Core
var moves = info.Moves;
if (count == -1)
return moves[moves.Length - 1] != 0;
return moves[^1] != 0;
var baseMoves = info.Learnset.GetBaseEggMoves(info.Level);
if (baseMoves.Length < count)
return false;
if (moves[moves.Length - 1] == 0 && count != baseMoves.Length)
if (moves[^1] == 0 && count != baseMoves.Length)
return false;
for (int i = count - 1, b = baseMoves.Length - 1; i >= 0; i--, b--)

View file

@ -103,12 +103,12 @@ namespace PKHeX.Core
var moves = info.Moves;
if (count == -1)
return moves[moves.Length - 1] != 0;
return moves[^1] != 0;
var baseMoves = info.Learnset.GetBaseEggMoves(info.Level);
if (baseMoves.Length < count)
return false;
if (moves[moves.Length - 1] == 0 && count != baseMoves.Length)
if (moves[^1] == 0 && count != baseMoves.Length)
return false;
for (int i = count - 1, b = baseMoves.Length - 1; i >= 0; i--, b--)

View file

@ -103,12 +103,12 @@ namespace PKHeX.Core
var moves = info.Moves;
if (count == -1)
return moves[moves.Length - 1] != 0;
return moves[^1] != 0;
var baseMoves = info.Learnset.GetBaseEggMoves(info.Level);
if (baseMoves.Length < count)
return false;
if (moves[moves.Length - 1] == 0 && count != baseMoves.Length)
if (moves[^1] == 0 && count != baseMoves.Length)
return false;
for (int i = count - 1, b = baseMoves.Length - 1; i >= 0; i--, b--)

View file

@ -42,7 +42,7 @@ namespace PKHeX.Core
get
{
while (index >= Seeds.Count)
Add(Advance(Seeds[Seeds.Count - 1]));
Add(Advance(Seeds[^1]));
return Values[index];
}
}
@ -55,7 +55,7 @@ namespace PKHeX.Core
public uint GetSeed(int index)
{
while (index >= Seeds.Count)
Add(Advance(Seeds[Seeds.Count - 1]));
Add(Advance(Seeds[^1]));
return Seeds[index];
}
}

View file

@ -22,8 +22,8 @@ namespace PKHeX.Core
var index = line.IndexOf('\t');
if (index < 0)
continue;
var name = line.Substring(0, index);
var text = line.Substring(index + 1);
var name = line[..index];
var text = line[(index + 1)..];
RibbonNames[name] = text;
}
}

View file

@ -36,6 +36,6 @@ namespace PKHeX.Core
return result;
}
public override bool Empty => Data.IsRangeAll((byte)0, 0, Data.Length);
public override bool Empty => new ReadOnlySpan<byte>(Data).IsRangeEmpty();
}
}

View file

@ -15,6 +15,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IndexRange" Version="1.0.0" />
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>

View file

@ -104,7 +104,7 @@ namespace PKHeX.Core
return new[] { G1TradeOTCode, G1TerminatorCode };
if (value.Length > maxLength)
value = value.Substring(0, maxLength); // Hard cap
value = value[..maxLength]; // Hard cap
var capacity = Math.Max(value.Length, padTo);
var arr = new List<byte>(capacity);

View file

@ -57,7 +57,7 @@ namespace PKHeX.Core
return new[] { G1TradeOTCode, G1TerminatorCode };
if (value.Length > maxLength)
value = value.Substring(0, maxLength); // Hard cap
value = value[..maxLength]; // Hard cap
var kor = U2GSC_KOR;
var dict = U2RBY_U;

View file

@ -47,7 +47,7 @@ namespace PKHeX.Core
public static byte[] SetString3(string value, int maxLength, bool jp, int padTo = 0, ushort padWith = 0)
{
if (value.Length > maxLength)
value = value.Substring(0, maxLength); // Hard cap
value = value[..maxLength]; // Hard cap
var data = new byte[value.Length + 1]; // +1 for Terminator
for (int i = 0; i < value.Length; i++)
{
@ -61,7 +61,7 @@ namespace PKHeX.Core
data[i] = val;
}
if (data.Length > 0)
data[data.Length - 1] = TerminatorByte;
data[^1] = TerminatorByte;
if (data.Length > maxLength && padTo <= maxLength)
{
// Truncate
@ -100,7 +100,7 @@ namespace PKHeX.Core
public static byte[] SetBEString3(string value, int maxLength, int padTo = 0, ushort padWith = TerminatorBigEndian)
{
if (value.Length > maxLength)
value = value.Substring(0, maxLength); // Hard cap
value = value[..maxLength]; // Hard cap
var sb = new StringBuilder(value);
StringConverter.SanitizeString(sb);
sb.Append(TerminatorBigEndian);

View file

@ -241,7 +241,7 @@ namespace PKHeX.Core
Debug.WriteLine($"Trying to convert {srcName} to {destName}.");
// All types that inherit PKM have the generation specifier as the last char in their class name.
int destGeneration = destName[destName.Length - 1] - '0';
int destGeneration = destName[^1] - '0';
var pkm = ConvertPKM(pk, destType, destGeneration, ref comment);
var msg = pkm == null ? MsgPKMConvertFailFormat : MsgPKMConvertSuccess;
var formatted = string.Format(msg, srcName, destName);
@ -346,10 +346,10 @@ namespace PKHeX.Core
pk.HeldItem = 0;
if (pk.Nickname.Length > limit.NickLength)
pk.Nickname = pk.Nickname.Substring(0, pk.NickLength);
pk.Nickname = pk.Nickname[..pk.NickLength];
if (pk.OT_Name.Length > limit.OTLength)
pk.OT_Name = pk.OT_Name.Substring(0, pk.OTLength);
pk.OT_Name = pk.OT_Name[..pk.OTLength];
if (pk.Moves.Any(move => move > limit.MaxMoveID))
pk.ClearInvalidMoves();

View file

@ -233,7 +233,7 @@ namespace PKHeX.Core
{
if (string.IsNullOrEmpty(ext))
return prefer;
return GetPKMFormatFromExtension(ext[ext.Length - 1], prefer);
return GetPKMFormatFromExtension(ext[^1], prefer);
}
/// <summary>

View file

@ -91,7 +91,7 @@ namespace PKHeX.Core
int payloadBegin = url.IndexOf('#');
if (payloadBegin < 0) // bad URL, need the payload separator
return null;
url = url.Substring(payloadBegin + 1); // Trim URL to right after #
url = url[(payloadBegin + 1)..]; // Trim URL to right after #
return Convert.FromBase64String(url);
}
#pragma warning disable CA1031 // Do not catch general exception types

View file

@ -53,11 +53,11 @@ namespace PKHeX.Core
var split = line.IndexOf('\t');
if (split < 0)
continue;
var hex = line.Substring(0, split);
var hex = line[..split];
if (!ulong.TryParse(hex, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out var value))
continue;
var name = line.Substring(split + 1);
var name = line[(split + 1)..];
if (!names.ContainsKey((uint) value))
names[(uint) value] = name;
}
@ -69,7 +69,7 @@ namespace PKHeX.Core
if (text.StartsWith("*"))
return text;
// key:X8, " - ", "####", " ", type
return text.Substring(8 + 3 + 4 + 1);
return text[(8 + 3 + 4 + 1)..];
}
private string GetBlockHint(SCBlock z, int i)

View file

@ -83,8 +83,8 @@ namespace PKHeX.Core
// Trim off Value summary if present
var space = fn.IndexOf(' ');
if (space >= 0)
fn = fn.Substring(0, space);
if (space != -1)
fn = fn[..space];
var hex = Util.GetHexValue(fn);
try

View file

@ -265,7 +265,7 @@ namespace PKHeX.Core
public override void SetBoxName(int box, string value)
{
if (value.Length > 8)
value = value.Substring(0, 8); // Hard cap
value = value[..8]; // Hard cap
SetString(value, 8).CopyTo(Data, GetBoxInfoOffset(box));
}

View file

@ -101,7 +101,7 @@ namespace PKHeX.Core
{
const int maxlen = 8;
if (value.Length > maxlen)
value = value.Substring(0, maxlen); // Hard cap
value = value[..maxlen]; // Hard cap
int offset = GetBoxNameOffset(box);
var str = SetString(value, maxlen);
SetData(Storage, str, offset);

View file

@ -49,7 +49,7 @@ namespace PKHeX.Core
{
const int maxlen = 8;
if (value.Length > maxlen)
value = value.Substring(0, maxlen); // Hard cap
value = value[..maxlen]; // Hard cap
int offset = GetBoxNameOffset(box);
var str = SetString(value, maxlen);
SetData(Storage, str, offset);

View file

@ -30,7 +30,7 @@ namespace PKHeX.Core
protected void ReloadBattleTeams()
{
var demo = this is SAV7SM && Data.IsRangeAll((byte)0, BoxLayout.Offset, 0x4C4); // up to Battle Box values
var demo = this is SAV7SM && new ReadOnlySpan<byte>(Data, BoxLayout.Offset, 0x4C4).IsRangeEmpty(); // up to Battle Box values
if (demo || !State.Exportable)
{
BoxLayout.ClearBattleTeams();

View file

@ -11,7 +11,7 @@ namespace PKHeX.Core
{
protected internal override string ShortSummary => $"{OT} ({Version}) - {Blocks.Played.LastSavedTime}";
public override string Extension => ".bin";
public override IReadOnlyList<string> PKMExtensions => PKM.Extensions.Where(f => f[1] == 'b' && f[f.Length - 1] == '7').ToArray();
public override IReadOnlyList<string> PKMExtensions => PKM.Extensions.Where(f => f[1] == 'b' && f[^1] == '7').ToArray();
public override Type PKMType => typeof(PB7);
public override PKM BlankPKM => new PB7();

View file

@ -97,7 +97,7 @@ namespace PKHeX.Core
{
var bakName = Util.CleanFileName(bak);
var fn = Path.GetFileName(path);
return fn.EndsWith(bakName) ? fn.Substring(0, fn.Length - bakName.Length) : fn;
return fn.EndsWith(bakName) ? fn[..^bakName.Length] : fn;
}
private void SetAsBlank()

View file

@ -91,7 +91,7 @@ namespace PKHeX.Core
public override byte[] SetString(string value, int maxLength, int PadToSize = 0, ushort PadWith = 0)
{
if (value.Length > maxLength)
value = value.Substring(0, maxLength); // Hard cap
value = value[..maxLength]; // Hard cap
string temp = value
.PadRight(value.Length + 1, (char)0) // Null Terminator
.PadRight(PadToSize, (char)PadWith); // Padding

View file

@ -1,5 +1,4 @@
using System;
using System.Linq;
namespace PKHeX.Core
{
@ -39,22 +38,14 @@ namespace PKHeX.Core
public string GameSyncID
{
get
{
var data = Data.AsSpan(Offset + 0x10, GameSyncIDSize / 2).ToArray();
Array.Reverse(data);
return BitConverter.ToString(data).Replace("-", string.Empty);
}
get => Util.GetHexStringFromBytes(Data, Offset + 0x10, GameSyncIDSize / 2);
set
{
if (value.Length > 16)
throw new ArgumentException(nameof(value));
Enumerable.Range(0, value.Length)
.Where(x => x % 2 == 0)
.Reverse()
.Select(x => Convert.ToByte(value.Substring(x, 2), 16))
.ToArray().CopyTo(Data, Offset + 0x10);
var data = Util.GetBytesFromHexString(value);
SAV.SetData(data, Offset + 0x10);
}
}

View file

@ -121,7 +121,7 @@ namespace PKHeX.Core
while ((data.Length & ~1) != 0)
{
chk += BigEndian.ToUInt16(data);
data = data.Slice(2);
data = data[2..];
}
return (uint)(chk << 16 | (ushort)(0xF004u - chk));
}

View file

@ -8,54 +8,21 @@ namespace PKHeX.Core
/// </summary>
public static class ArrayUtil
{
public static bool IsRangeAll<T>(this T[] data, T value, int offset, int length) where T : IEquatable<T>
public static bool IsRangeEmpty(this ReadOnlySpan<byte> data, byte value = 0)
{
int start = offset + length - 1;
int end = offset;
for (int i = start; i >= end; i--)
for (int i = data.Length - 1; i >= 0; i--)
{
if (!data[i].Equals(value))
if (data[i] != value)
return false;
}
return true;
}
public static byte[] Truncate(byte[] data, int newSize)
{
Array.Resize(ref data, newSize);
return data;
}
public static byte[] Slice(this byte[] src, int offset, int length)
{
byte[] data = new byte[length];
Buffer.BlockCopy(src, offset, data, 0, data.Length);
return data;
}
public static byte[] SliceEnd(this byte[] src, int offset)
{
int length = src.Length - offset;
byte[] data = new byte[length];
Buffer.BlockCopy(src, offset, data, 0, data.Length);
return data;
}
public static T[] Slice<T>(this T[] src, int offset, int length)
{
var data = new T[length];
Array.Copy(src, offset, data, 0, data.Length);
return data;
}
public static T[] SliceEnd<T>(this T[] src, int offset)
{
int length = src.Length - offset;
var data = new T[length];
Array.Copy(src, offset, data, 0, data.Length);
return data;
}
public static byte[] Truncate(byte[] data, int newSize) => data.AsSpan(0, newSize).ToArray();
public static byte[] Slice(this byte[] src, int offset, int length) => src.AsSpan(offset, length).ToArray();
public static byte[] SliceEnd(this byte[] src, int offset) => src.AsSpan(offset).ToArray();
public static T[] Slice<T>(this T[] src, int offset, int length) => src.AsSpan(offset, length).ToArray();
public static T[] SliceEnd<T>(this T[] src, int offset) => src.AsSpan(offset).ToArray();
public static bool WithinRange(int value, int min, int max) => min <= value && value < max;

View file

@ -20,7 +20,7 @@ namespace PKHeX.Core
for (int i = 1; i < inputCSV.Count; i++)
{
var line = inputCSV[i];
var val = line.Substring(0, 3);
var val = line[..3];
var text = StringUtil.GetNthEntry(line, index, 4);
var item = new ComboItem(text, Convert.ToInt32(val));
arr.Add(item);

View file

@ -15,7 +15,12 @@ namespace PKHeX.Core
/// <param name="input">Enumerable of translation definitions in the form "Property = Value".</param>
private static string[] GetProperties(IEnumerable<string> input)
{
return input.Select(l => l.Substring(0, l.IndexOf(TranslationSplitter, StringComparison.Ordinal))).ToArray();
static string AfterSplit(string l)
{
var split = l.IndexOf(TranslationSplitter, StringComparison.Ordinal);
return l[..split];
}
return input.Select(AfterSplit).ToArray();
}
private static IEnumerable<string> DumpStrings(Type t)
@ -64,8 +69,8 @@ namespace PKHeX.Core
var index = line.IndexOf(TranslationSplitter, StringComparison.Ordinal);
if (index < 0)
continue;
var prop = line.Substring(0, index);
var value = line.Substring(index + TranslationSplitter.Length);
var prop = line[..index];
var value = line[(index + TranslationSplitter.Length)..];
try
{

View file

@ -147,9 +147,8 @@ namespace PKHeX.Core
var line = raw[i];
if (line.Length == 0)
continue;
var last = line.Length - 1;
if (line[last] == '\r')
raw[i] = line.Substring(0, last);
if (line[^1] == '\r')
raw[i] = line[..^1];
}
lock (getStringListLoadLock) // Make sure only one thread can write to the cache

View file

@ -62,7 +62,7 @@ namespace PKHeX.Core
if (nth != 1)
start = line.IndexOfNth(separator, nth - 1, start + 1);
var end = line.IndexOfNth(separator, 1, start + 1);
return end < 0 ? line.Substring(start + 1) : line.Substring(start + 1, end - start - 1);
return end == -1 ? line[(start + 1)..] : line[(start + 1)..end];
}
private static int IndexOfNth(this string s, char t, int n, int start)

View file

@ -127,9 +127,8 @@ namespace PKHeX.Core
for (int i = 0; i < result.Length; i++)
{
var slice = seed.Substring(i * 2, 2);
result[i] = Convert.ToByte(slice, 16);
result[^(i+1)] = Convert.ToByte(slice, 16);
}
Array.Reverse(result);
return result;
}
@ -146,7 +145,7 @@ namespace PKHeX.Core
private static bool IsHexUpper(char c) => (uint)(c - 'A') <= 5;
private static bool IsHexLower(char c) => (uint)(c - 'a') <= 5;
private static bool IsHex(char c) => IsNum(c) || IsHexUpper(c) || IsHexLower(c);
private static string TitleCase(string word) => char.ToUpper(word[0]) + word.Substring(1, word.Length - 1).ToLower();
private static string TitleCase(string word) => char.ToUpper(word[0]) + word[1..].ToLower();
/// <summary>
/// Filters the string down to only valid hex characters, returning a new string.
@ -171,7 +170,7 @@ namespace PKHeX.Core
private static string TrimFromFirst(string input, char c)
{
int index = input.IndexOf(c);
return index < 0 ? input : input.Substring(0, index);
return index < 0 ? input : input[..index];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View file

@ -52,7 +52,7 @@ namespace PKHeX.Core
if (value is not string input)
return base.ConvertFrom(context, culture, value);
if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
input = input.Substring(2);
input = input[2..];
return ulong.TryParse(input, System.Globalization.NumberStyles.HexNumber, culture, out var result) ? result : 0ul;
}
}

View file

@ -1,6 +1,5 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
@ -63,20 +62,33 @@ namespace PKHeX.Drawing
if (!data.StartsWith(intro))
throw new FormatException();
string pkstr = data.Substring(intro.Length);
if (pkstr.Contains(qrcode)) // Remove multiple QR codes in same image
pkstr = pkstr.Substring(0, pkstr.IndexOf(qrcode, StringComparison.Ordinal));
pkstr = pkstr.Substring(0, pkstr.IndexOf(cap, StringComparison.Ordinal)); // Trim outro
string pkstr = data[intro.Length..];
// Remove multiple QR codes in same image
var qr = pkstr.IndexOf(qrcode, StringComparison.Ordinal);
if (qr != -1)
pkstr = pkstr[..qr];
// Trim outro
var outroIndex = pkstr.IndexOf(cap, StringComparison.Ordinal);
if (outroIndex == -1)
throw new FormatException();
pkstr = pkstr[..outroIndex];
if (!pkstr.StartsWith("http") && !pkstr.StartsWith("null")) // G7
{
string fstr = Regex.Unescape(pkstr);
byte[] raw = Encoding.Unicode.GetBytes(fstr);
// Remove 00 interstitials and retrieve from offset 0x30, take PK7 Stored Size (always)
return raw.Where((_, i) => i % 2 == 0).Skip(0x30).Take(0xE8).ToArray();
byte[] result = new byte[0xE8];
for (int i = 0; i < result.Length; i++)
result[i] = raw[(i + 0x30) * 2];
return result;
}
// All except G7
pkstr = pkstr.Substring(pkstr.IndexOf('#') + 1); // Trim URL
pkstr = pkstr[(pkstr.IndexOf('#') + 1)..]; // Trim URL
pkstr = pkstr.Replace("\\", string.Empty); // Rectify response
return Convert.FromBase64String(pkstr);

View file

@ -44,8 +44,9 @@ namespace PKHeX.WinForms.Controls
// don't grab sprite of pkm, no gender specific cries
var res = SpriteName.GetResourceStringSprite(pk.Species, pk.Form, 0, 0, format);
return res.Replace('_', '-') // people like - instead of _ file names ;)
.Substring(1); // skip leading underscore
// people like - instead of _ file names ;)
return res.Replace('_', '-')[1..]; // skip leading underscore
}
}
}
}

View file

@ -489,7 +489,7 @@ namespace PKHeX.WinForms
{ WinFormsUtil.Alert(MsgSimulatorFailClipboard); return; }
if (Set.Nickname.Length > C_SAV.SAV.NickLength)
Set.Nickname = Set.Nickname.Substring(0, C_SAV.SAV.NickLength);
Set.Nickname = Set.Nickname[..C_SAV.SAV.NickLength];
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MsgSimulatorLoad, Set.Text))
return;
@ -914,7 +914,7 @@ namespace PKHeX.WinForms
// Set the culture (makes it easy to pass language to other forms)
Settings.Startup.Language = CurrentLanguage;
Thread.CurrentThread.CurrentCulture = new CultureInfo(CurrentLanguage.Substring(0, 2));
Thread.CurrentThread.CurrentCulture = new CultureInfo(CurrentLanguage[..2]);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
Menu_Options.DropDown.Close();

View file

@ -25,7 +25,7 @@ namespace PKHeX.WinForms
foreach (var pair in pairs)
{
var split = pair.Name.Split('_');
var specName = split[0].Substring(G1OverworldSpawner.FlagPropertyPrefix.Length);
var specName = split[0][G1OverworldSpawner.FlagPropertyPrefix.Length..];
// convert species name to current localization language
int species = SpeciesName.GetSpeciesID(specName);

View file

@ -449,7 +449,7 @@ namespace PKHeX.WinForms
int maxlen = sender == TB_FacilityID ? 12 << 1 : 4 << 1;
if (t.Length > maxlen)
{
t = t.Substring(0, maxlen);
t = t[..maxlen];
editing = true;
((TextBox)sender).Text = t;
editing = false;

View file

@ -21,8 +21,8 @@ namespace PKHeX.WinForms
TB_OTName.MaxLength = SAV.OTLength;
B_MaxCash.Click += (sender, e) => MT_Money.Text = SAV.MaxMoney.ToString();
B_MaxCoins.Click += (sender, e) => MT_Coins.Text = SAV.MaxCoins.ToString();
MT_Money.Mask = "00000000000".Substring(0, SAV.MaxMoney.ToString().Length);
MT_Coins.Mask = "00000000000".Substring(0, SAV.MaxCoins.ToString().Length);
MT_Money.Mask = "".PadRight((int)Math.Floor(Math.Log10(SAV.MaxMoney) + 1));
MT_Coins.Mask = "".PadRight((int)Math.Floor(Math.Log10(SAV.MaxCoins) + 1));
CB_Gender.Items.Clear();
CB_Gender.Items.AddRange(Main.GenderSymbols.Take(2).ToArray()); // m/f depending on unicode selection

View file

@ -148,7 +148,7 @@ namespace PKHeX.WinForms
var path = Application.StartupPath;
const string projname = "PKHeX\\";
var pos = path.LastIndexOf(projname, StringComparison.Ordinal);
var str = path.Substring(0, pos + projname.Length);
var str = path[..(pos + projname.Length)];
var coreFolder = Path.Combine(str, "PKHeX.Core", "Resources", "text");
return coreFolder;

View file

@ -301,7 +301,7 @@ namespace PKHeX.WinForms
string pkx = pk.Extension;
bool allowEncrypted = pk.Format >= 3 && pkx[0] == 'p';
var genericFilter = $"Decrypted PKM File|*.{pkx}" +
(allowEncrypted ? $"|Encrypted PKM File|*.e{pkx.Substring(1)}" : string.Empty) +
(allowEncrypted ? $"|Encrypted PKM File|*.e{pkx[1..]}" : string.Empty) +
"|Binary File|*.bin" +
"|All Files|*.*";
using var sfd = new SaveFileDialog