This is the introduction to a multi-part series about the architecture and design of XenoBot. You can check out the first installment here.
Before I dive into the nitty-gritty of XenoBot's architecture, I think it's appropriate to introduce XenoBot at a high-level. XenoBot is a client modification for an MMORPG that you've probably never heard of called Tibia. The bot is capable of playing the game with very high competence, boasting the ability to autonomously play for days on end. It can kill monsters, loot bodies, walk around caves, complete quests, sell loot, purchase supplies, aim skill-shots, kite dozens of enemies, and even best the majority of people in player-versus-player combat. Moreover, it is capable of doing all of these things in a very natural, interleaved, and efficient manner. For instance, it is able to kite monsters while shooting them with runes and looting bodies as it approaches them during kiting, while also healing with spells and drinking mana potions.
The bot has two main components: the injector and the core. Both are written in C++. The injector is responsible for managing login, fetching updates, identifying running game clients, and injecting the core into running clients. The core is a dynamic-link library which gets injected into a game client.
The core is responsible for all of the functionality. It exists entirely in the memory space of the game client and acts as an extension of that client. The core behavior, planning, search, and logic algorithms are contained in this library and exposed through a scripting interface which is accessible via Lua.
This series will mainly focus on the core, but the injector will get some highlights as I talk about how the update system is designed.