All pastes #839123 Raw Edit

Anonymous

public text v1 · immutable
#839123 ·published 2007-12-30 21:22 UTC
rendered paste body
using System;
using System.Net;
using System.Net.Sockets;

using Chief;
using ChiefD2.Net;
using ChiefD2.Net.Packet;

using D2PacketsNew.D2Packets;

using MBNCSUtil;
using ETUtils;

namespace ChiefD2
{
    public class Client : IClient
    {
        #region IClient properties
        public PacketHandler PacketHandler
        {
            get { return this.Socket.PacketHandler; }
        }

        public event ClientStateChangeEventHandler LobbyEntered;
        public event ClientStateChangeEventHandler GameEntered;
        public event ClientStateChangeEventHandler GameExited;
        public event ClientStateChangeEventHandler Killed;
        #endregion

        #region Properties
        private D2Socket Socket;
        private Log DebugLog;

        private int ClientToken;
        private int ServerToken;

        private ushort GameCounter = 0;

        public BotProfile Profile;
        #endregion


        public Client(BotProfile profile)
        {
            this.DebugLog = new Log("clientless.log");

            this.Profile = profile;

            if (this.Profile.ClassicKey == null || this.Profile.LordOfDestructionKey == null)
                throw new Exception("You must enter the CD Keys to use a clientless connection!");

            this.Socket = new D2Socket();

            //this.Socket.PacketReceived += new UnknownPacketEventHandler(Socket_PacketReceived);
            //this.Socket.PacketSent += new UnknownPacketEventHandler(Socket_PacketSent);

            #region Listeners
            // Logging into bnet
            //this.Socket.PacketHandler.AddAsyncListener(BnetServerPacket.BnetPing, new PacketEventHandler(BnetPing));
            this.Socket.PacketHandler.AddAsyncListener(BnetServerPacket.BnetConnectionResponse, new PacketEventHandler(BnetConnectionResponse));
            this.Socket.PacketHandler.AddAsyncListener(BnetServerPacket.BnetAuthResponse, new PacketEventHandler(BnetAuthResponse));
            this.Socket.PacketHandler.AddAsyncListener(BnetServerPacket.BnetLogonResponse, new PacketEventHandler(BnetLogonResponse));

            this.Socket.PacketHandler.AddAsyncListener(BnetServerPacket.QueryRealmsResponse, new PacketEventHandler(QueryRealmsResponse));
            this.Socket.PacketHandler.AddAsyncListener(BnetServerPacket.RealmLogonResponse, new PacketEventHandler(RealmLogonResponse));

            // Realms
            this.Socket.PacketHandler.AddAsyncListener(RealmServerPacket.RealmStartupResponse, new PacketEventHandler(RealmStartupResponse));
            this.Socket.PacketHandler.AddAsyncListener(RealmServerPacket.CharacterLogonResponse, new PacketEventHandler(CharacterLogonResponse));

            // Game Server
            this.Socket.PacketHandler.AddAsyncListener(GameServerPacket.GameLogonSuccess, new PacketEventHandler(GameLogonSuccess));
            #endregion

            this.DebugLog.Append("Debugging started ---------------------------------------------------------");
        }

        #region packet events
        void Socket_PacketSent(PacketOrigin origin, byte[] data, int bytesTransferred)
        {
            string buffer = origin.ToString() + " Packet Sent";

            for (int i = 0; i < bytesTransferred; i++)
            {
                if (i % 10 == 0)
                    buffer += Environment.NewLine;

                string hex = ETUtils.ByteConverter.ToHexString(data, i, 1);

                buffer += hex + " ";
            }

            this.DebugLog.Append(buffer + Environment.NewLine);
        }

        void Socket_PacketReceived(PacketOrigin origin, byte[] data, int bytesTransferred)
        {
            string buffer = origin.ToString() + " Packet Received";

            for (int i = 0; i < bytesTransferred; i++)
            {
                if (i % 10 == 0)
                    buffer += Environment.NewLine;

                string hex = ETUtils.ByteConverter.ToHexString(data, i, 1);

                buffer += hex + " ";
            }

            this.DebugLog.Append(buffer + Environment.NewLine);
        }
        #endregion

        #region IClient methods
        public void Start()
        {
            this.Socket.ConnectBS(this.Profile.ServerName);

            this.DebugLog.Append("Sending connection request");
            this.Socket.SendBS(new byte[] { 0x01 });
            this.Socket.SendBS(new ChiefD2.Net.Packet.BC.ConnectionRequest().Data);
        }

        public void SendBS(byte[] data)
        {
            this.Socket.SendBS(data);
        }
        public void SendRS(byte[] data)
        {
            this.Socket.SendRS(data);
        }
        public void SendGS(byte[] data)
        {
            this.Socket.SendGS(data);
        }

        public void ReceiveGC(byte[] data)
        {
            // Doesn't do anything--we're clientless, no reason to receive packets!
        }

        public bool CreateGame()
        {
            return CreateGame(this.Profile.Difficulty, Util.RandomString(12), Util.RandomString(3));
        }
        public bool CreateGame(D2DataNew.GameDifficulty difficulty)
        {
            return CreateGame(difficulty, Util.RandomString(12), Util.RandomString(3));
        }
        public bool CreateGame(string name, string pass)
        {
            return CreateGame(this.Profile.Difficulty, name, pass);
        }
        public bool CreateGame(D2DataNew.GameDifficulty difficulty, string name, string pass)
        {
            // The first character in game name/pass has to be uppercase, dunno why
            name = name.ToUpper();
            pass = pass.ToUpper();

            this.GameCounter += 0x02;

            this.DebugLog.Append("Making game #" + this.GameCounter.ToString() + " " + name + "//" + pass + " for " + difficulty.ToString() + " difficulty");
            this.Socket.SendRS(
                new ChiefD2.Net.Packet.RC.CreateGame(
                    this.GameCounter,
                    difficulty,
                    name,
                    pass,
                    ""
                ).Data);

            D2Packet packet = this.Socket.PacketHandler.WaitForPacket(D2PacketsNew.D2Packets.RealmServerPacket.CreateGameResponse, 5000);

            if (packet == null)
                return false;

            D2PacketsNew.RealmServer.CreateGameResponse response = new D2PacketsNew.RealmServer.CreateGameResponse(packet.Data);

            if (response.Result != D2PacketsNew.RealmServer.CreateGameResult.Success)
                return false;

            this.DebugLog.Append("CreateGame success!");

            return JoinGame(name, pass);
        }

        public bool JoinGame(string name)
        {
            return JoinGame(name, "");
        }
        public bool JoinGame(string name, string pass)
        {
            this.DebugLog.Append("Joining game #" + this.GameCounter.ToString() + " " + name + "//" + pass);
            this.Socket.SendRS(new ChiefD2.Net.Packet.RC.JoinGame(this.GameCounter, name, pass).Data);

            D2Packet packet = this.Socket.PacketHandler.WaitForPacket(D2PacketsNew.D2Packets.RealmServerPacket.JoinGameResponse, 5000);

            if (packet == null)
                return false;

            D2PacketsNew.RealmServer.JoinGameResponse response = new D2PacketsNew.RealmServer.JoinGameResponse(packet.Data);

            if (response.Result != D2PacketsNew.RealmServer.JoinGameResult.Success)
                return false;

            this.DebugLog.Append("JoinGame success!");

            this.DebugLog.Append("Connecting to game server: " + response.GameServerIP.ToString());

            if (!this.Socket.ConnectGS(response.GameServerIP))
                return false;

            D2Packet requestLogonInfo = this.Socket.PacketHandler.WaitForPacket(D2PacketsNew.D2Packets.GameServerPacket.RequestLogonInfo, 5000);

            if (requestLogonInfo == null)
            {
                this.DebugLog.Append("Never received RequestLogonInfo");
                return false;
            }

            this.Socket.SendGS(
                new ChiefD2.Net.Packet.GC.GameLogon(
                    response.GameHash,
                    response.GameToken,
                    this.Profile.CharacterClass,
                    this.Profile.CharacterName
                ).Data);

            D2Packet gameLogonSuccess = this.Socket.PacketHandler.WaitForPacket(D2PacketsNew.D2Packets.GameServerPacket.GameLogonSuccess, 5000);

            if (gameLogonSuccess == null)
            {
                this.DebugLog.Append("Never received GameLogonSuccess");
                return false;
            }

            this.Socket.SendGS(new byte[] { 0x6b });

            return true;
        }

        public bool LeaveGame()
        {
            if (this.Socket.IsInGame)
            {
                this.Socket.SendGS(new byte[] { 0x69 });

                this.DebugLog.Append("Left game!");

                this.Socket.CloseGS();

                GameExited();

                System.Threading.Thread.Sleep(1000);

                LobbyEntered();

                return true;
            }

            return false;
        }

        public void Kill()
        {
            throw new NotImplementedException();
        }
        #endregion

        #region Listeners
        #region BattleNet
        //private void BnetPing(D2Packet packet)
        //{
        //    this.Socket.SendBS(new byte[] { 0 });
        //}

        private void BnetConnectionResponse(D2Packet d2packet)
        {
            D2PacketsNew.BnetServer.BnetConnectionResponse packet = new D2PacketsNew.BnetServer.BnetConnectionResponse(d2packet.Data);

            this.ClientToken = Environment.TickCount;
            this.ServerToken = packet.ServerToken;

            this.DebugLog.Append("Sending authorization check");
            this.Socket.SendBS(
                new ChiefD2.Net.Packet.BC.AuthorizationCheck(
                        (uint)this.ClientToken,
                        packet.VersionFileName,
                        packet.VersionFormulae,
                        new string[] { this.Profile.GameExe, this.Profile.BnClientDll, this.Profile.D2ClientDll },
                        this.Profile.ClassicKey,
                        this.Profile.LordOfDestructionKey,
                        (uint)this.ServerToken,
                        "Chief"
                    ).Data
                );
        }

        private void BnetAuthResponse(D2Packet d2packet)
        {
            D2PacketsNew.BnetServer.BnetAuthResponse packet = new D2PacketsNew.BnetServer.BnetAuthResponse(d2packet.Data);

            if (packet.Result != D2PacketsNew.BnetServer.BnetAuthResult.Success)
            {
                this.DebugLog.Append("Couldn't login: " + packet.Result.ToString());
                throw new Exception("Couldn't login: " + packet.Result.ToString());
            }

            this.DebugLog.Append("Logon success!");

            this.Socket.SendBS(
                new ChiefD2.Net.Packet.BC.AccountInfo(
                    this.Profile.Username, 
                    this.Profile.Password,
                    this.ClientToken,
                    this.ServerToken
                ).Data);
        }

        private void BnetLogonResponse(D2Packet d2packet)
        {
            D2PacketsNew.BnetServer.BnetLogonResponse packet = new D2PacketsNew.BnetServer.BnetLogonResponse(d2packet.Data);

            this.DebugLog.Append("Getting list of realms");
            this.Socket.SendBS(new MBNCSUtil.BncsPacket(0x40).GetData());
        }

        private void QueryRealmsResponse(D2Packet d2packet)
        {
            // PS, figured this out later, too lazy to change back :)
            // Doesn't work for some reason -- NullReference exception...
            //BnetServer.QueryRealmsResponse packet = new BnetServer.QueryRealmsResponse(d2packet.Data);

            // taken from the above function
            uint unknown = BitConverter.ToUInt32(d2packet.Data, 4);
            uint count = BitConverter.ToUInt32(d2packet.Data, 8);
            D2PacketsNew.D2Packets.RealmInfo[] realms = new D2PacketsNew.D2Packets.RealmInfo[count];

            int offset = 12;
            for (int i = 0; i < count; i++)
            {
                realms[i] = new D2PacketsNew.D2Packets.RealmInfo(d2packet.Data, offset);
                offset += 6 + realms[i].Name.Length + realms[i].Description.Length;
            }

            this.DebugLog.Append("Found realm: " + realms[0].Name);
            this.DebugLog.Append("Logging onto realm");
            this.Socket.SendBS(
                new ChiefD2.Net.Packet.BC.RealmLogon(
                    realms[0].Name,
                    this.ClientToken,
                    this.ServerToken
                ).Data);
        }

        private void RealmLogonResponse(D2Packet d2packet)
        {
            // This also doesn't work, for some reason it skips a byte or something?
            D2PacketsNew.BnetServer.RealmLogonResponse packet = new D2PacketsNew.BnetServer.RealmLogonResponse(d2packet.Data);

            if (packet.Result != D2PacketsNew.BnetServer.RealmLogonResult.Success)
            {
                this.DebugLog.Append("Couldn't log on to that realm: " + packet.Result.ToString());
                throw new Exception("Couldn't log on to that realm: " + packet.Result.ToString());
            }

            this.DebugLog.Append("Logged into realm!");

            this.DebugLog.Append("Connecting to realm " + packet.RealmServerIP.ToString());

            this.Socket.ConnectRS(packet.RealmServerIP);

            this.DebugLog.Append("Connected");

            this.Socket.SendRS(new byte[] {0x01});

            this.DebugLog.Append("Logging onto realm...");
            this.Socket.SendRS(
                new ChiefD2.Net.Packet.RC.Logon(
                    packet.Cookie,
                    packet.Status,
                    packet.MCPChunk1,
                    packet.MCPChunk2,
                    packet.Username
                ).Data);
        }
        #endregion

        #region Realm Server
        private void RealmStartupResponse(D2Packet d2packet)
        {
            D2PacketsNew.RealmServer.RealmStartupResponse packet = new D2PacketsNew.RealmServer.RealmStartupResponse(d2packet.Data);

            if (packet.Result != D2PacketsNew.RealmServer.RealmStartupResult.Success)
            {
                this.DebugLog.Append("Couldn't connect to that realm: " + packet.Result.ToString());
                throw new Exception("Couldn't connect to that realm: " + packet.Result.ToString());
            }

            this.DebugLog.Append("Realm logon success!");

            this.DebugLog.Append("Request list of characters, just for shits");

            System.Threading.Thread.Sleep(50);

            this.Socket.SendRS(new byte[] {0x07, 0x00, 0x19, 0x08, 0x00, 0x00, 0x00});

            this.Socket.PacketHandler.WaitForPacket(RealmServerPacket.CharacterList, 15000);

            System.Threading.Thread.Sleep(50);

            this.DebugLog.Append("Selecting character: " + this.Profile.CharacterName);
            this.Socket.SendRS(new ChiefD2.Net.Packet.RC.CharacterLogon(this.Profile.CharacterName).Data);
        }

        private void CharacterLogonResponse(D2Packet d2packet)
        {
            D2PacketsNew.RealmServer.CharacterLogonResponse packet = new D2PacketsNew.RealmServer.CharacterLogonResponse(d2packet.Data);

            if (packet.Result != D2PacketsNew.RealmServer.RealmCharacterActionResult.Success)
            {
                this.DebugLog.Append("Couldn't select character: " + packet.Result.ToString());
                throw new Exception("Couldn't select character: " + packet.Result.ToString());
            }

            this.DebugLog.Append("Character selected, entering lobby");

            //this.Socket.SendRS(new D2PacketsNew.BnetClient.EnterChatRequest();

            //this.Socket.PacketHandler.WaitForPacket(RealmServerPacket.CharacterList, 5000);

            this.DebugLog.Append("Ready to make games!");

            LobbyEntered();
        }
        #endregion

        #region Game Server
        private void GameLogonSuccess(D2Packet d2packet)
        {
            this.DebugLog.Append("Entered game!");

            GameEntered();
        }
        #endregion
        #endregion
    }
}