Welcome a new tool, which you can use to create automation - Macros. Before jumping into the details of macros, let’s do a brief overview of the existing tools.
Initially, there were only auras, which consist of Triggers and Actions. The idea is simple: when a trigger activates, your actions are executed.
This is still a good solution for simple event-action situations like sending notifications to Telegram or automating HP/MP potions. However, for anything more complex, this approach quickly becomes difficult to maintain, as you have to think about all possible events and reactions that may happen simultaneously.
To solve that problem, I’ve added scripts, which give you 100% control over your bot and its actions. The only real drawback is that it requires users to know C# and be able to code. Also, for some cases, writing the code may not be the best solution. For example, developing a bot that performs rotations in plain C# can be quite complex, as you have to track cooldowns, assess priorities, etc. We needed better tools for such cases.
BTs offer another approach to modeling logic and have proven themselves in game engines, where they are used to model NPC logic. BTs also solve the problem of handling multiple events simultaneously by running every action sequentially, allowing users to prioritize actions based on a set of conditions. In some cases, like building rotation logic, BTs offer the best experience. The main issue with BTs, however, is their steep learning curve, which, when combined with the learning curve of EyeAuras, made them inaccessible to many users, especially non-programmers. These users were left with the option of using auras, despite their limitations.
Introducing a new fourth option, which aims to become the default starting point for automation. The concept is simple: you have a series of commands that run sequentially. These commands can check the state of other auras, press buttons, run scripts, etc. They also allow you to have loops, conditions, and everything you would expect.
Macros are not reactive by default, meaning they won’t run on their own, unlike Auras, which always do something. To run a macro, you need to either bind it to a hotkey or configure another Enabling Condition. When the condition is met, the macro will either run once or periodically.
The real power of this approach lies in the ability to combine all three logic-building methods. For example, you can have auras tracking images/colors or performing neural network inference, check the state of those auras using IfThenElse
, and if the conditions are met, pass control to a Behavior Tree or run a script.
For example, suppose you want your character to farm mobs in a specific spot. If it dies, you resurrect, restock resources in a town, and return to the farming spot. If you attempt to build that entire logic using BTs, you’ll encounter some complexities, such as constantly tracking whether you’re in town or at the farming spot. However, with macros, you can have one large cycle that runs while the bot is activated. Within that cycle, you can easily check if you’re in a town to handle restocking or, if you’re at the farming spot, start running a farming behavior tree. This allows you to break the bot’s logic into smaller, manageable parts without always needing to account for all possible conditions.
All kinds of macros are supported, from building simple sequences of keypresses (like Send Sequence action, but much more flexible)
to building complex sequences of actions combinging scripts, behavior trees and auras together
A new button has been added to the main webpage, allowing users to download an archive with the most recent version. It is fully portable, with configuration separate from the main app. This mechanism has been tested for a few months in Packs and should work without major issues.
Test support for machine-learning models based on Yolo 10 has been implemented. Yolo 10 is cutting-edge technology for real-time object detection.
New functionality in Behavior Trees allows you to mark sub-trees as shared. This enables you to create nodes pointing to a specific sub-tree directly from the toolbar.
This node is now available in Macros and BTs. There are two variants of the node: one for absolute mouse movement and one for relative movement (which takes the current cursor position into consideration).
As in Send Sequence, you can now bind X and Y, link auras, and control where exactly to click on the found image or object. There are two editing modes: simple and advanced.
Advanced mode looks like this (yes, it's a bit overloaded with controls):
The KeyPress node now also supports sending mouse-related inputs. At this point, I’m not 100% sure that having multiple input nodes will improve the UX, but we’ll see how it goes.
One of the major features of EyeAuras is its C# script engine, which allows you to compile, load, and execute your code in real-time. It is used in actions, triggers, and behavior trees. Since there are virtually no restrictions on the code you can write, it’s not uncommon to make mistakes that lead to crashes, deadlocks, and other common programming issues. I’ve already discussed this in the 7060 changelog.
In this version, I’ve introduced a mechanism that extends your code to mitigate some common mistakes, such as not catching Task
exceptions, using Thread.Sleep
instead of EyeAuras’ Sleep
method (which offers much greater accuracy and is cancellable), or using infinite loops like while(true){}
instead of while(!cancellationToken.IsCancellationRequested){}
.
Although this mechanism will only catch some errors, the primary responsibility is still on the script developer to write functional code. Nonetheless, this system should help make life a bit easier.
Please report anything unusual you encounter!
You can use macros to simply send sequences of keypresses:
Or build full-blown rebuff/target/farm logic using conditions, loops, and scripts:
In contrast to BTs, this tool is much simpler and easier to understand. Essentially, you are building a program using small blocks, making it more accessible to new users looking to create their own automations.
The input smoother selection has been added to folder properties. The Input Smoother controls how the mouse moves from point A to point B and in how many steps.
As with other settings, this one is propagated to all items in that folder – nodes, actions, triggers, etc.
A new version of the links editor is being released. It appears whenever you link something (e.g., AuraIsActive or Enabling Conditions).
The new editor is much more flexible, making changes easier. Once this version stabilizes, I’ll add “Recent,” “Favourites,” and other improvements I have in mind. Please report any issues or suggested improvements – the initial implementation might have bugs, but hopefully, it will quickly surpass the old variant.
Waiting for something is a critical part of automation. EyeAuras constantly does this – timeouts between keypresses, ensuring that capture FPS is consistent, user-driven timeouts in scripts. The default methods provided by the operating system (e.g., Thread.Sleep
, Task.Delay
) aren’t accurate enough, so I implemented a combination of methods that ensured better accuracy.
This mechanism allowed sub-millisecond waits and worked well for 5-6 months. However, accuracy comes with a cost, and for most operations, it wasn’t needed.
That’s why, for the next few months, we’ll be trying a third version of Sleep(), which is expected to find a middle ground between accuracy and performance. On average, it should reach accuracy between 0.5 - 5ms
.
This means that if you set EA to wait for 1ms
, the effective wait time will range from 1 - 1.5ms
, which is more than enough for most use cases. For larger timeouts, such as 100ms
, the range will be 100 - 105ms
.
To balance the loss of accuracy, you’ll gain better performance. We’ll see how it performs in real-world scenarios.
This effect is very useful for analysis, as it splits an image into black and white, making further checks much simpler. For example, instead of dealing with a red HP bar with various shades, you can convert it to black and white, where white represents the filled part of the bar.
Another image simplification technique, Color Quantization reduces the total number of colors in an image. While not very useful by itself, it can help when combined with other effects.
The TextSearch trigger now exposes text segments and their locations. This feature is currently usable only via C# scripts and allows you to click on specific words.
You can find an example here: https://wiki.eyeauras.net/scripting/examples/basic/click-on-text
In the future, similar functionality will be available through the UI as well.
A new option, "Include All Matches," has been added for some corner-case scripting purposes. By default, image search finds the best possible match and tracks its movement, avoiding scanning the whole image every frame. This new option disables these optimizations, so the image is fully scanned on every tick. On the positive side, this gives you access to multiple candidates and their similarities. On the negative side, it significantly affects performance.
To access all found objects, use TemplateMatches
, which is returned as part of the ImageSearchTrigger.Refresh
result:
public interface IImageSearchDetectionResult : ICaptureTriggerDetectionResult
{
...
/// <summary>
/// Contains an array of all successful template matches and their bounds/similarity.
/// Will contain more than one element only if Include All Matches is enabled in ImageSearchTrigger.
/// </summary>
public ImmutableArray<TemplateMatchResult> TemplateMatches { get; init; }
...
}
This is extremely CPU-heavy task. On 1920x1080 you'll probably have at most 2-3 FPS to do a full scan. This is a huge contrast to ML search, which on the same resolution for the same task can give you up to 60 FPS, so if you really need to detect multiple instances of some object, I would highly recommend to look into training Yolo model and using it instead.
Load from preview pane
avoids copying debug dataT
to Nullable of T
(e.g. int
to int?
) #EA-660 v7569 by Gwynoddessax
Listen()
to ScriptVariable
- you can now use it instead of WatchCurrentValue
oddessax