Bloog Bot

Opening Our Eyes

In Part 2 we showed a simple example of how to call a function in the WoW client using the IsLoggedIn function. Now we're going to take a look at one of the most useful functions for our bot: EnumerateVisibleObjects.

In Part 1 I mentioned the different calling conventions available in C/C++. Up to this point we haven't had to worry about it because our first function IsLoggedIn didn't take any parameters, and didn't have a return value. The new EnumerableVisibleObjects has both parameters and a return value so we're going to need to think about calling convention here.

Remember that the default calling convention from C# is Stdcall and we can override that with the UnmanagedFunctionPointer annotation. The EnumerateVisibleObjects function uses Fastcall, so we're going to need to deviate from C#'s default behavior. Unfortunately, C# doesn't support Fastcall (check out the API docs on MSDN), so we're going to have to get creative.

The solution is to write a small library in C++ that exposes a method implemented with Stdcall that wraps the call to EnumerateVisibleObjects using Fastcall. So from C# we'll be calling EnumerateVisibleObjects indirectly through our Fastcall library. The library is a DLL project with the following code:

Make sure you set the output directory of the project to ..\Bot\ so that it ends up in the same place as the rest of our bot's dependencies.

The one thing worth noting here is the line extern "C". This post on stackoverflow has a good explanation, but the gist is: the C++ compiler performs "name mangling" to support function overloading, but that makes it difficult to identify the function by name when using DllImport from C#. So extern "C" disables that name mangling.

With that done, let's wire up the EnumerateVisibleObjects method in the Functions class.

Notice that unlike IsLoggedIn, instead of using Marshal.GetDelegateForFunctionPointer, we're going through our Fastcall library, so we have to import that using DllImport and specifying the entry point (this would be the failure point if we didn't use extern "C" as mentioned above). Also note that we don't need to specify a calling convention here because the default is Stdcall and that's what our Fastcall library uses to wrap the internal Fastcall function.

So, how does the EnumerateVisibleObjects function in the WoW client work? It takes two parameters: a callback function (IntPtr), and a filter (int). For each object that's in range of the Player, the WoW client will call your callback function passing in the GUID of the object and the filter value that was passed in. The filter argument has to be provided, but it's up to you to implement that in your callback function (or ignore it). You could, for example, only enumerate over the first n objects using that filter argument.

The guid of an object isn't that useful to us. What we really want is a pointer to the object in memory so we can read from offsets from that memory address to find interesting values associated with the object. Thankfully the WoW client exposes a function called GetObjectPtr that takes a GUID as a single parameter and returns a pointer to that game object. Here's the code:

Notice the lack of [UnmanagedFunctionPointer(CallingConvention.StdCall)] annotating the delegate. In this case, the GetObjectPtr function is implemented using Stdcall in the WoW client so we can defer to C#'s default behavior.

All objects in WoW have a "type". There are obvious differences between an Item and a Player. These different types of objects all have a place in an object inheritance hierarchy. We will explore that hierarchy fully down the road, but for now, let's outline what the different types are using an enum, and define a base class WoWObject that holds a few properties that all objects in the game share.

There are 8 different object types in the WoW client, so we define those all in the enum. Every object in the game has a GUID, a Pointer to the object, and an ObjectType, so we add those as properties to the WoWObject class. Eventually we'll inherit from this base class when we create classes for items, players, etc, and those derived classes will have their own specific properties and methods.

There's one more thing to talk about before showing the ObjectManager. Remember that the we pass a callback function to the EnumerateVisibleObjects function, then that function calls our callback passing in the object's GUID as a parameter which we then pass to GetObjectPtr to get a pointer to the object in memory. From there, we'll use the same principles that allowed us to find the Player's health in BloogsQuest from Part 1 to find the WoW object's values in memory near the object's starting address. The first thing we'll find is the object's type, and to do that we need to know the offset of the ObjectType property from the start of the object in memory.

We also need a slightly different approach for reading memory from that location. In previous examples we used ReadProcessMemory, but now that we're in-process that isn't necessary. Instead we can simply dereference the pointer, but in order to do so we'll need to be operating in an unsafe context. Here's an MSDN article that talks about working with pointers from C# if you want to learn more. In our case, we're going to create a new class called MemoryReader that we'll use to do our pointer dereferencing, and we'll also need to turn on the unsafe code flag for our project. The class doesn't have much, but we'll build on it as we move forward:

The type of an object is stored as a byte offset 0x14 from the object's starting address, so the MemoryReader class has a single method that reads from an address and parses the value as a byte.

Now we're going to add the ObjectManager class. This class is responsible for defining the callback function and passing that to EnumerateVisibleObjects, then maintaining a list of all the game objects that were found. Here's the code for that class:

Recall that we pass our callback to the EnumerateVisibleObjects function by its pointer, so we have to define a delegate and then wire up the Callback method with the delegate using Marshal.GetFunctionPointerForDelegate. Then we expose an EnumerateVisibleObjects method that first clears the object list, then calls EnumerateVisibleObjects in the WoW client, passing it the callback pointer and a filter of 0 (we'll be ignoring the filter in our callback).

The callback is the interesting part. Like I mentioned earlier, WoW's EnumerateVisibleObjects function will call our callback for every object visible to the Player, so it's up to us to specify what we want to do with that object. For now, we'll just be adding all the objects to a list. But first we need to get the object's pointer which we do by calling GetObjectPtr. From there, we retrieve the ObjectType using our memory reader, reading from a 0x14 offset from the object's pointer.

We're ready for a test. In our ViewModel, let's change the Test button to call EnumerateVisibleObjects then print some results to the log. Here's the new code in the ViewModel: