www.pudn.com > boogiebot.zip > WorldServerClient.cs


//#define LOG 
 
using System; 
using System.Collections; 
using System.Net; 
using System.Text; 
using System.Net.Sockets; 
using System.Xml; 
using System.Timers; 
using System.IO; 
using System.Threading; 
using System.Runtime.InteropServices; 
using System.Resources; 
 
using Foole.Crypt; 
using Foole.Utils; 
using Foole.WoW; 
 
 
namespace BoogieBot.Common 
{ 
    public partial class WorldServerClient 
    { 
        #region Member variables 
 
        [DllImport("winmm.dll", EntryPoint = "timeGetTime")] 
        public static extern uint MM_GetTime(); 
        private UInt32 LastUpdateTime = 0; 
 
        public Thread WorldThread = null; 
 
        private bool isRunning; 
 
        private string mUsername; 
 
        protected WoWCrypt mCrypt = new WoWCrypt(); 
        private int mSendCryptSize; 
        private int mRecvCryptSize; 
        private byte[] Key; 
 
        private UInt32 ServerSeed; 
        private UInt32 ClientSeed; 
        private Random random = new Random(); 
        private Socket mSocket; 
        System.Timers.Timer aTimer = new System.Timers.Timer(); 
        System.Timers.Timer uTimer = new System.Timers.Timer(); 
 
        // Ping stuffs 
        private UInt32 Ping_Seq; 
        private UInt32 Ping_Req_Time; 
        private UInt32 Ping_Res_Time; 
        public UInt32 Latency; 
 
        private ArrayList Objects = new ArrayList(); 
        private Hashtable EntryList = new Hashtable(); 
        private Hashtable EntryQueue = new Hashtable(); 
 
#if (LOG) 
        private TextWriter tw = File.CreateText("packets.txt"); 
#endif 
 
        public Character[] characterList; 
 
 
        // Ah temp vars 
        bool SentHello = false; 
        UInt32 AHEntry = 0; 
 
 
        // TILE stuff 
 
        static int TilesCount = 64; 
        static float TileSize = 533.33333f; 
        float _maxY = (TilesCount*TileSize/2); 
        float _maxX = (TilesCount*TileSize/2); 
        float _minY = (-TilesCount*TileSize/2); 
        float _minX = (-TilesCount*TileSize/2); 
 
        static int CellsPerTile = 8; 
        float _cellSize = (TileSize / CellsPerTile); 
 
        #endregion 
 
        public WorldServerClient(IPEndPoint ep, string username, byte[] key) 
        { 
            isRunning = false; 
 
            mSendCryptSize = 6; // 2 length + 4 opcode 
            mRecvCryptSize = 2; // 2 opcode 
 
            mUsername = username; 
            Key = key; 
 
            try 
            { 
                mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); 
                mSocket.Connect(ep); 
            } 
            catch(SocketException ex) 
            { 
                BoogieCore.Log(LogType.Error, "Failed to connect to realm: {0}", ex.Message); 
                return; 
            } 
 
            isRunning = true; 
 
 
            WorldThread = new Thread(new ThreadStart(this.Start)); 
            WorldThread.Name = "WS Client Thread"; 
            WorldThread.IsBackground = true; 
            LastUpdateTime = MM_GetTime(); 
            WorldThread.Start(); 
 
            BoogieCore.Log(LogType.System, "{0}: WS Thread Started", Time.GetTime()); 
        } 
 
        private void Start() 
        { 
            // Setup ping timer/initial values 
            aTimer.Elapsed += new ElapsedEventHandler(Ping); 
            aTimer.Interval = 10000; 
            aTimer.Enabled = false; 
 
            Ping_Seq = 1; 
            Latency = 1; 
 
            // Loopdeloop 
 
            Loop(); 
 
            // Thread is dead if it gets to this point 
 
        } 
 
        private void Loop() 
        { 
            byte[] data; 
            int dataSize; 
 
            do 
            { 
                try 
                { 
                    UInt32 TimeNow = MM_GetTime(); 
                    Update(TimeNow - LastUpdateTime); 
                    LastUpdateTime = MM_GetTime(); 
 
                    dataSize = parseSize(OnReceive(2)); 
                    data = OnReceive(dataSize); 
                    decryptData(data); 
                    processData(data); 
                } 
                catch (Exception ex)    // Server dc'd us most likely ;P 
                { 
                    BoogieCore.Log(LogType.Error, "Caught Exception while reading off the network: {0}", ex.Message); 
                    BoogieCore.Log(LogType.Error, "{0}", ex.StackTrace); 
                } 
            } 
            while (isRunning); 
 
            isRunning = false; 
 
            if (mSocket.Connected) 
                mSocket.Disconnect(false); 
 
            BoogieCore.Log(LogType.System, "WS: Thread Stopping: {0}", Time.GetTime()); 
        } 
 
        private void Update(UInt32 diff) 
        { 
            // Fill in the blanks 
            //  
        } 
 
        public void StopThread(bool wait) 
        { 
            isRunning = false; 
 
            if (mSocket.Connected) 
                mSocket.Disconnect(false); 
 
            if (wait)   // Wait till this thread shuts down. 
                WorldThread.Join(); 
        } 
 
        private void Ping(object source, ElapsedEventArgs e) 
        { 
            if (!mSocket.Connected) 
            { 
                aTimer.Enabled = false; 
                aTimer.Stop(); 
                return; 
            } 
 
            Ping_Req_Time = MM_GetTime(); 
 
            BoogieCore.Log(LogType.System, "Ping!"); 
            WoWWriter ww = new WoWWriter(OpCode.CMSG_PING); 
            ww.Write(Ping_Seq); 
            ww.Write(Latency); 
            Send(ww.ToArray()); 
        } 
 
//#region  Socket Functions 
 
        ///  
        /// Reads bytes from the WoW Server. 
        ///  
        /// Number of bytes to read. 
        /// The data recieved. It will be exactly of mSize. 
        protected byte[] OnReceive(int mSize) 
        { 
            byte[] data = new byte[mSize]; 
            int readSoFar = 0; 
 
            // Keep looping till we recieve exactly how much we need. 
            do 
            { 
                mSocket.Poll(10, SelectMode.SelectRead); 
 
                if (mSocket.Available > 0) 
                { 
                    int read = mSocket.Receive(data, readSoFar, mSize - readSoFar, SocketFlags.None); 
                    readSoFar += read; 
                    Thread.Sleep(10); 
                } 
            } 
            while (readSoFar < mSize && isRunning); 
 
            return data; 
        } 
 
        private int parseSize(byte[] SizeBytes) 
        { 
            mCrypt.Decrypt(SizeBytes, 2); 
            return ((SizeBytes[0] * 256) + SizeBytes[1]); 
        } 
 
        private void decryptData(byte[] Data) 
        { 
            mCrypt.Decrypt(Data, mRecvCryptSize); 
#if (LOG) 
            WoWReader wr = new WoWReader(Data); 
            OpCode Op = (OpCode)wr.ReadUInt16(); 
            tw.WriteLine("Server->Client Opcode: {1} Size: {0}", Data.Length, Op); 
            Debug.DumpBuffer(Data, Data.Length, tw); 
            tw.WriteLine(); 
            tw.Flush(); 
#endif 
        } 
 
        public void Send(WoWWriter wr) 
        { 
            Send(wr.ToArray()); 
        } 
 
        public void Send(byte[] Data) 
        { 
 
#if (LOG) 
            WoWReader wr = new WoWReader(Data); 
            OpCode Op = (OpCode)wr.ReadUInt16(); 
 
            tw.WriteLine("Client->Server OpCode: {1} Size: {0}", Data.Length, Op); 
            Debug.DumpBuffer(Data, Data.Length, tw); 
            tw.WriteLine(); 
            tw.Flush(); 
#endif 
            int Length = Data.Length; 
            byte[] Packet = new byte[2 + Length]; 
            Packet[0] = (byte)(Length >> 8); 
            Packet[1] = (byte)(Length & 0xff); 
            Data.CopyTo(Packet, 2); 
            mCrypt.Encrypt(Packet, mSendCryptSize); 
 
            try 
            { 
                mSocket.Send(Packet); 
            } 
            catch(SocketException e) 
            { 
                BoogieCore.Log(LogType.Error, "Unable to send packet! Error: {0}", e.Message); 
                isRunning = false; 
                 
            } 
        } 
         
 
        //private WoWReader Receive(OpCode ExpectedOp) 
        //{ 
        //    WoWReader wr = Receive(); 
        //    if (wr == null) return null; 
        //    UInt16 length = wr.ReadUInt16(); 
        //    OpCode op = (OpCode)wr.ReadUInt16(); 
        //    if (op != ExpectedOp) 
        //    { 
        //        throw new Exception(String.Format("Got wsop {0}, expecting {1}", op, ExpectedOp)); 
        //    } 
        //    return wr; 
        //} 
 
        //private WoWReader Receive() 
        //{ 
        //    byte[] buffer = new byte[10024]; 
 
        //    mSocket.Poll(-1, SelectMode.SelectRead); 
        //    if (mSocket.Available == 0) return null; // TODO: Something smarter 
 
        //    int Read = mSocket.Receive(buffer, mSocket.Available, SocketFlags.None); 
        //    WoWReader wr = new WoWReader(Trim(buffer, Read)); 
        //    return wr; 
        //} 
 
        //private byte[] Trim(byte[] Data, int Length) 
        //{ 
        //    byte[] Trimmed = new byte[Length]; 
        //    Array.Copy(Data, 0, Trimmed, 0, Length); 
        //    return Trimmed; 
        //} 
 
        public void Close() 
        { 
            mSocket.Close(); 
        } 
 
//#endregion 
 
        private void SMSG_Debug(WoWReader wr) 
        { 
            Debug.DumpBuffer(wr.ToArray()); 
        } 
 
        public bool IsRunning 
        { 
            get { return isRunning; } 
        } 
 
 
    } 
}