Apoc
Well-Known Member
- Joined
- Jan 16, 2010
- Messages
- 2,790
- Reaction score
- 94
Over the months (years?) there have been a lot of developers in this community, who aren't quite "learned" in the ways of Honorbuddy code-execution within WoW. This post is simply some explanations, common pitfalls, and workarounds to ensure things don't go bonkers, and you're not running into excessive performance issues.
Note: Most of the code in this post will be beyond most beginner level programmers. If you don't understand it, don't worry, you will eventually. I will not be going in-depth into language/CLR specific features that the code takes advantage of. (Nor will I be explaining coding methodologies or theories)
How Injection Without Injecting Works
First of all, Honorbuddy itself does NOT inject any libraries into WoW. Ever.
Without going into too many internal details, Honorbuddy is able to execute a code stub every "frame" in game. (Typically 30-60 times per second) The usual things we will inject for, are things that perform actions (such as casting a spell, any form of Lua interaction, TraceLine, click to move, etc.).
This means, we can only execute *one* thing per-frame. For example:
The above code (which would call "TraceLine") would take 30 frames to execute. (On a 30fps client, thats roughly 1 second [actually more])
Thats the basic explanation of how things work as far as injecting, without injecting.
Common Pitfalls
There are a lot of developers out there, that will do something like the following:
Note: The above code is more or less example code. There is no Lua API called "GetAuraCount"!
The above code will take "numBuffs" frames to execute, which is obviously going to be incredibly slow, and potentially lock the client, or HB up in the process.
The same goes for basically any loop that calls a method that deals with injection.
How to Execute In a Single Frame
A long time ago, we introduced the idea of a "FrameLock", which would in essence, lock the frame and allow you to execute as much stuff as you want, without allowing WoW to render another frame. This becomes *incredibly* powerful when dealing with loops of injections.
The above code will now execute the full loop, in a single frame. (And far, far faster)
Keep in mind, FrameLock's are ref counted. The frame will not be released until ALL locks have been disposed. (So you are safe to nest a bunch of FrameLocks without any repercussions.)
API That Injects
If you have any questions, comments, or suggestions to clean the post up, please feel free to comment.
I'll try and keep this thread updated as new things are added.
Note: Most of the code in this post will be beyond most beginner level programmers. If you don't understand it, don't worry, you will eventually. I will not be going in-depth into language/CLR specific features that the code takes advantage of. (Nor will I be explaining coding methodologies or theories)
How Injection Without Injecting Works
First of all, Honorbuddy itself does NOT inject any libraries into WoW. Ever.
Without going into too many internal details, Honorbuddy is able to execute a code stub every "frame" in game. (Typically 30-60 times per second) The usual things we will inject for, are things that perform actions (such as casting a spell, any form of Lua interaction, TraceLine, click to move, etc.).
This means, we can only execute *one* thing per-frame. For example:
PHP:
for(int i = 0; i < 30; i++)
CallTraceLine();
The above code (which would call "TraceLine") would take 30 frames to execute. (On a 30fps client, thats roughly 1 second [actually more])
Thats the basic explanation of how things work as far as injecting, without injecting.
Common Pitfalls
There are a lot of developers out there, that will do something like the following:
PHP:
int numBuffs = Lua.GetReturnVal<int>("return GetAuraCount('player')", 0);
for (int i = 1; i <= numBuffs; i++)
{
Logging.Write(Lua.GetReturnVal<string>("return UnitAura('player', " + i + ")", 0));
}
Note: The above code is more or less example code. There is no Lua API called "GetAuraCount"!
The above code will take "numBuffs" frames to execute, which is obviously going to be incredibly slow, and potentially lock the client, or HB up in the process.
The same goes for basically any loop that calls a method that deals with injection.
How to Execute In a Single Frame
A long time ago, we introduced the idea of a "FrameLock", which would in essence, lock the frame and allow you to execute as much stuff as you want, without allowing WoW to render another frame. This becomes *incredibly* powerful when dealing with loops of injections.
PHP:
using (new FrameLock())
{
int numBuffs = Lua.GetReturnVal<int>("return GetAuraCount('player')", 0);
for (int i = 1; i <= numBuffs; i++)
{
Logging.Write(Lua.GetReturnVal<string>("return UnitAura('player', " + i + ")", 0));
}
}
The above code will now execute the full loop, in a single frame. (And far, far faster)
Keep in mind, FrameLock's are ref counted. The frame will not be released until ALL locks have been disposed. (So you are safe to nest a bunch of FrameLocks without any repercussions.)
API That Injects
- Anything that is within the "Lua" class.
- Anything in the "LuaEvents" class that performs an action.
- Anything in the "GameWorld" class.
- Anything in the "WoWMovement" class that executes an action. (This includes wrappers in the WoWObject class, and descendants)
- Anything having to do with the WoWCache class. (Injections are done to pull cache records)
- Others that are not mentioned. A general rule of thumb, if its something you think performs an action in game, or deals with Lua in any way, you can assume will be doing an injection.
If you have any questions, comments, or suggestions to clean the post up, please feel free to comment.
I'll try and keep this thread updated as new things are added.