fix stacks removed not triggering BUFF_REMOVED events and add additional state arg

This commit is contained in:
avitasia
2026-02-10 10:03:35 -08:00
parent d61c9ce0ed
commit a39ba6d2ce
7 changed files with 10012 additions and 10004 deletions
+9 -3
View File
@@ -257,13 +257,19 @@ All eight events pass the same parameters:
4. int stackCount - current stack count for the aura (1 for a new aura; 0 when fully removed)
5. int auraLevel - caster level for the aura from UnitFields.auraLevels (uint8 per slot, 48 entries)
6. int auraSlot - the raw 0-based aura slot index (0-31 for buffs, 32-47 for debuffs). This is the raw internal slot, not the Lua slot. Consistent with unit data fields, GetPlayerAuraDuration, and BUFF/DEBUFF_UPDATE_DURATION_SELF events.
7. int state - indicates why the event fired: `0` = newly added, `1` = newly removed, `2` = modified (stack change). When state is `2`, the event type (*_ADDED_* or *_REMOVED_*) reflects whether stacks increased or decreased.
Buff stack gains also fire the appropriate *_ADDED_* events.
Stack changes also fire the appropriate *_ADDED_* or *_REMOVED_* events (not just new applications). When stacks increase, the corresponding *_ADDED_* event fires; when stacks decrease, the corresponding *_REMOVED_* event fires.
Example:
```
local function onAuraEvent(eventName, guid, luaSlot, spellId, stacks, auraLevel, auraSlot)
DEFAULT_CHAT_FRAME:AddMessage(string.format("[%s] %s luaSlot=%d spell=%d stacks=%d level=%d auraSlot=%d", eventName, guid, luaSlot, spellId, stacks, auraLevel, auraSlot))
local AURA_STATE_ADDED = 0
local AURA_STATE_REMOVED = 1
local AURA_STATE_MODIFIED = 2
local function onAuraEvent(eventName, guid, luaSlot, spellId, stacks, auraLevel, auraSlot, state)
local stateNames = { [0] = "added", [1] = "removed", [2] = "modified" }
DEFAULT_CHAT_FRAME:AddMessage(string.format("[%s] %s luaSlot=%d spell=%d stacks=%d level=%d auraSlot=%d state=%s", eventName, guid, luaSlot, spellId, stacks, auraLevel, auraSlot, stateNames[state] or "unknown"))
end
for _, eventName in ipairs({"BUFF_ADDED_SELF", "BUFF_REMOVED_SELF", "DEBUFF_ADDED_OTHER", "DEBUFF_REMOVED_OTHER"}) do
+9975 -9975
View File
File diff suppressed because it is too large Load Diff
+20 -18
View File
@@ -11,7 +11,8 @@ namespace Nampower {
uint32_t gAuraExpirationTime[MAX_AURA_SLOTS] = {};
// Helper function to trigger buff/debuff events
void TriggerAuraEvent(uintptr_t *unit, uint32_t slot, uint32_t spellId, bool wasAdded) {
// state: 0 = newly added, 1 = newly removed, 2 = modified (stack change)
void TriggerAuraEvent(uintptr_t *unit, uint32_t slot, uint32_t spellId, bool wasAdded, uint32_t state) {
// Determine if the unit is the active player (self) or another unit (other)
auto unitGuid = game::UnitGetGuid(unit);
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
@@ -29,7 +30,7 @@ namespace Nampower {
auto auraLevels = unitFields->auraLevels;
auto auraStacks = unitFields->auraApplications;
auto luaStacks = auraStacks[slot];
auto luaStacks = (state == 1) ? auraStacks[slot] : auraStacks[slot] + 1; // for some crazy reason the stack count is 0 indexed but also 0 instead of -1 when removed
if (isBuff) {
// count empty buff slots before slot to adjust luaSlot for actual buff/debuff index
@@ -42,8 +43,6 @@ namespace Nampower {
luaUnitSlot = luaUnitSlot - emptyCount;
if (wasAdded) {
luaStacks += 1; // count offset by 1
// Buff added
eventToTrigger = isSelf ? game::BUFF_ADDED_SELF : game::BUFF_ADDED_OTHER;
} else {
@@ -63,8 +62,6 @@ namespace Nampower {
luaUnitSlot = luaUnitSlot - emptyCount;
if (wasAdded) {
luaStacks += 1; // count offset by 1
// Debuff added
eventToTrigger = isSelf ? game::DEBUFF_ADDED_SELF : game::DEBUFF_ADDED_OTHER;
} else {
@@ -73,7 +70,7 @@ namespace Nampower {
}
}
static char format[] = "%s%d%d%d%d%d";
static char format[] = "%s%d%d%d%d%d%d";
char *guidStr = new char[21]; // 2 for 0x prefix, 18 for the number, and 1 for '\0'
if (isSelf) {
std::snprintf(guidStr, 21, "0x%016llX", static_cast<unsigned long long>(playerGuid));
@@ -82,7 +79,7 @@ namespace Nampower {
}
// Trigger the event with spellId as parameter
((int (__cdecl *)(int, char *, char *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)) Offsets::SignalEventParam)(
((int (__cdecl *)(int, char *, char *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)) Offsets::SignalEventParam)(
eventToTrigger,
format,
guidStr,
@@ -90,7 +87,8 @@ namespace Nampower {
spellId,
luaStacks,
auraLevels[slot],
slot);
slot,
state);
delete[] guidStr;
}
@@ -102,7 +100,7 @@ namespace Nampower {
// Call the original function
onAuraRemoved(unit, dummy_edx, slot, spellId);
TriggerAuraEvent(unit, slot, spellId, false);
TriggerAuraEvent(unit, slot, spellId, false, 1);
}
void CGUnit_C_OnAuraAddedHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, void *dummy_edx, uint32_t slot,
@@ -112,22 +110,26 @@ namespace Nampower {
// Call the original function
onAuraAdded(unit, dummy_edx, slot, spellId);
TriggerAuraEvent(unit, slot, spellId, true);
TriggerAuraEvent(unit, slot, spellId, true, 0);
}
void CGUnit_C_OnAuraAddedStackHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, int slot) {
auto const unitAuraAddedStack = detour->GetTrampolineT<CGUnit_C_OnAuraAddedStackT>();
// Call the original function
unitAuraAddedStack(unit, slot);
void CGUnit_C_OnAuraStacksChangedHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, void *dummy_edx, int slot, uint8_t stackCount) {
auto const onAuraStacksChanged = detour->GetTrampolineT<CGUnit_C_OnAuraStacksChangedT>();
// Get spell ID from the aura slot
auto *unitFields = *reinterpret_cast<game::UnitFields **>(unit + 68);
auto auras = unitFields->aura;
uint32_t spellId = auras[slot];
// Trigger the aura event for stack added
TriggerAuraEvent(unit, slot, spellId, true);
// Check if stacks increased or decreased (auraApplications is 0-indexed, convert to 1-indexed)
uint8_t currentStacks = unitFields->auraApplications[slot];
// Call the original function
onAuraStacksChanged(unit, dummy_edx, slot, stackCount);
bool wasAdded = stackCount < currentStacks;
TriggerAuraEvent(unit, slot, spellId, wasAdded, 2);
}
void CGBuffBar_UpdateDurationHook(hadesmem::PatchDetourBase *detour, uint8_t auraSlot, int durationMs) {
+2 -2
View File
@@ -14,13 +14,13 @@ namespace Nampower {
using CGUnit_C_OnAuraRemovedT = void (__fastcall *)(uintptr_t *unit, void *dummy_edx,uint32_t slot, uint32_t spellId);
using CGUnit_C_OnAuraAddedT = void (__fastcall *)(uintptr_t *unit, void *dummy_edx,uint32_t slot, uint32_t spellId);
using CGUnit_C_OnAuraAddedStackT = void (__fastcall *)(uintptr_t *unit, int slot);
using CGUnit_C_OnAuraStacksChangedT = void (__fastcall *)(uintptr_t *unit, void *dummy_edx, int slot, uint8_t stackCount);
using UnitCombatLogUnitDeadT = void (__fastcall *)(uint64_t guid);
using CGBuffBar_UpdateDurationT = void (__fastcall *)(uint8_t auraSlot, int durationMs);
void CGUnit_C_OnAuraRemovedHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, void *dummy_edx, uint32_t slot, uint32_t spellId);
void CGUnit_C_OnAuraAddedHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, void *dummy_edx, uint32_t slot, uint32_t spellId);
void CGUnit_C_OnAuraAddedStackHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, int slot);
void CGUnit_C_OnAuraStacksChangedHook(hadesmem::PatchDetourBase *detour, uintptr_t *unit, void *dummy_edx, int slot, uint8_t stackCount);
void UnitCombatLogUnitDeadHook(hadesmem::PatchDetourBase *detour, uint64_t guid);
void CGBuffBar_UpdateDurationHook(hadesmem::PatchDetourBase *detour, uint8_t auraSlot, int durationMs);
}
+4 -4
View File
@@ -146,7 +146,7 @@ namespace Nampower {
std::unique_ptr<hadesmem::PatchDetour<CGActionBar_UseActionT> > gCGActionBar_UseActionDetour;
std::unique_ptr<hadesmem::PatchDetour<CGUnit_C_OnAuraRemovedT> > gCGUnit_C_OnAuraRemovedDetour;
std::unique_ptr<hadesmem::PatchDetour<CGUnit_C_OnAuraAddedT> > gCGUnit_C_OnAuraAddedDetour;
std::unique_ptr<hadesmem::PatchDetour<CGUnit_C_OnAuraAddedStackT> > gCGUnit_C_OnAuraAddedStackDetour;
std::unique_ptr<hadesmem::PatchDetour<CGUnit_C_OnAuraStacksChangedT> > gCGUnit_C_OnAuraStacksChangedDetour;
std::unique_ptr<hadesmem::PatchDetour<UnitCombatLogUnitDeadT> > gUnitCombatLogUnitDeadDetour;
std::unique_ptr<hadesmem::PatchDetour<CGBuffBar_UpdateDurationT> > gCGBuffBar_UpdateDurationDetour;
@@ -1390,9 +1390,9 @@ namespace Nampower {
&CGUnit_C_OnAuraRemovedHook);
gCGUnit_C_OnAuraAddedDetour = createHook<CGUnit_C_OnAuraAddedT>(process, Offsets::CGUnit_C_OnAuraAdded,
&CGUnit_C_OnAuraAddedHook);
gCGUnit_C_OnAuraAddedStackDetour = createHook<CGUnit_C_OnAuraAddedStackT>(
process, Offsets::CGUnit_C_OnAuraAddedStack,
&CGUnit_C_OnAuraAddedStackHook);
gCGUnit_C_OnAuraStacksChangedDetour = createHook<CGUnit_C_OnAuraStacksChangedT>(
process, Offsets::CGUnit_C_OnAuraStacksChanged,
&CGUnit_C_OnAuraStacksChangedHook);
gUnitCombatLogUnitDeadDetour = createHook<UnitCombatLogUnitDeadT>(process, Offsets::UnitCombatLogUnitDead,
&UnitCombatLogUnitDeadHook);
gCGBuffBar_UpdateDurationDetour = createHook<CGBuffBar_UpdateDurationT>(process, Offsets::CGBuffBar_UpdateDuration,
+1 -1
View File
@@ -25,7 +25,7 @@ namespace Nampower {
constexpr uint32_t DISENCHANT_QUALITY_PURPLE = 0x04; // Epic
constexpr uint32_t MAJOR_VERSION = 2;
constexpr uint32_t MINOR_VERSION = 31;
constexpr uint32_t MINOR_VERSION = 32;
constexpr uint32_t PATCH_VERSION = 0;
constexpr int32_t LUA_REGISTRYINDEX = -10000;
+1 -1
View File
@@ -205,7 +205,7 @@ enum class Offsets : std::uint32_t {
CanInspectUnit = 0x004944a0,
CGUnit_C_OnAuraRemoved = 0x00612320,
CGUnit_C_OnAuraAdded = 0x006123f0,
CGUnit_C_OnAuraAddedStack = 0x0062b800,
CGUnit_C_OnAuraStacksChanged = 0x00612450,
UnitCombatLogUnitDead = 0x0062c160,
CGUnitGetUnitName = 0x00609210,
CGUnitCanAttack = 0x00606980,