From 1d405d63c8cea2f8014ac21e6ee0ceb5c7e79d70 Mon Sep 17 00:00:00 2001 From: Kurt Date: Thu, 28 Dec 2017 23:24:12 -0800 Subject: [PATCH] speed up pkm crypt GetBytes returns an array that is immediately discarded (GC pressure) reduces overhead when loading large pkm collections from save files (shaved off a couple seconds from my loading from 200+ bak saves) could probably go faster with unsafe code to r/w ushort directly then again im profiling under debug but i'd assume the improvements made actually do improve speed for release builds --- PKHeX.Core/PKM/PKX.cs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/PKHeX.Core/PKM/PKX.cs b/PKHeX.Core/PKM/PKX.cs index a8aeba424..c58aa5f08 100644 --- a/PKHeX.Core/PKM/PKX.cs +++ b/PKHeX.Core/PKM/PKX.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; namespace PKHeX.Core { @@ -410,7 +411,7 @@ public static byte[] DecryptArray(byte[] ekx) // Decrypt Blocks with RNG Seed for (int i = 8; i < 232; i += 2) - BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkx, i) ^ LCRNG(ref seed) >> 16)).CopyTo(pkx, i); + Crypt(pkx, ref seed, i); // Deshuffle pkx = ShuffleArray(pkx, sv); @@ -419,7 +420,7 @@ public static byte[] DecryptArray(byte[] ekx) seed = pv; if (pkx.Length <= 232) return pkx; for (int i = 232; i < 260; i += 2) - BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkx, i) ^ LCRNG(ref seed) >> 16)).CopyTo(pkx, i); + Crypt(pkx, ref seed, i); return pkx; } @@ -442,7 +443,7 @@ public static byte[] EncryptArray(byte[] pkx) // Encrypt Blocks with RNG Seed for (int i = 8; i < 232; i += 2) - BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekx, i) ^ LCRNG(ref seed) >> 16)).CopyTo(ekx, i); + Crypt(ekx, ref seed, i); // If no party stats, return. if (ekx.Length <= 232) return ekx; @@ -450,7 +451,7 @@ public static byte[] EncryptArray(byte[] pkx) // Encrypt the Party Stats seed = pv; for (int i = 232; i < 260; i += 2) - BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekx, i) ^ LCRNG(ref seed) >> 16)).CopyTo(ekx, i); + Crypt(ekx, ref seed, i); return ekx; } @@ -649,7 +650,7 @@ public static byte[] DecryptArray45(byte[] ekm) // Decrypt Blocks with RNG Seed for (int i = 8; i < 136; i += 2) - BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkm, i) ^ LCRNG(ref seed) >> 16)).CopyTo(pkm, i); + Crypt(pkm, ref seed, i); // Deshuffle pkm = ShuffleArray45(pkm, sv); @@ -658,7 +659,7 @@ public static byte[] DecryptArray45(byte[] ekm) seed = pv; if (pkm.Length <= 136) return pkm; for (int i = 136; i < pkm.Length; i += 2) - BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkm, i) ^ LCRNG(ref seed) >> 16)).CopyTo(pkm, i); + Crypt(pkm, ref seed, i); return pkm; } @@ -682,7 +683,7 @@ public static byte[] EncryptArray45(byte[] pkm) // Encrypt Blocks with RNG Seed for (int i = 8; i < 136; i += 2) - BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekm, i) ^ LCRNG(ref seed) >> 16)).CopyTo(ekm, i); + Crypt(ekm, ref seed, i); // If no party stats, return. if (ekm.Length <= 136) return ekm; @@ -690,12 +691,22 @@ public static byte[] EncryptArray45(byte[] pkm) // Encrypt the Party Stats seed = pv; for (int i = 136; i < ekm.Length; i += 2) - BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekm, i) ^ LCRNG(ref seed) >> 16)).CopyTo(ekm, i); + Crypt(ekm, ref seed, i); // Done return ekm; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Crypt(byte[] data, ref uint seed, int i) + { + var val = data[i] | data[i + 1] << 8; + seed = 0x41C64E6D * seed + 0x00006073; + val ^= (ushort)(seed >> 16); + data[i] = (byte)val; + data[i + 1] = (byte)(val >> 8); + } + /// /// Gets the Unown Forme ID from PID. ///