Added stub implementation of Wifi Plaza gamestats server. (mostly replay responses for now)

This commit is contained in:
Greg Edwards
2015-03-10 21:30:12 -04:00
parent 41748eb422
commit b89eb29c62
6 changed files with 464 additions and 2 deletions

View File

@@ -4,6 +4,8 @@ using System.IO;
using System.Linq;
using System.Web;
using GamestatsBase;
using PkmnFoundations.Data;
using PkmnFoundations.Structures;
namespace PkmnFoundations.GTS
{
@@ -30,7 +32,180 @@ namespace PkmnFoundations.GTS
ShowError(context, 404);
return;
// todo: Implement Wi-Fi Plaza gamestats handlers here.
case "/pokemondpds/web/enc/lobby/checkProfile.asp":
{
if (request.Length != 168)
{
ShowError(context, 400);
return;
}
// I am going to guess that the PID provided second is the
// one whose data should appear in the response.
int requestedPid = BitConverter.ToInt32(request, 0);
byte[] requestDataPrefix = new byte[12];
byte[] requestData = new byte[152];
Array.Copy(request, 4, requestDataPrefix, 0, 12);
Array.Copy(request, 16, requestData, 0, 152);
TrainerProfilePlaza requestProfile = new TrainerProfilePlaza(pid, requestDataPrefix, requestData);
Database.Instance.PlazaSetProfile(requestProfile);
TrainerProfilePlaza responseProfile = Database.Instance.PlazaGetProfile(requestedPid);
response.Write(responseProfile.Data, 0, 152);
} break;
case "/pokemondpds/web/enc/lobby/getSchedule.asp":
{
// This is a replayed response from a game I had with Pipian.
// It appears to be 49 ints.
// todo: A real implementation
response.Write(new byte[]
{
0x00, 0x00, 0x00, 0x00, 0xb0, 0x04, 0x00, 0x00,
0x9e, 0xc4, 0x70, 0xa7, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
0x09, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
0x0d, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
0x0f, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00,
0x0e, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x33, 0x04, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00,
0x0d, 0x00, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x74, 0x04, 0x00, 0x00,
0x0b, 0x00, 0x00, 0x00, 0xb0, 0x04, 0x00, 0x00,
0x13, 0x00, 0x00, 0x00
}, 0, 196);
} break;
case "/pokemondpds/web/enc/lobby/getVIP.asp":
{
response.Write(new byte[] { 0x00, 0x00, 0x00, 0x00 }, 0, 4);
} break;
case "/pokemondpds/web/enc/lobby/getQuestionnaire.asp":
{
response.Write(new byte[]{
0x00, 0x00, 0x00, 0x00, 0x2a, 0x01, 0x00,
0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x01, 0x00,
0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
0x00, 0x46, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00,
0x00, 0x64, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00,
0x00, 0x83, 0x00, 0x00, 0x00
}, 0, 732);
} break;
case "/pokemondpds/web/enc/lobby/submitQuestionnaire.asp":
{
// literally 'thx' in ascii... lol
response.Write(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x74, 0x68, 0x78, 0x00 }, 0, 8);
} break;
}
}
}

View File

@@ -81,6 +81,61 @@ namespace PkmnFoundations.Data
}
}
public GtsRecord4 GtsGetRecord4(MySqlTransaction tran, long tradeId, bool isExchanged, bool allowHistory)
{
MySqlDataReader reader = (MySqlDataReader)tran.ExecuteReader("SELECT Data, Species, Gender, Level, " +
"RequestedSpecies, RequestedGender, RequestedMinLevel, RequestedMaxLevel, " +
"Unknown1, TrainerGender, Unknown2, TimeDeposited, TimeExchanged, pid, " +
"TrainerName, TrainerOT, TrainerCountry, TrainerRegion, TrainerClass, " +
"IsExchanged, TrainerVersion, TrainerLanguage FROM GtsPokemon4 " +
"WHERE id = @id AND IsExchanged = @is_exchanged",
new MySqlParameter("@id", tradeId),
new MySqlParameter("@is_exchanged", isExchanged ? 1 : 0));
if (reader.Read())
{
GtsRecord4 result = Record4FromReader(reader);
reader.Close();
return result;
}
if (allowHistory)
{
reader = (MySqlDataReader)tran.ExecuteReader("SELECT Data, Species, Gender, Level, " +
"RequestedSpecies, RequestedGender, RequestedMinLevel, RequestedMaxLevel, " +
"Unknown1, TrainerGender, Unknown2, TimeDeposited, TimeExchanged, pid, " +
"TrainerName, TrainerOT, TrainerCountry, TrainerRegion, TrainerClass, " +
"IsExchanged, TrainerVersion, TrainerLanguage FROM GtsHistory4 " +
"WHERE trade_id = @id AND IsExchanged = @is_exchanged",
new MySqlParameter("@id", tradeId),
new MySqlParameter("@is_exchanged", isExchanged ? 1 : 0));
if (reader.Read())
{
GtsRecord4 result = Record4FromReader(reader);
reader.Close();
return result;
}
}
reader.Close();
return null;
}
public override GtsRecord4 GtsGetRecord4(long tradeId, bool isExchanged, bool allowHistory)
{
using (MySqlConnection db = CreateConnection())
{
db.Open();
using (MySqlTransaction tran = db.BeginTransaction())
{
GtsRecord4 result = GtsGetRecord4(tran, tradeId, isExchanged, allowHistory);
tran.Commit();
return result;
}
}
}
public bool GtsDepositPokemon4(MySqlTransaction tran, GtsRecord4 record)
{
if (record.Data.Length != 236) throw new FormatException("pkm data must be 236 bytes.");
@@ -844,6 +899,88 @@ namespace PkmnFoundations.Data
}
#endregion
#region Wi-fi Plaza
public override TrainerProfilePlaza PlazaGetProfile(int pid)
{
using (MySqlConnection db = CreateConnection())
{
db.Open();
using (MySqlTransaction tran = db.BeginTransaction())
{
TrainerProfilePlaza result = PlazaGetProfile(tran, pid);
tran.Commit();
return result;
}
}
}
public TrainerProfilePlaza PlazaGetProfile(MySqlTransaction tran, int pid)
{
MySqlDataReader reader = (MySqlDataReader)tran.ExecuteReader("SELECT " +
"DataPrefix, Data FROM pkmncf_plaza_profiles " +
"WHERE pid = @pid",
new MySqlParameter("@pid", pid));
if (reader.Read())
{
return new TrainerProfilePlaza(pid, reader.GetByteArray(0, 12), reader.GetByteArray(1, 152));
}
else return null;
}
public override bool PlazaSetProfile(TrainerProfilePlaza profile)
{
using (MySqlConnection db = CreateConnection())
{
db.Open();
using (MySqlTransaction tran = db.BeginTransaction())
{
bool result = PlazaSetProfile(tran, profile);
tran.Commit();
return result;
}
}
}
public bool PlazaSetProfile(MySqlTransaction tran, TrainerProfilePlaza profile)
{
if (profile.DataPrefix.Length != 12) throw new FormatException("Profile data prefix must be 12 bytes.");
if (profile.Data.Length != 152) throw new FormatException("Profile data must be 152 bytes.");
long exists = (long)tran.ExecuteScalar("SELECT EXISTS(SELECT * FROM pkmncf_plaza_profiles WHERE pid = @pid)", new MySqlParameter("@pid", profile.PID));
MySqlParameter[] _params = new MySqlParameter[]{
new MySqlParameter("@pid", profile.PID),
new MySqlParameter("@data_prefix", profile.DataPrefix),
new MySqlParameter("@data", profile.Data),
new MySqlParameter("@version", (byte)profile.Version),
new MySqlParameter("@language", (byte)profile.Language),
new MySqlParameter("@country", profile.Country),
new MySqlParameter("@region", profile.Region),
new MySqlParameter("@ot", profile.OT),
new MySqlParameter("@name", profile.Name.RawData)
};
if (exists != 0)
{
return tran.ExecuteNonQuery("UPDATE pkmncf_plaza_profiles " +
"SET DataPrefix = @data_prefix, Data = @data, " +
"Version = @version, Language = @language, Country = @country, " +
"Region = @region, OT = @ot, Name = @name, ParseVersion = 1, " +
"TimeUpdated = UTC_TIMESTAMP() " +
"WHERE pid = @pid", _params) > 0;
}
else
{
return tran.ExecuteNonQuery("INSERT INTO pkmncf_plaza_profiles " +
"(pid, DataPrefix, Data, Version, Language, Country, Region, OT, Name, " +
"ParseVersion, TimeAdded, TimeUpdated) VALUES " +
"(@pid, @data_prefix, @data, @version, @language, @country, @region, @ot, " +
"@name, 1, UTC_TIMESTAMP(), UTC_TIMESTAMP())", _params) > 0;
}
}
#endregion
#region Other Gamestats 4
public override bool GamestatsSetProfile4(TrainerProfile4 profile)
{
@@ -934,6 +1071,63 @@ namespace PkmnFoundations.Data
}
}
public GtsRecord5 GtsGetRecord5(MySqlTransaction tran, long tradeId, bool isExchanged, bool allowHistory)
{
MySqlDataReader reader = (MySqlDataReader)tran.ExecuteReader("SELECT Data, Unknown0, " +
"Species, Gender, Level, " +
"RequestedSpecies, RequestedGender, RequestedMinLevel, RequestedMaxLevel, " +
"Unknown1, TrainerGender, Unknown2, TimeDeposited, TimeExchanged, pid, " +
"TrainerOT, TrainerName, TrainerCountry, TrainerRegion, TrainerClass, " +
"IsExchanged, TrainerVersion, TrainerLanguage, TrainerBadges, TrainerUnityTower " +
"FROM GtsPokemon5 WHERE id = @id AND IsExchanged = @is_exchanged",
new MySqlParameter("@id", tradeId),
new MySqlParameter("@is_exchanged", isExchanged ? 1 : 0));
if (reader.Read())
{
GtsRecord5 result = Record5FromReader(reader);
reader.Close();
return result;
}
if (allowHistory)
{
reader = (MySqlDataReader)tran.ExecuteReader("SELECT Data, Unknown0, " +
"Species, Gender, Level, " +
"RequestedSpecies, RequestedGender, RequestedMinLevel, RequestedMaxLevel, " +
"Unknown1, TrainerGender, Unknown2, TimeDeposited, TimeExchanged, pid, " +
"TrainerOT, TrainerName, TrainerCountry, TrainerRegion, TrainerClass, " +
"IsExchanged, TrainerVersion, TrainerLanguage, TrainerBadges, TrainerUnityTower " +
"FROM GtsHistory5 WHERE trade_id = @id AND IsExchanged = @is_exchanged",
new MySqlParameter("@id", tradeId),
new MySqlParameter("@is_exchanged", isExchanged ? 1 : 0));
if (reader.Read())
{
GtsRecord5 result = Record5FromReader(reader);
reader.Close();
return result;
}
}
reader.Close();
return null;
}
public override GtsRecord5 GtsGetRecord5(long tradeId, bool isExchanged, bool allowHistory)
{
using (MySqlConnection db = CreateConnection())
{
db.Open();
using (MySqlTransaction tran = db.BeginTransaction())
{
GtsRecord5 result = GtsGetRecord5(tran, tradeId, isExchanged, allowHistory);
tran.Commit();
return result;
}
}
}
public bool GtsDepositPokemon5(MySqlTransaction tran, GtsRecord5 record)
{
if (record == null) throw new ArgumentNullException("record");

View File

@@ -64,6 +64,7 @@ namespace PkmnFoundations.Data
public const int GTS_VERSION_4 = 0;
public abstract GtsRecord4 GtsDataForUser4(int pid);
public abstract GtsRecord4 GtsGetRecord4(long tradeId, bool isExchanged, bool allowHistory);
public abstract bool GtsDepositPokemon4(GtsRecord4 record);
@@ -85,6 +86,11 @@ namespace PkmnFoundations.Data
public abstract BattleTowerProfile4[] BattleTowerGetLeaders4(byte rank, byte roomNum);
#endregion
#region Wi-fi Plaza
public abstract TrainerProfilePlaza PlazaGetProfile(int pid);
public abstract bool PlazaSetProfile(TrainerProfilePlaza profile);
#endregion
#region Other Gamestats 4
public abstract bool GamestatsSetProfile4(TrainerProfile4 profile);
#endregion
@@ -93,6 +99,7 @@ namespace PkmnFoundations.Data
public const int GTS_VERSION_5 = 0;
public abstract GtsRecord5 GtsDataForUser5(int pid);
public abstract GtsRecord5 GtsGetRecord5(long tradeId, bool isExchanged, bool allowHistory);
public abstract bool GtsDepositPokemon5(GtsRecord5 record);

View File

@@ -99,6 +99,7 @@
<Compile Include="Structures\StatValuesBase.cs" />
<Compile Include="Structures\TrainerProfile4.cs" />
<Compile Include="Structures\TrainerProfile5.cs" />
<Compile Include="Structures\TrainerProfilePlaza.cs" />
<Compile Include="Support\AssertHelper.cs" />
<Compile Include="Support\EncodedString4.cs" />
<Compile Include="Support\EncodedString5.cs" />

View File

@@ -23,7 +23,7 @@ namespace PkmnFoundations.Structures
// todo: encapsulate these so calculated fields are always correct
public int PID;
public byte[] Data;
public byte[] Data; // 100 bytes
public Versions Version
{

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PkmnFoundations.Support;
namespace PkmnFoundations.Structures
{
public class TrainerProfilePlaza
{
public TrainerProfilePlaza()
{
}
public TrainerProfilePlaza(int pid, byte[] data_prefix, byte[] data)
{
if (data.Length != 152) throw new ArgumentException("Profile data must be 152 bytes.");
PID = pid;
DataPrefix = data_prefix;
Data = data;
}
// todo: encapsulate these so calculated fields are always correct
public int PID;
public byte[] DataPrefix; // 12 bytes
public byte[] Data; // 152 bytes
// todo: These 4 values are basically big guesses. Fact check.
// todo: Add more fields
public Versions Version
{
get
{
return (Versions)DataPrefix[0x03];
}
}
public Languages Language
{
get
{
return (Languages)DataPrefix[0x04];
}
}
public byte Country
{
get
{
return Data[0x50];
}
}
public byte Region
{
get
{
return Data[0x52];
}
}
public uint OT
{
get
{
return BitConverter.ToUInt32(Data, 8);
}
}
public EncodedString4 Name
{
get
{
return new EncodedString4(Data, 12, 16);
}
}
public TrainerProfilePlaza Clone()
{
return new TrainerProfilePlaza(PID, DataPrefix.ToArray(), Data.ToArray());
}
}
}