Created by: Andrew
This commit is contained in:
Andrew
2016-08-27 22:43:23 -04:00
commit 6d74d5b59e
31 changed files with 3002 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{F163DAAB-BDD2-4510-9A20-604D73D334D0}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>KartExtreme</RootNamespace>
<AssemblyName>Common</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="MySql.Data">
<HintPath>..\..\MySql.Data.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Constants.cs" />
<Compile Include="Data\Database.cs" />
<Compile Include="Data\Datum.cs" />
<Compile Include="Data\Meta.cs" />
<Compile Include="Data\RowNotUniqueException.cs" />
<Compile Include="IO\Packet\InPacket.cs" />
<Compile Include="IO\Log.cs" />
<Compile Include="IO\Packet\OutPacket.cs" />
<Compile Include="IO\Packet\PacketReadException.cs" />
<Compile Include="IO\SettingReadException.cs" />
<Compile Include="IO\Settings.cs" />
<Compile Include="Net\Acceptor.cs" />
<Compile Include="IO\Packet\PacketBase.cs" />
<Compile Include="Net\Cryptography.cs" />
<Compile Include="Net\SendPacketException.cs" />
<Compile Include="Net\Session.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

19
trunk/Common/Constants.cs Normal file
View File

@@ -0,0 +1,19 @@
namespace KartExtreme
{
public static class Constants
{
public static readonly Version Version = new Version()
{
Localisation = 5002,
Major = 1,
Minor = 26
};
}
public struct Version
{
public short Localisation { get; set; }
public short Major { get; set; }
public short Minor { get; set; }
}
}

View File

@@ -0,0 +1,206 @@
using System;
using System.IO;
using MySql.Data.MySqlClient;
using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics;
using KartExtreme.IO;
namespace KartExtreme.Data
{
public class TemporaryConnection : IDisposable
{
private string oldHost;
private string oldSchema;
private string oldUsername;
private string oldPassword;
internal TemporaryConnection(string host, string schema, string username, string password)
{
this.oldHost = Database.Host;
this.oldSchema = Database.Schema;
this.oldUsername = Database.Username;
this.oldPassword = Database.Password;
Database.Host = host;
Database.Schema = schema;
Database.Username = username;
Database.Password = password;
}
public void Dispose()
{
Database.Host = this.oldHost;
Database.Schema = this.oldSchema;
Database.Username = this.oldUsername;
Database.Password = this.oldPassword;
}
}
public class TemporarySchema : IDisposable
{
private string oldSchema;
internal TemporarySchema(string schema)
{
this.oldSchema = Database.Schema;
Database.Schema = schema;
}
public void Dispose()
{
Database.Schema = this.oldSchema;
}
}
public static class Database
{
public static string Host { get; set; }
public static string Schema { get; set; }
public static string Username { get; set; }
public static string Password { get; set; }
internal static string CorrectFields(string fields)
{
string final = string.Empty;
string[] tokens = fields.Replace(",", " ").Replace(";", " ").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
int processed = 0;
foreach (string field in tokens)
{
final += field;
processed++;
if (processed < tokens.Length)
{
final += ", ";
}
}
return final;
}
internal static string ConnectionString
{
get
{
return string.Format("server={0}; database={1}; uid={2}; password={3}; convertzerodatetime=yes;",
Database.Host,
Database.Schema,
Database.Username,
Database.Password);
}
}
internal static void Execute(string nonQuery, params object[] args)
{
MySqlHelper.ExecuteNonQuery(Database.ConnectionString, string.Format(nonQuery, args));
}
public static string DefaultSchema
{
get
{
string name = Assembly.GetEntryAssembly().GetName().Name;
switch (name)
{
case "WvsCenter":
return "wvsmaple-center";
case "WvsLogin":
return "wvsmaple-login";
default:
return "wvsmaple-game";
}
}
}
public static void Test()
{
using (MySqlConnection connection = new MySqlConnection(Database.ConnectionString))
{
connection.Open();
Log.Inform("Able to connect to database '{0}'.", connection.Database);
connection.Close();
}
}
public static void Analyze()
{
using (Database.TemporarySchema("information_schema"))
{
Meta.Initialize();
}
}
public static void Delete(string table, string constraints, params object[] args)
{
Database.Execute("DELETE FROM {0} WHERE {1}", table, string.Format(constraints, args));
}
public static bool Exists(string table, string constraints, params object[] args)
{
using (MySqlDataReader reader = MySqlHelper.ExecuteReader(Database.ConnectionString, string.Format("SELECT * FROM {0} WHERE {1}", table, string.Format(constraints, args))))
{
return reader.HasRows;
}
}
public static dynamic Fetch(string table, string field, string constraints, params object[] args)
{
object value = new Datum(table).PopulateWith(field, constraints, args).Dictionary[field];
if (value is DBNull)
{
return null;
}
else if (value is byte && Meta.IsBool(table, field))
{
return (byte)value > 0;
}
else
{
return value;
}
}
public static void ExecuteScript(string host, string username, string password, string query, params object[] args)
{
using (MySqlConnection connection = new MySqlConnection(string.Format("SERVER={0}; UID={1}; PASSWORD={2};", host, username, password)))
{
connection.Open();
new MySqlScript(connection, string.Format(query, args)).Execute();
connection.Close();
}
}
public static void ExecuteFile(string host, string username, string password, string path)
{
using (MySqlConnection connection = new MySqlConnection(string.Format("SERVER={0}; UID={1}; PASSWORD={2};", host, username, password)))
{
connection.Open();
using (TextReader reader = new StreamReader(path))
{
new MySqlScript(connection, reader.ReadToEnd()).Execute();
}
connection.Close();
}
}
public static TemporaryConnection TemporaryConnection(string host, string schema, string username, string password)
{
return new TemporaryConnection(host, schema, username, password);
}
public static TemporarySchema TemporarySchema(string schema)
{
return new TemporarySchema(schema);
}
}
}

307
trunk/Common/Data/Datum.cs Normal file
View File

@@ -0,0 +1,307 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Dynamic;
using MySql.Data.MySqlClient;
namespace KartExtreme.Data
{
public class Datums : IEnumerable<Datum>
{
private List<Datum> Values { get; set; }
private string Table { get; set; }
public Datums(string table = null)
{
this.Table = table;
}
internal void PopulateInternal(string fields, string constraints)
{
this.Values = new List<Datum>();
string query = string.Format("SELECT {0} FROM {1}{2}", fields == null ? "*" : Database.CorrectFields(fields), this.Table, constraints != null ? " WHERE " + constraints : string.Empty);
using (MySqlDataReader reader = MySqlHelper.ExecuteReader(Database.ConnectionString, query))
{
while (reader.Read())
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++)
{
dictionary.Add(reader.GetName(i), reader.GetValue(i));
}
this.Values.Add(new Datum(this.Table, dictionary));
}
}
}
internal void PopulateInternalFree(string query)
{
this.Values = new List<Datum>();
using (MySqlDataReader reader = MySqlHelper.ExecuteReader(Database.ConnectionString, query))
{
while (reader.Read())
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
for (int i = 0; i < reader.FieldCount; i++)
{
dictionary.Add(reader.GetName(i), reader.GetValue(i));
}
this.Values.Add(new Datum(this.Table, dictionary));
}
}
}
public dynamic Populate()
{
this.PopulateInternal(null, null);
return this;
}
public dynamic Populate(string constraints, params object[] args)
{
this.PopulateInternal(null, string.Format(constraints, args));
return this;
}
public dynamic PopulateWith(string fields)
{
this.PopulateInternal(fields, null);
return this;
}
public dynamic PopulateWith(string fields, string constraints, params object[] args)
{
this.PopulateInternal(fields, string.Format(constraints, args));
return this;
}
public dynamic PopulateFree(string query)
{
this.PopulateInternalFree(query);
return this;
}
public IEnumerator<Datum> GetEnumerator()
{
foreach (Datum loopDatum in this.Values)
{
yield return loopDatum;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)this.GetEnumerator();
}
}
public class Datum : DynamicObject
{
public string Table { get; private set; }
internal Dictionary<string, object> Dictionary { get; set; }
public Datum(string table)
{
this.Table = table;
this.Dictionary = new Dictionary<string, object>();
}
internal Datum(string table, Dictionary<string, object> values)
{
this.Table = table;
this.Dictionary = values;
}
internal void Populate(string query)
{
using (MySqlDataReader reader = MySqlHelper.ExecuteReader(Database.ConnectionString, query))
{
if (reader.RecordsAffected > 1)
{
throw new RowNotUniqueException();
}
if (!reader.HasRows)
{
throw new RowNotInTableException();
}
reader.Read();
for (int i = 0; i < reader.FieldCount; i++)
{
string name = reader.GetName(i);
object value = reader.GetValue(i);
if (this.Dictionary.ContainsKey(name))
{
this.Dictionary[name] = value;
}
else
{
this.Dictionary.Add(name, value);
}
}
}
}
public dynamic Populate(string constraints, params object[] args)
{
this.Populate(string.Format("SELECT * FROM {0} WHERE {1}", this.Table, string.Format(constraints, args)));
return this;
}
public dynamic PopulateWith(string fields, string constraints, params object[] args)
{
this.Populate(string.Format("SELECT {0} FROM {1} WHERE {2}", Database.CorrectFields(fields), this.Table, string.Format(constraints, args)));
return this;
}
public void Insert()
{
string fields = "( ";
int processed = 0;
foreach (KeyValuePair<string, object> loopPair in this.Dictionary)
{
fields += loopPair.Key;
processed++;
if (processed < this.Dictionary.Count)
{
fields += ", ";
}
}
fields += " ) VALUES ( ";
processed = 0;
foreach (KeyValuePair<string, object> loopPair in this.Dictionary)
{
fields += string.Format("'{0}'", loopPair.Value is bool ? (((bool)loopPair.Value) ? 1 : 0) : loopPair.Value);
processed++;
if (processed < this.Dictionary.Count)
{
fields += ", ";
}
}
fields += " )";
Database.Execute("INSERT INTO {0} {1}", this.Table, fields);
}
public void Update(string constraints, params object[] args)
{
int processed = 0;
string fields = string.Empty;
foreach (KeyValuePair<string, object> loopPair in this.Dictionary)
{
fields += string.Format("{0}='{1}'", loopPair.Key, loopPair.Value is bool ? (((bool)loopPair.Value) ? 1 : 0) : loopPair.Value);
processed++;
if (processed < this.Dictionary.Count)
{
fields += ", ";
}
}
Database.Execute("UPDATE {0} SET {1} WHERE {2}", this.Table, fields, string.Format(constraints, args));
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (this.Dictionary.ContainsKey(binder.Name))
{
if (this.Dictionary[binder.Name] is DBNull)
{
result = null;
}
else if (this.Dictionary[binder.Name] is byte && Meta.IsBool(this.Table, binder.Name))
{
result = (byte)this.Dictionary[binder.Name] > 0;
}
else
{
result = this.Dictionary[binder.Name];
}
return true;
}
else
{
result = default(object);
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (value is DateTime)
{
if (Meta.IsDate(this.Table, binder.Name))
{
value = ((DateTime)value).ToString("yyyy-MM-dd");
}
else if (Meta.IsDateTime(this.Table, binder.Name))
{
value = ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
}
}
if (this.Dictionary.ContainsKey(binder.Name))
{
this.Dictionary[binder.Name] = value;
}
else
{
this.Dictionary.Add(binder.Name, value);
}
return true;
}
public override string ToString()
{
string result = this.Table + " [ ";
int processed = 0;
foreach (KeyValuePair<string, object> value in this.Dictionary)
{
result += value.Key;
processed++;
if (processed < this.Dictionary.Count)
{
result += ", ";
}
}
result += " ]";
return result;
}
}
}

70
trunk/Common/Data/Meta.cs Normal file
View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
namespace KartExtreme.Data
{
internal static class Meta
{
public static Dictionary<string, Dictionary<string, Column>> Tables = new Dictionary<string, Dictionary<string, Column>>();
public static void Initialize()
{
Meta.Tables.Clear();
foreach (dynamic datum in new Datums("COLUMNS").Populate("TABLE_SCHEMA = '{0}'", Database.DefaultSchema))
{
Meta.Add(datum);
}
}
private static void Add(dynamic datum)
{
Dictionary<string, Column> table;
string tableName = datum.TABLE_NAME;
if (Meta.Tables.ContainsKey(tableName))
{
table = Meta.Tables[tableName];
}
else
{
table = new Dictionary<string, Column>();
Meta.Tables.Add(tableName, table);
}
table.Add(datum.COLUMN_NAME, new Column(datum));
}
public static bool IsBool(String tableName, String fieldName)
{
return Meta.Tables[tableName][fieldName].ColumnType == "tinyint(1) unsigned";
}
public static bool IsDate(String tableName, String fieldName)
{
return Meta.Tables[tableName][fieldName].ColumnType == "date";
}
public static bool IsDateTime(String tableName, String fieldName)
{
return Meta.Tables[tableName][fieldName].ColumnType == "datetime";
}
}
internal class Column
{
public string Name { get; private set; }
public bool IsPrimaryKey { get; private set; }
public bool IsUniqueKey { get; private set; }
public string ColumnType { get; private set; }
public Column(dynamic datum)
{
this.Name = datum.COLUMN_NAME;
this.IsPrimaryKey = datum.COLUMN_KEY == "PRI";
this.IsUniqueKey = datum.COLUMN_KEY == "UNI";
this.ColumnType = datum.COLUMN_TYPE;
}
}
}

View File

@@ -0,0 +1,13 @@
namespace System.Data
{
public class RowNotUniqueException : DataException
{
public override string Message
{
get
{
return "Obtained row is not unique.";
}
}
}
}

View File

@@ -0,0 +1,151 @@
using System;
using System.IO;
namespace KartExtreme.IO.Packet
{
public class InPacket : PacketBase
{
private readonly byte[] _buffer;
private int _index;
public override int Position
{
get { return _index; }
}
public override int Length
{
get { return _buffer.Length; }
}
public int Available
{
get
{
return _buffer.Length - _index;
}
}
public InPacket(byte[] packet)
{
_buffer = packet;
_index = 0;
}
private void CheckLength(int length)
{
if (_index + length > _buffer.Length || length < 0)
throw new PacketReadException("Not enough space");
}
public bool ReadBool()
{
return ReadByte() == 1;
}
public byte ReadByte()
{
CheckLength(1);
return _buffer[_index++];
}
public sbyte ReadSByte()
{
return (sbyte)ReadByte();
}
public byte[] ReadBytes(int count)
{
CheckLength(count);
var temp = new byte[count];
Buffer.BlockCopy(_buffer, _index, temp, 0, count);
_index += count;
return temp;
}
public unsafe short ReadShort()
{
CheckLength(2);
short value;
fixed (byte* ptr = _buffer)
{
value = *(short*)(ptr + _index);
}
_index += 2;
return value;
}
public ushort ReadUShort()
{
return (ushort)ReadShort();
}
public unsafe int ReadInt()
{
CheckLength(4);
int value;
fixed (byte* ptr = _buffer)
{
value = *(int*)(ptr + _index);
}
_index += 4;
return value;
}
public uint ReadUInt()
{
return (uint)ReadInt();
}
public unsafe long ReadLong()
{
CheckLength(8);
long value;
fixed (byte* ptr = _buffer)
{
value = *(long*)(ptr + _index);
}
_index += 8;
return value;
}
public ulong ReadULong()
{
return (ulong)ReadLong();
}
public string ReadString(int count)
{
CheckLength(count);
char[] final = new char[count];
for (int i = 0; i < count; i++)
{
final[i] = (char)ReadByte();
}
return new string(final);
}
public void Skip(int count)
{
CheckLength(count);
_index += count;
}
public override byte[] ToArray()
{
var final = new byte[_buffer.Length];
Buffer.BlockCopy(_buffer, 0, final, 0, _buffer.Length);
return final;
}
}
}

View File

@@ -0,0 +1,167 @@
using System;
using System.Globalization;
using System.IO;
using System.Text;
namespace KartExtreme.IO.Packet
{
public class OutPacket : PacketBase, IDisposable
{
private MemoryStream m_stream;
private bool m_disposed;
public override int Length
{
get { return (int)m_stream.Position; }
}
public override int Position
{
get { return (int)m_stream.Position; }
}
public bool Disposed
{
get
{
return m_disposed;
}
}
public OutPacket(int size = 64)
{
m_stream = new MemoryStream(size);
m_disposed = false;
}
//From LittleEndianByteConverter by Shoftee
private void Append(long value, int byteCount)
{
for (int i = 0; i < byteCount; i++)
{
m_stream.WriteByte((byte)value);
value >>= 8;
}
}
public void WriteBool(bool value)
{
ThrowIfDisposed();
WriteByte(value ? (byte)1 : (byte)0);
}
public void WriteByte(byte value = 0)
{
ThrowIfDisposed();
m_stream.WriteByte(value);
}
public void WriteSByte(sbyte value = 0)
{
WriteByte((byte)value);
}
public void WriteBytes(params byte[] value)
{
ThrowIfDisposed();
m_stream.Write(value, 0, value.Length);
}
public void WriteShort(short value = 0)
{
ThrowIfDisposed();
Append(value, 2);
}
public void WriteUShort(ushort value = 0)
{
WriteShort((short)value);
}
public void WriteInt(int value = 0)
{
ThrowIfDisposed();
Append(value, 4);
}
public void WriteUInt(uint value = 0)
{
WriteInt((int)value);
}
public void WriteLong(long value = 0)
{
ThrowIfDisposed();
Append(value, 8);
}
public void WriteULong(ulong value = 0)
{
WriteLong((long)value);
}
public void WriteString(string value)
{
if (value == null)
throw new ArgumentNullException("value");
WriteInt(value.Length);
WriteString(value, value.Length);
}
public void WriteString(string value, int length)
{
if (value == null ||
length < 1 ||
length > value.Length)
throw new ArgumentNullException("value");
var bytes = Encoding.Unicode.GetBytes(value);
var i = 0;
for (; i < value.Length & i < length; i++)
{
var offset = i * 2;
this.WriteByte(bytes[offset]);
this.WriteByte(bytes[offset + 1]);
}
for (; i < length; i++)
{
this.WriteShort();
}
}
public void WriteHexString(string value)
{
if (value == null)
throw new ArgumentNullException("value");
value = value.Replace(" ", "");
for (int i = 0; i < value.Length; i += 2)
{
WriteByte(byte.Parse(value.Substring(i, 2), NumberStyles.HexNumber));
}
}
private void ThrowIfDisposed()
{
if (m_disposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
}
public override byte[] ToArray()
{
ThrowIfDisposed();
return m_stream.ToArray();
}
public void Dispose()
{
m_disposed = true;
if (m_stream != null)
m_stream.Dispose();
m_stream = null;
}
}
}

View File

@@ -0,0 +1,25 @@
using System.IO;
using System.Text;
namespace KartExtreme.IO.Packet
{
public abstract class PacketBase
{
public abstract int Length { get; }
public abstract int Position { get; }
public abstract byte[] ToArray();
public override string ToString()
{
var sb = new StringBuilder();
foreach (byte b in this.ToArray())
{
sb.AppendFormat("{0:X2} ", b);
}
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace KartExtreme.IO.Packet
{
public sealed class PacketReadException : Exception
{
public PacketReadException(string message)
: base(message)
{
}
}
}

View File

@@ -0,0 +1,9 @@
using System;
namespace KartExtreme.IO
{
public class SettingReadException : Exception
{
public SettingReadException(string key) : base(string.Format("Failed to read setting '{0}'.", key)) { }
}
}

188
trunk/Common/IO/Settings.cs Normal file
View File

@@ -0,0 +1,188 @@
using KartExtreme.Data;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
namespace KartExtreme.IO
{
public static class Settings
{
private const string Comment = "#";
public static string Path { get; private set; }
private static Dictionary<string, string> Dictionary;
public static void Initialize(string path = null)
{
if (path == null)
{
path = "Configuration.ini";
}
if (Settings.Dictionary != null)
{
Settings.Dictionary.Clear();
}
Settings.Path = path;
Settings.Dictionary = new Dictionary<string, string>();
string[] array = Settings.Path.Split('\\');
string name = array[array.Length - 1];
if (!File.Exists(path))
{
throw new FileNotFoundException(string.Format("Unable to find configuration file '{0}'.", name));
}
else
{
string line;
string currentSection = string.Empty;
using (StreamReader file = new StreamReader(path))
{
while ((line = file.ReadLine()) != null)
{
if (line.StartsWith(Settings.Comment))
continue;
if (line.StartsWith("[") && line.EndsWith("]"))
{
currentSection = line.Trim('[', ']');
}
else if (line.Contains("="))
{
Settings.Dictionary.Add(string.Format("{0}{1}{2}",
currentSection,
(currentSection != string.Empty) ? "/" : string.Empty,
line.Split('=')[0]),
line.Split('=')[1].Split(';')[0]);
}
}
}
}
Database.Host = Settings.GetString("Database/Host");
Database.Schema = Settings.GetString("Database/Schema");
Database.Username = Settings.GetString("Database/Username");
Database.Password = Settings.GetString("Database/Password");
}
public static int GetInt(string key, params object[] args)
{
try
{
return int.Parse(Settings.Dictionary[string.Format(key, args)]);
}
catch
{
throw new SettingReadException(key);
}
}
public static short GetShort(string key, params object[] args)
{
try
{
return short.Parse(Settings.Dictionary[string.Format(key, args)]);
}
catch
{
throw new SettingReadException(key);
}
}
public static ushort GetUShort(string key, params object[] args)
{
try
{
return ushort.Parse(Settings.Dictionary[string.Format(key, args)]);
}
catch
{
throw new SettingReadException(key);
}
}
public static byte GetByte(string key, params object[] args)
{
try
{
return byte.Parse(Settings.Dictionary[string.Format(key, args)]);
}
catch
{
throw new SettingReadException(key);
}
}
public static sbyte GetSByte(string key, params object[] args)
{
try
{
return sbyte.Parse(Settings.Dictionary[string.Format(key, args)]);
}
catch
{
throw new SettingReadException(key);
}
}
public static bool GetBool(string key, params object[] args)
{
try
{
return bool.Parse(Settings.Dictionary[string.Format(key, args)]);
}
catch
{
throw new SettingReadException(key);
}
}
public static string GetString(string key, params object[] args)
{
try
{
return Settings.Dictionary[string.Format(key, args)];
}
catch
{
throw new SettingReadException(key);
}
}
public static IPAddress GetIPAddress(string key, params object[] args)
{
try
{
if (Settings.Dictionary[string.Format(key, args)] == "localhost")
{
return IPAddress.Loopback;
}
else
{
return IPAddress.Parse(Settings.Dictionary[string.Format(key, args)]);
}
}
catch
{
throw new SettingReadException(key);
}
}
public static T GetEnum<T>(string key, params object[] args)
{
try
{
return (T)Enum.Parse(typeof(T), Settings.Dictionary[string.Format(key, args)]);
}
catch
{
throw new SettingReadException(key);
}
}
}
}

294
trunk/Common/IO/lOG.cs Normal file
View File

@@ -0,0 +1,294 @@
using System;
using System.Text;
namespace KartExtreme.IO
{
public static class Log
{
private const byte LabelWidth = 11;
private static bool Entitled = false;
public static bool Running { get; private set; }
public static string Margin
{
get
{
return new string(' ', Log.LabelWidth);
}
}
public static string MaskString(string input, char mask = '*')
{
return new string(mask, input.Length);
}
static Log()
{
Console.BackgroundColor = ConsoleColor.Black;
Console.Clear();
Log.Running = true;
}
public static string Input(string label)
{
lock (typeof(Log))
{
Log.WriteItem("Input", ConsoleColor.Cyan, string.Empty);
Console.Write(label);
return Console.ReadLine();
}
}
public static string Input(string label, string defaultValue)
{
lock (typeof(Log))
{
Log.WriteItem("Input", ConsoleColor.Cyan, string.Empty);
Console.Write(label);
string result = Console.ReadLine();
if (result == string.Empty)
{
result = defaultValue;
Console.CursorTop--;
Console.CursorLeft = Log.Margin.Length + label.Length;
Console.WriteLine(defaultValue == string.Empty ? "(None)" : result);
}
return result;
}
}
/// <summary>
/// Writes a labeled item to the output.
/// </summary>
/// <param name="label">The label</param>
/// <param name="labelColor">The label's color</param>
/// <param name="value">The text</param>
/// <param name="args">Arguments</param>
private static void WriteItem(string label, ConsoleColor labelColor, string value, params object[] args)
{
lock (typeof(Log))
{
StringBuilder sb = new StringBuilder();
sb.Append(' ', Log.LabelWidth - label.Length - 3);
sb.Append("[");
sb.Append(label);
sb.Append("]");
sb.Append(" ");
label = sb.ToString();
value = string.Format(value, args);
Console.ForegroundColor = labelColor;
Console.Write(label);
Console.ForegroundColor = ConsoleColor.Gray;
bool first = true;
foreach (string s in value.Split('\n'))
{
string[] lines = new string[(int)Math.Ceiling((float)s.Length / (float)(Console.BufferWidth - Log.LabelWidth))];
for (int i = 0; i < lines.Length; i++)
{
if (i == lines.Length - 1)
{
lines[i] = s.Substring((Console.BufferWidth - Log.LabelWidth) * i);
}
else
{
lines[i] = s.Substring((Console.BufferWidth - Log.LabelWidth) * i, (Console.BufferWidth - Log.LabelWidth));
}
}
foreach (string line in lines)
{
if (!first)
{
Console.Write(Log.Margin);
}
if ((line.Length + Log.LabelWidth) < Console.BufferWidth)
{
Console.WriteLine(line);
}
else if ((line.Length + Log.LabelWidth) == Console.BufferWidth)
{
Console.Write(line);
}
first = false;
}
}
}
}
public static void SkipLine()
{
Console.WriteLine();
}
public static void Entitle(string value, params object[] args)
{
lock (typeof(Log))
{
Console.ForegroundColor = ConsoleColor.Yellow;
StringBuilder sb = new StringBuilder();
sb.Append("\n");
//for (int i = 0; i < Console.WindowWidth / 2 - value.Length / 2; i++)
//{
// sb.Append(' ');
//}
sb.Append('\t');
sb.Append((Log.Entitled ? "" : "") + string.Format(value, args) + '\n');
Console.WriteLine(sb.ToString());
Console.ForegroundColor = ConsoleColor.Gray;
Console.Title = string.Format(value, args);
Log.Entitled = true;
}
}
public static void Inform(string value, params object[] args)
{
Log.WriteItem("Info", ConsoleColor.White, value, args);
}
public static void Inform(object value)
{
Log.Inform(value.ToString());
}
public static void Warn(string value, params object[] args)
{
Log.WriteItem("Warning", ConsoleColor.Yellow, value, args);
}
public static void Warn(object value)
{
Log.Warn(value.ToString());
}
public static void Error(string value, params object[] args)
{
Log.WriteItem("Error", ConsoleColor.Red, value, args);
}
public static bool ShowStackTrace { get; set; }
public static void Error(Exception exception)
{
Log.WriteItem("Error", ConsoleColor.Red, Log.ShowStackTrace ? exception.ToString() : exception.Message);
}
public static void Error(string label, Exception exception, params object[] args)
{
Log.WriteItem("Error", ConsoleColor.Red, "{0}\n{1}", string.Format(label, args), Log.ShowStackTrace ? exception.ToString() : exception.Message);
}
public static void Debug(string value, params object[] args)
{
Log.WriteItem("Debug", ConsoleColor.Green, value, args);
}
public static void Success(object value)
{
Log.Debug(value.ToString());
}
public static void Sql(string value, params object[] args)
{
Log.WriteItem("Sql", ConsoleColor.Magenta, value, args);
}
public static void Hex(string label, byte[] value, params object[] args)
{
StringBuilder sb = new StringBuilder();
sb.Append(string.Format(label, args));
sb.Append('\n');
if (value == null || value.Length == 0)
{
sb.Append("(Empty)");
}
else
{
int lineSeparation = 0;
foreach (byte b in value)
{
if (lineSeparation == 16)
{
sb.Append('\n');
lineSeparation = 0;
}
sb.AppendFormat("{0:X2} ", b);
lineSeparation++;
}
}
Log.WriteItem("Hex", ConsoleColor.Magenta, sb.ToString());
}
public static void Hex(string label, byte b, params object[] args)
{
Log.Hex(label, new byte[] { b }, args);
}
public static void Quit()
{
Log.Running = false;
Log.Inform("Press any key to quit . . .");
Console.Read();
}
public static LoadingIndicator Load(string header)
{
return new LoadingIndicator(header);
}
}
public class LoadingIndicator : IDisposable
{
public static bool ShowTime { get; set; }
private DateTime LoadStartTime { get; set; }
internal LoadingIndicator(string header)
{
lock (typeof(Log))
{
Console.Write("{0} {1}... ", Log.Margin, header);
}
}
public void Dispose()
{
lock (typeof(Log))
{
if (LoadingIndicator.ShowTime)
{
Console.WriteLine("({0}ms)", (DateTime.Now - this.LoadStartTime).Milliseconds);
}
else
{
Console.WriteLine();
}
}
}
}
}

View File

@@ -0,0 +1,65 @@
using KartExtreme.IO;
using System;
using System.Net;
using System.Net.Sockets;
namespace KartExtreme.Net
{
public sealed class Acceptor
{
public const int Backlog = 25;
public ushort Port { get; private set; }
private readonly TcpListener m_listener;
private bool m_disposed;
public Action<Socket> OnClientAccepted;
public Acceptor(ushort port) : this(IPAddress.Any, port) { }
public Acceptor(IPAddress ip, ushort port)
{
Port = port;
m_listener = new TcpListener(IPAddress.Any, port);
OnClientAccepted = null;
m_disposed = false;
}
public void Start()
{
m_listener.Start(Backlog);
m_listener.BeginAcceptSocket(EndAccept, null);
Log.Inform("Initialized clients listener on {0}.", this.Port);
}
public void Stop()
{
Dispose();
}
private void EndAccept(IAsyncResult iar)
{
if (m_disposed) { return; }
Socket client = m_listener.EndAcceptSocket(iar);
if (OnClientAccepted != null)
OnClientAccepted(client);
if (!m_disposed)
m_listener.BeginAcceptSocket(EndAccept, null);
}
public void Dispose()
{
if (!m_disposed)
{
m_disposed = true;
m_listener.Server.Close();
}
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace KartExtreme.Net
{
class Cryptography
{
public static uint HashPacket(byte[] pData, uint pKey, bool pEncrypt, uint npacketLength)
{
uint hash1 = (pKey ^ 0x14B307C8);
uint hash2 = (pKey ^ 0x8CBF12AC);
uint hash3 = (pKey ^ 0x240397C1);
uint hash4 = (pKey ^ 0xF3BD29C0);
uint checksum = 0;
int packetLength = (int)npacketLength;//pData.Length;
Action<int, uint> doHash = (index, hash) =>
{
pData[index + 0] ^= (byte)(hash & 0xFF);
pData[index + 1] ^= (byte)((hash << 8) & 0xFF);
pData[index + 2] ^= (byte)((hash << 16) & 0xFF);
pData[index + 3] ^= (byte)((hash << 24) & 0xFF);
};
int offset = 0;
int i = 0;
for (i = 0; i < (packetLength >> 4); ++i)
{
if (pEncrypt)
checksum ^= (uint)(BitConverter.ToUInt32(pData, offset + 12) ^ BitConverter.ToUInt32(pData, offset + 8) ^ BitConverter.ToUInt32(pData, offset + 4) ^ BitConverter.ToUInt32(pData, offset + 0));
doHash(offset + 0, hash1);
doHash(offset + 4, hash2);
doHash(offset + 8, hash3);
doHash(offset + 12, hash4);
if (!pEncrypt)
checksum ^= (uint)(BitConverter.ToUInt32(pData, offset + 12) ^ BitConverter.ToUInt32(pData, offset + 8) ^ BitConverter.ToUInt32(pData, offset + 4) ^ BitConverter.ToUInt32(pData, offset + 0));
offset += 16;
}
i *= 16;
int sub = 0;
///Note: it has a problem with Checksum Calculation
while (i < packetLength)
{
if (pEncrypt) checksum ^= (uint)(pData[i] << sub);
pData[i] ^= (byte)(hash1 << (sub * 8));
if (!pEncrypt) checksum ^= (uint)(pData[i] << sub);
sub++;
i++;
}
/*
for (int i = offset; i < packetLength; i++)
{
if (pEncrypt) checksum ^= (uint)(pData[i] << sub);
pData[i] ^= (byte)(hash1 << (sub * 8));
if (!pEncrypt) checksum ^= (uint)(pData[i] << sub);
sub++;
}*/
return checksum;
}
}
}

View File

@@ -0,0 +1,12 @@
using System;
namespace KartExtreme.Net
{
public sealed class SendPacketException : Exception
{
public SendPacketException()
: base("Disconnected while sending packet")
{
}
}
}

294
trunk/Common/Net/Session.cs Normal file
View File

@@ -0,0 +1,294 @@
using KartExtreme.IO;
using System;
using System.Diagnostics;
using System.Net.Sockets;
using KartExtreme.IO.Packet;
namespace KartExtreme.Net
{
public abstract class Session
{
private Socket _socket;
private byte[] _buffer;
private int _bufferIndex;
private bool _header;
private bool _connected;
private string _label;
private uint riv;
private uint siv;
private object _lock;
public string Label
{
get
{
return _label;
}
}
public bool IsConnected
{
get
{
return _connected;
}
}
/// <summary>
/// Initializes a new instance of the Session class.
/// </summary>
/// <param name="socket"></param>
public Session(Socket socket)
{
this._socket = socket;
this._socket.NoDelay = true;
this._label = this._socket.RemoteEndPoint.ToString();
this._connected = true;
this._lock = new object();
this.InitiateReceive(4, true);
}
/// <summary>
/// Initiates the receiving mechanism.
/// </summary>
/// <param name="length">The length of the data</param>
/// <param name="header">Indicates if a header is received</param>
private void InitiateReceive(uint length, bool header = false)
{
if (!this._connected)
{
return;
}
this._header = header;
this._buffer = new byte[length];
this._bufferIndex = 0;
this.BeginReceive();
}
/// <summary>
/// Begins to asynchronously receive data from the socket.
/// </summary>
private void BeginReceive()
{
if (!this._connected)
{
return;
}
var error = SocketError.Success;
this._socket.BeginReceive(this._buffer,
this._bufferIndex,
this._buffer.Length - this._bufferIndex,
SocketFlags.None, out error,
EndReceive,
null);
if (error != SocketError.Success)
{
this.Close();
}
}
/// <summary>
/// Reads the data from the callback and handles it.
/// </summary>
/// <param name="iar"></param>
private void EndReceive(IAsyncResult iar)
{
if (!this._connected)
{
return;
}
var error = SocketError.Success;
int received = this._socket.EndReceive(iar, out error);
if (received == 0 || error != SocketError.Success)
{
this.Close();
return;
}
this._bufferIndex += received;
if (this._bufferIndex == this._buffer.Length)
{
if (this._header)
{
uint header = BitConverter.ToUInt32(this._buffer, 0);
if(riv != 0)
header = (riv ^ header ^ 0xF834A608);
this.InitiateReceive(header, false);
}
else
{
if (riv != 0)
{
int bufferLength = _buffer.Length - 4;
uint originalChecksum = (uint)(riv ^ BitConverter.ToUInt32(this._buffer, bufferLength) ^ 0xC9F84A90);
Array.Resize<byte>(ref this._buffer, bufferLength);
uint checksum = Cryptography.HashPacket(this._buffer, riv, false, (uint)bufferLength);
if (originalChecksum != checksum)
{
Log.Warn("Decrypt Checksum different!");
}
riv += 21446425;
if (riv == 0)
riv = 1;
}
this.OnPacket(new InPacket(this._buffer));
this.InitiateReceive(4, true);
}
}
else
{
this.BeginReceive();
}
}
/// <summary>
/// Sends the initial patch data packet to the socket.
/// </summary>
/// <param name="version">The version's information</param>
/// <param name="patchLocation">The patch data URL</param>
public void SendPatchData(Version version, string patchLocation)
{
//Fuck!!!!!
Random rnd = new Random();
uint val_first = 0;//(uint)rnd.Next();
uint val_second = 0;//(uint)rnd.Next() ;
using (OutPacket outPacket = new OutPacket())
{
outPacket.WriteHexString("80 05 2B 28"); // NOTE: Header. Do not change. Probably typeid() of handler.
outPacket.WriteShort(version.Localisation);
outPacket.WriteShort(version.Major);
outPacket.WriteShort(version.Minor);
outPacket.WriteString(patchLocation);
outPacket.WriteInt((int)val_first); // NOTE: IV Keys. Should we do random stuffs?
outPacket.WriteInt((int)val_second);
outPacket.WriteByte(0xE0); // NOTE: Some stuff used on Region / Service Area.
outPacket.WriteHexString("03 00 09 03 00 00 03 00 00 00 00 00 83 A3 E5 47 00 00 15 00 0D 00 00 00 03 00 00 00 00 00 65");
this.Send(outPacket);
}
riv = val_first ^ val_second;
siv = val_first ^ val_second;
}
/// <summary>
/// Sends a KartExtreme.IO.OutPacket array to the socket.
/// </summary>
/// <param name="outPacket"></param>
public void Send(OutPacket outPacket)
{
this.Send(outPacket.ToArray());
}
/// <summary>
/// Sends data to the socket.
/// </summary>
/// <param name="buffer"></param>
public void Send(byte[] buffer)
{
if (!this._connected)
{
return;
}
lock (_lock)
{
byte[] data = new byte[buffer.Length + (siv != 0 ? 8 : 4)];
if (siv == 0)
{
Buffer.BlockCopy(BitConverter.GetBytes((int)buffer.Length), 0, data, 0, 4);
}
else
{
uint newHash = Cryptography.HashPacket(buffer, siv, true, (uint)buffer.Length);
// NOTE: Length at beginning.
Buffer.BlockCopy(BitConverter.GetBytes((int)(siv ^ (buffer.Length + 4) ^ 0xF834A608)), 0, data, 0, 4);
// NOTE: Checksum at end.
Buffer.BlockCopy(BitConverter.GetBytes((uint)(siv ^ newHash ^ 0xC9F84A90)), 0, data, data.Length - 4, 4);
siv += 0x1473F19;
if (siv == 0)
siv = 1;
}
Buffer.BlockCopy(buffer, 0, data, 4, buffer.Length);
this.SendRaw(data);
}
}
private void SendRaw(byte[] data)
{
if (!this._connected)
{
return;
}
int offset = 0;
while (offset < data.Length)
{
SocketError error = SocketError.Success;
int sent = this._socket.Send(data, offset, data.Length - offset, SocketFlags.None, out error);
if (sent == 0 || error != SocketError.Success)
{
throw new SendPacketException();
}
offset += sent;
}
}
/// <summary>
/// Closes the socket.
/// </summary>
public void Close()
{
if (!this._connected)
{
return;
}
this._socket.Shutdown(SocketShutdown.Both);
this._socket.Close();
this.OnDisconnect();
}
public abstract void OnDisconnect();
public abstract void OnPacket(InPacket inPacket);
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Common")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Common")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("740eb84a-eada-43e8-b6ed-a278afc3b1a1")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]