All pastes #585301 Raw Edit

Anonymous

public text v1 · immutable
·published 2007-06-23 05:18 UTC
rendered paste body
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;

using Tamir.IPLib;

using D2Sniffer;
using D2Data;
using D2Packets;

namespace Chief
{
    public delegate bool PacketConfirmation(object packet);

    public class Game
    {
        #region Win32
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern uint MapVirtualKey(uint uCode, uint uMapType);

        [DllImport("user32.dll")]
        private static extern bool FlashWindow(IntPtr hwnd, bool bInvert);

        /*
        [DllImport("user32.dll")]
        private static extern bool TranslateMessage([In] ref MSG lpMsg);

        private struct MSG
        {
            public IntPtr hwnd;
            public uint message;
            public IntPtr wParam;
            public IntPtr lParam;
            public uint time;
            public POINT pt;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct POINT
        {
            public int X;
            public int Y;

            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }

            public static implicit operator System.Drawing.Point(POINT p)
            {
                return new System.Drawing.Point(p.X, p.Y);
            }

            public static implicit operator POINT(System.Drawing.Point p)
            {
                return new POINT(p.X, p.Y);
            }
        }*/
        #endregion

        //private OutOfGameState State = OutOfGameState.None;

        #region Collections
        public Games Games = new Games();
        public Items Items = new Items();
        public Objects Objects = new Objects();
        public Units Units = new Units();
        #endregion

        public D2Toolkit.D2Instance Diablo;

        public Hero Hero = new Hero();

        private PacketSniffer Sniffer = new PacketSniffer();

        public Game()
        {

        }

        public void Attach(Process proc)
        {
            this.Diablo = new D2Toolkit.D2Instance(proc.MainWindowHandle);

            if (!this.Sniffer.StartSniffing(this.Diablo.ProcessID))
                throw new Exception("Couldn't start sniffing.");

            // Realm Server Packets
            this.Sniffer.AddAsyncListener(RealmServerPacket.GameList, new PacketEventHandler(this.GameList));

            // Game Server Packets
            this.Sniffer.AddAsyncListener(GameServerPacket.AssignPlayer, new PacketEventHandler(this.AssignPlayer));
            this.Sniffer.AddAsyncListener(GameServerPacket.AssignNPC, new PacketEventHandler(this.AssignNPC));
            this.Sniffer.AddAsyncListener(GameServerPacket.AssignGameObject, new PacketEventHandler(this.AssignGameObject));
            this.Sniffer.AddAsyncListener(GameServerPacket.AssignSkill, new PacketEventHandler(this.AssignSkill));

            this.Sniffer.AddAsyncListener(GameServerPacket.SetNPCMode, new PacketEventHandler(this.SetNPCMode));

            this.Sniffer.AddAsyncListener(GameServerPacket.NPCMove, new PacketEventHandler(this.NPCMove));
            this.Sniffer.AddAsyncListener(GameServerPacket.WalkVerify, new PacketEventHandler(this.WalkVerify));
            this.Sniffer.AddAsyncListener(GameServerPacket.PlayerReassign, new PacketEventHandler(this.PlayerReassign));

            //this.Sniffer.AddAsyncListener(GameServerPacket.WorldItemAction, new PacketEventHandler(this.WorldItemAction));
            this.Sniffer.AddAsyncListener(GameServerPacket.OwnedItemAction, new PacketEventHandler(this.OwnedItemAction));
            
            // Game Client Packets
            this.Sniffer.AddAsyncListener(GameClientPacket.SelectSkill, new PacketEventHandler(this.SelectSkill));
            
            this.Sniffer.AddAsyncListener(GameClientPacket.RequestReassign, new PacketEventHandler(this.RequestReassign));

            //this.Sniffer.AddAsyncListener(GameClientPacket.WaypointInteract, new PacketEventHandler(this.WaypointInteract));
        }

        public void Clear()
        {
            this.Units.Clear();
            this.Objects.Clear();
            this.Items.Clear();
            this.Games.Clear();
        }

        #region Packet interpreting
        #region Realm Server
        private void GameList(object sender, PacketEventArgs args)
        {
            RealmServer.GameList gameList = (args.Packet as RealmServer.GameList);

            this.Games.Add(gameList);
        }
        #endregion

        #region Game Server
        private void AssignPlayer(object sender, PacketEventArgs args)
        {
            GameServer.AssignPlayer packet = args.Packet as GameServer.AssignPlayer;

            // Grab our bot's character UID, if it's not already found
            if (this.Hero.UID == 0)
            {
                this.Hero.Initialize(packet);
            }
        }

        private void AssignNPC(object sender, PacketEventArgs args)
        {
            NPC npc = new NPC(args.Packet as GameServer.AssignNPC);

            // Add NPC if it doesn't already exist, otherwise just update
            NPC npcInList = this.Units.Find(npc.UID);

            if (npcInList != null)
                npcInList = npc;
            else
                this.Units.Add(npc);
        }

        private void AssignGameObject(object sender, PacketEventArgs args)
        {
            Object theObject = new Object(args.Packet as GameServer.AssignGameObject);

            // Add Object if it doesn't already exist, otherwise just update
            Object objectInList = this.Objects.Find(theObject.UID);

            if (objectInList != null)
                objectInList = theObject;
            else
                this.Objects.Add(theObject);
        }

        private void AssignSkill(object sender, PacketEventArgs args)
        {
            GameServer.AssignSkill packet = args.Packet as GameServer.AssignSkill;

            // Grab our bot's character UID, if it's not already found
            if (this.Hero.UID == packet.UID)
            {
                this.Hero.SetSkillSelected(packet.Hand, packet.Skill);
            }
        }

        private void SetNPCMode(object sender, PacketEventArgs args)
        {
            uint uid = (args.Packet as GameServer.SetNPCMode).UID;

            NPC npc = this.Units.Find(uid);
            if (npc != null)
                npc.UpdateMode(args.Packet as GameServer.SetNPCMode);
        }

        private void WalkVerify(object sender, PacketEventArgs args)
        {
            GameServer.WalkVerify packet = args.Packet as GameServer.WalkVerify;

            this.Hero.X = (uint)packet.X;
            this.Hero.Y = (uint)packet.Y;
        }

        private void PlayerReassign(object sender, PacketEventArgs args)
        {
            GameServer.PlayerReassign packet = args.Packet as GameServer.PlayerReassign;

            this.Hero.X = (uint)packet.X;
            this.Hero.Y = (uint)packet.Y;
        }

        private void NPCMove(object sender, PacketEventArgs args)
        {
            NPC npc = this.Units.Find((args.Packet as GameServer.NPCMove).UID);

            if (npc != null)
            {
                npc.UpdatePosition(args.Packet as GameServer.NPCMove);
            }
        }

        private void WorldItemAction(object sender, PacketEventArgs args)
        {
            //GameServer.WorldItemAction item = (args.Packet as GameServer.WorldItemAction);
            Item item = new Item(args.Packet as GameServer.WorldItemAction);

            if (!this.Items.ContainsKey(item.UID) && item != null)
                try
                {
                    this.Items.Add(item.UID, item);
                }
                catch (NullReferenceException)
                { /* TODO: Why do I get this exception? Do some items not have UID's?*/ }
        }

        private void OwnedItemAction(object sender, PacketEventArgs args)
        {
            Item item = new Item(args.Packet as GameServer.OwnedItemAction);

            if (!this.Hero.Items.ContainsKey(item.UID))
                try
                {
                    this.Hero.Items.Add(item.UID, item);
                }
                catch (NullReferenceException)
                { /* TODO: Why do I get this exception? Do some items not have UID's?*/ }
        }
        #endregion

        #region Game Client
        private void SelectSkill(object sender, PacketEventArgs args)
        {
            GameClient.SelectSkill packet = args.Packet as GameClient.SelectSkill;

            this.Hero.SetSkillSelected(packet.Hand, packet.Skill);
        }

        private void RequestReassign(object sender, PacketEventArgs args)
        {
            GameClient.RequestReassign packet = args.Packet as GameClient.RequestReassign;

            // Grab our bot's character UID, if it's not already found
            if (this.Hero.UID == 0)
            {
                this.Hero.UID = packet.MeUID;
            }
        }

        private void WaypointInteract(object sender, PacketEventArgs args)
        {
            // When we go through a waypoint, we should remove all objects/npcs/etc. so we don't
            // get any mix ups
            this.Clear();
        }
        #endregion
        #endregion

        #region Packet actions
        public void Move(int x, int y)
        {
            this.Diablo.Sender.SendToGameServer(new GameClient.RunToLocation((ushort)x, (ushort)y).Data);

            uint myUID = this.Hero.UID;
            uint toX = (uint)x;
            uint toY = (uint)y;
            uint fromX = this.Hero.X;
            uint fromY = this.Hero.Y;

            byte[] PlayerMove = new byte[] 
                    { 
                        0x0F, // PlayerMove
                        0x00, // Client Type (always 0x00)
                        (byte)(myUID & 0xFF), (byte)((myUID >> 8) & 0xFF), (byte)((myUID >> 16) & 0xFF), (byte)(myUID >> 24), // Client ID
                        0x17, // Run/Walk (0x01 for walk, 0x17 for run)
                        (byte)(toX & 0xFF), (byte)((toX >> 8) & 0xFF), (byte)(toY & 0xFF), (byte)((toY >> 8) & 0xFF), // Location to walk to
                        0x00, // Unknown, always 0x00
                        (byte)(fromX & 0xFF), (byte)((fromX >> 8) & 0xFF), (byte)(fromY & 0xFF), (byte)((fromY >> 8) & 0xFF) // Current location of the client
                    };

            

            this.Diablo.Sender.SendToGameClient(new GameServer.PlayerMove(PlayerMove).Data);
        }
        public void Move(Unit unit)
        {
            this.Diablo.Sender.SendToGameServer(new GameClient.RunToLocation((ushort)unit.X, (ushort)unit.Y).Data);
            this.Diablo.Sender.SendToGameServer(new GameClient.RunToTarget(UnitType.NPC, unit.UID).Data);

            uint myUID = this.Hero.UID;
            uint toX = (uint)unit.X;
            uint toY = (uint)unit.Y;
            uint fromX = this.Hero.X;
            uint fromY = this.Hero.Y;

            byte[] PlayerMove = new byte[] 
                    { 
                        0x0F, // PlayerMove
                        0x00, // Client Type (always 0x00)
                        (byte)(myUID & 0xFF), (byte)((myUID >> 8) & 0xFF), (byte)((myUID >> 16) & 0xFF), (byte)(myUID >> 24), // Client ID
                        0x17, // Run/Walk (0x01 for walk, 0x17 for run)
                        (byte)(toX & 0xFF), (byte)((toX >> 8) & 0xFF), (byte)(toY & 0xFF), (byte)((toY >> 8) & 0xFF), // Location to walk to
                        0x00, // Unknown, always 0x00
                        (byte)(fromX & 0xFF), (byte)((fromX >> 8) & 0xFF), (byte)(fromY & 0xFF), (byte)((fromY >> 8) & 0xFF) // Current location of the client
                    };

            this.Diablo.Sender.SendToGameClient(new GameServer.PlayerMove(PlayerMove).Data);
        }

        public bool MoveWait(int x, int y)
        {
            Move(x, y);

            PacketConfirmation myDel = delegate(object packet)
                {
                    if ((packet as GameServer.WalkVerify).X == x && (packet as GameServer.WalkVerify).Y == y)
                        return true;
                    else
                        return false;
                };

            if (!WaitForPacket(GameServerPacket.WalkVerify, myDel, 5000))
                return false;

            return true;
        }
        public bool MoveWait(Unit unit)
        {
            Move(unit);

            PacketConfirmation myDel = delegate(object packet)
                {
                    if ((packet as GameServer.WalkVerify).X == unit.X && (packet as GameServer.WalkVerify).Y == unit.Y)
                        return true;
                    else
                        return false;
                };

            if (!WaitForPacket(GameServerPacket.WalkVerify, myDel, 5000))
                return false;

            return true;
        }

        public bool PortalInteract(Object unit)
        {
            // If we didn't move on the first try, try 1 more time
            //if (!MoveWait(unit))
            Move(unit);

            this.Diablo.Sender.SendToGameServer(new GameClient.UnitInteract(UnitType.GameObject, unit.UID).Data);

            //if (!WaitForPacket(GameServerPacket.PortalInfo, 5000))
            //    return false;

            this.Diablo.Sender.SendToGameServer(new GameClient.RequestReassign(UnitType.NPC, this.Hero.UID).Data);
            return true;
        }

        public bool WaypointInteract(Object waypoint, WaypointDestination destination)
        {
            Move(waypoint);

            this.Diablo.Sender.SendToGameServer(new GameClient.UnitInteract(UnitType.GameObject, waypoint.UID).Data);
            this.Diablo.Sender.SendToGameServer(new GameClient.WaypointInteract(waypoint.UID, destination).Data);
            this.Diablo.Sender.SendToGameServer(new GameClient.RequestReassign(UnitType.NPC, this.Hero.UID).Data);
            return false;
        }

        public bool TeleportWait(int x, int y)
        {
            SelectSkill(SkillHand.Right, SkillType.Teleport);

            this.CastRightSkill(x, y);

            if (!WaitForPacket(GameServerPacket.PlayerReassign, 5000))
                return false;

            // Delay so we don't keep teleporting
            System.Threading.Thread.Sleep(200);

            return true;
        }

        public void Attack(NPC npc, SkillType skill)
        {
            SelectSkill(SkillHand.Left, skill);

            this.Diablo.Sender.SendToGameServer(new GameClient.CastLeftSkill((ushort)npc.X, (ushort)npc.Y).Data);
        }

        public bool SelectSkill(SkillHand hand, SkillType type)
        {
            if (!this.Hero.IsSkillSelected(hand, type))
            {
                this.Diablo.Sender.SendToGameServer(new GameClient.SelectSkill(type, hand).Data);

                if (!WaitForPacket(GameServerPacket.AssignSkill, 5000))
                    return false;
            }

            return true;
        }


        public void CastLeftSkill(int x, int y)
        {
            this.Diablo.Sender.SendToGameServer(new GameClient.CastLeftSkill((ushort)x, (ushort)y).Data);
        }
        public void CastRightSkill(int x, int y)
        {
            this.Diablo.Sender.SendToGameServer(new GameClient.CastRightSkill((ushort)x, (ushort)y).Data);
        }



        public bool SwitchWeaponSlotWait()
        {
            this.Diablo.Sender.SendToGameServer(new GameClient.SwitchWeapons().Data);

            PacketConfirmation myDel = delegate(object packet)
                {
                    if ((packet as GameServer.OwnedItemAction).Destination == ItemDestination.Equipment)
                        return true;
                    else
                        return false;
                };

            if (!WaitForPacket(GameServerPacket.OwnedItemAction, myDel, 5000))
                return false;

            return true;
        }

        public void SendChatMessage(string text)
        {
            this.Diablo.Sender.SendToGameServer(new GameClient.SendMessage(GameMessageType.GameMessage, text).Data);
        }

        public bool WaitForPacket(RealmServerPacket packet, int timeOut)
        {
            return WaitForPacket(packet, delegate(object pckt) { return true; }, timeOut);
        }
        public bool WaitForPacket(RealmServerPacket packet, PacketConfirmation confirmation, int timeOut)
        {
            bool isBusy = true;

            this.Sniffer.AddAsyncListener(packet,
                delegate(object sender, PacketEventArgs args)
                {
                    if (confirmation(args.Packet))
                        isBusy = false;
                });

            DateTime start = DateTime.Now;

            while (isBusy)
            {
                if (((TimeSpan)DateTime.Now.Subtract(start)).TotalMilliseconds > timeOut)
                    return false;

                System.Threading.Thread.Sleep(10);
            }

            return true;
        }
        
        public bool WaitForPacket(RealmClientPacket packet, int timeOut)
        {
            return WaitForPacket(packet, delegate(object pckt) { return true; }, timeOut);
        }
        public bool WaitForPacket(RealmClientPacket packet, PacketConfirmation confirmation, int timeOut)
        {
            bool isBusy = true;

            this.Sniffer.AddAsyncListener(packet,
                delegate(object sender, PacketEventArgs args)
                {
                    if (confirmation(args.Packet))
                        isBusy = false;
                });

            DateTime start = DateTime.Now;

            while (isBusy)
            {
                if (((TimeSpan)DateTime.Now.Subtract(start)).TotalMilliseconds > timeOut)
                    return false;

                System.Threading.Thread.Sleep(10);
            }

            return true;
        }

        public bool WaitForPacket(GameServerPacket packet, int timeOut)
        {
            return WaitForPacket(packet, delegate(object pckt) { return true; }, timeOut);
        }
        public bool WaitForPacket(GameServerPacket packet, PacketConfirmation confirmation, int timeOut)
        {
            bool isBusy = true;

            this.Sniffer.AddAsyncListener(packet,
                delegate(object sender, PacketEventArgs args)
                {
                    if (confirmation(args.Packet))
                        isBusy = false;
                });

            DateTime start = DateTime.Now;

            while (isBusy)
            {
                if (((TimeSpan)DateTime.Now.Subtract(start)).TotalMilliseconds > timeOut)
                    return false;

                System.Threading.Thread.Sleep(10);
            }

            return true;
        }
        
        public bool WaitForPacket(GameClientPacket packet, int timeOut)
        {
            return WaitForPacket(packet, delegate(object pckt) { return true; }, timeOut);
        }
        public bool WaitForPacket(GameClientPacket packet, PacketConfirmation confirmation, int timeOut)
        {
            bool isBusy = true;

            this.Sniffer.AddAsyncListener(packet,
                delegate(object sender, PacketEventArgs args)
                {
                    if (confirmation(args.Packet))
                        isBusy = false;
                });

            DateTime start = DateTime.Now;

            while (isBusy)
            {
                if (((TimeSpan)DateTime.Now.Subtract(start)).TotalMilliseconds > timeOut)
                    return false;

                System.Threading.Thread.Sleep(10);
            }

            return true;
        }

        public bool WaitForPacket(BnetServerPacket packet, int timeOut)
        {
            return WaitForPacket(packet, delegate(object pckt) { return true; }, timeOut);
        }
        public bool WaitForPacket(BnetServerPacket packet, PacketConfirmation confirmation, int timeOut)
        {
            bool isBusy = true;

            this.Sniffer.AddAsyncListener(packet,
                delegate(object sender, PacketEventArgs args)
                {
                    if (confirmation(args.Packet))
                        isBusy = false;
                });

            DateTime start = DateTime.Now;

            while (isBusy)
            {
                if (((TimeSpan)DateTime.Now.Subtract(start)).TotalMilliseconds > timeOut)
                    return false;

                System.Threading.Thread.Sleep(10);
            }

            return true;
        }
        
        public bool WaitForPacket(BnetClientPacket packet, int timeOut)
        {
            return WaitForPacket(packet, delegate(object pckt) { return true; }, timeOut);
        }
        public bool WaitForPacket(BnetClientPacket packet, PacketConfirmation confirmation, int timeOut)
        {
            bool isBusy = true;

            this.Sniffer.AddAsyncListener(packet,
                delegate(object sender, PacketEventArgs args)
                {
                    if (confirmation(args.Packet))
                        isBusy = false;
                });

            DateTime start = DateTime.Now;

            while (isBusy)
            {
                if (((TimeSpan)DateTime.Now.Subtract(start)).TotalMilliseconds > timeOut)
                    return false;

                System.Threading.Thread.Sleep(10);
            }

            return true;
        }
        #endregion

        #region Out of game
        /// <summary>
        /// Creates and attaches to Diablo II instance
        /// </summary>
        /// <param name="workingPath"></param>
        /// <param name="exe"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public bool Launch(string workingPath, string exe, string parameters)
        {
            Process tempProcess = new Process();

            tempProcess.StartInfo.WorkingDirectory = workingPath;
            tempProcess.StartInfo.FileName = exe;
            tempProcess.StartInfo.Arguments = parameters;

            if (!tempProcess.Start())
                return false;

            // DEBUG -- non-static delay here, maybe?
            System.Threading.Thread.Sleep(1000);

            this.Attach(tempProcess);

            // Assume -skiptobnet
            return this.WaitForPacket(BnetClientPacket.ExtraWorkResponse, 15000);
        }

        public bool Login(string username, string password)
        {
            // Type in name/pass
            this.Diablo.SendKey(System.Windows.Forms.Keys.Tab);
            this.SendKeys(username);
            this.Diablo.SendKey(System.Windows.Forms.Keys.Tab);
            this.SendKeys(password);
            this.Diablo.SendKey(System.Windows.Forms.Keys.Enter);

            return this.WaitForPacket(RealmServerPacket.CharacterList, 15000);
        }

        public bool CharacterSelect(int slot)
        {
            if(slot % 2 == 0)
            {
                this.Diablo.SendKey(System.Windows.Forms.Keys.Right);
            }

            for (int i = 2; i < slot; i+=2)
            {
                this.Diablo.SendKey(System.Windows.Forms.Keys.Down);
            }

            this.Diablo.SendKey(System.Windows.Forms.Keys.Enter);

            return this.WaitForPacket(RealmServerPacket.MessageOfTheDay, 15000);
        }

        public bool CreateGame(string name, string password, Difficulty difficulty)
        {
            // Create Game 
            this.Diablo.Click(592, 460, Poseur32.ClickType.Left);

            // Type in name/pass
            this.SendKeys(name);
            this.Diablo.SendKey(System.Windows.Forms.Keys.Tab);
            this.SendKeys(password);

            // Difficulty
            Point difficultyRadio = new Point();

            switch(difficulty)
            {
                case Difficulty.Normal:
                    difficultyRadio  = new Point(440, 374);
                    break;
                case Difficulty.Nightmare:
                    difficultyRadio  = new Point(565, 375);
                    break;
                case Difficulty.Hell:
                    difficultyRadio  = new Point(707, 375);
                    break;
            }

            this.Diablo.Click(difficultyRadio.X, difficultyRadio.Y, Poseur32.ClickType.Left);

            // Create the game
            this.Diablo.Click(681, 419, Poseur32.ClickType.Left);

            return this.WaitForPacket(D2Packets.GameServerPacket.PlayerReassign, 15000);
        }

        public bool JoinGame(string name, string password)
        {
            // Type in name/pass
            this.SendKeys(name);
            this.Diablo.SendKey(System.Windows.Forms.Keys.Tab);
            this.SendKeys(password);

            // Join
            this.Diablo.Click(678, 417, Poseur32.ClickType.Left);

            this.Games.Clear();

            return this.WaitForPacket(D2Packets.GameServerPacket.PlayerReassign, 15000);
        }

        public bool JoinGame(string name)
        {
            return this.JoinGame(name, "");
        }

        /// <summary>
        /// Joins a random game, with the most people
        /// </summary>
        public bool JoinGame()
        {
            // Join game
            this.Diablo.Click(713, 461, Poseur32.ClickType.Left);

            // Wait for list of games
            this.WaitForPacket(D2Packets.RealmServerPacket.GameList, 5000);

            System.Threading.Thread.Sleep(2000);
            
            // Select the best game
            string bestGame = "";

            for (int i = 7; i > 0; i--)
            {
                foreach (RealmServer.GameList gameList in this.Games)
                {
                    if (gameList.PlayerCount >= i)
                    {
                        bestGame = gameList.Name;
                        break;
                    }
                }

                if (bestGame != "")
                    break;
            }

            return this.JoinGame(bestGame);
        }

        public void SendKeys(string text)
        {
            foreach (char c in text)
            {
                this.Diablo.SendKey(c);
                //System.Threading.Thread.Sleep(5);
            }
        }
        #endregion

        public void Kill()
        {
            this.Diablo.Exit(true);
        }

        public void FlashWindow()
        {
            FlashWindow(this.Diablo.Process.MainWindowHandle, true);
        }
    }

    /*
    public enum OutOfGameState
    {
        None,
        Login,
        CharacterSelect,
        Chat,
        CreateGame,
        JoinGame,
        InGame
    }
    */

    public enum Difficulty
    {
        Normal,
        Nightmare,
        Hell
    }
}