Major upgrade in the scripting engine - it can now compile Razor components. Blazor (Razor components are part of Blazor infrastructure) is one of the best (my opinion - for desktop apps just the best) UI technology which allows to have full power of C# and at the same time great performance/convenience of Web (HTML/CSS/JS) world.
EyeAuras is also using it under the hood since 2023 and is gradually being rewritten from WPF to Blazor. At some point in the future is expected to become full Blazor-driven app. Parts which are using it - BT editor, Macro editor, EventLog, Bindings, AuraTree. If some part of the program feels snappy you can bet it is using Blazor.
Previously, if you wanted to develop your own user interface for your bot, the only viable option was to use WebUI Overlay which at this point is using very dated text editor and, more importantly, uses older version of the scripting engine (V2) back from April 2023(!). Of course, you could load up the project in your IDE of choice (like Visual Studio or Rider), but that was definitely not very convenient and took some extra steps.
At the same time, BTs, Macros and C# Action/Trigger have been using the newer iteration of scripting engine since Jan 2024, but they newer really had Razor support as it was technically challenging task to add it there without preparing some other systems first. And, finally, today we're getting the first prototype. This is not just new feature - allowing users to create windows straight from the code makes it possible to develop full-blown standalone bots.
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
Worked on stability - should solve those problems which crashed server under peak load. Now it should just slow down :D Thanks everyone who became part of that pleasant problem, welcome aboard :)
Added new button to main web page which allow to download archive with the most recent version. It will be fully portable with a config that is separate from the main app. This mechanism has already been tested for a few months in Packs, so should work without major issues.
p.s. Please note that portable version is not available for Stable yet, it will be available right after I will push alpha to stable in the next few days.
T
to Nullable of T
(e.g. int
to int?
) #EA-660 v7569 by GwynVery useful for analysis as it allows to split image to black and white which makes further checks much more simple. E.g. instead of having red HP bar with a lot of shades, you can convert it to black/white image where white is filled area of the bar.
Another image simplification technique, allows to reduce total number of colors in the image. By itself it is mostly useless, but can help in combination with other effects.
Made is to IsMaximized in ExecuteScriptNode is stored in the node itself
Load from preview pane
avoids copying debug dataAwaiting for something is a mandatory part of any automation. EyeAuras constantly does that - timeouts between keypresses, ensuring that capture FPS is consistent, user-driven timeouts in scripts. Default instruments provided by operating system and default methods (like Thread.Sleep
, Task.Delay
and few others) are not accurate enough, so at some point I had to implement a combination of methods which ensured better accuracy.
This mechanism allowed sub-millisecond awaits and worked for the last 5-6 months. Unfortunately, accuracy comes with a cost and for most operations it not really needed.
That is why for the next few months we'll be trying a 3rd version of Sleep(), which is expected to meet middle-ground between accuracy and performance cost. On average, it is expected that it will reach accuracy of up 0.5 - 5ms
.
This means that if you are setting EA to wait for 1ms
, the effective wait time will be in range 1 - 1.5ms
, which is more than enough for most use cases. For larger timeouts, such as 100ms
, it may vary in range of 100 - 105ms
.
To counterweight loss of accuracy, you'll get much better performance. We'll see how it goes in real world scenarios. As a part of development for this feature, I've added integration layer which will allow you to use whatever Sleep() mechanism you see fit for your scenarios. Will post information on this later.
Made is to IsMaximized in ExecuteScriptNode is stored in the node itself
Listen()
to ScriptVariable
- you can now use it instead of WatchCurrentValue