mirror of
https://github.com/brues-code/nampower.git
synced 2026-10-08 14:40:02 +00:00
- Fix table references when reloading ui or logging out
- Block mounting when buff capped (can disable with NP_PreventMountingWhenBuffCapped) - add some additional information to GetTrinkets
This commit is contained in:
@@ -87,12 +87,16 @@ SET NP_TargetingQueueWindowMs "1000"
|
||||
|
||||
- `NP_PreventRightClickTargetChange` - Whether to prevent right-clicking from changing your current target when in combat. If you don't have a target right click will still change your target even with this on. This is mainly to prevent accidentally changing targets in combat when trying to adjust your camera. 0 to disable, 1 to enable. Default is 0.
|
||||
|
||||
- `NP_PreventRightClickPvPAttack` - Whether to prevent right-clicking on PvP flagged players to avoid accidental PvP attacks. 0 to disable, 1 to enable. Default is 1.
|
||||
- `NP_PreventRightClickPvPAttack` - Whether to prevent right-clicking on PvP flagged players to avoid accidental PvP attacks. 0 to disable, 1 to enable. Default is 0.
|
||||
|
||||
- `NP_DoubleCastToEndChannelEarly` - Whether to allow double casting a spell within 350ms to end channeling on the next tick. Takes into account your ChannelLatencyReductionPercentage. 0 to disable, 1 to enable. Default is 0.
|
||||
|
||||
- `NP_SpamProtectionEnabled` - Whether to enable spam protection functionality that blocks spamming spells while waiting for the server to respond to your initial cast due to issues spamming can cause. 0 to disable, 1 to enable. Default is 1.
|
||||
|
||||
- `NP_PreventMountingWhenBuffCapped` - Whether to prevent mounting when you have 32 buffs (buff capped) and are not already mounted. This prevents the issue where you mount but cannot dismount because the mount aura fails to apply due to the buff cap. When blocked, displays an error message. 0 to disable, 1 to enable. Default is 1.
|
||||
|
||||
- `NP_EnableAuraCastEvents` - Whether to enable AURA_CAST_ON_SELF and AURA_CAST_ON_OTHER events. 0 to disable, 1 to enable. Default is 0.
|
||||
|
||||
- `NP_ChannelLatencyReductionPercentage` - The percentage of your latency to subtract from the end of a channel duration to optimize cast time while hopefully not losing any ticks (more explanation below). Default is 75.
|
||||
|
||||
- `NP_NameplateDistance` - The distance in yards to display nameplates. Defaults to whatever was set by the game or vanilla tweaks.
|
||||
@@ -131,7 +135,7 @@ This includes functions for:
|
||||
|
||||
Cooldown detail tables now also expose `itemId`, `itemHasActiveSpell`, and `itemActiveSpellId` alongside the existing per-category timing data.
|
||||
|
||||
Use `GetTrinkets([copy])` to enumerate equipped trinkets and bagged trinkets (backpack/bags 1-4) with `itemId`, `trinketName`, `bagIndex` (nil when equipped), and 1-based `slotIndex`. It reuses cached tables by default; pass `1` (or any truthy value) to force a fresh copy.
|
||||
Use `GetTrinkets([copy])` to enumerate equipped trinkets and bagged trinkets (backpack/bags 1-4) with `itemId`, `trinketName`, `texture`, `itemLevel`, `bagIndex` (nil when equipped), and 1-based `slotIndex`. It reuses cached tables by default; pass `1` (or any truthy value) to force a fresh copy.
|
||||
|
||||
## Custom Events
|
||||
|
||||
|
||||
+40
-39
@@ -223,34 +223,6 @@ UseItemIdOrName("Hearthstone")
|
||||
UseItemIdOrName(13446, "player")
|
||||
```
|
||||
|
||||
#### UseTrinket(slot|itemIdOrName, [target])
|
||||
Uses a trinket from the equipped trinket slots (13 and 14 only).
|
||||
|
||||
**Parameters:**
|
||||
- `slot|itemIdOrName` (number|string):
|
||||
- `1` or `13` => use first trinket slot
|
||||
- `2` or `14` => use second trinket slot
|
||||
- Any other number => treat as item ID to find in trinket slots
|
||||
- String => item name (case-insensitive) to find in trinket slots
|
||||
- `target` (optional, string|number): Unit token or GUID. If omitted, uses `LockedTargetGuid` if set; otherwise falls back to active player GUID.
|
||||
|
||||
**Returns:**
|
||||
- `1` if the trinket was found and `CGItem_C::Use(...)` returned non-zero
|
||||
- `0` if the trinket was found but use returned zero
|
||||
- `-1` if no matching trinket was found in slots 13/14
|
||||
|
||||
**Examples:**
|
||||
```lua
|
||||
-- Use first trinket slot
|
||||
UseTrinket(1)
|
||||
-- Use second trinket slot on current target
|
||||
UseTrinket(2, "target")
|
||||
-- Use by item id if present in either trinket slot
|
||||
UseTrinket(18406)
|
||||
-- Use by name
|
||||
UseTrinket("Royal Seal of Eldre'Thalas")
|
||||
```
|
||||
|
||||
#### GetEquippedItems(unitToken)
|
||||
Returns a table reference containing all equipped items for the specified unit.
|
||||
|
||||
@@ -787,6 +759,24 @@ else
|
||||
end
|
||||
```
|
||||
|
||||
#### GetTrinkets([copy])
|
||||
Returns a table of trinkets from equipped trinket slots and carried bags.
|
||||
|
||||
**Parameters:**
|
||||
- `[copy]` (number|boolean, optional): Pass `1` (or any truthy value) to force creation of a fresh Lua table. By default the function reuses an internal table and entry tables for performance.
|
||||
|
||||
**Returns:**
|
||||
A Lua table where each entry contains:
|
||||
- `itemId` (number)
|
||||
- `trinketName` (string, `"Unknown"` if no name available)
|
||||
- `texture` (string): Texture name for the item icon
|
||||
- `bagIndex` (number|nil): `nil` when equipped; `0` for backpack; `1-4` for equipped bags
|
||||
- `slotIndex` (number): Lua 1-based slot within the container (or 1/2 for equipped trinket slots)
|
||||
|
||||
**Notes:**
|
||||
- Scans only equipped trinket slots and bags 0-4 (backpack + equipped bags). Does not scan bank or keyring.
|
||||
- Reuses cached Lua tables unless `copyTable` is truthy; prefer copies if you will mutate the returned tables.
|
||||
-
|
||||
#### GetTrinketCooldown(slot|itemIdOrName)
|
||||
Returns cooldown information for the equipped trinket(s) in slots 13 or 14. Accepts slot shortcuts or item identifiers.
|
||||
|
||||
@@ -816,22 +806,33 @@ if cd ~= -1 then
|
||||
end
|
||||
```
|
||||
|
||||
#### GetTrinkets([copy])
|
||||
Returns a table of trinkets from equipped trinket slots and carried bags.
|
||||
#### UseTrinket(slot|itemIdOrName, [target])
|
||||
Uses a trinket from the equipped trinket slots (13 and 14 only).
|
||||
|
||||
**Parameters:**
|
||||
- `[copy]` (number|boolean, optional): Pass `1` (or any truthy value) to force creation of a fresh Lua table. By default the function reuses an internal table and entry tables for performance.
|
||||
- `slot|itemIdOrName` (number|string):
|
||||
- `1` or `13` => use first trinket slot
|
||||
- `2` or `14` => use second trinket slot
|
||||
- Any other number => treat as item ID to find in trinket slots
|
||||
- String => item name (case-insensitive) to find in trinket slots
|
||||
- `target` (optional, string|number): Unit token or GUID. If omitted, uses `LockedTargetGuid` if set; otherwise falls back to active player GUID.
|
||||
|
||||
**Returns:**
|
||||
A Lua table where each entry contains:
|
||||
- `itemId` (number)
|
||||
- `trinketName` (string, `"Unknown"` if no name available)
|
||||
- `bagIndex` (number|nil): `nil` when equipped; `0` for backpack; `1-4` for equipped bags
|
||||
- `slotIndex` (number): Lua 1-based slot within the container (or 1/2 for equipped trinket slots)
|
||||
- `1` if the trinket was found and `CGItem_C::Use(...)` returned non-zero
|
||||
- `0` if the trinket was found but use returned zero
|
||||
- `-1` if no matching trinket was found in slots 13/14
|
||||
|
||||
**Notes:**
|
||||
- Scans only equipped trinket slots and bags 0-4 (backpack + equipped bags). Does not scan bank or keyring.
|
||||
- Reuses cached Lua tables unless `copyTable` is truthy; prefer copies if you will mutate the returned tables.
|
||||
**Examples:**
|
||||
```lua
|
||||
-- Use first trinket slot
|
||||
UseTrinket(1)
|
||||
-- Use second trinket slot on current target
|
||||
UseTrinket(2, "target")
|
||||
-- Use by item id if present in either trinket slot
|
||||
UseTrinket(18406)
|
||||
-- Use by name
|
||||
UseTrinket("Royal Seal of Eldre'Thalas")
|
||||
```
|
||||
|
||||
#### GetSpellIdForName(spellName)
|
||||
Returns:
|
||||
|
||||
+10962
-10932
File diff suppressed because it is too large
Load Diff
@@ -38,6 +38,8 @@ set(SOURCE_FILES
|
||||
unit_fields.cpp
|
||||
auras.hpp
|
||||
auras.cpp
|
||||
lua_refs.hpp
|
||||
lua_refs.cpp
|
||||
)
|
||||
|
||||
add_library(${DLL_NAME} SHARED ${SOURCE_FILES})
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "helper.hpp"
|
||||
#include "game.hpp"
|
||||
#include "items.hpp"
|
||||
#include "lua_refs.hpp"
|
||||
#include "offsets.hpp"
|
||||
|
||||
#include <cstring>
|
||||
@@ -192,11 +193,7 @@ namespace Nampower {
|
||||
static char isOnGcdCategoryCooldownKey[] = "isOnGcdCategoryCooldown";
|
||||
|
||||
// Get or create reusable table
|
||||
if (cooldownDetailTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
cooldownDetailTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, cooldownDetailTableRef);
|
||||
GetTableRef(luaState, cooldownDetailTableRef);
|
||||
|
||||
// Overall cooldown status
|
||||
PushTableValue(luaState, isOnCooldownKey, detail.isOnCooldown ? 1 : 0);
|
||||
@@ -376,4 +373,5 @@ namespace Nampower {
|
||||
PushCooldownDetailTable(luaState, cooldown);
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "main.hpp"
|
||||
#include "lua_refs.hpp"
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
@@ -151,13 +152,7 @@ namespace Nampower {
|
||||
lua_pushstring(luaState, const_cast<char*>(field.name));
|
||||
|
||||
// Get or create reusable table for this specific field name
|
||||
auto refIt = refMap.find(field.name);
|
||||
if (refIt == refMap.end()) {
|
||||
lua_newtable(luaState);
|
||||
int ref = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
refMap[field.name] = ref;
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, refMap[field.name]);
|
||||
GetTableRef(luaState, refMap[field.name]);
|
||||
|
||||
const char* fieldPtr = reinterpret_cast<const char*>(obj) + field.offset;
|
||||
|
||||
|
||||
@@ -196,4 +196,55 @@ namespace game {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool UnitIsBuffCapped(uintptr_t *unit) {
|
||||
if (!unit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *unitFields = *reinterpret_cast<UnitFields **>(unit + 68);
|
||||
if (!unitFields) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 31; i >= 0; --i) {
|
||||
if (unitFields->aura[i] == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnitIsDebuffCapped(uintptr_t *unit) {
|
||||
if (!unit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *unitFields = *reinterpret_cast<UnitFields **>(unit + 68);
|
||||
if (!unitFields) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 47; i >= 32; --i) {
|
||||
if (unitFields->aura[i] == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t UnitGetMountDisplayId(uintptr_t *unit) {
|
||||
if (!unit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto *unitFields = *reinterpret_cast<UnitFields **>(unit + 68);
|
||||
if (!unitFields) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return unitFields->mountDisplayId;
|
||||
}
|
||||
}
|
||||
@@ -1666,4 +1666,10 @@ namespace game {
|
||||
bool UnitIsPvpFlagged(uintptr_t *unit);
|
||||
|
||||
bool UnitIsInCombat(uintptr_t *unit);
|
||||
|
||||
bool UnitIsBuffCapped(uintptr_t *unit);
|
||||
|
||||
bool UnitIsDebuffCapped(uintptr_t *unit);
|
||||
|
||||
uint32_t UnitGetMountDisplayId(uintptr_t *unit);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace Nampower {
|
||||
// Lua function pointers
|
||||
lua_errorT lua_error = reinterpret_cast<lua_errorT>(Offsets::lua_error);
|
||||
lua_gettopT lua_gettop = reinterpret_cast<lua_gettopT>(Offsets::lua_gettop);
|
||||
lua_settopT lua_settop = reinterpret_cast<lua_settopT>(Offsets::lua_settop);
|
||||
lua_typeT lua_type = reinterpret_cast<lua_typeT>(Offsets::lua_type);
|
||||
lua_isstringT lua_isstring = reinterpret_cast<lua_isstringT>(Offsets::lua_isstring);
|
||||
lua_isnumberT lua_isnumber = reinterpret_cast<lua_isnumberT>(Offsets::lua_isnumber);
|
||||
lua_tostringT lua_tostring = reinterpret_cast<lua_tostringT>(Offsets::lua_tostring);
|
||||
@@ -208,6 +210,15 @@ namespace Nampower {
|
||||
spell->Effect[0] == game::SpellEffects::SPELL_EFFECT_OPEN_LOCK_ITEM);
|
||||
}
|
||||
|
||||
bool SpellIsMounting(const game::SpellRec *spell) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (spell->Effect[i] == game::SPELL_EFFECT_APPLY_AURA && spell->EffectApplyAuraName[i] == 78) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the spell is off cooldown, this will return the gcd, otherwise the cooldown
|
||||
uint32_t GetGcdOrCooldownForSpell(uint32_t spellId) {
|
||||
uint32_t duration;
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Nampower {
|
||||
// Lua function pointers
|
||||
extern lua_errorT lua_error;
|
||||
extern lua_gettopT lua_gettop;
|
||||
extern lua_settopT lua_settop;
|
||||
extern lua_typeT lua_type;
|
||||
extern lua_isstringT lua_isstring;
|
||||
extern lua_isnumberT lua_isnumber;
|
||||
extern lua_tostringT lua_tostring;
|
||||
@@ -30,6 +32,15 @@ namespace Nampower {
|
||||
#define LUA_REFNIL (-2)
|
||||
#endif
|
||||
|
||||
#ifndef LUA_TTABLE
|
||||
#define LUA_TTABLE 5
|
||||
#endif
|
||||
|
||||
// Lua helper function - lua_istable implementation
|
||||
inline bool lua_istable(uintptr_t *luaState, int idx) {
|
||||
return lua_type(luaState, idx) == LUA_TTABLE;
|
||||
}
|
||||
|
||||
uint32_t GetSpellSlotAndTypeForName(const char *spellName, uint32_t *spellType);
|
||||
|
||||
uint32_t GetSpellIdFromSpellName(const char *spellName);
|
||||
@@ -46,6 +57,8 @@ namespace Nampower {
|
||||
|
||||
bool SpellIsAttackTradeskillOrEnchant(const game::SpellRec *spell);
|
||||
|
||||
bool SpellIsMounting(const game::SpellRec *spell);
|
||||
|
||||
bool IsTargetingTerrainSpell();
|
||||
|
||||
uint32_t GetGcdOrCooldownForSpell(uint32_t spellId);
|
||||
|
||||
+26
-42
@@ -3,6 +3,7 @@
|
||||
#include "helper.hpp"
|
||||
#include "items.hpp"
|
||||
#include "logging.hpp"
|
||||
#include "lua_refs.hpp"
|
||||
#include "offsets.hpp"
|
||||
|
||||
#include <string>
|
||||
@@ -35,6 +36,8 @@ namespace Nampower {
|
||||
static char bagIndexKey[] = "bagIndex";
|
||||
static char slotIndexKey[] = "slotIndex";
|
||||
static char trinketNameKey[] = "trinketName";
|
||||
static char textureKey[] = "texture";
|
||||
static char itemLevelKey[] = "itemLevel";
|
||||
|
||||
void PushItemFoundResult(uintptr_t *luaState, int32_t bagIndex, uint32_t slot) {
|
||||
uint32_t adjustedSlot = slot;
|
||||
@@ -57,11 +60,7 @@ namespace Nampower {
|
||||
}
|
||||
|
||||
// Get or create reusable table
|
||||
if (basicItemInfoTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
basicItemInfoTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, basicItemInfoTableRef);
|
||||
GetTableRef(luaState, basicItemInfoTableRef);
|
||||
|
||||
PushTableValue(luaState, itemIdKey, cgItem->itemId);
|
||||
PushTableValue(luaState, permanentEnchantIdKey, cgItem->permanentEnchantId);
|
||||
@@ -78,11 +77,7 @@ namespace Nampower {
|
||||
auto itemFields = item->itemFields;
|
||||
|
||||
// Get or create reusable table
|
||||
if (itemInfoTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
itemInfoTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, itemInfoTableRef);
|
||||
GetTableRef(luaState, itemInfoTableRef);
|
||||
|
||||
PushTableValue(luaState, itemIdKey, itemId);
|
||||
PushTableValue(luaState, stackCountKey, itemFields->stackCount);
|
||||
@@ -311,6 +306,7 @@ namespace Nampower {
|
||||
|
||||
auto const getBagItem = reinterpret_cast<CGBag_C_GetItemAtSlotT>(Offsets::CGBag_C_GetItemAtSlot);
|
||||
auto const getContainerGuid = reinterpret_cast<GetContainerGuidT>(Offsets::GetContainerGuid);
|
||||
auto const getInventoryArt = reinterpret_cast<GetInventoryArtT>(Offsets::CGItem_C_GetInventoryArt);
|
||||
|
||||
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
|
||||
auto playerUnit = game::GetObjectPtr(playerGuid);
|
||||
@@ -325,20 +321,10 @@ namespace Nampower {
|
||||
trinketEntryRefsInitialized = true;
|
||||
}
|
||||
|
||||
if (!copyTable && trinketsTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
trinketsTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
if (copyTable) {
|
||||
lua_newtable(luaState);
|
||||
} else {
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, trinketsTableRef);
|
||||
for (uint32_t i = 1; i <= lastTrinketCount; ++i) {
|
||||
lua_pushnumber(luaState, static_cast<double>(i));
|
||||
lua_pushnil(luaState);
|
||||
lua_settable(luaState, -3);
|
||||
}
|
||||
GetTableRef(luaState, trinketsTableRef);
|
||||
}
|
||||
|
||||
if (!playerUnit) {
|
||||
@@ -370,12 +356,7 @@ namespace Nampower {
|
||||
if (copyTable || luaIndex - 2 >= MAX_TRINKET_ENTRY_TABLES) {
|
||||
lua_newtable(luaState);
|
||||
} else {
|
||||
auto &entryRef = trinketEntryTableRefs[luaIndex - 2];
|
||||
if (entryRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
entryRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, entryRef);
|
||||
GetTableRef(luaState, trinketEntryTableRefs[luaIndex - 2]);
|
||||
}
|
||||
PushTableValue(luaState, itemIdKey, itemId);
|
||||
if (bagIndex == EQUIPPED_BAG_INDEX) {
|
||||
@@ -388,6 +369,20 @@ namespace Nampower {
|
||||
PushTableValue(luaState, slotIndexKey, luaSlot);
|
||||
const char *trinketName = itemStats->m_displayName[0] ? itemStats->m_displayName[0] : "Unknown";
|
||||
PushTableValue(luaState, trinketNameKey, trinketName);
|
||||
PushTableValue(luaState, itemLevelKey, itemStats->m_itemLevel);
|
||||
|
||||
// Get texture path using display ID
|
||||
if (itemStats && itemStats->m_displayInfoID > 0) {
|
||||
char *texturePath = getInventoryArt(itemStats->m_displayInfoID);
|
||||
if (texturePath && texturePath[0] != '\0') {
|
||||
PushTableValue(luaState, textureKey, texturePath);
|
||||
} else {
|
||||
PushTableValue(luaState, textureKey, reinterpret_cast<const char *>(Offsets::InvQuestionMark));
|
||||
}
|
||||
} else {
|
||||
PushTableValue(luaState, textureKey, reinterpret_cast<const char *>(Offsets::InvQuestionMark));
|
||||
}
|
||||
|
||||
lua_settable(luaState, -3);
|
||||
};
|
||||
|
||||
@@ -457,11 +452,7 @@ namespace Nampower {
|
||||
}
|
||||
|
||||
// Get or create reusable table
|
||||
if (equippedItemsTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
equippedItemsTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, equippedItemsTableRef);
|
||||
GetTableRef(luaState, equippedItemsTableRef);
|
||||
|
||||
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
|
||||
bool isPlayer = (guid == playerGuid);
|
||||
@@ -700,11 +691,7 @@ namespace Nampower {
|
||||
auto const getBagItem = reinterpret_cast<CGBag_C_GetItemAtSlotT>(Offsets::CGBag_C_GetItemAtSlot);
|
||||
|
||||
// Get or create reusable table
|
||||
if (bagItemsTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
bagItemsTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, bagItemsTableRef);
|
||||
GetTableRef(luaState, bagItemsTableRef);
|
||||
|
||||
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
|
||||
auto player = game::GetObjectPtr(playerGuid);
|
||||
@@ -713,11 +700,7 @@ namespace Nampower {
|
||||
lua_pushnumber(luaState, static_cast<double>(0));
|
||||
|
||||
// Get or create reusable bag table
|
||||
if (bagTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
bagTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, bagTableRef);
|
||||
GetTableRef(luaState, bagTableRef);
|
||||
|
||||
for (uint32_t slot = 23; slot <= 38; slot++) {
|
||||
auto item = getBagItem(inventory, slot);
|
||||
@@ -782,4 +765,5 @@ namespace Nampower {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -512,4 +512,10 @@ namespace Nampower {
|
||||
|
||||
DEBUG_LOG("Export initialized. ProcessItemExport will be called each frame from processQueues.");
|
||||
}
|
||||
|
||||
void StartItemExport() {
|
||||
isExporting = true;
|
||||
currentExportItemId = 1;
|
||||
pendingItemIds.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Nampower {
|
||||
|
||||
using DBCache_ItemCacheDBGetRowT = uint32_t * (__thiscall *)(void *this_ptr, uint32_t itemId, uint64_t *guid, TooltipItemStatsCallbackT callback, uintptr_t *userData, bool requestIfMissing);
|
||||
|
||||
using GetInventoryArtT = char * (__fastcall *)(uint32_t displayId);
|
||||
|
||||
constexpr int32_t EQUIPPED_BAG_INDEX = -3;
|
||||
constexpr int32_t BANK_BAG_INDEX = -1;
|
||||
constexpr int32_t KEYRING_BAG_INDEX = -2;
|
||||
@@ -24,6 +26,7 @@ namespace Nampower {
|
||||
};
|
||||
|
||||
void ExportAllItems();
|
||||
void StartItemExport();
|
||||
bool LoadItem(uint32_t itemId); // Returns true if item needs async load (caller should wait)
|
||||
bool ProcessItemExport(); // Process one item export per frame, returns true if still exporting
|
||||
game::ItemStats_C* GetItemStats(uint32_t itemId);
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "lua_refs.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "logging.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace Nampower {
|
||||
// Vector to store pointers to all registered table refs
|
||||
static std::vector<int*> registeredTableRefs;
|
||||
|
||||
void RegisterTableRef(int* tableRefPtr) {
|
||||
// Only register if not already in the list
|
||||
for (auto ref : registeredTableRefs) {
|
||||
if (ref == tableRefPtr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
registeredTableRefs.push_back(tableRefPtr);
|
||||
}
|
||||
|
||||
void GetTableRef(uintptr_t* luaState, int& tableRef) {
|
||||
// Create table if needed and push onto stack
|
||||
if (tableRef == LUA_REFNIL) {
|
||||
// Register this table ref if it's a new one
|
||||
RegisterTableRef(&tableRef);
|
||||
|
||||
lua_newtable(luaState);
|
||||
tableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, tableRef);
|
||||
}
|
||||
|
||||
void CleanupAllLuaTableRefs() {
|
||||
DEBUG_LOG("Clearing all LUA table references");
|
||||
for (auto tableRefPtr : registeredTableRefs) {
|
||||
*tableRefPtr = LUA_REFNIL;
|
||||
}
|
||||
registeredTableRefs.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Created for Lua table reference management
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Nampower {
|
||||
// Register a table ref to be cleaned up on shutdown
|
||||
void RegisterTableRef(int* tableRefPtr);
|
||||
|
||||
// Get or create a table reference (renamed from EnsureValidTableRef)
|
||||
void GetTableRef(uintptr_t* luaState, int& tableRef);
|
||||
|
||||
// Cleanup all registered table refs
|
||||
void CleanupAllLuaTableRefs();
|
||||
}
|
||||
+88
-101
@@ -42,6 +42,7 @@
|
||||
#include "cooldown_scripts.hpp"
|
||||
#include "item_scripts.hpp"
|
||||
#include "auras.hpp"
|
||||
#include "lua_refs.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
@@ -145,8 +146,11 @@ namespace Nampower {
|
||||
|
||||
// Forward declarations for hook functions
|
||||
void LoadScriptFunctionsHook(hadesmem::PatchDetourBase *detour);
|
||||
|
||||
void FrameScript_CreateEventsHook(hadesmem::PatchDetourBase *detour, int param_1, uint32_t maxEventId);
|
||||
void Framescript_SetEventCountHook(hadesmem::PatchDetourBase *detour, void *thisPtr, void *dummy_edx, uint32_t count);
|
||||
|
||||
void Framescript_SetEventCountHook(hadesmem::PatchDetourBase *detour, void *thisPtr, void *dummy_edx,
|
||||
uint32_t count);
|
||||
|
||||
uint32_t GetTime() {
|
||||
return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
@@ -643,6 +647,9 @@ namespace Nampower {
|
||||
} else if (strcmp(cvar, "NP_EnableAuraCastEvents") == 0) {
|
||||
gUserSettings.enableAuraCastEvents = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_EnableAuraCastEvents to " << gUserSettings.enableAuraCastEvents);
|
||||
} else if (strcmp(cvar, "NP_PreventMountingWhenBuffCapped") == 0) {
|
||||
gUserSettings.preventMountingWhenBuffCapped = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_PreventMountingWhenBuffCapped to " << gUserSettings.preventMountingWhenBuffCapped);
|
||||
} else if (strcmp(cvar, "NP_MinBufferTimeMs") == 0) {
|
||||
gUserSettings.minBufferTimeMs = atoi(value);
|
||||
DEBUG_LOG("Set NP_MinBufferTimeMs and current buffer to " << gUserSettings.minBufferTimeMs);
|
||||
@@ -761,42 +768,6 @@ namespace Nampower {
|
||||
|
||||
DEBUG_LOG("Loading nampower v" << MAJOR_VERSION << "." << MINOR_VERSION << "." << PATCH_VERSION);
|
||||
|
||||
// default values
|
||||
gUserSettings.queueCastTimeSpells = true;
|
||||
gUserSettings.queueInstantSpells = true;
|
||||
gUserSettings.queueChannelingSpells = true;
|
||||
gUserSettings.queueTargetingSpells = true;
|
||||
gUserSettings.queueOnSwingSpells = false;
|
||||
gUserSettings.queueSpellsOnCooldown = true;
|
||||
|
||||
gUserSettings.interruptChannelsOutsideQueueWindow = false;
|
||||
|
||||
gUserSettings.retryServerRejectedSpells = true;
|
||||
gUserSettings.quickcastTargetingSpells = false;
|
||||
gUserSettings.replaceMatchingNonGcdCategory = false;
|
||||
gUserSettings.optimizeBufferUsingPacketTimings = false;
|
||||
|
||||
gUserSettings.preventRightClickTargetChange = false;
|
||||
gUserSettings.preventRightClickPvPAttack = true;
|
||||
|
||||
gUserSettings.doubleCastToEndChannelEarly = false;
|
||||
gUserSettings.quickcastOnDoubleCast = false;
|
||||
|
||||
gUserSettings.spamProtectionEnabled = true;
|
||||
gUserSettings.enableAuraCastEvents = false;
|
||||
|
||||
gUserSettings.minBufferTimeMs = 55; // time in ms to buffer cast to minimize server failure
|
||||
gUserSettings.nonGcdBufferTimeMs = 100; // time in ms to buffer non-GCD spells to minimize server failure
|
||||
gUserSettings.maxBufferIncreaseMs = 30;
|
||||
|
||||
gUserSettings.spellQueueWindowMs = 500; // time in ms before cast to allow queuing spells
|
||||
gUserSettings.onSwingBufferCooldownMs = 500; // time in ms to wait before queuing on swing spell after a swing
|
||||
gUserSettings.channelQueueWindowMs = 1500; // time in ms before channel ends to allow queuing spells
|
||||
gUserSettings.targetingQueueWindowMs = 500; // time in ms before cast to allow targeting
|
||||
gUserSettings.cooldownQueueWindowMs = 250; // time in ms before cooldown is up to allow queuing spells
|
||||
|
||||
gUserSettings.channelLatencyReductionPercentage = 75; // percent of latency to reduce channel time by
|
||||
|
||||
char defaultTrue[] = "1";
|
||||
char defaultFalse[] = "0";
|
||||
|
||||
@@ -977,6 +948,16 @@ namespace Nampower {
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_PreventMountingWhenBuffCapped[] = "NP_PreventMountingWhenBuffCapped";
|
||||
CVarRegister(NP_PreventMountingWhenBuffCapped, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
gUserSettings.preventMountingWhenBuffCapped ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_OnSwingBufferCooldownMs[] = "NP_OnSwingBufferCooldownMs";
|
||||
CVarRegister(NP_OnSwingBufferCooldownMs, // name
|
||||
nullptr, // help
|
||||
@@ -1103,6 +1084,7 @@ namespace Nampower {
|
||||
|
||||
loadUserVar("NP_SpamProtectionEnabled");
|
||||
loadUserVar("NP_EnableAuraCastEvents");
|
||||
loadUserVar("NP_PreventMountingWhenBuffCapped");
|
||||
|
||||
loadUserVar("NP_MinBufferTimeMs");
|
||||
loadUserVar("NP_NonGcdBufferTimeMs");
|
||||
@@ -1132,76 +1114,76 @@ namespace Nampower {
|
||||
}
|
||||
|
||||
void initHooks() {
|
||||
std::call_once(initHooksFlag, []() {
|
||||
const hadesmem::Process process(::GetCurrentProcessId());
|
||||
const hadesmem::Process process(::GetCurrentProcessId());
|
||||
|
||||
gSetCVarDetour = createHook<SetCVarT>(process, Offsets::Script_SetCVar, &Script_SetCVarHook);
|
||||
gCGSpellBook_CastSpellDetour = createHook<CGSpellBook_CastSpellT>(
|
||||
process, Offsets::CGSpellBook_CastSpell, &CGSpellBook_CastSpellHook);
|
||||
gCGActionBar_UseActionDetour = createHook<CGActionBar_UseActionT>(
|
||||
process, Offsets::CGActionBar_UseAction, &CGActionBar_UseActionHook);
|
||||
gCastDetour = createHook<CastSpellT>(process, Offsets::Spell_C_CastSpell, &Spell_C_CastSpellHook);
|
||||
gSendCastDetour = createHook<SendCastT>(process, Offsets::SendCast, &SendCastHook);
|
||||
gCancelSpellDetour = createHook<CancelSpellT>(process, Offsets::CancelSpell, &CancelSpellHook);
|
||||
gCastResultHandlerDetour = createHook<PacketHandlerT>(process, Offsets::CastResultHandler,
|
||||
&CastResultHandlerHook);
|
||||
gSpellStartHandlerDetour = createHook<FastCallPacketHandlerT>(process, Offsets::SpellStartHandler,
|
||||
&SpellStartHandlerHook);
|
||||
gPeriodicAuraLogHandlerDetour = createHook<FastCallPacketHandlerT>(process, Offsets::PeriodicAuraLogHandler,
|
||||
&PeriodicAuraLogHandlerHook);
|
||||
gSpellNonMeleeDmgLogHandlerDetour = createHook<FastCallPacketHandlerT>(process,
|
||||
Offsets::SpellNonMeleeDmgLogHandler,
|
||||
&SpellNonMeleeDmgLogHandlerHook);
|
||||
gSpellChannelStartHandlerDetour = createHook<PacketHandlerT>(process, Offsets::SpellChannelStartHandler,
|
||||
&SpellChannelStartHandlerHook);
|
||||
gSpellChannelUpdateHandlerDetour = createHook<PacketHandlerT>(process, Offsets::SpellChannelUpdateHandler,
|
||||
&SpellChannelUpdateHandlerHook);
|
||||
gSpellFailedDetour = createHook<Spell_C_SpellFailedT>(process, Offsets::Spell_C_SpellFailed,
|
||||
&Spell_C_SpellFailedHook);
|
||||
gSpellGoDetour = createHook<SpellGoT>(process, Offsets::SpellGo, &SpellGoHook);
|
||||
gSpellDelayedDetour = createHook<PacketHandlerT>(process, Offsets::SpellDelayed, &SpellDelayedHook);
|
||||
gSpellTargetUnitDetour = createHook<LuaScriptT>(process, Offsets::Script_SpellTargetUnit,
|
||||
&Script_SpellTargetUnitHook);
|
||||
gSpellStopCastingDetour = createHook<LuaScriptT>(process, Offsets::Script_SpellStopCasting,
|
||||
&Script_SpellStopCastingHook);
|
||||
gSpell_C_TargetSpellDetour = createHook<Spell_C_TargetSpellT>(process, Offsets::Spell_C_TargetSpell,
|
||||
&Spell_C_TargetSpellHook);
|
||||
gSpell_C_HandleTerrainClickDetour = createHook<Spell_C_HandleTerrainClickT>(
|
||||
process, Offsets::Spell_C_HandleTerrainClick,
|
||||
&Spell_C_HandleTerrainClickHook);
|
||||
gCGWorldFrame_OnLayerTrackTerrainDetour = createHook<CGWorldFrame_OnLayerTrackTerrainT>(
|
||||
process, Offsets::CGWorldFrame_OnLayerTrackTerrain,
|
||||
&CGWorldFrame_OnLayerTrackTerrainHook);
|
||||
gOnSpriteRightClickDetour = createHook<OnSpriteRightClickT>(process, Offsets::OnSpriteRightClick,
|
||||
OnSpriteRightClickHook);
|
||||
gIEndSceneDetour = createHook<ISceneEndT>(process, Offsets::ISceneEndPtr, &ISceneEndHook);
|
||||
gInvalidFunctionPtrCheckDetour = createHook<InvalidFunctionPtrCheckT>(process, Offsets::InvalidFunctionPtrCheck,
|
||||
&InvalidFunctionPtrCheckHook);
|
||||
gGetSpellSlotFromLuaDetour = createHook<GetSpellSlotFromLuaT>(process, Offsets::GetSpellSlotFromLua,
|
||||
&GetSpellSlotFromLuaHook);
|
||||
gCGUnit_C_OnAuraRemovedDetour = createHook<CGUnit_C_OnAuraRemovedT>(process, Offsets::CGUnit_C_OnAuraRemoved,
|
||||
&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);
|
||||
gUnitCombatLogUnitDeadDetour = createHook<UnitCombatLogUnitDeadT>(process, Offsets::UnitCombatLogUnitDead,
|
||||
&UnitCombatLogUnitDeadHook);
|
||||
gLoadScriptFunctionsDetour = createHook<LoadScriptFunctionsT>(process, Offsets::LoadScriptFunctions,
|
||||
&LoadScriptFunctionsHook);
|
||||
gCreateEventsDetour = createHook<FrameScript_CreateEventsT>(process, Offsets::FrameScript_CreateEvents,
|
||||
&FrameScript_CreateEventsHook);
|
||||
gSetEventCountDetour = createHook<FramescriptSetEventCountT>(process, Offsets::Framescript_SetEventCount,
|
||||
&Framescript_SetEventCountHook);
|
||||
});
|
||||
gSetCVarDetour = createHook<SetCVarT>(process, Offsets::Script_SetCVar, &Script_SetCVarHook);
|
||||
gCGSpellBook_CastSpellDetour = createHook<CGSpellBook_CastSpellT>(
|
||||
process, Offsets::CGSpellBook_CastSpell, &CGSpellBook_CastSpellHook);
|
||||
gCGActionBar_UseActionDetour = createHook<CGActionBar_UseActionT>(
|
||||
process, Offsets::CGActionBar_UseAction, &CGActionBar_UseActionHook);
|
||||
gCastDetour = createHook<CastSpellT>(process, Offsets::Spell_C_CastSpell, &Spell_C_CastSpellHook);
|
||||
gSendCastDetour = createHook<SendCastT>(process, Offsets::SendCast, &SendCastHook);
|
||||
gCancelSpellDetour = createHook<CancelSpellT>(process, Offsets::CancelSpell, &CancelSpellHook);
|
||||
gCastResultHandlerDetour = createHook<PacketHandlerT>(process, Offsets::CastResultHandler,
|
||||
&CastResultHandlerHook);
|
||||
gSpellStartHandlerDetour = createHook<FastCallPacketHandlerT>(process, Offsets::SpellStartHandler,
|
||||
&SpellStartHandlerHook);
|
||||
gPeriodicAuraLogHandlerDetour = createHook<FastCallPacketHandlerT>(process, Offsets::PeriodicAuraLogHandler,
|
||||
&PeriodicAuraLogHandlerHook);
|
||||
gSpellNonMeleeDmgLogHandlerDetour = createHook<FastCallPacketHandlerT>(process,
|
||||
Offsets::SpellNonMeleeDmgLogHandler,
|
||||
&SpellNonMeleeDmgLogHandlerHook);
|
||||
gSpellChannelStartHandlerDetour = createHook<PacketHandlerT>(process, Offsets::SpellChannelStartHandler,
|
||||
&SpellChannelStartHandlerHook);
|
||||
gSpellChannelUpdateHandlerDetour = createHook<PacketHandlerT>(process, Offsets::SpellChannelUpdateHandler,
|
||||
&SpellChannelUpdateHandlerHook);
|
||||
gSpellFailedDetour = createHook<Spell_C_SpellFailedT>(process, Offsets::Spell_C_SpellFailed,
|
||||
&Spell_C_SpellFailedHook);
|
||||
gSpellGoDetour = createHook<SpellGoT>(process, Offsets::SpellGo, &SpellGoHook);
|
||||
gSpellDelayedDetour = createHook<PacketHandlerT>(process, Offsets::SpellDelayed, &SpellDelayedHook);
|
||||
gSpellTargetUnitDetour = createHook<LuaScriptT>(process, Offsets::Script_SpellTargetUnit,
|
||||
&Script_SpellTargetUnitHook);
|
||||
gSpellStopCastingDetour = createHook<LuaScriptT>(process, Offsets::Script_SpellStopCasting,
|
||||
&Script_SpellStopCastingHook);
|
||||
gSpell_C_TargetSpellDetour = createHook<Spell_C_TargetSpellT>(process, Offsets::Spell_C_TargetSpell,
|
||||
&Spell_C_TargetSpellHook);
|
||||
gSpell_C_HandleTerrainClickDetour = createHook<Spell_C_HandleTerrainClickT>(
|
||||
process, Offsets::Spell_C_HandleTerrainClick,
|
||||
&Spell_C_HandleTerrainClickHook);
|
||||
gCGWorldFrame_OnLayerTrackTerrainDetour = createHook<CGWorldFrame_OnLayerTrackTerrainT>(
|
||||
process, Offsets::CGWorldFrame_OnLayerTrackTerrain,
|
||||
&CGWorldFrame_OnLayerTrackTerrainHook);
|
||||
gOnSpriteRightClickDetour = createHook<OnSpriteRightClickT>(process, Offsets::OnSpriteRightClick,
|
||||
OnSpriteRightClickHook);
|
||||
gIEndSceneDetour = createHook<ISceneEndT>(process, Offsets::ISceneEndPtr, &ISceneEndHook);
|
||||
gInvalidFunctionPtrCheckDetour = createHook<InvalidFunctionPtrCheckT>(process, Offsets::InvalidFunctionPtrCheck,
|
||||
&InvalidFunctionPtrCheckHook);
|
||||
gGetSpellSlotFromLuaDetour = createHook<GetSpellSlotFromLuaT>(process, Offsets::GetSpellSlotFromLua,
|
||||
&GetSpellSlotFromLuaHook);
|
||||
gCGUnit_C_OnAuraRemovedDetour = createHook<CGUnit_C_OnAuraRemovedT>(process, Offsets::CGUnit_C_OnAuraRemoved,
|
||||
&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);
|
||||
gUnitCombatLogUnitDeadDetour = createHook<UnitCombatLogUnitDeadT>(process, Offsets::UnitCombatLogUnitDead,
|
||||
&UnitCombatLogUnitDeadHook);
|
||||
gLoadScriptFunctionsDetour = createHook<LoadScriptFunctionsT>(process, Offsets::LoadScriptFunctions,
|
||||
&LoadScriptFunctionsHook);
|
||||
gCreateEventsDetour = createHook<FrameScript_CreateEventsT>(process, Offsets::FrameScript_CreateEvents,
|
||||
&FrameScript_CreateEventsHook);
|
||||
gSetEventCountDetour = createHook<FramescriptSetEventCountT>(process, Offsets::Framescript_SetEventCount,
|
||||
&Framescript_SetEventCountHook);
|
||||
}
|
||||
|
||||
void SysMsgInitializeHook(hadesmem::PatchDetourBase *detour) {
|
||||
auto const sysMsgInitialize = detour->GetTrampolineT<SysMsgInitializeT>();
|
||||
sysMsgInitialize();
|
||||
loadConfig();
|
||||
initHooks();
|
||||
std::call_once(initHooksFlag, []() {
|
||||
loadConfig();
|
||||
initHooks();
|
||||
});
|
||||
}
|
||||
|
||||
void addCustomEvent(uint32_t code, char *name) {
|
||||
@@ -1286,6 +1268,8 @@ namespace Nampower {
|
||||
auto const loadScriptFunctions = detour->GetTrampolineT<LoadScriptFunctionsT>();
|
||||
loadScriptFunctions();
|
||||
|
||||
CleanupAllLuaTableRefs();
|
||||
|
||||
// register our own lua functions
|
||||
DEBUG_LOG("Registering Custom Lua functions");
|
||||
char queueSpellByName[] = "QueueSpellByName";
|
||||
@@ -1329,6 +1313,9 @@ namespace Nampower {
|
||||
char getItemStats[] = "GetItemStats";
|
||||
RegisterLuaFunction(getItemStats, reinterpret_cast<uintptr_t *>(Script_GetItemStats));
|
||||
|
||||
char startItemExport[] = "StartItemExport";
|
||||
RegisterLuaFunction(startItemExport, reinterpret_cast<uintptr_t *>(Script_StartItemExport));
|
||||
|
||||
char getSpellRec[] = "GetSpellRec";
|
||||
RegisterLuaFunction(getSpellRec, reinterpret_cast<uintptr_t *>(Script_GetSpellRec));
|
||||
|
||||
|
||||
+6
-3
@@ -30,8 +30,8 @@ namespace Nampower {
|
||||
constexpr uint32_t BUFFER_DECREASE_FREQUENCY = 10000; // time in ms between changes to lower buffer
|
||||
|
||||
constexpr uint32_t MAJOR_VERSION = 2;
|
||||
constexpr uint32_t MINOR_VERSION = 19;
|
||||
constexpr uint32_t PATCH_VERSION = 1;
|
||||
constexpr uint32_t MINOR_VERSION = 20;
|
||||
constexpr uint32_t PATCH_VERSION = 0;
|
||||
|
||||
constexpr int32_t LUA_REGISTRYINDEX = -10000;
|
||||
constexpr int32_t LUA_GLOBALSINDEX = -10001;
|
||||
@@ -125,6 +125,7 @@ namespace Nampower {
|
||||
using GetUnitFromNameT = uintptr_t *(__fastcall *)(const char *);
|
||||
using lua_gettableT = void (__fastcall *)(uintptr_t *luaState, int globalsIndex);
|
||||
using lua_gettopT = int (__fastcall *)(uintptr_t *);
|
||||
using lua_typeT = int (__fastcall *)(uintptr_t *, int);
|
||||
using lua_isstringT = bool (__fastcall *)(uintptr_t *, int);
|
||||
using lua_isnumberT = bool (__fastcall *)(uintptr_t *, int);
|
||||
using lua_tostringT = char *(__fastcall *)(uintptr_t *, int);
|
||||
@@ -172,6 +173,8 @@ namespace Nampower {
|
||||
|
||||
using InvalidFunctionPtrCheckT = void (__fastcall *)(uint32_t param_1);
|
||||
|
||||
using CGGameUI_DisplayErrorT = void (__cdecl *)(uint32_t errorCode);
|
||||
|
||||
void RegisterLuaFunction(char *, uintptr_t *func);
|
||||
|
||||
void LuaCall(const char *code);
|
||||
@@ -206,4 +209,4 @@ namespace Nampower {
|
||||
|
||||
void SetAttackTarget(uint64_t target);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+13
-29
@@ -8,6 +8,7 @@
|
||||
#include "dbc_fields.hpp"
|
||||
#include "unit_fields.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "lua_refs.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace Nampower {
|
||||
@@ -123,11 +124,7 @@ namespace Nampower {
|
||||
}
|
||||
|
||||
// Get or create reusable table
|
||||
if (castInfoTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
castInfoTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, castInfoTableRef);
|
||||
GetTableRef(luaState, castInfoTableRef);
|
||||
|
||||
// Get current time and calculate offset to convert to WoW time
|
||||
uint32_t currentTime = GetTime();
|
||||
@@ -308,11 +305,7 @@ namespace Nampower {
|
||||
if (useCopy) {
|
||||
lua_newtable(luaState);
|
||||
} else {
|
||||
if (itemStatsTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
itemStatsTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, itemStatsTableRef);
|
||||
GetTableRef(luaState, itemStatsTableRef);
|
||||
}
|
||||
|
||||
// Push all simple fields using descriptors
|
||||
@@ -401,13 +394,7 @@ namespace Nampower {
|
||||
lua_newtable(luaState);
|
||||
} else {
|
||||
// Get or create reusable table for this specific field name
|
||||
auto refIt = itemStatsArrayFieldRefs.find(fieldName);
|
||||
if (refIt == itemStatsArrayFieldRefs.end()) {
|
||||
lua_newtable(luaState);
|
||||
int ref = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
itemStatsArrayFieldRefs[fieldName] = ref;
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, itemStatsArrayFieldRefs[fieldName]);
|
||||
GetTableRef(luaState, itemStatsArrayFieldRefs[fieldName]);
|
||||
}
|
||||
|
||||
const char *fieldPtr = reinterpret_cast<const char *>(item) + field.offset;
|
||||
@@ -454,6 +441,12 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// won't do anything unless you uncomment line in process queues
|
||||
uint32_t Script_StartItemExport(uintptr_t *luaState) {
|
||||
StartItemExport();
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Script_GetUnitData(uintptr_t *luaState) {
|
||||
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
|
||||
|
||||
@@ -495,11 +488,7 @@ namespace Nampower {
|
||||
if (useCopy) {
|
||||
lua_newtable(luaState);
|
||||
} else {
|
||||
if (unitDataTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
unitDataTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, unitDataTableRef);
|
||||
GetTableRef(luaState, unitDataTableRef);
|
||||
}
|
||||
|
||||
// Push all simple fields using descriptors
|
||||
@@ -590,13 +579,7 @@ namespace Nampower {
|
||||
lua_newtable(luaState);
|
||||
} else {
|
||||
// Get or create reusable table for this specific field name
|
||||
auto refIt = unitFieldsArrayFieldRefs.find(fieldName);
|
||||
if (refIt == unitFieldsArrayFieldRefs.end()) {
|
||||
lua_newtable(luaState);
|
||||
int ref = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
unitFieldsArrayFieldRefs[fieldName] = ref;
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, unitFieldsArrayFieldRefs[fieldName]);
|
||||
GetTableRef(luaState, unitFieldsArrayFieldRefs[fieldName]);
|
||||
}
|
||||
|
||||
const char *fieldPtr = reinterpret_cast<const char *>(unitFields) + field.offset;
|
||||
@@ -627,4 +610,5 @@ namespace Nampower {
|
||||
lua_error(luaState, "Unknown field name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,5 +28,7 @@ namespace Nampower {
|
||||
|
||||
uint32_t Script_GetUnitField(uintptr_t *luaState);
|
||||
|
||||
uint32_t Script_StartItemExport(uintptr_t *luaState);
|
||||
|
||||
bool RunQueuedScript(int priority);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ enum class Offsets : std::uint32_t {
|
||||
ChannelTargetGuid = 0xC4D980,
|
||||
NameplateDistance = 0xC4D988, // float containing the distance squared ready to be pythagorean'd
|
||||
DBCacheGetRecord = 0X0055BA30,
|
||||
InvQuestionMark = 0X00847FE4,
|
||||
|
||||
ItemDBCache = 0xC0E2A0,
|
||||
|
||||
@@ -147,6 +148,7 @@ enum class Offsets : std::uint32_t {
|
||||
|
||||
lua_state_ptr = 0x7040D0,
|
||||
|
||||
lua_type = 0x006F3460,
|
||||
lua_isstring = 0x006F3510,
|
||||
lua_isnumber = 0X006F34D0,
|
||||
lua_tostring = 0x006F3690,
|
||||
@@ -168,7 +170,6 @@ enum class Offsets : std::uint32_t {
|
||||
luaL_ref = 0x006F5310,
|
||||
luaL_unref = 0x006F5400,
|
||||
|
||||
|
||||
CGInputControlGetActive = 0XBE1148,
|
||||
LastHardwareAction = 0X00CF0BC8,
|
||||
CGInputControlSetReleaseAction = 0x514810,
|
||||
@@ -181,6 +182,7 @@ enum class Offsets : std::uint32_t {
|
||||
|
||||
IntIntParamFormat = 0X00843342,
|
||||
StringIntParamFormat = 0X00847FBC,
|
||||
StringParamFormat = 0X0082E280,
|
||||
|
||||
QueueEventStringPtr = 0X00BE175C, // unused event 369 0x171
|
||||
CastEventStringPtr = 0X00BE1A08, // unused event 540 0x21C
|
||||
@@ -203,6 +205,7 @@ enum class Offsets : std::uint32_t {
|
||||
CGCharacterInfo_UseItem = 0x004c7970,
|
||||
|
||||
CGItem_C_Use = 0x005D8D00,
|
||||
CGItem_C_GetInventoryArt = 0x005D88B0,
|
||||
|
||||
DBCache_ItemCacheDBGetRow = 0x0055BA30,
|
||||
|
||||
@@ -211,4 +214,5 @@ enum class Offsets : std::uint32_t {
|
||||
ClearCursor = 0x00495190,
|
||||
CursorSetCursorMode = 0x00523d20,
|
||||
CursorModelSetSequence = 0x00523c20,
|
||||
CGGameUI_DisplayError = 0x00496720,
|
||||
};
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include "spell_scripts.hpp"
|
||||
#include "helper.hpp"
|
||||
#include "lua_refs.hpp"
|
||||
#include "offsets.hpp"
|
||||
#include "items.hpp"
|
||||
#include "dbc_fields.hpp"
|
||||
#include <cstring>
|
||||
|
||||
@@ -297,11 +297,7 @@ namespace Nampower {
|
||||
if (useCopy) {
|
||||
lua_newtable(luaState);
|
||||
} else {
|
||||
if (spellRecTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
spellRecTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, spellRecTableRef);
|
||||
GetTableRef(luaState, spellRecTableRef);
|
||||
}
|
||||
|
||||
// Push all simple fields using descriptors
|
||||
@@ -394,13 +390,7 @@ namespace Nampower {
|
||||
lua_newtable(luaState);
|
||||
} else {
|
||||
// Get or create reusable table for this specific field name
|
||||
auto refIt = spellRecArrayFieldRefs.find(fieldName);
|
||||
if (refIt == spellRecArrayFieldRefs.end()) {
|
||||
lua_newtable(luaState);
|
||||
int ref = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
spellRecArrayFieldRefs[fieldName] = ref;
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, spellRecArrayFieldRefs[fieldName]);
|
||||
GetTableRef(luaState, spellRecArrayFieldRefs[fieldName]);
|
||||
}
|
||||
|
||||
const char *fieldPtr = reinterpret_cast<const char *>(spell) + field.offset;
|
||||
@@ -569,4 +559,5 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+28
-27
@@ -452,7 +452,10 @@ namespace Nampower {
|
||||
// it is possible when spamming to attempt to cast before queues are processed
|
||||
processQueues();
|
||||
|
||||
if (item == nullptr && casterUnit != game::GetObjectPtr(game::ClntObjMgrGetActivePlayerGuid())) {
|
||||
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
|
||||
auto playerUnit = (playerGuid > 0) ? game::GetObjectPtr(playerGuid) : nullptr;
|
||||
|
||||
if (item == nullptr && casterUnit != playerUnit) {
|
||||
DEBUG_LOG("Ignoring non active player cast of spell " << game::GetSpellName(spellId) << " " << spellId);
|
||||
// just call original function if caster is not the active player
|
||||
// happens with Doomguard rain of fire
|
||||
@@ -471,6 +474,24 @@ namespace Nampower {
|
||||
auto const spellIsChanneling = SpellIsChanneling(spell);
|
||||
auto const spellIsTargeting = SpellIsTargeting(spell);
|
||||
auto const isSpecialSpell = SpellIsAttackTradeskillOrEnchant(spell);
|
||||
|
||||
if (casterUnit == playerUnit && gUserSettings.preventMountingWhenBuffCapped) {
|
||||
// Check for mount spell when player is buff capped
|
||||
if (SpellIsMounting(spell)) {
|
||||
if (playerUnit && game::UnitIsBuffCapped(playerUnit) && game::UnitGetMountDisplayId(playerUnit) == 0) {
|
||||
DEBUG_LOG("Blocking mount spell " << spellName << " due to buff cap");
|
||||
|
||||
static char message[] = "Preventing mounting due to buff cap (breaks dismount)";
|
||||
((int (__cdecl *)(int, char *, char *)) Offsets::SignalEventParam)(
|
||||
game::UI_ERROR_MESSAGE,
|
||||
(char *) Offsets::StringParamFormat,
|
||||
message);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto const currentTargetGuid = game::GetCurrentTargetGuid();
|
||||
|
||||
if (spellIsChanneling) {
|
||||
@@ -505,10 +526,10 @@ namespace Nampower {
|
||||
|
||||
uint32_t itemId = 0;
|
||||
if (item) {
|
||||
itemId = game::GetItemId((game::CGItem_C *) item);
|
||||
itemId = game::GetItemId(reinterpret_cast<game::CGItem_C *>(item));
|
||||
}
|
||||
|
||||
DEBUG_LOG("Attempt cast " << spellName << " item " << item << " on guid " << guid << " target "
|
||||
DEBUG_LOG("Attempt cast " << spellName << " itemId " << itemId << " on guid " << guid << " target "
|
||||
<< currentTargetGuid
|
||||
<< ", time since last cast " << currentTime - gLastCastData.startTimeMs);
|
||||
|
||||
@@ -856,7 +877,7 @@ namespace Nampower {
|
||||
}
|
||||
|
||||
bool doesSpellApplyAura(const game::SpellRec *spell) {
|
||||
for (unsigned int i : spell->Effect) {
|
||||
for (unsigned int i: spell->Effect) {
|
||||
switch (i) {
|
||||
case game::SPELL_EFFECT_APPLY_AURA:
|
||||
case game::SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
|
||||
@@ -889,29 +910,8 @@ namespace Nampower {
|
||||
auto *targetUnit = game::ClntObjMgrObjectPtr(
|
||||
static_cast<game::TypeMask>(game::TYPEMASK_PLAYER | game::TYPEMASK_UNIT), targetGuid);
|
||||
|
||||
bool targetIsBuffCapped = false;
|
||||
bool targetIsDebuffCapped = false;
|
||||
|
||||
if (targetUnit) {
|
||||
auto *unitFields = *reinterpret_cast<game::UnitFields **>(targetUnit + 68);
|
||||
if (unitFields) {
|
||||
targetIsBuffCapped = true;
|
||||
for (int i = 31; i >= 0; --i) {
|
||||
if (unitFields->aura[i] == 0) {
|
||||
targetIsBuffCapped = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
targetIsDebuffCapped = true;
|
||||
for (int i = 47; i >= 32; --i) {
|
||||
if (unitFields->aura[i] == 0) {
|
||||
targetIsDebuffCapped = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool targetIsBuffCapped = game::UnitIsBuffCapped(targetUnit);
|
||||
bool targetIsDebuffCapped = game::UnitIsDebuffCapped(targetUnit);
|
||||
|
||||
char *casterGuidStr = ConvertGuidToString(casterGuid);
|
||||
char *targetGuidStr = ConvertGuidToString(targetGuid);
|
||||
@@ -1005,6 +1005,7 @@ namespace Nampower {
|
||||
|
||||
if (gUserSettings.enableAuraCastEvents && doesSpellApplyAura(spell)) {
|
||||
auto targetGuidVal = targetGUID ? *targetGUID : *casterGUID;
|
||||
|
||||
TriggerAuraCastEvent(spell, *casterGUID, targetGuidVal, activePlayerGuid, castByActivePlayer);
|
||||
}
|
||||
}
|
||||
|
||||
+27
-26
@@ -8,39 +8,40 @@
|
||||
#include <cstdint>
|
||||
|
||||
struct UserSettings {
|
||||
bool queueCastTimeSpells;
|
||||
bool queueInstantSpells;
|
||||
bool queueOnSwingSpells;
|
||||
bool queueChannelingSpells;
|
||||
bool queueTargetingSpells;
|
||||
bool queueSpellsOnCooldown;
|
||||
bool queueCastTimeSpells = true;
|
||||
bool queueInstantSpells = true;
|
||||
bool queueOnSwingSpells = false;
|
||||
bool queueChannelingSpells = true;
|
||||
bool queueTargetingSpells = true;
|
||||
bool queueSpellsOnCooldown = true;
|
||||
|
||||
bool interruptChannelsOutsideQueueWindow;
|
||||
bool retryServerRejectedSpells;
|
||||
bool quickcastTargetingSpells;
|
||||
bool replaceMatchingNonGcdCategory;
|
||||
bool optimizeBufferUsingPacketTimings;
|
||||
bool interruptChannelsOutsideQueueWindow = false;
|
||||
bool retryServerRejectedSpells = true;
|
||||
bool quickcastTargetingSpells = false;
|
||||
bool replaceMatchingNonGcdCategory = false;
|
||||
bool optimizeBufferUsingPacketTimings = false;
|
||||
|
||||
bool preventRightClickTargetChange;
|
||||
bool preventRightClickPvPAttack;
|
||||
bool preventRightClickTargetChange = false;
|
||||
bool preventRightClickPvPAttack = false;
|
||||
|
||||
bool doubleCastToEndChannelEarly;
|
||||
bool quickcastOnDoubleCast;
|
||||
bool doubleCastToEndChannelEarly = false;
|
||||
bool quickcastOnDoubleCast = false;
|
||||
|
||||
bool spamProtectionEnabled;
|
||||
bool enableAuraCastEvents;
|
||||
bool spamProtectionEnabled = true;
|
||||
bool enableAuraCastEvents = false;
|
||||
bool preventMountingWhenBuffCapped = true;
|
||||
|
||||
uint32_t spellQueueWindowMs;
|
||||
uint32_t onSwingBufferCooldownMs;
|
||||
uint32_t channelQueueWindowMs;
|
||||
uint32_t targetingQueueWindowMs;
|
||||
uint32_t cooldownQueueWindowMs;
|
||||
uint32_t spellQueueWindowMs = 500;
|
||||
uint32_t onSwingBufferCooldownMs = 500;
|
||||
uint32_t channelQueueWindowMs = 1500;
|
||||
uint32_t targetingQueueWindowMs = 500;
|
||||
uint32_t cooldownQueueWindowMs = 250;
|
||||
|
||||
uint32_t minBufferTimeMs;
|
||||
uint32_t maxBufferIncreaseMs;
|
||||
uint32_t nonGcdBufferTimeMs;
|
||||
uint32_t minBufferTimeMs = 55;
|
||||
uint32_t maxBufferIncreaseMs = 30;
|
||||
uint32_t nonGcdBufferTimeMs = 100;
|
||||
|
||||
int32_t channelLatencyReductionPercentage;
|
||||
int32_t channelLatencyReductionPercentage = 75;
|
||||
};
|
||||
|
||||
enum CastType {
|
||||
|
||||
Reference in New Issue
Block a user