At this point I think I can say that the Harvest bot and Navigation core are pretty solid so far. In the past few weeks I have been working on avoiding getting stuck, pathfinding speed improvements (from 15 seconds for a long path down to 0.8 is pretty nice) and a bunch of bug fixing. The biggest problem I had was the movement working properly at a low FPS. The “click to move” feature of WoW did not work very well for flying navigation and started to fail horribly when the pitch angle between the player and the target was close to 90 degrees. So I ended up doing it manually which is where the problem of the low FPS came in. When the game is only running at 10 FPS it easily happens that the player overshoots the target, which is what I want to avoid because it can lead to unpredicted results (falling off a ledge/cliff or shooting off into a random direction when in druid flight form), so I ended up having to predict the position the player is going to have in the next frame and act based on that.
Other improvements are mailing functionality to clear the inventory when it’s full and continue harvesting. I ended up adding another module that keeps a journal of interesting objects (mail boxes, repair npcs, etc.) and take care of the moving to it and finding the actual object to interact with.
Similarily I have also been working on battleground functionality and with that combat related functions. Biggest problem was of course dealing with target decisions and line of sight/range. Thankfully the guys behind the old OpenBot have put a lot of thoughts into that already, so it helped it a lot. Basically there is a range in which the player will move into range of his target and another in which he will actually pull it, at which point the class routine kicks in.
Since I am currently using a manually generated navigation mesh it happens a lot that no path to the target exists and the player can’t move into range. I will be trying to move directly to the player through line of sight checks if the path to the target is empty and even. An ideal solution would be to use the map/model data from the client, but that’s a project on its own.
Anyway, here’s some videos of the bot mining and some battleground combat.
And finally, another post, and more progress. In the last few weeks I have mainly been busy with refactoring my code base so it is easier to plug into the Warden protection I have. That basically requires that all memory changes (hooks and overwritten variables so far) are kept track of so they can be removed when Warden starts a scan and later restored again when the scan finished. I took that opportunity to refactor most of my code which has been mostly consisting of hacks and such to include newly gained knowledge from reverse engineering and such.
Additionally I did some more Warden REing to get a better idea of how it works and especially how and what it scans. So far I can at least see what memory addresses it reads, which is pretty interesting in itself, but not nearly all of what it scans. However since reverse engineering takes a bunch of time and I would like to get back to writing the bot itself again, I left it with that and am going to continue it whenever the need or time arises. I intend to set up a page here to list all addresses it currently scans and their frequency since I like statistics :)
Since the refactoring also made everything much easier I also made some progress on the flying harvesting state machine. This mostly includes a bunch of fixes to movement and combat related portions. Things that are usually obvious to a human (or should be) are not to the AI and need to be specially handled, and since a lot of these cases only happen in certain circumstances and are difficult to reproduce. For example, in this video you can see that the bot at some points attacks a mob that doesn’t even attack the player. This happened because the targeting module prioritizes targets on certain factors like health, aggressiveness, distance, etc. and valued that mob higher than the one currently attacking the player because of wrong weights on these factors.
Additionally it shouldn’t even attack mobs that aren’t specifically attacking the player (or in more accurate terms: targeting the player). But since it sometimes takes a few seconds for the combat status to drop off the player it immediately takes the target on top of the targets list and attacks that.
This is of course one of the easier problems and easily fixed, but sometimes there are problems that are difficult to make out or diagnose, at which points it becomes very difficult to reproduce them. That’s one of the big problems with writing “hacks” for closed source games, debugging them is a nightmare.
In any case, so far the harvesting state is working very well, a more up to date video can be seen here. What’s still missing is a way to recover from death, which will probably be the next part on the TODO list, since that’s a feature required by all sorts of states anyway.
Not much to say lately since I don’t really want to test my bots on my main account, so there’s only the Mangos server left to test things. In any case, I have so far implemented the flying harvesting thing and it works pretty well. Here‘s a short video showing some of the features.
It starts with mounting up and ascending, at which it point it starts to follow a set of waypoints specified earlier in a “hotspots” set. Once it sees a node it flies exactly above it and descends. The first node in the video happens to be under water, so it can’t reach it. After roughly 20 seconds that node gets blacklisted (put on an ignore list) and it starts to ascend and follow the waypoints again. Once a node is reached while descending the character dismounts and starts mining + looting the node, at which point the entire thing starts over (mount up, ascend, patrol..).
While flying you can notice that it sometimes bobs horribly, that happens because the pitch of it isn’t zero, so when flying forward it actually flies down. I plan to address that too, which shouldn’t be problematic since everything required for that is available in the WoW Lua API already (GetUnitPitch, PitchDownStart/Stop, etc.).
To test all this on the live servers I intend to transfer a character to a new account so I can do it without compromising my main account. Although I am sure that I have created adequate protection, there’s always a chance left :)
Next thing to come is going to be some sort of BG bot. That’s going to be the first time combat is actually important, so it’ll involve lots of combat related revamps.
This is probably the reason for the long time since the last update, but after having a testing account getting banned for some of the memory modifications I make in WoW, there really was no way around it. Since there was very little information available on Warden and the fact that it wasn’t really my area of interest, it took some with a lot of big breaks to get this done.
As you should know, Warden is (one of) World of Warcraft’s anti-cheat tools, the main logic behind it is sent, decrypted and dynamically linked at runtime, making the reverse engineering of it a bit more involved. I don’t want to get into much detail regarding this, but what I do right now to protect myself from Warden is pretty much the “standard” way it is done right now; hooking the scan function and removing all modifications before doing the scan and reapplying them again. Some testing whether this actually works still needs to be done, but so far it is working.
This means I can actually get back on the bot development now. To get some useful results, I want to create some basic “gathering” controller for my current framework. The idea is to fly around looking for mining nodes and harvest them, defending against attacking mobs (which is probably the smallest problem since a combat state/routine framework is already present) only to mount, fly up and continue. A bit more detailed my current plan looks like this:
- Works a lot like the Targets service by keeping a list of possible nodes
- Updated each tick in order to keep the list up to date every time
- Also filters nodes that are above the player’s skill (currently a hardcoded list of skill levels for each node, but I hope to dynamically retrieve that information either from some DBC files (they probably don’t contain that) or checking some “usable” flag on the node (whether the text on the tooltip would be red)
Mount module/functionality to determine whether the player can mount in the current situation and what mount to use (flying/ground). At the moment this information is hardcoded too.
Logic in the form of states to put the previous functionality to use. So far I intend to separate this into the following states:
- Generic waypoint following in the air, following a predefined set of waypoints in a circle, switching to the next state when a node is found
- Moving into range of the node to mine it by flying directly above the node and then flying straight down. Once in range, dismount and switch to the next state
- Mining the node, looting all its content
- Mounting up again and flying straight up, ideally to the point where the descend started, and switch back to state one again
- In the last two states, especially in the third one, react to possible combat and switch to combat state (which is where the routine kicks in and handles things)
This is the idea so far, I’ll probably write the next post once I discover something new.
In this post I will talk about the bot itself. After having roughly covered the foundation of it (which isn’t too interesting), I’d like to get a bit closer to where I am now with the development of the bot.
The bot itself is divided into separate modules of different types. On one side are the “service” modules which get updated every n frames, defined by the module, on the other side are normal modules which are just there to encapsulate part of the functionality. A small explanation of the modules in the diagram on the right:
- Mapper: The core of the map and path finding, records new walkable nodes and connects them to neighbors. At runtime a quadtree is filled with the nodes in order to easily and efficiently find nodes in a radius around a point. They are stored in a simple array, without any compression so far, but that isn’t very important right now, neither is it a big problem.
- Navigation: Takes care of player movement and puts the map data gathered by the Mapper service to an use. It finds a path from the source to the destination and then follows that path until it arrives or the movement is cancelled.
- Harvest: Finds suitable mining nodes, herbs, corpses, chests, etc. to harvest/loot and keeps an updated list of them.
- Targets: Keeps an updated list of possible targets and their priority, which is determined with a bunch of weights for factors like health, aggressiveness, distance, etc.
- State: The logic behind the bot, keeps track of the current and previous state, and another global state that is always run. A state can also be a “sub state”, in which case it doesn’t override the previous state, this is helpful for state transition situations like Roam -> Pull -> Combat -> Roam.
- Routines: Provides a loose framework for class specific functionality used by the different routines, for example pulling, combat, resting, buffing…
- Player: Will encapsulate some generic functionality required by the different modules and especially the routines regarding player functions like targeting the best target. Not much in there yet, since there hasn’t been much work on routines yet.
- Hotspots: Keeps track of grind hotspots the “Roam” state follows with the help of the Navigation service. It basically just cycles between a set of spots. I might replace this module with something more generic later on, since I don’t like this very much.
- GUI: Not shown on the diagram, this service takes care of the GUI updating and displaying, it retrieves the GUI elements of the different modules (if they have a GUI) and updates them.
That’s it for the modules so far, there’s probably going to be more in the future, but since I’m not that far with the development yet, the picture will change a lot. Going to go a bit into detail on the problems I have right now in the next post I guess.