mirror of
https://github.com/mm201/pkmn-classic-framework.git
synced 2026-08-22 10:14:07 -05:00
WIP of GTS database logic
This commit is contained in:
24
gts/BoxUploadDecode.aspx
Normal file
24
gts/BoxUploadDecode.aspx
Normal file
@@ -0,0 +1,24 @@
|
||||
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="BoxUploadDecode.aspx.cs" Inherits="PokeFoundations.GTS.BoxUploadDecode" %>
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head runat="server">
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<form id="form1" runat="server">
|
||||
|
||||
<p>Please upload your captured TCP request here:</p>
|
||||
<div>
|
||||
<asp:FileUpload ID="fuRequest" runat="server" />
|
||||
<asp:Button ID="btnUpload" Text="Upload" runat="server" />
|
||||
</div>
|
||||
<div>
|
||||
<asp:Literal ID="litDecrypted" runat="server" />
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
35
gts/BoxUploadDecode.aspx.cs
Normal file
35
gts/BoxUploadDecode.aspx.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
using System.Text;
|
||||
|
||||
namespace PokeFoundations.GTS
|
||||
{
|
||||
public partial class BoxUploadDecode : System.Web.UI.Page
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
byte data = 0x00;
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (int x = 0; x < 512; x++)
|
||||
{
|
||||
data = runRng(data);
|
||||
builder.Append(data.ToString("x2"));
|
||||
builder.Append(" ");
|
||||
if (x % 16 == 15) builder.Append("<br />");
|
||||
}
|
||||
|
||||
litDecrypted.Text = builder.ToString();
|
||||
}
|
||||
|
||||
private byte runRng(byte data)
|
||||
{
|
||||
return (byte)((data + 0x4f) * 0x1c);
|
||||
}
|
||||
}
|
||||
}
|
||||
51
gts/BoxUploadDecode.aspx.designer.cs
generated
Normal file
51
gts/BoxUploadDecode.aspx.designer.cs
generated
Normal file
@@ -0,0 +1,51 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace PokeFoundations.GTS {
|
||||
|
||||
|
||||
public partial class BoxUploadDecode {
|
||||
|
||||
/// <summary>
|
||||
/// form1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.HtmlControls.HtmlForm form1;
|
||||
|
||||
/// <summary>
|
||||
/// fuRequest control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.FileUpload fuRequest;
|
||||
|
||||
/// <summary>
|
||||
/// btnUpload control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.Button btnUpload;
|
||||
|
||||
/// <summary>
|
||||
/// litDecrypted control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.Literal litDecrypted;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,5 @@
|
||||
</asp:Content>
|
||||
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="cpMain" runat="server">
|
||||
customGTS<br />
|
||||
<asp:Literal ID="litDebug" runat="server" />
|
||||
</asp:Content>
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="mysql.data">
|
||||
<HintPath>..\library\lib\mysql.data.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Core" />
|
||||
@@ -51,6 +54,7 @@
|
||||
<Reference Include="System.Web.ApplicationServices" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="BoxUploadDecode.aspx" />
|
||||
<Content Include="Default.aspx" />
|
||||
<Content Include="Global.asax" />
|
||||
<Content Include="Web.config" />
|
||||
@@ -62,6 +66,13 @@
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BoxUploadDecode.aspx.cs">
|
||||
<DependentUpon>BoxUploadDecode.aspx</DependentUpon>
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="BoxUploadDecode.aspx.designer.cs">
|
||||
<DependentUpon>BoxUploadDecode.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="pokemondpds.ashx.cs">
|
||||
<DependentUpon>pokemondpds.ashx</DependentUpon>
|
||||
</Compile>
|
||||
@@ -100,6 +111,12 @@
|
||||
<ItemGroup>
|
||||
<Content Include="pokemondpds.ashx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\library\Library.csproj">
|
||||
<Project>{408EFC7E-C6B0-4160-8628-2679E34385CE}</Project>
|
||||
<Name>Library</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
|
||||
<ProjectExtensions>
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.SessionState;
|
||||
using PokeFoundations.Data;
|
||||
|
||||
namespace PokeFoundations.GTS
|
||||
{
|
||||
@@ -41,8 +42,9 @@ namespace PokeFoundations.GTS
|
||||
context.Request.QueryString["data"].Length < 12)
|
||||
{
|
||||
// arguments missing, partial check for data length.
|
||||
// (require data to hold at least 7 bytes.
|
||||
// In reality, it must hold at least 8.)
|
||||
// (Here, we require data to hold at least 7 bytes.
|
||||
// In reality, it must hold at least 8, which is checked
|
||||
// for below after decoding)
|
||||
Error400(context);
|
||||
return;
|
||||
}
|
||||
@@ -63,6 +65,8 @@ namespace PokeFoundations.GTS
|
||||
if (data.Length < 4)
|
||||
{
|
||||
// data too short to contain a pid
|
||||
// We check for 4 bytes, not 8, since the decrypt seed
|
||||
// isn't included in DecryptData's result.
|
||||
Error400(context);
|
||||
return;
|
||||
}
|
||||
@@ -87,13 +91,34 @@ namespace PokeFoundations.GTS
|
||||
{
|
||||
default:
|
||||
// unrecognized page url
|
||||
// should be error 404 once we're done debugging
|
||||
context.Response.Write("Almost there. Your path is:\n");
|
||||
context.Response.Write(session.URL);
|
||||
return;
|
||||
|
||||
|
||||
case "/worldexchange/info.asp":
|
||||
context.Response.Write("It worked");
|
||||
context.Response.OutputStream.Write(new byte[] { 0x01, 0x00 }, 0, 2);
|
||||
break;
|
||||
|
||||
|
||||
case "/common/setProfile.asp":
|
||||
// todo: Figure out what fun stuff is contained in this blob!
|
||||
|
||||
context.Response.OutputStream.Write(new byte[]
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
0, 8);
|
||||
break;
|
||||
|
||||
|
||||
case "/worldexchange/result.asp":
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -30,10 +30,19 @@ namespace PokeFoundations.GTS
|
||||
Dictionary<String, GtsSession4> sessions = context.AllSessions4();
|
||||
DateTime now = DateTime.UtcNow;
|
||||
|
||||
foreach (KeyValuePair<String, GtsSession4> session in sessions)
|
||||
lock (sessions)
|
||||
{
|
||||
if (session.Value.ExpiryDate < now) sessions.Remove(session.Key);
|
||||
Queue<String> toRemove = new Queue<String>();
|
||||
foreach (KeyValuePair<String, GtsSession4> session in sessions)
|
||||
{
|
||||
if (session.Value.ExpiryDate < now) toRemove.Enqueue(session.Key);
|
||||
}
|
||||
while (toRemove.Count > 0)
|
||||
{
|
||||
sessions.Remove(toRemove.Dequeue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ namespace PokeFoundations.GTS
|
||||
byte[] data = new byte[longToken.Length];
|
||||
MemoryStream stream = new MemoryStream(data);
|
||||
StreamWriter writer = new StreamWriter(stream);
|
||||
writer.Write(longToken);
|
||||
writer.Write(longToken); // fixme: this throws an OutOfBoundsException if the passed token contains non-ascii.
|
||||
writer.Flush();
|
||||
|
||||
return m_sha1.ComputeHash(data).ToHexStringLower();
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace PokeFoundations.GTS
|
||||
|
||||
for (int x = 0; x < token.Length; x++)
|
||||
{
|
||||
// tokens have 62 chars: 0-9, A-Z, and a-z
|
||||
// tokens have 62 possible chars: 0-9, A-Z, and a-z
|
||||
m_rng.GetBytes(data);
|
||||
uint rand = BitConverter.ToUInt32(data, 0) % 62u;
|
||||
|
||||
|
||||
@@ -3,22 +3,40 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using PokeFoundations.Structures;
|
||||
|
||||
namespace PokeFoundations.Data
|
||||
{
|
||||
public abstract class DataAbstract
|
||||
{
|
||||
public static String SqlSanitize(String s)
|
||||
{
|
||||
return SqlSanitize(s, "");
|
||||
}
|
||||
#region Initialization
|
||||
private static DataAbstract m_instance;
|
||||
|
||||
public static String SqlSanitize(String s, String newChar)
|
||||
public static DataAbstract Instance
|
||||
{
|
||||
String result = s.Replace("\'", newChar).Replace("[", newChar).Replace("]", newChar).Replace("`", newChar);
|
||||
int x = result.IndexOf("--");
|
||||
if (x != -1) result = result.Substring(0, x);
|
||||
return result;
|
||||
get
|
||||
{
|
||||
if (m_instance == null)
|
||||
{
|
||||
m_instance = new DataMysql();
|
||||
}
|
||||
return m_instance;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Utility
|
||||
#endregion
|
||||
|
||||
#region GTS
|
||||
public abstract GtsDatagram4 GtsDataForUser4(int pid);
|
||||
|
||||
public abstract void GtsDepositPokemon4(GtsDatagram4 datagram);
|
||||
|
||||
public abstract void GtsDeletePokemon4(int pid);
|
||||
|
||||
public abstract void GtsTradePokemon4(int pidSrc, int pidDest);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,173 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using MySql.Data.MySqlClient;
|
||||
using PokeFoundations.Structures;
|
||||
using PokeFoundations.Support;
|
||||
|
||||
namespace PokeFoundations.Data
|
||||
{
|
||||
public class DataMysql : DataAbstract
|
||||
{
|
||||
#region Initialization
|
||||
private MySqlConnection CreateConnection()
|
||||
{
|
||||
return new MySqlConnection("Server=localhost;Database=pfound;User ID=pfound;Password=goldeen need log;Pooling=true;");
|
||||
// hard-coded for now, will need to add configuration later
|
||||
return new MySqlConnection("Server=10.211.55.2;Database=gts;User ID=gts;Password=gts;Pooling=true;");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Utility
|
||||
public static String SqlSanitize(String s)
|
||||
{
|
||||
return SqlSanitize(s, "");
|
||||
}
|
||||
|
||||
public static String SqlSanitize(String s, String newChar)
|
||||
{
|
||||
String result = s.Replace("\'", newChar).Replace("[", newChar).Replace("]", newChar).Replace("`", newChar);
|
||||
int x = result.IndexOf("--");
|
||||
if (x != -1) result = result.Substring(0, x);
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GTS
|
||||
public override GtsDatagram4 GtsDataForUser4(int pid)
|
||||
{
|
||||
using (MySqlConnection db = CreateConnection())
|
||||
{
|
||||
db.Open();
|
||||
MySqlDataReader reader = (MySqlDataReader)db.ExecuteReader("SELECT Data, Species, Gender, Level, " +
|
||||
"RequestedSpecies, RequestedGender, RequestedMinLevel, RequestedMaxLevel, " +
|
||||
"Unknown1, TrainerGender, Unknown2, TimeDeposited, TimeWithdrawn, pid, " +
|
||||
"TrainerName, TrainerOT, TrainerCountry, TrainerRegion, TrainerClass, " +
|
||||
"IsExchanged, TrainerVersion, TrainerLanguage FROM GtsPokemon4 WHERE pid = @pid",
|
||||
new MySqlParameter("@pid", pid));
|
||||
|
||||
if (!reader.Read()) return null;
|
||||
GtsDatagram4 result = new GtsDatagram4();
|
||||
|
||||
byte[] data = new byte[236];
|
||||
reader.GetBytes(0, 0, data, 0, 236);
|
||||
result.Data = data;
|
||||
data = null;
|
||||
|
||||
result.Species = reader.GetUInt16(1);
|
||||
result.Gender = (Genders)reader.GetByte(2);
|
||||
result.Level = reader.GetByte(3);
|
||||
result.RequestedSpecies = reader.GetUInt16(4);
|
||||
result.RequestedGender = (Genders)reader.GetByte(5);
|
||||
result.RequestedMinLevel = reader.GetByte(6);
|
||||
result.RequestedMaxLevel = reader.GetByte(7);
|
||||
result.Unknown1 = reader.GetByte(8);
|
||||
result.TrainerGender = (GtsTrainerGenders)reader.GetByte(9);
|
||||
result.Unknown2 = reader.GetByte(10);
|
||||
result.TimeDeposited = reader.GetDateTime(11);
|
||||
result.TimeWithdrawn = reader.GetDateTime(12);
|
||||
result.PID = reader.GetInt32(13);
|
||||
|
||||
data = new byte[16];
|
||||
reader.GetBytes(14, 0, data, 0, 16);
|
||||
result.TrainerName = data;
|
||||
data = null;
|
||||
|
||||
result.TrainerOT = reader.GetUInt16(15);
|
||||
result.TrainerCountry = reader.GetByte(16);
|
||||
result.TrainerRegion = reader.GetByte(17);
|
||||
result.TrainerClass = reader.GetByte(18);
|
||||
result.IsExchanged = reader.GetByte(19);
|
||||
result.TrainerVersion = reader.GetByte(20);
|
||||
result.TrainerLanguage = reader.GetByte(21);
|
||||
#if DEBUG
|
||||
AssertHelper.Equals(result.PID, pid);
|
||||
#endif
|
||||
reader.Close();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool GtsDepositPokemon4(GtsDatagram4 datagram)
|
||||
{
|
||||
if (datagram.Data.Length != 236) throw new FormatException("pkm data must be 236 bytes.");
|
||||
if (datagram.TrainerName.Length != 16) throw new FormatException("Trainer name must be 16 bytes.");
|
||||
// note that IsTraded being true in the datagram is not an error condition
|
||||
// since it might have use later on. You should check for this in the upload handler.
|
||||
|
||||
using (MySqlConnection db = CreateConnection())
|
||||
{
|
||||
db.Open();
|
||||
|
||||
/*
|
||||
MySqlDataReader reader = (MySqlDataReader)db.ExecuteReader("SELECT Data, Species, Gender, Level, " +
|
||||
"RequestedSpecies, RequestedGender, RequestedMinLevel, RequestedMaxLevel, " +
|
||||
"Unknown1, TrainerGender, Unknown2, TimeDeposited, TimeWithdrawn, pid, " +
|
||||
"TrainerName, TrainerOT, TrainerCountry, TrainerRegion, TrainerClass, " +
|
||||
"IsExchanged, TrainerVersion, TrainerLanguage FROM GtsPokemon4 WHERE pid = @pid",
|
||||
new MySqlParameter("@pid", pid));
|
||||
*
|
||||
* */
|
||||
|
||||
MySqlTransaction tran = db.BeginTransaction();
|
||||
|
||||
int count = (int)tran.ExecuteScalar("SELECT Count(*) FROM GtsPokemon4 WHERE pid = @pid",
|
||||
new MySqlParameter("@pid", datagram.PID));
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
// This player already has a pokemon in the system.
|
||||
// we can possibly allow multiples under some future conditions
|
||||
tran.Rollback();
|
||||
return false;
|
||||
}
|
||||
|
||||
tran.ExecuteNonQuery("INSERT INTO GtsPokemon4 " +
|
||||
"(Data, Species, Gender, Level, RequestedSpecies, RequestedGender, " +
|
||||
"RequestedMinLevel, RequestedMaxLevel, Unknown1, TrainerGender, " +
|
||||
"Unknown2, TimeDeposited, TimeWithdrawn, pid, TrainerName, TrainerOT, " +
|
||||
"TrainerCountry, TrainerRegion, TrainerClass, IsExchanged, TrainerVersion, " +
|
||||
"TrainerLanguage) " +
|
||||
"VALUES (@Data, @Species, @Gender, @Level, @RequestedSpecies, " +
|
||||
"@RequestedGender, @RequestedMinLevel, @RequestedMaxLevel, @Unknown1, " +
|
||||
"@TrainerGender, @Unknown2, @TimeDeposited, @TimeWithdrawn, @pid, " +
|
||||
"@TrainerName, @TrainerOT, @TrainerCountry, @TrainerRegion, @TrainerClass, " +
|
||||
"@IsExchanged, @TrainerVersion, @TrainerLanguage)",
|
||||
new MySqlParameter("@Data", datagram.Data),
|
||||
new MySqlParameter("@Species", datagram.Species),
|
||||
new MySqlParameter("@Gender", (byte)datagram.Gender),
|
||||
new MySqlParameter("@Level", datagram.Level),
|
||||
new MySqlParameter("@RequestedSpecies", datagram.RequestedSpecies),
|
||||
new MySqlParameter("@RequestedGender", (byte)datagram.RequestedGender),
|
||||
new MySqlParameter("@RequestedMinLevel", datagram.RequestedMinLevel),
|
||||
new MySqlParameter("@RequestedMaxLevel", datagram.RequestedMaxLevel),
|
||||
new MySqlParameter("@Unknown1", datagram.Unknown1),
|
||||
new MySqlParameter("@TrainerGender", (byte)datagram.TrainerGender),
|
||||
new MySqlParameter("@Unknown2", datagram.Unknown2),
|
||||
new MySqlParameter("@TimeDeposited", datagram.TimeDeposited),
|
||||
new MySqlParameter("@TimeWithdrawn", datagram.TimeWithdrawn),
|
||||
new MySqlParameter("@pid", datagram.PID),
|
||||
new MySqlParameter("@TrainerName", datagram.TrainerName),
|
||||
new MySqlParameter("@TrainerOT", datagram.TrainerOT),
|
||||
new MySqlParameter("@TrainerCountry", datagram.TrainerCountry),
|
||||
new MySqlParameter("@TrainerRegion", datagram.TrainerRegion),
|
||||
new MySqlParameter("@TrainerClass", datagram.TrainerClass),
|
||||
new MySqlParameter("@IsExchanged", datagram.IsExchanged),
|
||||
new MySqlParameter("@TrainerVersion", datagram.TrainerVersion),
|
||||
new MySqlParameter("@TrainerLanguage", datagram.TrainerLanguage));
|
||||
|
||||
tran.Commit();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GtsDeletePokemon4(int pid)
|
||||
{
|
||||
}
|
||||
|
||||
public override void GtsTradePokemon4(int pidSrc, int pidDest)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
<Compile Include="Data\DataSqlite.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Structures\Enums.cs" />
|
||||
<Compile Include="Structures\GtsDatagram4.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Support\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
||||
@@ -11,7 +11,8 @@ namespace PokeFoundations.Structures
|
||||
Generation2 = 2,
|
||||
Generation3 = 3,
|
||||
Generation4 = 4,
|
||||
Generation5 = 5
|
||||
Generation5 = 5,
|
||||
Generation6 = 6
|
||||
}
|
||||
|
||||
[FlagsAttribute]
|
||||
@@ -21,10 +22,11 @@ namespace PokeFoundations.Structures
|
||||
Generation2 = 2,
|
||||
Generation3 = 4,
|
||||
Generation4 = 8,
|
||||
Generation5 = 16
|
||||
Generation5 = 16,
|
||||
Generation6 = 32
|
||||
}
|
||||
|
||||
public enum EvolutionMethods
|
||||
public enum EvolutionTriggers
|
||||
{
|
||||
Level = 1,
|
||||
Item = 2,
|
||||
@@ -65,4 +67,18 @@ namespace PokeFoundations.Structures
|
||||
Erratic = 5,
|
||||
Fluctuating = 6
|
||||
}
|
||||
|
||||
public enum Genders : byte
|
||||
{
|
||||
Male = 1,
|
||||
Female = 2,
|
||||
None = 3,
|
||||
Either = 3
|
||||
}
|
||||
|
||||
public enum GtsTrainerGenders : byte
|
||||
{
|
||||
Male = 0,
|
||||
Female = 1
|
||||
}
|
||||
}
|
||||
|
||||
140
library/Structures/GtsDatagram4.cs
Normal file
140
library/Structures/GtsDatagram4.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime.Serialization;
|
||||
using System.IO;
|
||||
|
||||
namespace PokeFoundations.Structures
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure used to represent Pokémon on the GTS in Generation IV.
|
||||
/// Includes a Pokémon box structure and metadata related to the trainer
|
||||
/// and request.
|
||||
/// </summary>
|
||||
[Serializable()]
|
||||
public class GtsDatagram4 : ISerializable
|
||||
{
|
||||
/// <summary>
|
||||
/// Obfuscated Pokémon (pkm) data. 236 bytes
|
||||
/// </summary>
|
||||
public byte[] Data;
|
||||
|
||||
/// <summary>
|
||||
/// National Dex species number
|
||||
/// </summary>
|
||||
public ushort Species;
|
||||
|
||||
/// <summary>
|
||||
/// Pokémon gender
|
||||
/// </summary>
|
||||
public Genders Gender;
|
||||
|
||||
/// <summary>
|
||||
/// Pokémon level
|
||||
/// </summary>
|
||||
public byte Level;
|
||||
|
||||
/// <summary>
|
||||
/// Requested National Dex species number
|
||||
/// </summary>
|
||||
public ushort RequestedSpecies;
|
||||
|
||||
public Genders RequestedGender;
|
||||
|
||||
public byte RequestedMinLevel;
|
||||
public byte RequestedMaxLevel;
|
||||
public byte Unknown1;
|
||||
public GtsTrainerGenders TrainerGender;
|
||||
public byte Unknown2;
|
||||
|
||||
public DateTime TimeDeposited;
|
||||
public DateTime TimeWithdrawn;
|
||||
|
||||
/// <summary>
|
||||
/// User ID of the player (not Personality Value)
|
||||
/// </summary>
|
||||
public int PID;
|
||||
|
||||
/// <summary>
|
||||
/// 16 bytes
|
||||
/// </summary>
|
||||
public byte[] TrainerName; // todo: decode/encode to unicode and provide a String wrapper.
|
||||
|
||||
public ushort TrainerOT;
|
||||
|
||||
public byte TrainerCountry;
|
||||
public byte TrainerRegion;
|
||||
public byte TrainerClass;
|
||||
|
||||
public byte IsExchanged;
|
||||
|
||||
public byte TrainerVersion;
|
||||
public byte TrainerLanguage;
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
// todo: enclose in properties and validate these when assigning.
|
||||
if (Data.Length != 0xEC) throw new FormatException("PKM length is incorrect");
|
||||
if (TrainerName.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(TimeDeposited.ToBinary()), 0, 8);
|
||||
s.Write(BitConverter.GetBytes(TimeWithdrawn.ToBinary()), 0, 8);
|
||||
s.Write(BitConverter.GetBytes(PID), 0, 4);
|
||||
s.Write(TrainerName, 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;
|
||||
}
|
||||
|
||||
public void Load(byte[] data)
|
||||
{
|
||||
if (data.Length != 292) throw new FormatException("GTS datagram length is incorrect.");
|
||||
|
||||
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 = (GtsTrainerGenders)data[0xF6];
|
||||
Unknown2 = data[0xF7];
|
||||
// todo: Figure out what the correct binary storage format is for
|
||||
// official GTS timestamps
|
||||
TimeDeposited = DateTime.FromBinary(BitConverter.ToInt64(data, 0xF8));
|
||||
TimeWithdrawn = DateTime.FromBinary(BitConverter.ToInt64(data, 0x100));
|
||||
PID = BitConverter.ToInt32(data, 0x108);
|
||||
TrainerName = new byte[0x10];
|
||||
Array.Copy(data, 0x10C, TrainerName, 0, 0x10);
|
||||
TrainerOT = BitConverter.ToUInt16(data, 0x11C);
|
||||
TrainerCountry = data[0x11E];
|
||||
TrainerRegion = data[0x11F];
|
||||
TrainerClass = data[0x120];
|
||||
IsExchanged = data[0x121];
|
||||
TrainerVersion = data[0x122];
|
||||
TrainerLanguage = data[0x123];
|
||||
}
|
||||
}
|
||||
}
|
||||
49
library/Support/AssertHelper.cs
Normal file
49
library/Support/AssertHelper.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace PokeFoundations.Support
|
||||
{
|
||||
public class AssertHelper
|
||||
{
|
||||
public static void Assert(bool condition, String message)
|
||||
{
|
||||
if (!condition) try
|
||||
{
|
||||
using (StreamWriter s = File.CreateText("assert.log"))
|
||||
{
|
||||
s.Write("Assert failed: ");
|
||||
s.WriteLine(message);
|
||||
s.Write("Date: ");
|
||||
s.WriteLine(DateTime.Now.ToString("G"));
|
||||
s.Write("Stack trace: ");
|
||||
s.WriteLine(new StackTrace(true).ToString());
|
||||
s.WriteLine();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// directory not found or no write permissions there
|
||||
}
|
||||
|
||||
Debug.Assert(condition, message);
|
||||
}
|
||||
|
||||
public static void Assert(bool condition)
|
||||
{
|
||||
Assert(condition, "Assert failed.");
|
||||
}
|
||||
|
||||
public static void Unreachable()
|
||||
{
|
||||
Assert(false, "Unreachable code has been reached.");
|
||||
}
|
||||
|
||||
public static void Equals<T>(T first, T second) where T : IEquatable<T>
|
||||
{
|
||||
Assert((IEquatable<T>)first == (IEquatable<T>)second, "Values are not equal.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user