Add ranch r(/w?) support

not gonna edit the metadata

properly handle an irregular sized display box
This commit is contained in:
Kurt 2019-01-14 21:31:53 -08:00
parent f0d9e3f2e5
commit ae6010f169
8 changed files with 112 additions and 14 deletions

View file

@ -411,7 +411,7 @@ namespace PKHeX.Core
public virtual int SecondsToFame { get; set; }
public virtual uint Money { get; set; }
public abstract int BoxCount { get; }
public int SlotCount => BoxCount * BoxSlotCount;
public virtual int SlotCount => BoxCount * BoxSlotCount;
public virtual int PartyCount { get; protected set; }
public virtual int MultiplayerSpriteID { get => 0; set { } }
@ -665,7 +665,7 @@ namespace PKHeX.Core
PartyCount--;
}
protected bool IsSlotSwapProtected(int box, int slot) => false;
protected virtual bool IsSlotSwapProtected(int box, int slot) => false;
private bool IsRegionOverwriteProtected(int min, int max)
{

View file

@ -24,7 +24,5 @@ namespace PKHeX.Core
public override int GetBoxOffset(int box) => Box + (BoxDataSize * box);
public override string GetBoxName(int box) => GetString(GetBoxNameOffset(box), BoxNameSize);
private int GetBoxNameOffset(int box) => 0x25800 + (9 * box);
public static Bank3 GetBank3(byte[] data) => new Bank3(data);
}
}

View file

@ -24,7 +24,5 @@ namespace PKHeX.Core
public override int GetBoxOffset(int box) => Box + (BoxDataSize * box);
public override string GetBoxName(int box) => GetString(GetBoxNameOffset(box), BoxNameSize / 2);
private int GetBoxNameOffset(int box) => 0x3FC00 + (0x19 * box);
public static Bank4 GetBank4(byte[] data) => new Bank4(data);
}
}

View file

@ -51,7 +51,7 @@ namespace PKHeX.Core
public override int MaxGameID => blank.MaxGameID;
public override int OTLength => blank.OTLength;
public override int NickLength => blank.NickLength;
public bool BigEndian => blank is BK4 || blank is XK3 || blank is CK3;
public bool IsBigEndian => blank is BK4 || blank is XK3 || blank is CK3;
private readonly Func<byte[], int, bool> GetIsPKMPresent;
public override bool IsPKMPresent(int Offset) => GetIsPKMPresent(Data, Offset);
@ -65,9 +65,9 @@ namespace PKHeX.Core
public override int GetPartyOffset(int slot) => int.MinValue;
public override string GetString(byte[] data, int offset, int length)
=> StringConverter.GetString(data, Generation, blank.Japanese, BigEndian, length, offset);
=> StringConverter.GetString(data, Generation, blank.Japanese, IsBigEndian, length, offset);
public override byte[] SetString(string value, int maxLength, int PadToSize = 0, ushort PadWith = 0)
=> StringConverter.SetString(value, Generation, blank.Japanese, BigEndian, maxLength, padTo: PadToSize, padWith: PadWith);
=> StringConverter.SetString(value, Generation, blank.Japanese, IsBigEndian, maxLength, padTo: PadToSize, padWith: PadWith);
}
}

View file

@ -0,0 +1,96 @@
using System;
using System.Security.Cryptography;
using System.Text;
namespace PKHeX.Core
{
public sealed class SAV4Ranch : BulkStorage
{
private const int SIZE_MII = 0x28;
private const int SIZE_MIILINK = 0x2C;
public override int SIZE_STORED => 0x88 + 0x1C;
protected override int SIZE_PARTY => SIZE_STORED;
public override int BoxCount { get; }
public override int SlotCount { get; }
public override string PlayTimeString => SaveUtil.CRC16(Data, 0, Data.Length).ToString("X4");
protected override string BAKText => $"{OT} {PlayTimeString}";
public override string Extension => ".bin";
public override string Filter { get; } = "Ranch G4 Storage|*.bin*";
public override PKM GetPKM(byte[] data) => new PK4(data);
public override byte[] DecryptPKM(byte[] data) => PKX.DecryptArray45(data);
public override StorageSlotFlag GetSlotFlags(int index) => index >= SlotCount ? StorageSlotFlag.Locked : StorageSlotFlag.None;
protected override bool IsSlotSwapProtected(int box, int slot) => IsSlotOverwriteProtected(box, slot);
public SAV4Ranch(byte[] data) : base(data, typeof(PK4), 0)
{
Personal = PersonalTable.Pt;
Version = GameVersion.DPPt;
HeldItems = Legal.HeldItems_Pt;
OT = GetString(0x770, 0x12);
// Unpack the binary a little:
// count, Mii data[count]
// count, Mii Link data[count]
// count, Pokemon (PK4 + metadata)[count]
/* ====Metadata====
* uint8_t poke_type;// 01 trainer, 04 hayley, 05 traded
* uint8_t tradeable;// 02 is tradeable, normal 00
* uint16_t tid;
* uint16_t sid;
* uint32_t name1;
* uint32_t name2;
* uint32_t name3;
* uint32_t name4;
*/
const int miiCountOffset = 0x22AC;
var miiCount = BigEndian.ToInt32(Data, miiCountOffset);
var miiLinkCountOffset = miiCountOffset + 4 + (SIZE_MII * miiCount) + 4;
var miiLinkCount = BigEndian.ToInt32(Data, miiLinkCountOffset);
var pkCountOffset = miiLinkCountOffset + 4 + (SIZE_MIILINK * miiLinkCount) + 4;
SlotCount = BigEndian.ToInt32(Data, pkCountOffset);
BoxCount = (int)Math.Ceiling((decimal)SlotCount / SlotsPerBox);
Box = pkCountOffset + 4;
FinalCountOffset = pkCountOffset + 4 + (SIZE_STORED * SlotCount);
FinalCount = BigEndian.ToInt32(Data, FinalCountOffset);
}
private readonly int FinalCount;
private readonly int FinalCountOffset;
protected override void SetChecksums()
{
BigEndian.GetBytes(FinalCount).CopyTo(Data, FinalCountOffset); // ensure the final data is written if the user screws stuff up
var goodlen = (FinalCountOffset + 4);
Array.Clear(Data, goodlen, Data.Length - goodlen);
// 20 byte SHA checksum at the top of the file, which covers all data that follows.
using (var hash = SHA1.Create())
{
var result = hash.ComputeHash(Data, 20, Data.Length - 20);
SetData(result, 0);
}
}
public override string GetString(byte[] data, int offset, int length) => Util.TrimFromZero(Encoding.BigEndianUnicode.GetString(data, offset, length));
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
string temp = value
.PadRight(value.Length + 1, (char)0) // Null Terminator
.PadRight(PadToSize, (char)PadWith); // Padding
return Encoding.BigEndianUnicode.GetBytes(temp);
}
}
}

View file

@ -103,7 +103,7 @@ namespace PKHeX.Core
public static int ImportPKMs(this SaveFile SAV, IEnumerable<PKM> compat, bool overwrite = false, int boxStart = 0, bool? noSetb = null)
{
int startCount = boxStart * SAV.BoxSlotCount;
int maxCount = SAV.BoxCount * SAV.BoxSlotCount;
int maxCount = SAV.SlotCount;
int index = startCount;
foreach (var pk in compat)

View file

@ -48,6 +48,7 @@ namespace PKHeX.Core
// Bank Binaries
public const int SIZE_G7BANK = 0xACA48;
public const int SIZE_G4BANK = 0x405C4;
public const int SIZE_G4RANCH = 0x54000;
private static readonly HashSet<int> SIZES_2 = new HashSet<int>
{
@ -64,7 +65,7 @@ namespace PKHeX.Core
// SIZES_2 covers gen2 sizes since there's so many
SIZE_G1RAW, SIZE_G1BAT,
SIZE_G7BANK, SIZE_G4BANK,
SIZE_G7BANK, SIZE_G4BANK, SIZE_G4RANCH,
};
private static readonly int[] mainSizes = { SIZE_G6XY, SIZE_G6ORAS, SIZE_G7SM, SIZE_G7USUM };
@ -111,6 +112,8 @@ namespace PKHeX.Core
return GameVersion.HGSS;
if (GetIsBank3(data)) // pokestock
return GameVersion.RS;
if (GetIsRanch4(data)) // ranch
return GameVersion.DP;
return GameVersion.Invalid;
}
@ -444,6 +447,7 @@ namespace PKHeX.Core
private static bool GetIsBank7(byte[] data) => data.Length == SIZE_G7BANK && data[0] != 0;
private static bool GetIsBank4(byte[] data) => data.Length == SIZE_G4BANK && BitConverter.ToUInt32(data, 0x3FC00) != 0; // box name present
private static bool GetIsBank3(byte[] data) => data.Length == SIZE_G4BANK && BitConverter.ToUInt32(data, 0x3FC00) == 0; // size collision with ^
private static bool GetIsRanch4(byte[] data) => data.Length == SIZE_G4RANCH && BigEndian.ToUInt32(data, 0x22AC) != 0;
/// <summary>Creates an instance of a SaveFile using the given save data.</summary>
/// <param name="path">File location from which to create a SaveFile.</param>
@ -493,9 +497,10 @@ namespace PKHeX.Core
case GameVersion.GG: return new SAV7b(data);
// Bulk Storage
case GameVersion.RS: return new Bank3(data);
case GameVersion.DP: return new SAV4Ranch(data);
case GameVersion.HGSS: return new Bank4(data);
case GameVersion.USUM: return Bank7.GetBank7(data);
case GameVersion.HGSS: return Bank4.GetBank4(data);
case GameVersion.RS: return Bank3.GetBank3(data);
// No pattern matched
default: return null;

View file

@ -167,10 +167,11 @@ namespace PKHeX.WinForms.Controls
int slot = M?.ColorizedBox == box ? M.ColorizedSlot : -1;
int index = box * SAV.BoxSlotCount;
for (int i = 0; i < BoxSlotCount; i++)
{
var pb = SlotPictureBoxes[i];
if (i < SAV.BoxSlotCount)
if (i < SAV.BoxSlotCount && index + i < SAV.SlotCount)
GetSlotFiller(boxoffset + (SAV.SIZE_STORED * i), pb, box, i);
else
pb.Visible = false;