Dienstag, 7. Oktober 2014

[WoW 1.12.1 / C#] The first steps towards "our" bot

today I want to continue the WoW 1.12.1 C# series.
Previous posts which you should read in order to understand what we are doing:
  1. A basic window mover
  2. Memory manipulation using BlackMagic
  3. Memory manipulation without third party libraries
A few more words before we get into coding:

Why do you work with version 1.12.1?
The very first reason is that vanilla WoW is probably the only game I stil play in my spare time. Its a part of my childhood and in conclusion associated with many good memories. Things were more time consuming and rewarding. It wasnt designed to give even the biggest noob a feeling of success. Flying mounts werent implemented which is a big plus for me since I love world PvP. There was no dungeon finder nor teleports to dungeon. It was more about the community to organise things and not some mechanism like LFR doing all the work. Since you actually need to travel in vanilla WoW the whole world feels more populated and not only centered around a few zones like it is on retail.
In general: "hard" games > casual games

Beside from all those gameplay related arguments there are also some reasons why I choose to write the tutorial for 1.12.1:
Retail WoW is constantly evolving. Writing a long tutorial about coding a bot for an executable which is constantly changing is just a waste:
  1. People cant work with the code snippets provided after an update since many memory addresses aswell mechanics change with patches.
  2. I dont expect that this tutorial series would be done within one patch which would mean updating old posts over and over again to make them fit with the newest update. Using 1.12.1 we have all time we need (me with writing those posts aswell you understanding what is happening)
  3. There are dozen projects (like Kronos) running a server supporting the 1.12.1 client.
With that being said: Im not a professional programmer so dont expect my solutions to be the best. Just take it as a inspiration to do it better :).

Lets get started?

My bot basically consists of two parts:
One thread obtaining all informations (Cooldowns, Objects around the player etc.)
Another thread evaluating the obtained infos and choosing what to do depending on whats going on (resting, fighting, ghost walking, searching a new target, vendoring, going to the next target etc.)

Today we will learn how to obtain informations about objects around the player or to be more exact: Items, containers, units, players, gameobjects, dynamicobjects and corpses.
Every object around our player is an object in memory. The objectmanager is basically a list holding pointers to all those objects. Each object contains fields about informations belonging to the object like the x, y and z coordinates aswell the type of the object and a pointer to the next object.

So what we do? Read the objectmanager from the first to the last object and save them.

1. Addresses we need to know (those are obtained with a alpha patchdiff):

 static uint objectManager = 0x00B41414;  
 static uint firstObjPtr = 0xac;  
 static uint nextObjPtr = 0x3c;  
 static uint objType = 0x14;  
 static uint descriptorOffset = 0x8;  

2. Object types:

 private enum ObjTypes : byte  
      OT_NONE = 0,  
      OT_ITEM = 1,  
      OT_CONTAINER = 2,  
      OT_UNIT = 3,  
      OT_PLAYER = 4,  
      OT_GAMEOBJ = 5,  
      OT_DYNOBJ = 6,  
      OT_CORPSE = 7,  

3. Obtain the pointer to the very first object:

 uint curObj = BmWrapper.mem.ReadUInt(BmWrapper.mem.ReadUInt(objectManager) + firstObjPtr);  
 uint nextObj = curObj;  

4. Now that we obtained the first object in the list we can read its type and decide what to do next depending on the result:

 uint curObjType = BmWrapper.mem.ReadByte(curObj + objType);  
 switch (curObjType)  
      case (byte)ObjTypes.OT_CONTAINER:  
           // Do something  
      case (byte)ObjTypes.OT_PLAYER:  
           // Do something  
      case (byte)ObjTypes.OT_UNIT:  
           // Do something  
      case (byte)ObjTypes.OT_GAMEOBJ:  
           // Do something  
      case (byte)ObjTypes.OT_CORPSE:  
           // Do something  

5. After processing the first object its time to get the next in line. If the pointer to the next object is 0 or equal to the pointer to the current object we arrived at the end of the list:

 while (curObj != 0 && (curObj & 1) == 0)  
      // Do stuff with current object here  
      nextObj = BmWrapper.mem.ReadUInt(curObj + nextObjPtr);  
      if (nextObj == curObj)  
           curObj = nextObj;  

6. The current code doesnt fulfill any need: We dont process the objects nor we save them but thats not important for the moment. This post is just proof of concept or better said a showcase how we iterate over the objectmanager.
In the next few episodes we will learn what we can do with all those objects.

Final words:

I will release a sample command line program every new post to demonstrate the current progress.
With the current state we can archiv a basic output:

Having an address to each object gives a lot of new room to tinker around a bit.
Sample Project download: https://github.com/Zz9uk3/CmdObjectManager