mirror of
https://github.com/kwsch/PKHeX
synced 2025-02-17 13:58:33 +00:00
Rearrange src, speed up encryption
No need to shuffle 11*, just have the precomputed final shuffle values and redirect. Rearrangement removes PKX/PGT interaction (now only refers to past gen code base)
This commit is contained in:
parent
8218fbfefb
commit
aa7974e158
3 changed files with 142 additions and 113 deletions
79
Misc/PGT.cs
79
Misc/PGT.cs
|
@ -38,7 +38,7 @@ namespace PKHeX
|
|||
byte[] ekdata = new byte[PK4.SIZE_PARTY];
|
||||
Array.Copy(Data, 8, ekdata, 0, ekdata.Length);
|
||||
// Decrypt PK4
|
||||
PKM = new PK4(PKX.decryptG4Array(ekdata, BitConverter.ToUInt16(ekdata, 6)));
|
||||
PK = new PK4(PKM.decryptArray(ekdata, BitConverter.ToUInt16(ekdata, 6)));
|
||||
|
||||
Unknown = new byte[0x10];
|
||||
Array.Copy(Data, 0xF4, Unknown, 0, 0x10);
|
||||
|
@ -48,7 +48,7 @@ namespace PKHeX
|
|||
// Unused 0x01
|
||||
public byte Slot { get { return Data[2]; } set { Data[2] = value; } }
|
||||
public byte Detail { get { return Data[3]; } set { Data[3] = value; } }
|
||||
public PK4 PKM;
|
||||
public PK4 PK;
|
||||
public byte[] Unknown;
|
||||
|
||||
public bool IsPokémon { get { return CardType == 1; } set { if (value) CardType = 1; } }
|
||||
|
@ -61,37 +61,38 @@ namespace PKHeX
|
|||
if (!PokémonGift)
|
||||
return null;
|
||||
|
||||
PK4 pk4 = new PK4(PK.Data);
|
||||
if (!IsPokémon && Detail == 0)
|
||||
{
|
||||
PKM.OT_Name = "PKHeX";
|
||||
PKM.TID = 12345;
|
||||
PKM.SID = 54321;
|
||||
PKM.OT_Gender = (int)(Util.rnd32()%2);
|
||||
pk4.OT_Name = "pk4HeX";
|
||||
pk4.TID = 12345;
|
||||
pk4.SID = 54321;
|
||||
pk4.OT_Gender = (int)(Util.rnd32()%2);
|
||||
}
|
||||
if (IsManaphyEgg)
|
||||
{
|
||||
// Since none of this data is populated, fill in default info.
|
||||
PKM.Species = 490;
|
||||
pk4.Species = 490;
|
||||
// Level 1 Moves
|
||||
PKM.Move1 = 294;
|
||||
PKM.Move2 = 145;
|
||||
PKM.Move3 = 346;
|
||||
PKM.FatefulEncounter = true;
|
||||
PKM.Ball = 4;
|
||||
PKM.Version = 10; // Diamond
|
||||
PKM.Language = 2; // English
|
||||
PKM.Nickname = "MANAPHY";
|
||||
PKM.Egg_Location = 1; // Ranger (will be +3000 later)
|
||||
pk4.Move1 = 294;
|
||||
pk4.Move2 = 145;
|
||||
pk4.Move3 = 346;
|
||||
pk4.FatefulEncounter = true;
|
||||
pk4.Ball = 4;
|
||||
pk4.Version = 10; // Diamond
|
||||
pk4.Language = 2; // English
|
||||
pk4.Nickname = "MANAPHY";
|
||||
pk4.Egg_Location = 1; // Ranger (will be +3000 later)
|
||||
}
|
||||
|
||||
// Generate IV
|
||||
uint seed = Util.rnd32();
|
||||
if (PKM.PID == 1) // Create Nonshiny
|
||||
if (pk4.PID == 1) // Create Nonshiny
|
||||
{
|
||||
uint pid1 = PKX.LCRNG(ref seed) >> 16;
|
||||
uint pid2 = PKX.LCRNG(ref seed) >> 16;
|
||||
uint pid1 = PKM.LCRNG(ref seed) >> 16;
|
||||
uint pid2 = PKM.LCRNG(ref seed) >> 16;
|
||||
|
||||
while ((pid1 ^ pid2 ^ PKM.TID ^ PKM.SID) < 8)
|
||||
while ((pid1 ^ pid2 ^ pk4.TID ^ pk4.SID) < 8)
|
||||
{
|
||||
uint testPID = pid1 | (pid2 << 16);
|
||||
|
||||
|
@ -101,39 +102,41 @@ namespace PKHeX
|
|||
pid1 = testPID & 0xFFFF;
|
||||
pid2 = testPID >> 16;
|
||||
}
|
||||
PKM.PID = pid1 | (pid2 << 16);
|
||||
pk4.PID = pid1 | (pid2 << 16);
|
||||
}
|
||||
|
||||
// Generate IVs
|
||||
if (PKM.IV32 == 0)
|
||||
if (pk4.IV32 == 0)
|
||||
{
|
||||
uint iv1 = PKX.LCRNG(ref seed) >> 16;
|
||||
uint iv2 = PKX.LCRNG(ref seed) >> 16;
|
||||
PKM.IV32 = (iv1 | (iv2 << 16)) & 0x3FFFFFFF;
|
||||
uint iv1 = PKM.LCRNG(ref seed) >> 16;
|
||||
uint iv2 = PKM.LCRNG(ref seed) >> 16;
|
||||
pk4.IV32 = (iv1 | (iv2 << 16)) & 0x3FFFFFFF;
|
||||
}
|
||||
|
||||
// Generate Met Info
|
||||
DateTime dt = DateTime.Now;
|
||||
if (IsPokémon)
|
||||
{
|
||||
PKM.Met_Location = PKM.Egg_Location + 3000;
|
||||
PKM.Egg_Location = 0;
|
||||
PKM.Met_Day = dt.Day;
|
||||
PKM.Met_Month = dt.Month;
|
||||
PKM.Met_Year = dt.Year - 2000;
|
||||
PKM.IsEgg = false;
|
||||
pk4.Met_Location = pk4.Egg_Location + 3000;
|
||||
pk4.Egg_Location = 0;
|
||||
pk4.Met_Day = dt.Day;
|
||||
pk4.Met_Month = dt.Month;
|
||||
pk4.Met_Year = dt.Year - 2000;
|
||||
pk4.IsEgg = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
PKM.Egg_Location = PKM.Egg_Location + 3000;
|
||||
PKM.Egg_Day = dt.Day;
|
||||
PKM.Egg_Month = dt.Month;
|
||||
PKM.Egg_Year = dt.Year - 2000;
|
||||
PKM.IsEgg = false;
|
||||
// Met Location is modified when transferred to PK5; don't worry about it.
|
||||
pk4.Egg_Location = pk4.Egg_Location + 3000;
|
||||
pk4.Egg_Day = dt.Day;
|
||||
pk4.Egg_Month = dt.Month;
|
||||
pk4.Egg_Year = dt.Year - 2000;
|
||||
pk4.IsEgg = false;
|
||||
// Met Location is modified when transferred to pk5; don't worry about it.
|
||||
}
|
||||
if (pk4.Species == 201) // Never will be true; Unown was never distributed.
|
||||
pk4.AltForm = PKM.getUnownForm(pk4.PID);
|
||||
|
||||
return PKM;
|
||||
return pk4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
96
Misc/PKM.cs
96
Misc/PKM.cs
|
@ -5,6 +5,23 @@ namespace PKHeX
|
|||
{
|
||||
public class PKM // Past Gen
|
||||
{
|
||||
internal static uint LCRNG(uint seed)
|
||||
{
|
||||
const uint a = 0x41C64E6D;
|
||||
const uint c = 0x00006073;
|
||||
|
||||
seed = (seed * a + c) & 0xFFFFFFFF;
|
||||
return seed;
|
||||
}
|
||||
internal static uint LCRNG(ref uint seed)
|
||||
{
|
||||
const uint a = 0x41C64E6D;
|
||||
const uint c = 0x00006073;
|
||||
|
||||
seed = (seed * a + c) & 0xFFFFFFFF;
|
||||
return seed;
|
||||
}
|
||||
|
||||
internal static Converter Config = new Converter();
|
||||
internal static string[] speclang_ja = Util.getStringList("Species", "ja");
|
||||
internal static string[] speclang_en = Util.getStringList("Species", "en");
|
||||
|
@ -19,6 +36,85 @@ namespace PKHeX
|
|||
return index < 0 ? input : input.Substring(0, index);
|
||||
}
|
||||
|
||||
// Past Gen Manipulation
|
||||
internal static readonly byte[][] blockPosition =
|
||||
{
|
||||
new byte[] {0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3},
|
||||
new byte[] {1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2},
|
||||
new byte[] {2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2, 0, 0, 0, 0, 0, 0, 3, 2, 3, 2, 1, 1},
|
||||
new byte[] {3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
internal static readonly byte[] blockPositionInvert =
|
||||
{
|
||||
0, 1, 2, 4, 3, 5, 6, 7, 12, 18, 13, 19, 8, 10, 14, 20, 16, 22, 9, 11, 15, 21, 17, 23
|
||||
};
|
||||
internal static byte[] shuffleArray(byte[] data, uint sv)
|
||||
{
|
||||
byte[] sdata = new byte[PK4.SIZE_PARTY];
|
||||
Array.Copy(data, sdata, 8); // Copy unshuffled bytes
|
||||
|
||||
// Shuffle Away!
|
||||
for (int block = 0; block < 4; block++)
|
||||
Array.Copy(data, 8 + 32 * blockPosition[block][sv], sdata, 8 + 32 * block, 32);
|
||||
|
||||
// Fill the Battle Stats back
|
||||
if (data.Length > 136)
|
||||
Array.Copy(data, 136, sdata, 136, 100);
|
||||
|
||||
return sdata;
|
||||
}
|
||||
internal static byte[] decryptArray(byte[] ekm, uint seed = 0x10000)
|
||||
{
|
||||
byte[] pkm = (byte[])ekm.Clone();
|
||||
|
||||
uint pv = BitConverter.ToUInt32(pkm, 0);
|
||||
uint sv = (((pv & 0x3E000) >> 0xD) % 24);
|
||||
|
||||
seed = seed > 0xFFFF ? pv : seed;
|
||||
|
||||
// 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);
|
||||
|
||||
// Deshuffle
|
||||
pkm = shuffleArray(pkm, sv);
|
||||
|
||||
// Decrypt the Party Stats
|
||||
seed = pv;
|
||||
if (pkm.Length <= 136) return pkm;
|
||||
for (int i = 136; i < 236; i += 2)
|
||||
BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(pkm, i);
|
||||
|
||||
return pkm;
|
||||
}
|
||||
internal static byte[] encryptArray(byte[] pkm, uint seed = 0x10000)
|
||||
{
|
||||
// Shuffle
|
||||
uint pv = BitConverter.ToUInt32(pkm, 0);
|
||||
uint sv = (((pv & 0x3E000) >> 0xD) % 24);
|
||||
|
||||
byte[] ekm = (byte[])pkm.Clone();
|
||||
|
||||
ekm = shuffleArray(ekm, blockPositionInvert[sv]);
|
||||
|
||||
seed = seed > 0xFFFF ? pv : seed;
|
||||
|
||||
// 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);
|
||||
|
||||
// If no party stats, return.
|
||||
if (ekm.Length <= 136) return ekm;
|
||||
|
||||
// Encrypt the Party Stats
|
||||
seed = pv;
|
||||
for (int i = 136; i < 236; i += 2)
|
||||
BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(ekm, i);
|
||||
|
||||
// Done
|
||||
return ekm;
|
||||
}
|
||||
|
||||
internal static int getUnownForm(uint PID)
|
||||
{
|
||||
byte[] data = BitConverter.GetBytes(PID);
|
||||
|
|
80
Misc/PKX.cs
80
Misc/PKX.cs
|
@ -450,6 +450,10 @@ namespace PKHeX
|
|||
new byte[] {2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2, 0, 0, 0, 0, 0, 0, 3, 2, 3, 2, 1, 1},
|
||||
new byte[] {3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0},
|
||||
};
|
||||
internal static readonly byte[] blockPositionInvert =
|
||||
{
|
||||
0, 1, 2, 4, 3, 5, 6, 7, 12, 18, 13, 19, 8, 10, 14, 20, 16, 22, 9, 11, 15, 21, 17, 23
|
||||
};
|
||||
internal static byte[] shuffleArray(byte[] data, uint sv)
|
||||
{
|
||||
byte[] sdata = new byte[260];
|
||||
|
@ -497,10 +501,7 @@ namespace PKHeX
|
|||
|
||||
byte[] ekx = (byte[])pkx.Clone();
|
||||
|
||||
// If I unshuffle 11 times, the 12th (decryption) will always decrypt to ABCD.
|
||||
// 2 x 3 x 4 = 12 (possible unshuffle loops -> total iterations)
|
||||
for (int i = 0; i < 11; i++)
|
||||
ekx = shuffleArray(ekx, sv);
|
||||
ekx = shuffleArray(ekx, blockPositionInvert[sv]);
|
||||
|
||||
uint seed = pv;
|
||||
|
||||
|
@ -581,77 +582,6 @@ namespace PKHeX
|
|||
return pid;
|
||||
}
|
||||
|
||||
// Past Gen Manipulation
|
||||
internal static byte[] shuffleG4Array(byte[] data, uint sv)
|
||||
{
|
||||
byte[] sdata = new byte[PK4.SIZE_PARTY];
|
||||
Array.Copy(data, sdata, 8); // Copy unshuffled bytes
|
||||
|
||||
// Shuffle Away!
|
||||
for (int block = 0; block < 4; block++)
|
||||
Array.Copy(data, 8 + 32 * blockPosition[block][sv], sdata, 8 + 32 * block, 32);
|
||||
|
||||
// Fill the Battle Stats back
|
||||
if (data.Length > 136)
|
||||
Array.Copy(data, 136, sdata, 136, 100);
|
||||
|
||||
return sdata;
|
||||
}
|
||||
internal static byte[] decryptG4Array(byte[] ekm, uint seed = 0x10000)
|
||||
{
|
||||
byte[] pkm = (byte[])ekm.Clone();
|
||||
|
||||
uint pv = BitConverter.ToUInt32(pkm, 0);
|
||||
uint sv = (((pv & 0x3E000) >> 0xD) % 24);
|
||||
|
||||
seed = seed > 0xFFFF ? pv : seed;
|
||||
|
||||
// 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);
|
||||
|
||||
// Deshuffle
|
||||
pkm = shuffleG4Array(pkm, sv);
|
||||
|
||||
// Decrypt the Party Stats
|
||||
seed = pv;
|
||||
if (pkm.Length <= 136) return pkm;
|
||||
for (int i = 136; i < 236; i += 2)
|
||||
BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(pkm, i);
|
||||
|
||||
return pkm;
|
||||
}
|
||||
internal static byte[] encryptG4Array(byte[] pkm, uint seed = 0x10000)
|
||||
{
|
||||
// Shuffle
|
||||
uint pv = BitConverter.ToUInt32(pkm, 0);
|
||||
uint sv = (((pv & 0x3E000) >> 0xD) % 24);
|
||||
|
||||
byte[] ekm = (byte[])pkm.Clone();
|
||||
|
||||
// If I unshuffle 11 times, the 12th (decryption) will always decrypt to ABCD.
|
||||
// 2 x 3 x 4 = 12 (possible unshuffle loops -> total iterations)
|
||||
for (int i = 0; i < 11; i++)
|
||||
ekm = shuffleArray(ekm, sv);
|
||||
|
||||
seed = seed > 0xFFFF ? pv : seed;
|
||||
|
||||
// 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);
|
||||
|
||||
// If no party stats, return.
|
||||
if (ekm.Length <= 136) return ekm;
|
||||
|
||||
// Encrypt the Party Stats
|
||||
seed = pv;
|
||||
for (int i = 136; i < 236; i += 2)
|
||||
BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(ekm, i);
|
||||
|
||||
// Done
|
||||
return ekm;
|
||||
}
|
||||
|
||||
// SAV Manipulation
|
||||
/// <summary>Calculates the CRC16-CCITT checksum over an input byte array.</summary>
|
||||
/// <param name="chunk">Input byte array</param>
|
||||
|
|
Loading…
Add table
Reference in a new issue