Created base class for GTS records implementing BinarySerializableBase

This commit is contained in:
Greg Edwards
2015-04-18 17:19:52 -04:00
parent d1f7a47ef0
commit 156abbe83c
4 changed files with 181 additions and 166 deletions

View File

@@ -90,6 +90,7 @@
<Compile Include="Structures\GtsRecord5.cs" />
<Compile Include="Structures\Enums.cs" />
<Compile Include="Structures\GtsRecord4.cs" />
<Compile Include="Structures\GtsRecordBase.cs" />
<Compile Include="Structures\IvStatValues.cs" />
<Compile Include="Structures\MoveSlot.cs" />
<Compile Include="Structures\MusicalRecord5.cs" />

View File

@@ -13,19 +13,24 @@ namespace PkmnFoundations.Structures
/// Includes a Pokémon box structure and metadata related to the trainer
/// and request.
/// </summary>
public class GtsRecord4 : IEquatable<GtsRecord4>
public class GtsRecord4 : GtsRecordBase, IEquatable<GtsRecord4>
{
// todo: We should have a base class for Gen4/5 GTS records.
public GtsRecord4()
public GtsRecord4() : base()
{
Initialize();
}
public GtsRecord4(byte[] data)
public GtsRecord4(byte[] data) : base()
{
Initialize();
Load(data);
}
private void Initialize()
{
}
/// <summary>
/// Obfuscated Pokémon (pkm) data. 236 bytes
/// </summary>
@@ -83,66 +88,65 @@ namespace PkmnFoundations.Structures
public byte TrainerVersion;
public byte TrainerLanguage;
public byte[] Save()
protected override void Save(BinaryWriter writer)
{
// todo: enclose in properties and validate these when assigning.
if (Data.Length != 0xEC) throw new FormatException("PKM length is incorrect");
if (TrainerName.RawData.Length != 0x10) throw new FormatException("Trainer name length is incorrect");
byte[] data = new byte[292];
MemoryStream s = new MemoryStream(data);
s.Write(Data, 0, 0xEC);
s.Write(BitConverter.GetBytes(Species), 0, 2);
s.WriteByte((byte)Gender);
s.WriteByte(Level);
s.Write(BitConverter.GetBytes(RequestedSpecies), 0, 2);
s.WriteByte((byte)RequestedGender);
s.WriteByte(RequestedMinLevel);
s.WriteByte(RequestedMaxLevel);
s.WriteByte(Unknown1);
s.WriteByte((byte)TrainerGender);
s.WriteByte(Unknown2);
s.Write(BitConverter.GetBytes(DateToTimestamp(TimeDeposited)), 0, 8);
s.Write(BitConverter.GetBytes(DateToTimestamp(TimeExchanged)), 0, 8);
s.Write(BitConverter.GetBytes(PID), 0, 4);
s.Write(TrainerName.RawData, 0, 0x10);
s.Write(BitConverter.GetBytes(TrainerOT), 0, 2);
s.WriteByte(TrainerCountry);
s.WriteByte(TrainerRegion);
s.WriteByte(TrainerClass);
s.WriteByte(IsExchanged);
s.WriteByte(TrainerVersion);
s.WriteByte(TrainerLanguage);
s.Close();
return data;
writer.Write(Data, 0, 0xEC); // 0x0000
writer.Write(Species); // 0x00EC
writer.Write((byte)Gender); // 0x00EE
writer.Write(Level); // 0x00EF
writer.Write(RequestedSpecies); // 0x00F0
writer.Write((byte)RequestedGender); // 0x00F2
writer.Write(RequestedMinLevel); // 0x00F3
writer.Write(RequestedMaxLevel); // 0x00F4
writer.Write(Unknown1); // 0x00F5
writer.Write((byte)TrainerGender); // 0x00F6
writer.Write(Unknown2); // 0x00F7
writer.Write(DateToTimestamp(TimeDeposited)); // 0x00F8
writer.Write(DateToTimestamp(TimeExchanged)); // 0x0100
writer.Write(PID); // 0x0108
writer.Write(TrainerName.RawData, 0, 0x10); // 0x010C
writer.Write(TrainerOT); // 0x011C
writer.Write(TrainerCountry); // 0x011E
writer.Write(TrainerRegion); // 0x011F
writer.Write(TrainerClass); // 0x0120
writer.Write(IsExchanged); // 0x0121
writer.Write(TrainerVersion); // 0x0122
writer.Write(TrainerLanguage); // 0x0123
}
public void Load(byte[] data)
protected override void Load(BinaryReader reader)
{
if (data.Length != 292) throw new FormatException("GTS record length is incorrect.");
Data = reader.ReadBytes(0xEC); // 0x0000
Species = reader.ReadUInt16(); // 0x00EC
Gender = (Genders)reader.ReadByte(); // 0x00EE
Level = reader.ReadByte(); // 0x00EF
RequestedSpecies = reader.ReadUInt16(); // 0x00F0
RequestedGender = (Genders)reader.ReadByte(); // 0x00F2
RequestedMinLevel = reader.ReadByte(); // 0x00F3
RequestedMaxLevel = reader.ReadByte(); // 0x00F4
Unknown1 = reader.ReadByte(); // 0x00F5
TrainerGender = (TrainerGenders)reader.ReadByte(); // 0x00F6
Unknown2 = reader.ReadByte(); // 0x00F7
TimeDeposited = TimestampToDate(reader.ReadUInt64()); // 0x00F8
TimeExchanged = TimestampToDate(reader.ReadUInt64()); // 0x0100
PID = reader.ReadInt32(); // 0x0108
TrainerName = new EncodedString4(reader.ReadBytes(0x10)); // 0x010C
TrainerOT = reader.ReadUInt16(); // 0x011C
TrainerCountry = reader.ReadByte(); // 0x011E
TrainerRegion = reader.ReadByte(); // 0x011F
TrainerClass = reader.ReadByte(); // 0x0120
IsExchanged = reader.ReadByte(); // 0x0121
TrainerVersion = reader.ReadByte(); // 0x0122
TrainerLanguage = reader.ReadByte(); // 0x0123
}
Data = new byte[0xEC];
Array.Copy(data, 0, Data, 0, 0xEC);
Species = BitConverter.ToUInt16(data, 0xEC);
Gender = (Genders)data[0xEE];
Level = data[0xEF];
RequestedSpecies = BitConverter.ToUInt16(data, 0xF0);
RequestedGender = (Genders)data[0xF2];
RequestedMinLevel = data[0xF3];
RequestedMaxLevel = data[0xF4];
Unknown1 = data[0xF5];
TrainerGender = (TrainerGenders)data[0xF6];
Unknown2 = data[0xF7];
TimeDeposited = TimestampToDate(BitConverter.ToUInt64(data, 0xF8));
TimeExchanged = TimestampToDate(BitConverter.ToUInt64(data, 0x100));
PID = BitConverter.ToInt32(data, 0x108);
TrainerName = new EncodedString4(data, 0x10C, 0x10);
TrainerOT = BitConverter.ToUInt16(data, 0x11C);
TrainerCountry = data[0x11E];
TrainerRegion = data[0x11F];
TrainerClass = data[0x120];
IsExchanged = data[0x121];
TrainerVersion = data[0x122];
TrainerLanguage = data[0x123];
public override int Size
{
get { return 292; }
}
public GtsRecord4 Clone()
@@ -187,47 +191,6 @@ namespace PkmnFoundations.Structures
IsExchanged = 0x01;
}
public static bool CheckLevels(byte min, byte max, byte other)
{
if (max == 0) max = 255;
return other >= min && other <= max;
}
public static DateTime ? TimestampToDate(ulong timestamp)
{
if (timestamp == 0) return null;
ushort year = (ushort)((timestamp >> 0x30) & 0xffff);
byte month = (byte)((timestamp >> 0x28) & 0xff);
byte day = (byte)((timestamp >> 0x20) & 0xff);
byte hour = (byte)((timestamp >> 0x18) & 0xff);
byte minute = (byte)((timestamp >> 0x10) & 0xff);
byte second = (byte)((timestamp >> 0x08) & 0xff);
//byte fractional = (byte)(timestamp & 0xff); // always 0
try
{
return new DateTime(year, month, day, hour, minute, second);
}
catch (ArgumentOutOfRangeException)
{
return null;
}
}
public static ulong DateToTimestamp(DateTime ? date)
{
if (date == null) return 0;
DateTime date2 = (DateTime)date;
return (ulong)(date2.Year & 0xffff) << 0x30
| (ulong)(date2.Month & 0xff) << 0x28
| (ulong)(date2.Day & 0xff) << 0x20
| (ulong)(date2.Hour & 0xff) << 0x18
| (ulong)(date2.Minute & 0xff) << 0x10
| (ulong)(date2.Second & 0xff) << 0x08;
}
public static bool operator ==(GtsRecord4 a, GtsRecord4 b)
{
if ((object)a == null && (object)b == null) return true;

View File

@@ -13,19 +13,24 @@ namespace PkmnFoundations.Structures
/// Includes a Pokémon box structure and metadata related to the trainer
/// and request.
/// </summary>
public class GtsRecord5 : IEquatable<GtsRecord5>
public class GtsRecord5 : GtsRecordBase, IEquatable<GtsRecord5>
{
// todo: We should have a base class for Gen4/5 GTS records.
public GtsRecord5()
{
Initialize();
}
public GtsRecord5(byte[] data)
{
Initialize();
Load(data);
}
private void Initialize()
{
}
// xxx: Data and Unknown0 should be one field.
/// <summary>
@@ -93,73 +98,72 @@ namespace PkmnFoundations.Structures
public byte TrainerBadges; // speculative. Usually 8.
public byte TrainerUnityTower;
public byte[] Save()
protected override void Save(BinaryWriter writer)
{
// todo: enclose in properties and validate these when assigning.
if (Data.Length != 0xDC) throw new FormatException("PKM length is incorrect");
if (TrainerName.RawData.Length != 0x10) throw new FormatException("Trainer name length is incorrect");
byte[] data = new byte[296];
MemoryStream s = new MemoryStream(data);
s.Write(Data, 0, 0xDC);
s.Write(Unknown0, 0, 0x10);
s.Write(BitConverter.GetBytes(Species), 0, 2);
s.WriteByte((byte)Gender);
s.WriteByte(Level);
s.Write(BitConverter.GetBytes(RequestedSpecies), 0, 2);
s.WriteByte((byte)RequestedGender);
s.WriteByte(RequestedMinLevel);
s.WriteByte(RequestedMaxLevel);
s.WriteByte(Unknown1);
s.WriteByte((byte)TrainerGender);
s.WriteByte(Unknown2);
s.Write(BitConverter.GetBytes(GtsRecord4.DateToTimestamp(TimeDeposited)), 0, 8);
s.Write(BitConverter.GetBytes(GtsRecord4.DateToTimestamp(TimeExchanged)), 0, 8);
s.Write(BitConverter.GetBytes(PID), 0, 4);
s.Write(BitConverter.GetBytes(TrainerOT), 0, 4);
s.Write(TrainerName.RawData, 0, 0x10);
s.WriteByte(TrainerCountry);
s.WriteByte(TrainerRegion);
s.WriteByte(TrainerClass);
s.WriteByte(IsExchanged);
s.WriteByte(TrainerVersion);
s.WriteByte(TrainerLanguage);
s.WriteByte(TrainerBadges);
s.WriteByte(TrainerUnityTower);
s.Close();
return data;
writer.Write(Data, 0, 0xDC); // 0x0000
writer.Write(Unknown0, 0, 0x10); // 0x00DC
writer.Write(Species); // 0x00EC
writer.Write((byte)Gender); // 0x00EE
writer.Write(Level); // 0x00EF
writer.Write(RequestedSpecies); // 0x00F0
writer.Write((byte)RequestedGender); // 0x00F2
writer.Write(RequestedMinLevel); // 0x00F3
writer.Write(RequestedMaxLevel); // 0x00F4
writer.Write(Unknown1); // 0x00F5
writer.Write((byte)TrainerGender); // 0x00F6
writer.Write(Unknown2); // 0x00F7
writer.Write(DateToTimestamp(TimeDeposited)); // 0x00F8
writer.Write(DateToTimestamp(TimeExchanged)); // 0x0100
writer.Write(PID); // 0x0108
writer.Write(TrainerOT); // 0x010C
writer.Write(TrainerName.RawData, 0, 0x10); // 0x0110
writer.Write(TrainerCountry); // 0x0120
writer.Write(TrainerRegion); // 0x0121
writer.Write(TrainerClass); // 0x0122
writer.Write(IsExchanged); // 0x0123
writer.Write(TrainerVersion); // 0x0124
writer.Write(TrainerLanguage); // 0x0125
writer.Write(TrainerBadges); // 0x0126
writer.Write(TrainerUnityTower); // 0x0127
}
public void Load(byte[] data)
protected override void Load(BinaryReader reader)
{
if (data.Length != 296) throw new FormatException("GTS record length is incorrect.");
Data = reader.ReadBytes(0xDC); // 0x0000
Unknown0 = reader.ReadBytes(0x10); // 0x00DC
Species = reader.ReadUInt16(); // 0x00EC
Gender = (Genders)reader.ReadByte(); // 0x00EE
Level = reader.ReadByte(); // 0x00EF
RequestedSpecies = reader.ReadUInt16(); // 0x00F0
RequestedGender = (Genders)reader.ReadByte(); // 0x00F2
RequestedMinLevel = reader.ReadByte(); // 0x00F3
RequestedMaxLevel = reader.ReadByte(); // 0x00F4
Unknown1 = reader.ReadByte(); // 0x00F5
TrainerGender = (TrainerGenders)reader.ReadByte(); // 0x00F6
Unknown2 = reader.ReadByte(); // 0x00F7
TimeDeposited = TimestampToDate(reader.ReadUInt64()); // 0x00F8
TimeExchanged = TimestampToDate(reader.ReadUInt64()); // 0x0100
PID = reader.ReadInt32(); // 0x0108
TrainerOT = reader.ReadUInt32(); // 0x010C
TrainerName = new EncodedString5(reader.ReadBytes(0x10)); // 0x0110
TrainerCountry = reader.ReadByte(); // 0x0120
TrainerRegion = reader.ReadByte(); // 0x0121
TrainerClass = reader.ReadByte(); // 0x0122
IsExchanged = reader.ReadByte(); // 0x0123
TrainerVersion = reader.ReadByte(); // 0x0124
TrainerLanguage = reader.ReadByte(); // 0x0125
TrainerBadges = reader.ReadByte(); // 0x0126
TrainerUnityTower = reader.ReadByte(); // 0x0127
}
Data = new byte[0xDC];
Array.Copy(data, 0, Data, 0, 0xDC);
Unknown0 = new byte[0x10];
Array.Copy(data, 0xDC, Unknown0, 0, 0x10);
Species = BitConverter.ToUInt16(data, 0xEC);
Gender = (Genders)data[0xEE];
Level = data[0xEF];
RequestedSpecies = BitConverter.ToUInt16(data, 0xF0);
RequestedGender = (Genders)data[0xF2];
RequestedMinLevel = data[0xF3];
RequestedMaxLevel = data[0xF4];
Unknown1 = data[0xF5];
TrainerGender = (TrainerGenders)data[0xF6];
Unknown2 = data[0xF7];
TimeDeposited = GtsRecord4.TimestampToDate(BitConverter.ToUInt64(data, 0xF8));
TimeExchanged = GtsRecord4.TimestampToDate(BitConverter.ToUInt64(data, 0x100));
PID = BitConverter.ToInt32(data, 0x108);
TrainerOT = BitConverter.ToUInt32(data, 0x10C);
TrainerName = new EncodedString5(data, 0x110, 0x10);
TrainerCountry = data[0x120];
TrainerRegion = data[0x121];
TrainerClass = data[0x122];
IsExchanged = data[0x123];
TrainerVersion = data[0x124];
TrainerLanguage = data[0x125];
TrainerBadges = data[0x126];
TrainerUnityTower = data[0x127];
public override int Size
{
get { return 296; }
}
public GtsRecord5 Clone()
@@ -204,12 +208,6 @@ namespace PkmnFoundations.Structures
IsExchanged = 0x01;
}
public static bool CheckLevels(byte min, byte max, byte other)
{
if (max == 0) max = 255;
return other >= min && other <= max;
}
public static bool operator ==(GtsRecord5 a, GtsRecord5 b)
{
if ((object)a == null && (object)b == null) return true;

View File

@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PkmnFoundations.Structures
{
public abstract class GtsRecordBase : BinarySerializableBase
{
public static bool CheckLevels(byte min, byte max, byte other)
{
if (max == 0) max = 255;
return other >= min && other <= max;
}
public static ulong DateToTimestamp(DateTime? date)
{
if (date == null) return 0;
DateTime date2 = (DateTime)date;
return (ulong)(date2.Year & 0xffff) << 0x30
| (ulong)(date2.Month & 0xff) << 0x28
| (ulong)(date2.Day & 0xff) << 0x20
| (ulong)(date2.Hour & 0xff) << 0x18
| (ulong)(date2.Minute & 0xff) << 0x10
| (ulong)(date2.Second & 0xff) << 0x08;
}
public static DateTime? TimestampToDate(ulong timestamp)
{
if (timestamp == 0) return null;
ushort year = (ushort)((timestamp >> 0x30) & 0xffff);
byte month = (byte)((timestamp >> 0x28) & 0xff);
byte day = (byte)((timestamp >> 0x20) & 0xff);
byte hour = (byte)((timestamp >> 0x18) & 0xff);
byte minute = (byte)((timestamp >> 0x10) & 0xff);
byte second = (byte)((timestamp >> 0x08) & 0xff);
//byte fractional = (byte)(timestamp & 0xff); // always 0
try
{
return new DateTime(year, month, day, hour, minute, second);
}
catch (ArgumentOutOfRangeException)
{
return null;
}
}
}
}