jnnshschl / ameisenbotx Goto Github PK
View Code? Open in Web Editor NEWA bot, aimed at full automatic gameplay
License: GNU General Public License v3.0
A bot, aimed at full automatic gameplay
License: GNU General Public License v3.0
Blacklisting currently is a pain in ass. The IEnumerable type is immutable, therefore not suitable for rapid addition/deletion of items.
What do we actually want from a blacklist implementation?
Do we actually need Ordering?
Do we actually need Concurrency?
What about some kind of timed cache?
public class Cache<TKey, TValue>
{
private readonly Dictionary<TKey, CacheItem<TValue>> _cache = new();
public void Store(TKey key, TValue value, TimeSpan expiresAfter)
{
_cache[key] = new CacheItem<TValue>(value, expiresAfter);
}
public TValue Get(TKey key)
{
if (!_cache.ContainsKey(key))
return default;
var cached = _cache[key];
if (DateTimeOffset.Now - cached.Created < cached.ExpiresAfter)
return cached.Value;
_cache.Remove(key);
return default;
}
public int Count() => _cache.Count;
}
private class CacheItem<T>
{
public T Value { get; }
internal DateTimeOffset Created { get; } = DateTimeOffset.Now;
internal TimeSpan ExpiresAfter { get; }
public CacheItem(T value, TimeSpan expiresAfter)
{
Value = value;
ExpiresAfter = expiresAfter;
}
}
seems canceling the equip frame?
I will write down issues here relating to code quality which i think could be done better or require an explanation.
Reduce branching/nesting where possible
There are areas where unnecessary branching/nesting is introduced. Ultimately as complexity of the code grows so does the overhead introduced by these control flow features. If we assume a ideal Combat Class which manages from lvl 1 to top tier raids. Its likely in current style of code it would include thousands of control structures in case of need to handle every unique case that may happen during various states of execution. This would result in a lot of time spent traversing branches. A rewrite in well written behavioral trees approach would greatly reduce this overhead and make code much more readable.
Variable/parameters/args naming conventions
Some variables/parameters/args conform neither to PascalCasing nor to camelCasing conventions.
For loops where foreach loop suffices
Some for loops actually don't have any need for use of the index, the item of foreach loop suffices
This is adressed in #114
Variables can be just var
Depends on consensus i am fine with vars where the underlying type is obvious from context
There are many places where variable type is apparent no need to speficy, like:
int totalSeconds = (int)totalTime.TotalSeconds;
Separate code and data constants
It would be great to isolate various magic numbers, scripts, texts from code into data constants
Some namespaces are incorrect
This is resolved in #111
Project structural problems
Combat classes do not belong to engines, however moving them proper namespace would trigger instantiation of abstract classes and therefore compilation would fail.
Enforce line ending
Matter of consensus indeed however according to theory by Markus Itkonen, Typography and readability
the optimal size of a single line should be 40 to 90 characters wide, historicaly programmers have been biased since ancient times to magically decide the number to be 80, Its hard to read file compares when lines are too long.
No need to introduce nesting on control flow feature which is followed only by one statement
This depends on consensus (IDE0011) but i vote for
csharp_prefer_braces = when_multiline
or multi-conditional or linq-foreachloop
if (true)
{
Something();
}
just
if (true) Something();
csharp_prefer_simple_using_statement = true
using var a = b;
When going to some position prefer roads as much as possible
So finally got my combat class working to leave it run for few hours grinding.
I have noticed that every several hour run of grind ended up in either client silently crashing or being frozen and unresponsive with bot reporting no exceptions.
This is a severe problem and will need more investigation.
It wanted to approach an cactus in valley of strength but got stuck on one and just kept running without making progress.
In this case the bot should have an unstuck routine.
AFAIK beside spellEntry from clients DB (DBC) it would be useful to parse the following wow client caches (WDB):
CreatureCache.wdb
GameObjectCache.wdb
ItemCache.wdb
QuestCache.wdb
Ranged classes wont move closer if enemy is not in LOS
Ranged classes will move closer upon first cast
Melee classes interacting with target end up with too quick animations being played, something wrong with Bot.Wow.InteractWithUnit(target.BaseAddress);
Warrior335a.VictoryRush requires tracking of time elapsed since last kill for proper timing
Currently the way that Lua is parsed and executes is kind of confusing:
public void ClickOnTrainButton()
{
LuaDoString("LoadAddOn\"Blizzard_TrainerUI\"f=ClassTrainerTrainButton;f.e=0;if f:GetScript\"OnUpdate\"then f:SetScript(\"OnUpdate\",nil)else f:SetScript(\"OnUpdate\",function(f,a)f.e=f.e+a;if f.e>.01 then f.e=0;f:Click()end end)end");
}
Why can't we have it like this?
public void ClickOnTrainButton()
{
LuaDoString(@"
LoadAddOn"Blizzard_TrainerUI"
local trainButton = ClassTrainerTrainButton
trainButton.e = 0
if trainButton:GetScript"OnUpdate" then
trainButton:SetScript("OnUpdate", nil)
else
trainButton:SetScript("OnUpdate", function(trainButton, e)
trainButton.e = trainButton.e + e
if trainButton.e > .01 then
trainButton.e = 0
trainButton:Click()
end
end)
end")
}
System.ComponentModel.Win32Exception
HResult=0x80004005
Message=The data area passed to a system call is too small.
Source=WindowsBase
StackTrace:
at MS.Win32.UnsafeNativeMethods.GetWindowText(HandleRef hWnd, StringBuilder lpString, Int32 nMaxCount)
at System.Windows.Automation.Peers.WindowAutomationPeer.GetNameCore()
at System.Windows.Automation.Peers.AutomationPeer.UpdateSubtree()
at System.Windows.ContextLayoutManager.fireAutomationEvents()
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)
at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run()
at AmeisenBotX.App.Main()
Currently spells are done via Lua hack workaround. A proper implementation of SpellManager will require a memory interfacing and local wow storage interfacing.
The current implementation is insufficient for all that has to be automated with regards to spells.
Most of the work with regard to parsing Spell.dbc is already done by SpellWork
Memory interface
ISpellManager interface
HasSpell()
CanCastSpell()
CanBuff()
CanDebuff()
CastSpellAtLocation()
StopCasting()
Been experimenting with trainer gossip and here's something fishy i did not get to bottom of:
Once you have gossip frame open with trainer following scenarios unfold:
which calls:
public void SelectGossipOptionSimple(int gossipId)
{
LuaDoString($"SelectGossipOption({gossipId}))");
}
result: does nothing
which calls:
public void SelectGossipOption(int gossipId)
{
LuaDoString($"SelectGossipOption(max({gossipId}, GetNumGossipOptions()))");
}
result: unlearn talents frame opens
result: learn skills frame opens
So the question is how are the case 1 and 3 different? if they lead to such drastically different results.
Aura manager fails to re-apply buff when possible. Only happens at certain periods and mostly out of combat.
should only refresh
So to change engine config you have to restart the bot entirely. Not very useful, helpful or friendly.
Crashes when target gets lost. Try (Bot.Target != null)
AmeisenBotX/AmeisenBotX.Core/AmeisenBot.cs
Line 694 in 4404183
Currently bot will throw exception if we enter ingame without combat class. This isn't very nice for two reasons.
If user starts the bot for first time its very hard to pause the bot before jumping ingame on high-end rigs. Thus its not possible to stop the bot and select combat class without running into exception.
Not all engines should require a combat class. Doing profession tasks while at secure location in town doesn't have much need for a combat class.
I have not red the entire source, but what i saw in few snippets this is mainly a Lua bot if i understand correctly?
What are the main obstacles that this cannot become a packet based or memory based bot?
As i understand it interfacing wow client follows a priority hierarchy.
Packet based -> Memory based -> Lua based
AFAIK the wow client has only thread for Lua, what happens if i want to run a Lua addon which is computation heavy (as in uses a lot of Lua thread time) and at the same time rely on the Lua calls for the bot?
Thanks for your time.
berserkering and frost nova claim spell is valid when on cooldown
Well i think it would be good idea to have data like Vendors/Trainer/Mailboxes localized in profiles rather then somewhere global, i am also open to discussion wherever FreeBagSlots or SellByItemQuality shouldn't also be included as sometimes i would want less free space sometimes more free space depending on profile not a global settings.
initial implementation done in #94
Just use this pack of mmaps. https://drive.google.com/file/d/1ELjvJTyr2_ek-FVCBZtxTOjF5j7cEcfa/view?usp=sharing
Things which are missing:
Blacklist/whitelist mobs
Blacklist/whitelist nodes
Define nodes by geometry/surface topology
Filter mobs by ID
Filter mobs by FactionID
Filter mobs by WoWCreatureType
Filter mobs by Min/Max Level
Filter mobs by RarityLevel
I am starting to see that your mainly using the bot to test dungeons. That's not very wise as dungeons are much easier to bot then outside world.
protected bool IsValidUnit(IWowUnit wowUnit)
{
return !wowUnit.IsDead
&& !wowUnit.IsNotAttackable
&& wowUnit.IsInCombat
&& !IsBlacklisted(wowUnit)
&& Bot.Db.GetReaction(wowUnit, Bot.Player) == WowUnitReaction.Hostile
&& wowUnit.DistanceTo(Bot.Player) < 80.0f;
}
!wowUnit.IsDead
is actually not simple to decide as
bool IsDead => (Health == 0 || UnitFlagsDynamic[(int)WowUnitDynamicFlags.Dead]) && !UnitFlags2[(int)WowUnit2Flags.FeignDeath];
there exist few units which are at Health == 0 && !UnitFlagsDynamic[(int)WowUnitDynamicFlags.Dead]
The 'Dead' flag doesn't ensure the unit is dead. It just ensures it has a gray name.
!IsBlacklisted(wowUnit)
Its a good question what kind of role a global blacklist would have, in most cases a local blacklist dependent upon profile is more optimal.
The global blacklist is only good for mobs which roam very big area. Of which there are only very few and mostly rare ones.
Bot.Db.GetReaction(wowUnit, Bot.Player) == WowUnitReaction.Hostile
Not very friendly, i do like to fight non-hostiles, filter critters if not used for skinning/leatherworking
wowUnit.DistanceTo(Bot.Player) < 80.0f;
Maybe be irrelevant on staircase/cliff, distance may be such that interaction radius overlaps and yet traversal cost is massive.
Please keep in mind:
DynamicFlags are only for visuals!
Well need to come up with much better mechanics of unit validation, more dynamic, more flexible.
The interaction with the trainer will be similar to merchant via Lua hacks :/
A very stupid solution that visits trainer every level up and assume having more cash then price of services
This is implemented in #88
Some more refined spell training
This should use the Lua API for trainer:
BuyTrainerService(), GetTrainerServiceInfo(), GetTrainerServiceCost()
LearnSpellByName()
LearnSpellById()
LearnAllSpells()
CanLearnNewSpells()
CanImproveSpellsRank()
This leads to question:
The question remains where are we gonna check for these data from? prolly hold it in external LiteDB or in json/xml/csv
Well the world is composed of other objects then just navmesh. Things like doodads, structures will have to be ultimately resolved their bounding box acknowledged and checked if nav path goes thru such a bounding box. Currently the bot doesn't understand being blocked by a tree, cacti, fence etc..
What if the enemy is nearby but above or below us. In such a case some more refined path measurement like traversal cost would be more beneficial rather then measurement like Euclidian distance.
these are just 2 things i noticed but likely many cases of similar issues arise, ill have to write my combat class for now :]
in general the bot should be aware of other things then just navmesh with regard to pathing decisions.
System.NullreferenceException in ConfigEditorWindow.xaml.cs #538:
foreach (IIdleAction x in AmeisenBot.Bot.IdleActions.IdleActions)
AmeisenBot object is null at this point when creating 'New Config'
For ranged classes the looting state passes faster then time needed to traverse to corpse, as such many loots are missed.
noticed my priest would not un-equip staff before equipping main-hand mace as upgrade
When I switched from the Grinding Engine to the questing engine, it didnt switch. I needed to pause and unpause the bot first.
Additionally to the eat until there should be an eat when
<HintPath>..\dep\AnTCP.Client.dll</HintPath>
However the only file present is AnTCP.Client.1.0.0.nupkg which i had to restore manually to be able to build.
Some additional questions:
It would be nice to have overlays for thing which are hard to debug from logs like positioning/facing/line of sight.
So what id love to see would be overlays for :
Circle to represent interaction sizes which often don't match model size.
Angles
Position
Rays to see if something is in line of sight or not
Bounding boxes
This issue serves as repository for all issues relating to bot being stuck unable to proceed without human intervention.
All such issues should be described here.
The generic stuck problem template:
Evidence?
Happens during execution of a profile?
If so, When during execution of a profile stuck occurs?
Can stuckness be resolved by existing unstuck routine?
If NOT so, Can stuckness be resolved by alternative unstuck routine?
Is the stuckness related to pathing/traversing only?
If NOT so, What kind of activities contribute to getting stuck?
Problem description:
Client-sided workaround possible?
If so, What kind of client patch solves the problem?
Further notes:
Currently only the MiningProfile implements mailing, but this should really be a state
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.