From 6d74d5b59e65cc6932cbda27b6889e98e4ca47d6 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 27 Aug 2016 22:43:23 -0400 Subject: [PATCH] source Created by: Andrew --- .gitattributes | 17 + .gitignore | 174 +++++++++ LICENSE | 339 ++++++++++++++++++ README.md | 5 + add loopback.bat | 12 + trunk/Common/Common.csproj | 75 ++++ trunk/Common/Constants.cs | 19 + trunk/Common/Data/Database.cs | 206 +++++++++++ trunk/Common/Data/Datum.cs | 307 ++++++++++++++++ trunk/Common/Data/Meta.cs | 70 ++++ trunk/Common/Data/RowNotUniqueException.cs | 13 + trunk/Common/IO/Packet/InPacket.cs | 151 ++++++++ trunk/Common/IO/Packet/OutPacket.cs | 167 +++++++++ trunk/Common/IO/Packet/PacketBase.cs | 25 ++ trunk/Common/IO/Packet/PacketReadException.cs | 16 + trunk/Common/IO/SettingReadException.cs | 9 + trunk/Common/IO/Settings.cs | 188 ++++++++++ trunk/Common/IO/lOG.cs | 294 +++++++++++++++ trunk/Common/Net/Acceptor.cs | 65 ++++ trunk/Common/Net/Cryptography.cs | 74 ++++ trunk/Common/Net/SendPacketException.cs | 12 + trunk/Common/Net/Session.cs | 294 +++++++++++++++ trunk/Common/Properties/AssemblyInfo.cs | 36 ++ trunk/KartExtreme.sln | 28 ++ trunk/KartExtreme/Application.cs | 51 +++ trunk/KartExtreme/Kart/Player.cs | 61 ++++ trunk/KartExtreme/KartExtreme.csproj | 70 ++++ trunk/KartExtreme/Net/KartClient.cs | 138 +++++++ trunk/KartExtreme/Net/Server.cs | 47 +++ trunk/KartExtreme/Properties/AssemblyInfo.cs | 36 ++ trunk/KartExtreme/app.config | 3 + 31 files changed, 3002 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 add loopback.bat create mode 100644 trunk/Common/Common.csproj create mode 100644 trunk/Common/Constants.cs create mode 100644 trunk/Common/Data/Database.cs create mode 100644 trunk/Common/Data/Datum.cs create mode 100644 trunk/Common/Data/Meta.cs create mode 100644 trunk/Common/Data/RowNotUniqueException.cs create mode 100644 trunk/Common/IO/Packet/InPacket.cs create mode 100644 trunk/Common/IO/Packet/OutPacket.cs create mode 100644 trunk/Common/IO/Packet/PacketBase.cs create mode 100644 trunk/Common/IO/Packet/PacketReadException.cs create mode 100644 trunk/Common/IO/SettingReadException.cs create mode 100644 trunk/Common/IO/Settings.cs create mode 100644 trunk/Common/IO/lOG.cs create mode 100644 trunk/Common/Net/Acceptor.cs create mode 100644 trunk/Common/Net/Cryptography.cs create mode 100644 trunk/Common/Net/SendPacketException.cs create mode 100644 trunk/Common/Net/Session.cs create mode 100644 trunk/Common/Properties/AssemblyInfo.cs create mode 100644 trunk/KartExtreme.sln create mode 100644 trunk/KartExtreme/Application.cs create mode 100644 trunk/KartExtreme/Kart/Player.cs create mode 100644 trunk/KartExtreme/KartExtreme.csproj create mode 100644 trunk/KartExtreme/Net/KartClient.cs create mode 100644 trunk/KartExtreme/Net/Server.cs create mode 100644 trunk/KartExtreme/Properties/AssemblyInfo.cs create mode 100644 trunk/KartExtreme/app.config diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bdb0cab --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..748683d --- /dev/null +++ b/.gitignore @@ -0,0 +1,174 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml + +# NuGet Packages Directory +packages/ +## TODO: If the tool you use requires repositories.config uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +# This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) +!packages/build/ + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..22fbe5d --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8828ca4 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ + + +A KartRider emulator coded in C# + +Coded by: Andrew \ No newline at end of file diff --git a/add loopback.bat b/add loopback.bat new file mode 100644 index 0000000..dc895e9 --- /dev/null +++ b/add loopback.bat @@ -0,0 +1,12 @@ +@echo off +rem Loginservers +netsh int ip add addr 1 address=64.94.106.161 mask=255.255.255.255 st=ac +netsh int ip add addr 1 address=64.94.106.162 mask=255.255.255.255 st=ac +netsh int ip add addr 1 address=64.94.106.163 mask=255.255.255.255 st=ac +netsh int ip add addr 1 address=64.94.106.164 mask=255.255.255.255 st=ac +netsh int ip add addr 1 address=64.94.106.165 mask=255.255.255.255 st=ac + +rem Webserver +netsh int ip add addr 1 address=63.251.217.214 mask=255.255.255.255 st=ac + +pause diff --git a/trunk/Common/Common.csproj b/trunk/Common/Common.csproj new file mode 100644 index 0000000..8e9a7e3 --- /dev/null +++ b/trunk/Common/Common.csproj @@ -0,0 +1,75 @@ + + + + + Debug + AnyCPU + {F163DAAB-BDD2-4510-9A20-604D73D334D0} + Library + Properties + KartExtreme + Common + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + ..\..\MySql.Data.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/trunk/Common/Constants.cs b/trunk/Common/Constants.cs new file mode 100644 index 0000000..22fadb5 --- /dev/null +++ b/trunk/Common/Constants.cs @@ -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; } + } +} diff --git a/trunk/Common/Data/Database.cs b/trunk/Common/Data/Database.cs new file mode 100644 index 0000000..7b826fd --- /dev/null +++ b/trunk/Common/Data/Database.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/trunk/Common/Data/Datum.cs b/trunk/Common/Data/Datum.cs new file mode 100644 index 0000000..81ad725 --- /dev/null +++ b/trunk/Common/Data/Datum.cs @@ -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 + { + private List 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(); + + 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 dictionary = new Dictionary(); + + 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(); + + using (MySqlDataReader reader = MySqlHelper.ExecuteReader(Database.ConnectionString, query)) + { + while (reader.Read()) + { + Dictionary dictionary = new Dictionary(); + + 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 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 Dictionary { get; set; } + + public Datum(string table) + { + this.Table = table; + this.Dictionary = new Dictionary(); + } + + internal Datum(string table, Dictionary 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 loopPair in this.Dictionary) + { + fields += loopPair.Key; + processed++; + + if (processed < this.Dictionary.Count) + { + fields += ", "; + } + } + + fields += " ) VALUES ( "; + + processed = 0; + + foreach (KeyValuePair 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 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 value in this.Dictionary) + { + result += value.Key; + processed++; + + if (processed < this.Dictionary.Count) + { + result += ", "; + } + } + + result += " ]"; + + return result; + } + } +} diff --git a/trunk/Common/Data/Meta.cs b/trunk/Common/Data/Meta.cs new file mode 100644 index 0000000..2c875f1 --- /dev/null +++ b/trunk/Common/Data/Meta.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; + +namespace KartExtreme.Data +{ + internal static class Meta + { + public static Dictionary> Tables = new Dictionary>(); + + 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 table; + + string tableName = datum.TABLE_NAME; + + if (Meta.Tables.ContainsKey(tableName)) + { + table = Meta.Tables[tableName]; + } + else + { + table = new Dictionary(); + 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; + } + } +} diff --git a/trunk/Common/Data/RowNotUniqueException.cs b/trunk/Common/Data/RowNotUniqueException.cs new file mode 100644 index 0000000..4e470ca --- /dev/null +++ b/trunk/Common/Data/RowNotUniqueException.cs @@ -0,0 +1,13 @@ +namespace System.Data +{ + public class RowNotUniqueException : DataException + { + public override string Message + { + get + { + return "Obtained row is not unique."; + } + } + } +} diff --git a/trunk/Common/IO/Packet/InPacket.cs b/trunk/Common/IO/Packet/InPacket.cs new file mode 100644 index 0000000..706c7b3 --- /dev/null +++ b/trunk/Common/IO/Packet/InPacket.cs @@ -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; + } + } +} diff --git a/trunk/Common/IO/Packet/OutPacket.cs b/trunk/Common/IO/Packet/OutPacket.cs new file mode 100644 index 0000000..5ec54b1 --- /dev/null +++ b/trunk/Common/IO/Packet/OutPacket.cs @@ -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; + } + } +} diff --git a/trunk/Common/IO/Packet/PacketBase.cs b/trunk/Common/IO/Packet/PacketBase.cs new file mode 100644 index 0000000..39b7bc4 --- /dev/null +++ b/trunk/Common/IO/Packet/PacketBase.cs @@ -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(); + } + } +} diff --git a/trunk/Common/IO/Packet/PacketReadException.cs b/trunk/Common/IO/Packet/PacketReadException.cs new file mode 100644 index 0000000..eff5cc0 --- /dev/null +++ b/trunk/Common/IO/Packet/PacketReadException.cs @@ -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) + { + } + } +} diff --git a/trunk/Common/IO/SettingReadException.cs b/trunk/Common/IO/SettingReadException.cs new file mode 100644 index 0000000..de9a236 --- /dev/null +++ b/trunk/Common/IO/SettingReadException.cs @@ -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)) { } + } +} diff --git a/trunk/Common/IO/Settings.cs b/trunk/Common/IO/Settings.cs new file mode 100644 index 0000000..de6148e --- /dev/null +++ b/trunk/Common/IO/Settings.cs @@ -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 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[] 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(string key, params object[] args) + { + try + { + return (T)Enum.Parse(typeof(T), Settings.Dictionary[string.Format(key, args)]); + } + catch + { + throw new SettingReadException(key); + } + } + } +} diff --git a/trunk/Common/IO/lOG.cs b/trunk/Common/IO/lOG.cs new file mode 100644 index 0000000..79bedc4 --- /dev/null +++ b/trunk/Common/IO/lOG.cs @@ -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; + } + } + + /// + /// Writes a labeled item to the output. + /// + /// The label + /// The label's color + /// The text + /// Arguments + 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(); + } + } + } + } +} diff --git a/trunk/Common/Net/Acceptor.cs b/trunk/Common/Net/Acceptor.cs new file mode 100644 index 0000000..2c00dab --- /dev/null +++ b/trunk/Common/Net/Acceptor.cs @@ -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 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(); + } + } + } +} diff --git a/trunk/Common/Net/Cryptography.cs b/trunk/Common/Net/Cryptography.cs new file mode 100644 index 0000000..14c9734 --- /dev/null +++ b/trunk/Common/Net/Cryptography.cs @@ -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 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; + } + } +} diff --git a/trunk/Common/Net/SendPacketException.cs b/trunk/Common/Net/SendPacketException.cs new file mode 100644 index 0000000..df71b41 --- /dev/null +++ b/trunk/Common/Net/SendPacketException.cs @@ -0,0 +1,12 @@ +using System; + +namespace KartExtreme.Net +{ + public sealed class SendPacketException : Exception + { + public SendPacketException() + : base("Disconnected while sending packet") + { + } + } +} diff --git a/trunk/Common/Net/Session.cs b/trunk/Common/Net/Session.cs new file mode 100644 index 0000000..9fe7ed1 --- /dev/null +++ b/trunk/Common/Net/Session.cs @@ -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; + } + } + + /// + /// Initializes a new instance of the Session class. + /// + /// + 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); + } + + /// + /// Initiates the receiving mechanism. + /// + /// The length of the data + /// Indicates if a header is received + 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(); + } + + /// + /// Begins to asynchronously receive data from the socket. + /// + 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(); + } + } + + /// + /// Reads the data from the callback and handles it. + /// + /// + 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(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(); + } + } + + /// + /// Sends the initial patch data packet to the socket. + /// + /// The version's information + /// The patch data URL + 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; + } + + /// + /// Sends a KartExtreme.IO.OutPacket array to the socket. + /// + /// + public void Send(OutPacket outPacket) + { + this.Send(outPacket.ToArray()); + } + + /// + /// Sends data to the socket. + /// + /// + 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; + } + } + + /// + /// Closes the socket. + /// + 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); + } +} diff --git a/trunk/Common/Properties/AssemblyInfo.cs b/trunk/Common/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..70a74d1 --- /dev/null +++ b/trunk/Common/Properties/AssemblyInfo.cs @@ -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")] diff --git a/trunk/KartExtreme.sln b/trunk/KartExtreme.sln new file mode 100644 index 0000000..54b5d55 --- /dev/null +++ b/trunk/KartExtreme.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KartExtreme", "KartExtreme\KartExtreme.csproj", "{C3521ADE-F5D2-4C53-8F2F-0E40A380AE6F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csproj", "{F163DAAB-BDD2-4510-9A20-604D73D334D0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C3521ADE-F5D2-4C53-8F2F-0E40A380AE6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3521ADE-F5D2-4C53-8F2F-0E40A380AE6F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3521ADE-F5D2-4C53-8F2F-0E40A380AE6F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3521ADE-F5D2-4C53-8F2F-0E40A380AE6F}.Release|Any CPU.Build.0 = Release|Any CPU + {F163DAAB-BDD2-4510-9A20-604D73D334D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F163DAAB-BDD2-4510-9A20-604D73D334D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F163DAAB-BDD2-4510-9A20-604D73D334D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F163DAAB-BDD2-4510-9A20-604D73D334D0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/trunk/KartExtreme/Application.cs b/trunk/KartExtreme/Application.cs new file mode 100644 index 0000000..8e8a5b8 --- /dev/null +++ b/trunk/KartExtreme/Application.cs @@ -0,0 +1,51 @@ +using KartExtreme.IO; +using KartExtreme.Net; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace KartExtreme +{ + internal static class Application + { + private static bool _isRunning = false; + + [STAThread] + private static void Main(string[] args) + { + Log.Entitle("KartExtreme"); + + DateTime dt = DateTime.Now; + + try + { + Server.Initialize(); + + Application._isRunning = true; + } + catch (Exception e) + { + Log.Error(e); + } + + if (Application._isRunning) + { + Log.Inform("Initialized in {0}ms.", (DateTime.Now - dt).TotalMilliseconds); + } + else + { + Log.Inform("Unable to initialize."); + } + + Log.SkipLine(); + + while (Application._isRunning) + { + Console.Read(); + } + + Log.Quit(); + } + } +} diff --git a/trunk/KartExtreme/Kart/Player.cs b/trunk/KartExtreme/Kart/Player.cs new file mode 100644 index 0000000..0324e55 --- /dev/null +++ b/trunk/KartExtreme/Kart/Player.cs @@ -0,0 +1,61 @@ +using KartExtreme.Data; +using KartExtreme.Net; + +namespace KartExtreme.Kart +{ + public class Player + { + public KartClient Client { get; private set; } + + public int ID { get; private set; } + public string Name { get; private set; } + public byte Level { get; private set; } + public int Lucci { get; private set; } + + private bool Assigned { get; set; } + + public Player(int id = 0, KartClient client = null) + { + this.ID = id; + this.Client = client; + } + + public void Load() + { + foreach (dynamic datum in new Datums("players").Populate("ID = '{0}'", this.ID)) + { + this.Name = datum.Name; + this.Level = datum.Level; + this.Lucci = datum.Lucci; + + this.Assigned = true; + } + } + + public void Save() + { + dynamic datum = new Datum("players"); + + datum.ID = this.ID; + datum.Name = this.Name; + datum.Level = this.Level; + datum.Lucci = this.Lucci; + + if (this.Assigned) + { + datum.Update("ID = '{0}'", this.ID); + } + else + { + datum.Insert(); + } + } + + public void Delete() + { + Database.Delete("players", "ID = '{0}'", this.ID); + + this.Assigned = false; + } + } +} diff --git a/trunk/KartExtreme/KartExtreme.csproj b/trunk/KartExtreme/KartExtreme.csproj new file mode 100644 index 0000000..dbcc4c4 --- /dev/null +++ b/trunk/KartExtreme/KartExtreme.csproj @@ -0,0 +1,70 @@ + + + + + Debug + AnyCPU + {C3521ADE-F5D2-4C53-8F2F-0E40A380AE6F} + Exe + Properties + KartExtreme + KartExtreme + v4.5 + 512 + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + + + + + + + + + + + + {f163daab-bdd2-4510-9a20-604d73d334d0} + Common + + + + + \ No newline at end of file diff --git a/trunk/KartExtreme/Net/KartClient.cs b/trunk/KartExtreme/Net/KartClient.cs new file mode 100644 index 0000000..a927ac2 --- /dev/null +++ b/trunk/KartExtreme/Net/KartClient.cs @@ -0,0 +1,138 @@ +using KartExtreme.IO; +using System; +using System.Net.Sockets; +using System.Text; +using KartExtreme.IO.Packet; + +namespace KartExtreme.Net +{ + public sealed class KartClient : Session + { + public KartClient(Socket socket) + : base(socket) + { + this.SendPatchData(Constants.Version, "http://kart.dn.nexoncdn.co.kr/patch"); + + /* + using (OutPacket outPacket = new OutPacket()) + { + outPacket.WriteHexString("80 05 2B 28"); // NOTE: HEADER. DO NOT CHANGE. PROBABLY typeid() OF HANDLER? + // 8 + outPacket.WriteShort(5002); // Note: Localisation. + // 10 + outPacket.WriteShort(1); // NOTE: Service area/version. + // 12 + outPacket.WriteShort(26); // NOTE: Subversion number? Current = 26. 25 = Incompatible with server, 27 = Close client. + // 14 + outPacket.WriteString("http://kart.dn.nexoncdn.co.kr/patch"); + // 18 + + // outPacket.WriteHexString("81 82 83 84 85 86 87 88"); + // outPacket.WriteHexString("94 2E F9 A8 E1 4B 13 5D"); + // outPacket.WriteHexString("01 02 03 04 05 06 07 08"); + + outPacket.WriteInt(0x11111111); + outPacket.WriteInt(0x22222222); + outPacket.WriteByte(0xE0); + 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"); + // NOTE: Nothing more needed. + + if (false) + { + outPacket.WriteHexString("80 05 2B 28"); // NOTE: HEADER. DO NOT CHANGE. PROBABLY typeid() OF HANDLER? + outPacket.WriteHexString("EA 00 03 00 95 0B"); + outPacket.WriteString(""); + // NOTE: Nothing more needed. + + } + + if (false) + { + outPacket.WriteHexString("80 05 2B 28 EA 03 03 00 95 0B"); + outPacket.WriteString(""); + // NOTE: Nothing more needed. + } + if (false) + { + // NOTE: Original (Korean KartRider). + outPacket.WriteHexString("80 05 2B 28"); + outPacket.WriteHexString("EA 03 03 00 95 0B"); + outPacket.WriteString("http://kart.dn.nexoncdn.co.kr/patch"); + outPacket.WriteHexString("94 2E F9 A8 E1 4B 13 5D 76 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); + } + */ + } + + public override void OnDisconnect() + { + Log.Inform("Lost connection from {0}.", this.Label); + + Server.RemoveClient(this); + } + + public override void OnPacket(InPacket inPacket) + { + + try + { + + //int typeId = inPacket.ReadInt(); + //byte wdf = BitConverter. + + Log.Hex("Received Packet ", inPacket.ToArray()); + //Log.Inform("String val:" + Encoding.Unicode.GetString(inPacket.ToArray())); + + byte typeId = inPacket.ReadByte(); + byte a2 = inPacket.ReadByte(); + byte a3 = inPacket.ReadByte(); + byte a4 = inPacket.ReadByte(); + + int header = BitConverter.ToInt32(new byte[] { typeId, a2, a3, a4 }, 0); + switch (typeId) + { + case 0xBA: + using (OutPacket oPacket = new OutPacket()) + { + oPacket.WriteInt(header + 1); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + oPacket.WriteInt(0); // header + Send(oPacket); + //WALAO! + } + break; + default: + break; + } + } + catch (SendPacketException) + { + Log.Error("Client was disconnected while sending packet"); + Close(); + } + catch (Exception e) + { + Log.Error("Exception during packet handling from {0}: {1}", this.Label, e.ToString()); + } + } + } +} diff --git a/trunk/KartExtreme/Net/Server.cs b/trunk/KartExtreme/Net/Server.cs new file mode 100644 index 0000000..b9250ca --- /dev/null +++ b/trunk/KartExtreme/Net/Server.cs @@ -0,0 +1,47 @@ +using KartExtreme.Data; +using KartExtreme.IO; +using System; +using System.Collections.Generic; +using System.Net.Sockets; + +namespace KartExtreme.Net +{ + public static class Server + { + private static Acceptor _acceptor; + private static List _clients; + + public static void Initialize() + { + Server._clients = new List(); + + Settings.Initialize(); + + Database.Test(); + Database.Analyze(); + + Server._acceptor = new Acceptor(Settings.GetUShort("Net/Port")); + Server._acceptor.OnClientAccepted = Server.OnClientAccepted; + Server._acceptor.Start(); + } + + private static void OnClientAccepted(Socket socket) + { + KartClient client = new KartClient(socket); + + Log.Inform("Accepted connection from {0}.", client.Label); + + Server.AddClient(client); + } + + public static void AddClient(KartClient client) + { + Server._clients.Add(client); + } + + public static void RemoveClient(KartClient client) + { + Server._clients.Remove(client); + } + } +} diff --git a/trunk/KartExtreme/Properties/AssemblyInfo.cs b/trunk/KartExtreme/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3a12ccd --- /dev/null +++ b/trunk/KartExtreme/Properties/AssemblyInfo.cs @@ -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("KartExtreme")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("KartExtreme")] +[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("ae2be92d-a537-4b11-a719-5a6168df11df")] + +// 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")] diff --git a/trunk/KartExtreme/app.config b/trunk/KartExtreme/app.config new file mode 100644 index 0000000..51278a4 --- /dev/null +++ b/trunk/KartExtreme/app.config @@ -0,0 +1,3 @@ + + +