mirror of
https://github.com/brues-code/nampower.git
synced 2026-09-21 23:26:54 +00:00
switch to table references to reduce memory usage
This commit is contained in:
+125
-19
@@ -5,6 +5,7 @@ This document describes all custom Lua functions and events added by Nampower.
|
||||
For installation, configuration, and general usage information, see the main [README.md](README.md).
|
||||
|
||||
## Table of Contents
|
||||
- [Performance Optimization - Table References](#performance-optimization---table-references)
|
||||
- [Custom Lua Functions](#custom-lua-functions)
|
||||
- [Spell/Item/Unit Information](#spellitemunit-information)
|
||||
- [Spell Casting and Queuing](#spell-casting-and-queuing)
|
||||
@@ -12,18 +13,117 @@ For installation, configuration, and general usage information, see the main [RE
|
||||
- [Cooldown Information](#cooldown-information)
|
||||
---
|
||||
|
||||
## Performance Optimization - Table References
|
||||
|
||||
Nampower functions that return tables use **reusable table references** to reduce memory allocations and improve performance. This means the same table object is reused across multiple function calls, with its contents updated each time.
|
||||
|
||||
### Functions Using Reusable Table References
|
||||
|
||||
The following functions use reusable table references:
|
||||
|
||||
- **`GetCastInfo()`** - Returns cast information table
|
||||
- **`GetEquippedItems([unitToken])`** - Returns equipped items table
|
||||
- **`GetBagItems()`** - Returns bag items table
|
||||
- **`GetBagItem(bagIndex, slot)`** - Returns item info table
|
||||
- **`GetEquippedItem(unitToken, slot)`** - Returns item info table
|
||||
- **`GetSpellIdCooldown(spellId)`** - Returns cooldown detail table
|
||||
- **`GetItemIdCooldown(itemId)`** - Returns cooldown detail table
|
||||
-
|
||||
- **`GetItemStats(itemId, [copy])`** - Returns item stats table
|
||||
- **`GetUnitData(unitToken, [copy])`** - Returns unit data table
|
||||
- **`GetSpellRec(spellId, [copy])`** - Returns spell record table
|
||||
- **`GetItemStatsField(itemId, fieldName, [copy])`** - Returns individual item field value
|
||||
- **`GetUnitField(unitToken, fieldName, [copy])`** - Returns individual unit field value
|
||||
- **`GetSpellRecField(spellId, fieldName, [copy])`** - Returns individual spell field value
|
||||
|
||||
**Important:** When using these functions without the `copy` parameter, **immediately copy or extract** any values you need to store for later use. Do not store references to the returned tables themselves. Alternatively, pass `1` as the `copy` parameter to get an independent table that is safe to store.
|
||||
|
||||
**Note:** Functions like `GetItemStats`, `GetUnitData`, and `GetSpellRec` also use reusable references for their nested array fields (e.g., `bonusStat`, `auras`, `EffectImplicitTargetA`). Each nested array field name has its own dedicated reference that is reused across calls.
|
||||
|
||||
```lua
|
||||
-- ✓ SAFE - Extract values immediately
|
||||
local castInfo = GetCastInfo()
|
||||
if castInfo then
|
||||
local spellId = castInfo.spellId
|
||||
local castEnd = castInfo.castEndS
|
||||
-- Use spellId and castEnd later
|
||||
end
|
||||
|
||||
-- ✓ SAFE - Extract nested array values immediately
|
||||
local itemStats = GetItemStats(19019)
|
||||
if itemStats then
|
||||
local bonusStats = {}
|
||||
for i = 1, #itemStats.bonusStat do
|
||||
bonusStats[i] = itemStats.bonusStat[i]
|
||||
end
|
||||
-- Now bonusStats is a safe independent copy
|
||||
end
|
||||
|
||||
-- ✗ UNSAFE - Storing table references from the same function
|
||||
local cast1 = GetCastInfo() -- Gets table reference
|
||||
-- ... later ...
|
||||
local cast2 = GetCastInfo() -- Gets SAME table reference with new data
|
||||
-- cast1 and cast2 both point to the same table with cast2's data!
|
||||
|
||||
-- ✗ UNSAFE - Storing nested array references
|
||||
local item1 = GetItemStats(19019)
|
||||
local item1BonusStats = item1.bonusStat -- Stores reference to nested array
|
||||
local item2 = GetItemStats(22589)
|
||||
-- item1BonusStats was overwritten! The "bonusStat" nested array reference is reused
|
||||
|
||||
-- ✓ SAFE - Using copy parameter for nested arrays
|
||||
local item1 = GetItemStats(19019, 1) -- Pass 1 to get independent copy
|
||||
local item1BonusStats = item1.bonusStat -- Safe to store, it's an independent copy
|
||||
local item2 = GetItemStats(22589, 1) -- Another independent copy
|
||||
-- Both item1BonusStats and item2.bonusStat are independent tables
|
||||
```
|
||||
|
||||
**Important for array field functions:** Each field name gets its own dedicated table reference, but the table is still reused across calls with the same field name. **Always extract values immediately - never store the table reference itself.** Alternatively, pass `1` as the `copy` parameter to get an independent table copy:
|
||||
|
||||
```lua
|
||||
-- ✓ SAFE - Extract array values immediately
|
||||
local bonusStats = {}
|
||||
local tempTable = GetItemStatsField(itemId, "bonusStat")
|
||||
for i = 1, #tempTable do
|
||||
bonusStats[i] = tempTable[i]
|
||||
end
|
||||
-- Now bonusStats is a safe independent copy
|
||||
|
||||
-- ✓ EASIER - Use copy parameter to get independent table
|
||||
local bonusStats = GetItemStatsField(itemId, "bonusStat", 1)
|
||||
-- Safe to store, no manual copying needed!
|
||||
|
||||
-- ✗ UNSAFE - Storing table references (even with different field names)
|
||||
local bonusStats = GetItemStatsField(itemId, "bonusStat")
|
||||
local bonusAmounts = GetItemStatsField(itemId, "bonusAmount")
|
||||
-- Later...
|
||||
local newBonusStats = GetItemStatsField(otherItemId, "bonusStat")
|
||||
-- bonusStats was overwritten! The "bonusStat" reference is reused across calls
|
||||
|
||||
-- ✗ ALSO UNSAFE - Same field name, multiple calls
|
||||
local item1Stats = GetItemStatsField(19019, "bonusStat")
|
||||
local item2Stats = GetItemStatsField(22589, "bonusStat")
|
||||
-- item1Stats was immediately overwritten by the second call!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Custom Lua Functions
|
||||
|
||||
### Spell/Item/Unit information
|
||||
|
||||
#### GetItemStats(itemId)
|
||||
Returns a Lua table containing all fields for the item's `ItemStats` record (including localized `displayName` and `description`). Returns nil if the item cannot be found or loaded.
|
||||
#### GetItemStats(itemId, [copy])
|
||||
Returns a Lua table reference containing all fields for the item's `ItemStats` record (including localized `displayName` and `description`). Returns nil if the item cannot be found or loaded.
|
||||
|
||||
**Optional parameter:** Pass `1` for `copy` to get an independent table copy instead of a reusable reference.
|
||||
|
||||
Full field name lists are in [`DBC_FIELDS.md`](DBC_FIELDS.md).
|
||||
|
||||
#### GetItemStatsField(itemId, fieldName)
|
||||
#### GetItemStatsField(itemId, fieldName, [copy])
|
||||
Fast lookup for a single field on an item. Returns the requested field value; returns nil if the item is not found; raises a Lua error if the field name is invalid.
|
||||
|
||||
**Optional parameter:** Pass `1` for `copy` to get an independent table copy (for array fields only).
|
||||
|
||||
Full field name lists are in [`DBC_FIELDS.md`](DBC_FIELDS.md).
|
||||
|
||||
**Examples:**
|
||||
@@ -102,13 +202,13 @@ end
|
||||
```
|
||||
|
||||
#### GetEquippedItems(unitToken)
|
||||
Returns a table containing all equipped items for the specified unit.
|
||||
Returns a table reference containing all equipped items for the specified unit.
|
||||
|
||||
**Parameters:**
|
||||
- `unitToken` (string): Can be a standard unit token ("player", "target", "pet", etc.) or a GUID string
|
||||
|
||||
**Returns:**
|
||||
- A Lua table with equipment slot indices as keys (0-18) and item info tables as values
|
||||
- A Lua table reference with equipment slot indices as keys (0-18) and item info tables as values
|
||||
- Returns nil if the unit cannot be found or inspected
|
||||
|
||||
For the player, item info includes:
|
||||
@@ -162,7 +262,7 @@ Returns item info for a specific equipment slot on the specified unit.
|
||||
- 15 = Back, 16 = Main Hand, 17 = Off Hand, 18 = Ranged, 19 = Tabard
|
||||
|
||||
**Returns:**
|
||||
- A Lua table containing the item info (same fields as GetEquippedItems)
|
||||
- A Lua table reference containing the item info (same fields as GetEquippedItems)
|
||||
- Returns nil if the slot is empty, unit cannot be found, or unit cannot be inspected
|
||||
|
||||
**Examples:**
|
||||
@@ -184,10 +284,10 @@ end
|
||||
```
|
||||
|
||||
#### GetBagItems()
|
||||
Returns a nested table containing all items in all bags (including bank if open).
|
||||
Returns a nested table reference containing all items in all bags (including bank if open).
|
||||
|
||||
**Returns:**
|
||||
- A Lua table with bag indices as keys and bag contents as values
|
||||
- A Lua table reference with bag indices as keys and bag contents as values
|
||||
- Each bag contains **1-indexed** slot numbers as keys and item info tables as values
|
||||
- Bag indices:
|
||||
- 0 = Inventory pack (16 slots)
|
||||
@@ -243,7 +343,7 @@ Returns item info for a specific slot in a specific bag.
|
||||
- `slot` (number): **1-indexed** slot number within the bag
|
||||
|
||||
**Returns:**
|
||||
- A Lua table containing the item info (same fields as GetBagItems)
|
||||
- A Lua table reference containing the item info (same fields as GetBagItems)
|
||||
- Returns nil if the slot is empty or invalid
|
||||
|
||||
**Examples:**
|
||||
@@ -270,14 +370,18 @@ if bankItem then
|
||||
end
|
||||
```
|
||||
|
||||
#### GetSpellRec(spellId)
|
||||
Returns a Lua table containing all fields for the spell's `SpellRec` record (including localized `name` and `rank`). Returns nil if the spell cannot be found.
|
||||
#### GetSpellRec(spellId, [copy])
|
||||
Returns a Lua table reference containing all fields for the spell's `SpellRec` record (including localized `name` and `rank`). Returns nil if the spell cannot be found.
|
||||
|
||||
**Optional parameter:** Pass `1` for `copy` to get an independent table copy instead of a reusable reference.
|
||||
|
||||
Full field name lists are in [`DBC_FIELDS.md`](DBC_FIELDS.md).
|
||||
|
||||
#### GetSpellRecField(spellId, fieldName)
|
||||
#### GetSpellRecField(spellId, fieldName, [copy])
|
||||
Fast lookup for a single field on a spell. Returns the requested field value; returns nil if the spell is not found; raises a Lua error if the field name is invalid.
|
||||
|
||||
**Optional parameter:** Pass `1` for `copy` to get an independent table copy (for array fields only).
|
||||
|
||||
Full field name lists are in [`DBC_FIELDS.md`](DBC_FIELDS.md).
|
||||
|
||||
**Examples:**
|
||||
@@ -359,14 +463,15 @@ print("Flat damage bonus: " .. flatMod)
|
||||
print("Percent damage bonus: " .. percentMod .. "%")
|
||||
```
|
||||
|
||||
#### GetUnitData(unitToken)
|
||||
Returns a Lua table containing all unit fields for the specified unit. This provides access to low-level unit data like health, mana, stats, auras, resistances, and more.
|
||||
#### GetUnitData(unitToken, [copy])
|
||||
Returns a Lua table reference containing all unit fields for the specified unit. This provides access to low-level unit data like health, mana, stats, auras, resistances, and more.
|
||||
|
||||
**Parameters:**
|
||||
- `unitToken` (string): Can be a standard unit token ("player", "target", "pet", "mouseover", etc.) or a GUID string (e.g., "0xF5300000000000A5")
|
||||
- `copy` (number, optional): Pass `1` to get an independent table copy instead of a reusable reference
|
||||
|
||||
**Returns:**
|
||||
- A Lua table containing all unit fields, or nil if the unit cannot be found
|
||||
- A Lua table reference containing all unit fields, or nil if the unit cannot be found
|
||||
|
||||
Full field name lists are in [`UNIT_FIELDS.md`](UNIT_FIELDS.md).
|
||||
|
||||
@@ -384,12 +489,13 @@ end
|
||||
local data = GetUnitData("0xF5300000000000A5")
|
||||
```
|
||||
|
||||
#### GetUnitField(unitToken, fieldName)
|
||||
#### GetUnitField(unitToken, fieldName, [copy])
|
||||
Fast lookup for a single field on a unit. More efficient than GetUnitData when you only need one specific field.
|
||||
|
||||
**Parameters:**
|
||||
- `unitToken` (string): Can be a standard unit token ("player", "target", "pet", "mouseover", etc.) or a GUID string
|
||||
- `fieldName` (string): The name of the field to retrieve
|
||||
- `copy` (number, optional): Pass `1` to get an independent table copy (for array fields only)
|
||||
|
||||
**Returns:**
|
||||
- The requested field value; returns nil if the unit is not found; raises a Lua error if the field name is invalid
|
||||
@@ -497,7 +603,7 @@ Returns detailed information about the currently active cast or channel. Returns
|
||||
GetCurrentCastingInfo was made very early on and doesn't provide enough information for many use cases, but still has some uses and is available for backwards compatibility.
|
||||
|
||||
**Returns:**
|
||||
A Lua table with the following fields, or nil if no cast is active:
|
||||
A Lua table reference with the following fields, or nil if no cast is active:
|
||||
|
||||
- `castId` (number): Unique identifier for this cast
|
||||
- `spellId` (number): The spell ID being cast
|
||||
@@ -552,7 +658,7 @@ Returns detailed cooldown information for a spell from the spell history. This p
|
||||
- `spellId` (number): The spell ID to check
|
||||
|
||||
**Returns:**
|
||||
A Lua table with the following fields:
|
||||
A Lua table reference with the following fields:
|
||||
|
||||
- `isOnCooldown` (number): 1 if any cooldown is active, 0 otherwise
|
||||
- `cooldownRemainingMs` (number): Maximum remaining time across all cooldown types in milliseconds
|
||||
@@ -610,7 +716,7 @@ Returns detailed cooldown information for an item from the spell history. Works
|
||||
- `itemId` (number): The item ID to check
|
||||
|
||||
**Returns:**
|
||||
A Lua table with the same structure as GetSpellIdCooldown (see above).
|
||||
A Lua table reference with the same structure as GetSpellIdCooldown (see above).
|
||||
|
||||
**Notes:**
|
||||
- Returns the longest cooldown among all spells associated with the item
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include "offsets.hpp"
|
||||
|
||||
namespace Nampower {
|
||||
// Reusable table reference to reduce memory allocations
|
||||
static int cooldownDetailTableRef = LUA_REFNIL;
|
||||
|
||||
struct CooldownDetail {
|
||||
bool isOnCooldown = false;
|
||||
uint32_t cooldownRemainingMs = 0;
|
||||
@@ -156,7 +159,12 @@ namespace Nampower {
|
||||
static char gcdCategoryRemainingMsKey[] = "gcdCategoryRemainingMs";
|
||||
static char isOnGcdCategoryCooldownKey[] = "isOnGcdCategoryCooldown";
|
||||
|
||||
lua_newtable(luaState);
|
||||
// Get or create reusable table
|
||||
if (cooldownDetailTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
cooldownDetailTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, cooldownDetailTableRef);
|
||||
|
||||
// Overall cooldown status
|
||||
PushTableInt(luaState, isOnCooldownKey, detail.isOnCooldown ? 1 : 0);
|
||||
|
||||
@@ -141,4 +141,54 @@ namespace Nampower {
|
||||
lua_settable(luaState, -3);
|
||||
}
|
||||
}
|
||||
|
||||
// Version that uses reusable table references for each array field
|
||||
template<typename T>
|
||||
inline void PushArrayFieldsToLuaWithRefs(uintptr_t* luaState, const T* obj, const ArrayFieldDescriptor* fields,
|
||||
size_t fieldCount, std::unordered_map<std::string, int>& refMap) {
|
||||
for (size_t i = 0; i < fieldCount; ++i) {
|
||||
const auto& field = fields[i];
|
||||
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]);
|
||||
|
||||
const char* fieldPtr = reinterpret_cast<const char*>(obj) + field.offset;
|
||||
|
||||
for (size_t j = 0; j < field.count; ++j) {
|
||||
lua_pushnumber(luaState, j + 1); // Lua is 1-indexed
|
||||
|
||||
switch (field.type) {
|
||||
case FieldType::INT32:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const int32_t*>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::UINT32:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const uint32_t*>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::FLOAT:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const float*>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::UINT64:
|
||||
lua_pushnumber(luaState, static_cast<double>(reinterpret_cast<const uint64_t*>(fieldPtr)[j]));
|
||||
break;
|
||||
case FieldType::UINT8:
|
||||
lua_pushnumber(luaState, reinterpret_cast<const uint8_t*>(fieldPtr)[j]);
|
||||
break;
|
||||
case FieldType::STRING: {
|
||||
const char* str = reinterpret_cast<const char* const*>(fieldPtr)[j];
|
||||
lua_pushstring(luaState, str ? const_cast<char*>(str) : const_cast<char*>(""));
|
||||
break;
|
||||
}
|
||||
}
|
||||
lua_settable(luaState, -3);
|
||||
}
|
||||
lua_settable(luaState, -3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,9 @@ namespace Nampower {
|
||||
lua_pushnilT lua_pushnil = reinterpret_cast<lua_pushnilT>(Offsets::lua_pushnil);
|
||||
lua_newtableT lua_newtable = reinterpret_cast<lua_newtableT>(Offsets::lua_newtable);
|
||||
lua_settableT lua_settable = reinterpret_cast<lua_settableT>(Offsets::lua_settable);
|
||||
luaL_refT luaL_ref = reinterpret_cast<luaL_refT>(Offsets::luaL_ref);
|
||||
lua_rawgetiT lua_rawgeti = reinterpret_cast<lua_rawgetiT>(Offsets::lua_rawgeti);
|
||||
luaL_unrefT luaL_unref = reinterpret_cast<luaL_unrefT>(Offsets::luaL_unref);
|
||||
|
||||
|
||||
uint32_t GetSpellSlotAndTypeForName(const char *spellName, uint32_t *spellType) {
|
||||
|
||||
@@ -21,6 +21,14 @@ namespace Nampower {
|
||||
extern lua_pushnilT lua_pushnil;
|
||||
extern lua_newtableT lua_newtable;
|
||||
extern lua_settableT lua_settable;
|
||||
extern luaL_refT luaL_ref;
|
||||
extern lua_rawgetiT lua_rawgeti;
|
||||
extern luaL_unrefT luaL_unref;
|
||||
|
||||
// Lua 5.0 constants
|
||||
#ifndef LUA_REFNIL
|
||||
#define LUA_REFNIL (-2)
|
||||
#endif
|
||||
|
||||
uint32_t GetSpellSlotAndTypeForName(const char *spellName, uint32_t *spellType);
|
||||
|
||||
|
||||
@@ -14,6 +14,13 @@ namespace Nampower {
|
||||
// Local cache for item name lookups
|
||||
static std::unordered_map<std::string, uint32_t> itemNameToIdCache;
|
||||
|
||||
// Reusable table references to reduce memory allocations
|
||||
static int basicItemInfoTableRef = LUA_REFNIL;
|
||||
static int itemInfoTableRef = LUA_REFNIL;
|
||||
static int equippedItemsTableRef = LUA_REFNIL;
|
||||
static int bagItemsTableRef = LUA_REFNIL;
|
||||
static int bagTableRef = LUA_REFNIL;
|
||||
|
||||
// String keys used when pushing item data to Lua
|
||||
static char itemIdKey[] = "itemId";
|
||||
static char permanentEnchantIdKey[] = "permanentEnchantId";
|
||||
@@ -101,7 +108,12 @@ namespace Nampower {
|
||||
return;
|
||||
}
|
||||
|
||||
lua_newtable(luaState);
|
||||
// Get or create reusable table
|
||||
if (basicItemInfoTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
basicItemInfoTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, basicItemInfoTableRef);
|
||||
|
||||
PushTableValue(luaState, itemIdKey, cgItem->itemId);
|
||||
PushTableValue(luaState, permanentEnchantIdKey, cgItem->permanentEnchantId);
|
||||
@@ -117,7 +129,12 @@ namespace Nampower {
|
||||
auto itemId = game::GetItemId(item);
|
||||
auto itemFields = item->itemFields;
|
||||
|
||||
lua_newtable(luaState);
|
||||
// Get or create reusable table
|
||||
if (itemInfoTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
itemInfoTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, itemInfoTableRef);
|
||||
|
||||
PushTableValue(luaState, itemIdKey, itemId);
|
||||
PushTableValue(luaState, stackCountKey, itemFields->stackCount);
|
||||
@@ -298,7 +315,12 @@ namespace Nampower {
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_newtable(luaState);
|
||||
// Get or create reusable table
|
||||
if (equippedItemsTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
equippedItemsTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, equippedItemsTableRef);
|
||||
|
||||
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
|
||||
bool isPlayer = (guid == playerGuid);
|
||||
@@ -536,14 +558,25 @@ namespace Nampower {
|
||||
auto const getContainerGuid = reinterpret_cast<GetContainerGuidT>(Offsets::GetContainerGuid);
|
||||
auto const getBagItem = reinterpret_cast<CGBag_C_GetItemAtSlotT>(Offsets::CGBag_C_GetItemAtSlot);
|
||||
|
||||
lua_newtable(luaState);
|
||||
// Get or create reusable table
|
||||
if (bagItemsTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
bagItemsTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, bagItemsTableRef);
|
||||
|
||||
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
|
||||
auto player = game::GetObjectPtr(playerGuid);
|
||||
auto inventory = game::GetPlayerInventoryPtr(player);
|
||||
|
||||
lua_pushnumber(luaState, static_cast<double>(0));
|
||||
lua_newtable(luaState);
|
||||
|
||||
// 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);
|
||||
|
||||
for (uint32_t slot = 23; slot <= 38; slot++) {
|
||||
auto item = getBagItem(inventory, slot);
|
||||
@@ -565,7 +598,7 @@ namespace Nampower {
|
||||
if (!bagPtr) continue;
|
||||
|
||||
lua_pushnumber(luaState, static_cast<double>(bagIndex));
|
||||
lua_newtable(luaState);
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, bagTableRef);
|
||||
|
||||
auto bagSize = *bagPtr;
|
||||
for (uint32_t slot = 0; slot < bagSize; slot++) {
|
||||
@@ -591,7 +624,7 @@ namespace Nampower {
|
||||
if (!bagPtr) continue;
|
||||
|
||||
lua_pushnumber(luaState, static_cast<double>(bagIndex));
|
||||
lua_newtable(luaState);
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, bagTableRef);
|
||||
|
||||
auto bagSize = *bagPtr;
|
||||
for (uint32_t slot = 0; slot < bagSize; slot++) {
|
||||
|
||||
+170
-167
@@ -61,7 +61,7 @@ namespace Nampower {
|
||||
uint32_t gLastBufferIncreaseTimeMs;
|
||||
uint32_t gLastBufferDecreaseTimeMs;
|
||||
|
||||
uint32_t gBufferTimeMs; // adjusts dynamically depending on errors
|
||||
uint32_t gBufferTimeMs; // adjusts dynamically depending on errors
|
||||
|
||||
bool gForceQueueCast;
|
||||
bool gNoQueueCast;
|
||||
@@ -89,59 +89,59 @@ namespace Nampower {
|
||||
CastQueue gCastHistory = CastQueue(30);
|
||||
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<SpellVisualsInitializeT >> gSpellVisualsInitDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LoadScriptFunctionsT >> gLoadScriptFunctionsDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<FrameScript_CreateEventsT >> gCreateEventsDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<FramescriptSetEventCountT >> gSetEventCountDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<SpellVisualsInitializeT> > gSpellVisualsInitDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LoadScriptFunctionsT> > gLoadScriptFunctionsDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<FrameScript_CreateEventsT> > gCreateEventsDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<FramescriptSetEventCountT> > gSetEventCountDetour;
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<SetCVarT>> gSetCVarDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<CGSpellBook_CastSpellT>> gCGSpellBook_CastSpellDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<CastSpellT>> gCastDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<SendCastT>> gSendCastDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<CancelSpellT>> gCancelSpellDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<SignalEventT>> gSignalEventDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_SpellFailedT>> gSpellFailedDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_GetSpellModifiersT>> gSpell_C_GetSpellModifiersDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_GetSpellRadiusT>> gSpell_C_GetSpellRadiusDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<SetCVarT> > gSetCVarDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<CGSpellBook_CastSpellT> > gCGSpellBook_CastSpellDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<CastSpellT> > gCastDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<SendCastT> > gSendCastDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<CancelSpellT> > gCancelSpellDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<SignalEventT> > gSignalEventDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_SpellFailedT> > gSpellFailedDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_GetSpellModifiersT> > gSpell_C_GetSpellModifiersDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_GetSpellRadiusT> > gSpell_C_GetSpellRadiusDetour;
|
||||
std::unique_ptr<hadesmem::PatchRaw> gCastbarPatch;
|
||||
std::unique_ptr<hadesmem::PatchDetour<ISceneEndT>> gIEndSceneDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_GetAutoRepeatingSpellT>> gSpell_C_GetAutoRepeatingSpellDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_CooldownEventTriggeredT >> gSpell_C_CooldownEventTriggeredDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<SpellGoT>> gSpellGoDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gSpellTargetUnitDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT>> gSpellStopCastingDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<OnSpriteRightClickT>> gOnSpriteRightClickDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_HandleSpriteClickT>> gSpell_C_HandleSpriteClickDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_HandleTerrainClickT>> gSpell_C_HandleTerrainClickDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<CGWorldFrame_OnLayerTrackTerrainT>> gCGWorldFrame_OnLayerTrackTerrainDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_TargetSpellT>> gSpell_C_TargetSpellDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<ISceneEndT> > gIEndSceneDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_GetAutoRepeatingSpellT> > gSpell_C_GetAutoRepeatingSpellDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_CooldownEventTriggeredT> > gSpell_C_CooldownEventTriggeredDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<SpellGoT> > gSpellGoDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT> > gSpellTargetUnitDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<LuaScriptT> > gSpellStopCastingDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<OnSpriteRightClickT> > gOnSpriteRightClickDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_HandleSpriteClickT> > gSpell_C_HandleSpriteClickDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_HandleTerrainClickT> > gSpell_C_HandleTerrainClickDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<CGWorldFrame_OnLayerTrackTerrainT> > gCGWorldFrame_OnLayerTrackTerrainDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<Spell_C_TargetSpellT> > gSpell_C_TargetSpellDetour;
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gSpellCooldownDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gSpellDelayedDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gCastResultHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gSpellFailedHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gSpellChannelStartHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gSpellChannelUpdateHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT>> gPlaySpellVisualHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT> > gSpellCooldownDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT> > gSpellDelayedDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT> > gCastResultHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT> > gSpellFailedHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT> > gSpellChannelStartHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT> > gSpellChannelUpdateHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<PacketHandlerT> > gPlaySpellVisualHandlerDetour;
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<FastCallPacketHandlerT>> gSpellStartHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<FastCallPacketHandlerT>> gPeriodicAuraLogHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<FastCallPacketHandlerT>> gSpellNonMeleeDmgLogHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<FastCallPacketHandlerT> > gSpellStartHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<FastCallPacketHandlerT> > gPeriodicAuraLogHandlerDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<FastCallPacketHandlerT> > gSpellNonMeleeDmgLogHandlerDetour;
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<CGPlayer_C_OnAttackIconPressedT>> gCGPlayer_C_OnAttackIconPressedDetour;
|
||||
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<UnitCombatLogUnitDeadT>> gUnitCombatLogUnitDeadDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<CGPlayer_C_OnAttackIconPressedT> > gCGPlayer_C_OnAttackIconPressedDetour;
|
||||
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<UnitCombatLogUnitDeadT> > gUnitCombatLogUnitDeadDetour;
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<InvalidFunctionPtrCheckT>> gInvalidFunctionPtrCheckDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<InvalidFunctionPtrCheckT> > gInvalidFunctionPtrCheckDetour;
|
||||
|
||||
std::unique_ptr<hadesmem::PatchDetour<GetSpellSlotFromLuaT>> gGetSpellSlotFromLuaDetour;
|
||||
std::unique_ptr<hadesmem::PatchDetour<GetSpellSlotFromLuaT> > gGetSpellSlotFromLuaDetour;
|
||||
|
||||
uint32_t GetTime() {
|
||||
return static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()).count()) - gStartTime;
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()).count()) - gStartTime;
|
||||
}
|
||||
|
||||
std::string GetHumanReadableTime() {
|
||||
@@ -205,7 +205,8 @@ namespace Nampower {
|
||||
|
||||
void RegisterLuaFunction(char *name, uintptr_t *func) {
|
||||
DEBUG_LOG("Registering " << name << " to " << func);
|
||||
auto const registerFunction = reinterpret_cast<FrameScript_RegisterFunctionT>(Offsets::FrameScript_RegisterFunction);
|
||||
auto const registerFunction = reinterpret_cast<FrameScript_RegisterFunctionT>(
|
||||
Offsets::FrameScript_RegisterFunction);
|
||||
registerFunction(name, func);
|
||||
}
|
||||
|
||||
@@ -262,8 +263,10 @@ namespace Nampower {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto const remainingChannelTime = (gCastData.channelEndMs > currentTime) ? gCastData.channelEndMs -
|
||||
currentTime : 0;
|
||||
auto const remainingChannelTime = (gCastData.channelEndMs > currentTime)
|
||||
? gCastData.channelEndMs -
|
||||
currentTime
|
||||
: 0;
|
||||
return remainingChannelTime < gUserSettings.channelQueueWindowMs;
|
||||
}
|
||||
} else if (spellIsTargeting) {
|
||||
@@ -291,8 +294,10 @@ namespace Nampower {
|
||||
if (gCastData.channeling && gUserSettings.queueChannelingSpells) {
|
||||
if (gUserSettings.interruptChannelsOutsideQueueWindow) {
|
||||
auto currentTime = GetTime();
|
||||
auto const remainingChannelTime = (gCastData.channelEndMs > currentTime) ? gCastData.channelEndMs -
|
||||
currentTime : 0;
|
||||
auto const remainingChannelTime = (gCastData.channelEndMs > currentTime)
|
||||
? gCastData.channelEndMs -
|
||||
currentTime
|
||||
: 0;
|
||||
if (remainingChannelTime < gUserSettings.channelQueueWindowMs) {
|
||||
return gCastData.channelEndMs;
|
||||
}
|
||||
@@ -314,7 +319,6 @@ namespace Nampower {
|
||||
|
||||
gCastData.channelTickTimeMs = 0;
|
||||
gCastData.channelNumTicks = 0;
|
||||
|
||||
}
|
||||
|
||||
void ResetCastFlags() {
|
||||
@@ -355,8 +359,9 @@ namespace Nampower {
|
||||
auto const currentTime = GetTime();
|
||||
auto const elapsed = currentTime - gLastCastData.channelStartTimeMs;
|
||||
|
||||
auto remainingChannelTime = (gCastData.channelEndMs > currentTime) ? gCastData.channelEndMs - currentTime
|
||||
: 0;
|
||||
auto remainingChannelTime = (gCastData.channelEndMs > currentTime)
|
||||
? gCastData.channelEndMs - currentTime
|
||||
: 0;
|
||||
|
||||
auto const currentLatency = GetLatencyMs();
|
||||
uint32_t latencyReduction = 0;
|
||||
@@ -373,9 +378,9 @@ namespace Nampower {
|
||||
|
||||
if (remainingChannelTime <= 0) {
|
||||
DEBUG_LOG("Ending channel [" << elapsed << " elapsed > "
|
||||
<< gCastData.channelDuration << " original duration "
|
||||
<< " latency reduction " << latencyReduction << "]"
|
||||
<< " triggering queued spells");
|
||||
<< gCastData.channelDuration << " original duration "
|
||||
<< " latency reduction " << latencyReduction << "]"
|
||||
<< " triggering queued spells");
|
||||
|
||||
ResetChannelingFlags();
|
||||
} else if (gCastData.cancelChannelNextTick &&
|
||||
@@ -412,8 +417,8 @@ namespace Nampower {
|
||||
|
||||
if (remainingTickTime <= 0) {
|
||||
DEBUG_LOG("Ending channel due to cancelChannelNextTick. "
|
||||
<< "Remaining tick time: " << nextTickTimeMs - currentTime
|
||||
<< " latency reduction: " << latencyReduction);
|
||||
<< "Remaining tick time: " << nextTickTimeMs - currentTime
|
||||
<< " latency reduction: " << latencyReduction);
|
||||
ResetChannelingFlags();
|
||||
}
|
||||
}
|
||||
@@ -475,7 +480,7 @@ namespace Nampower {
|
||||
return true;
|
||||
} else {
|
||||
DEBUG_LOG("Ignoring queued cast of " << game::GetSpellName(gLastNormalCastParams.spellId)
|
||||
<< " due to max time since last cast");
|
||||
<< " due to max time since last cast");
|
||||
TriggerSpellQueuedEvent(NORMAL_QUEUE_POPPED, gLastNormalCastParams.spellId);
|
||||
gCastData.normalSpellQueued = false;
|
||||
gCastData.targetingSpellQueued = false;
|
||||
@@ -520,9 +525,8 @@ namespace Nampower {
|
||||
// if we have a target that is not the right click target, ignore the right click
|
||||
if (gUserSettings.preventRightClickTargetChange && currentTargetGuid &&
|
||||
currentTargetGuid != objectGUID) {
|
||||
|
||||
auto unitOrPlayer = game::ClntObjMgrObjectPtr(
|
||||
static_cast<game::TypeMask>(game::TYPEMASK_PLAYER | game::TYPEMASK_UNIT), objectGUID);
|
||||
static_cast<game::TypeMask>(game::TYPEMASK_PLAYER | game::TYPEMASK_UNIT), objectGUID);
|
||||
|
||||
// only prevent right click if guid is a unit/player
|
||||
if (unitOrPlayer) {
|
||||
@@ -596,12 +600,10 @@ namespace Nampower {
|
||||
} else if (strcmp(cvar, "NP_QueueSpellsOnCooldown") == 0) {
|
||||
gUserSettings.queueSpellsOnCooldown = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_QueueSpellsOnCooldown to " << gUserSettings.queueSpellsOnCooldown);
|
||||
|
||||
} else if (strcmp(cvar, "NP_InterruptChannelsOutsideQueueWindow") == 0) {
|
||||
gUserSettings.interruptChannelsOutsideQueueWindow = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_InterruptChannelsOutsideQueueWindow to "
|
||||
<< gUserSettings.interruptChannelsOutsideQueueWindow);
|
||||
|
||||
<< gUserSettings.interruptChannelsOutsideQueueWindow);
|
||||
} else if ((strcmp(cvar, "NP_RetryServerRejectedSpells") == 0)) {
|
||||
gUserSettings.retryServerRejectedSpells = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_RetryServerRejectedSpells to " << gUserSettings.retryServerRejectedSpells);
|
||||
@@ -614,27 +616,21 @@ namespace Nampower {
|
||||
} else if (strcmp(cvar, "NP_OptimizeBufferUsingPacketTimings") == 0) {
|
||||
gUserSettings.optimizeBufferUsingPacketTimings = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_OptimizeBufferUsingPacketTimings to " << gUserSettings.optimizeBufferUsingPacketTimings);
|
||||
|
||||
} else if (strcmp(cvar, "NP_PreventRightClickTargetChange") == 0) {
|
||||
gUserSettings.preventRightClickTargetChange = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_PreventRightClickTargetChange to " << gUserSettings.preventRightClickTargetChange);
|
||||
|
||||
} else if (strcmp(cvar, "NP_PreventRightClickPvPAttack") == 0) {
|
||||
gUserSettings.preventRightClickPvPAttack = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_PreventRightClickPvPAttack to " << gUserSettings.preventRightClickPvPAttack);
|
||||
|
||||
} else if (strcmp(cvar, "NP_DoubleCastToEndChannelEarly") == 0) {
|
||||
gUserSettings.doubleCastToEndChannelEarly = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_DoubleCastToEndChannelEarly to " << gUserSettings.doubleCastToEndChannelEarly);
|
||||
|
||||
} else if (strcmp(cvar, "NP_QuickcastOnDoubleCast") == 0) {
|
||||
gUserSettings.quickcastOnDoubleCast = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_QuickcastOnDoubleCast to " << gUserSettings.quickcastOnDoubleCast);
|
||||
|
||||
} else if (strcmp(cvar, "NP_SpamProtectionEnabled") == 0) {
|
||||
gUserSettings.spamProtectionEnabled = atoi(value) != 0;
|
||||
DEBUG_LOG("Set NP_SpamProtectionEnabled to " << gUserSettings.spamProtectionEnabled);
|
||||
|
||||
} else if (strcmp(cvar, "NP_MinBufferTimeMs") == 0) {
|
||||
gUserSettings.minBufferTimeMs = atoi(value);
|
||||
DEBUG_LOG("Set NP_MinBufferTimeMs and current buffer to " << gUserSettings.minBufferTimeMs);
|
||||
@@ -645,7 +641,6 @@ namespace Nampower {
|
||||
} else if (strcmp(cvar, "NP_MaxBufferIncreaseMs") == 0) {
|
||||
gUserSettings.maxBufferIncreaseMs = atoi(value);
|
||||
DEBUG_LOG("Set NP_MaxBufferIncreaseMs to " << gUserSettings.maxBufferIncreaseMs);
|
||||
|
||||
} else if (strcmp(cvar, "NP_SpellQueueWindowMs") == 0) {
|
||||
gUserSettings.spellQueueWindowMs = atoi(value);
|
||||
DEBUG_LOG("Set NP_SpellQueueWindowMs to " << gUserSettings.spellQueueWindowMs);
|
||||
@@ -661,17 +656,15 @@ namespace Nampower {
|
||||
} else if (strcmp(cvar, "NP_CooldownQueueWindowMs") == 0) {
|
||||
gUserSettings.cooldownQueueWindowMs = atoi(value);
|
||||
DEBUG_LOG("Set NP_CooldownQueueWindowMs to " << gUserSettings.cooldownQueueWindowMs);
|
||||
|
||||
} else if (strcmp(cvar, "NP_ChannelLatencyReductionPercentage") == 0) {
|
||||
gUserSettings.channelLatencyReductionPercentage = atoi(value);
|
||||
DEBUG_LOG(
|
||||
"Set NP_ChannelLatencyReductionPercentage to " << gUserSettings.channelLatencyReductionPercentage);
|
||||
|
||||
"Set NP_ChannelLatencyReductionPercentage to " << gUserSettings.channelLatencyReductionPercentage);
|
||||
} else if (strcmp(cvar, "NP_NameplateDistance") == 0) {
|
||||
auto distance = std::stof(value);
|
||||
SetNameplateDistance(distance);
|
||||
DEBUG_LOG(
|
||||
"Set NP_NameplateDistance to " << distance);
|
||||
"Set NP_NameplateDistance to " << distance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -742,7 +735,7 @@ namespace Nampower {
|
||||
|
||||
void loadConfig() {
|
||||
gStartTime = static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()).count());
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()).count());
|
||||
|
||||
// remove/rename previous logs
|
||||
safeRemove("nampower_debug.log.3");
|
||||
@@ -802,263 +795,265 @@ namespace Nampower {
|
||||
char NP_QueueCastTimeSpells[] = "NP_QueueCastTimeSpells";
|
||||
CVarRegister(NP_QueueCastTimeSpells, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.queueCastTimeSpells ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
5, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_QueueInstantSpells[] = "NP_QueueInstantSpells";
|
||||
CVarRegister(NP_QueueInstantSpells, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.queueInstantSpells ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_QueueChannelingSpells[] = "NP_QueueChannelingSpells";
|
||||
CVarRegister(NP_QueueChannelingSpells, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.queueChannelingSpells ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_QueueTargetingSpells[] = "NP_QueueTargetingSpells";
|
||||
CVarRegister(NP_QueueTargetingSpells, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.queueTargetingSpells ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_QueueOnSwingSpells[] = "NP_QueueOnSwingSpells";
|
||||
CVarRegister(NP_QueueOnSwingSpells, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.queueOnSwingSpells ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_QueueSpellsOnCooldown[] = "NP_QueueSpellsOnCooldown";
|
||||
CVarRegister(NP_QueueSpellsOnCooldown, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.queueSpellsOnCooldown ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_InterruptChannelsOutsideQueueWindow[] = "NP_InterruptChannelsOutsideQueueWindow";
|
||||
CVarRegister(NP_InterruptChannelsOutsideQueueWindow, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
gUserSettings.interruptChannelsOutsideQueueWindow ? defaultTrue
|
||||
: defaultFalse, // default value address
|
||||
0, // unk1
|
||||
gUserSettings.interruptChannelsOutsideQueueWindow
|
||||
? defaultTrue
|
||||
: defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_RetryServerRejectedSpells[] = "NP_RetryServerRejectedSpells";
|
||||
CVarRegister(NP_RetryServerRejectedSpells, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.retryServerRejectedSpells ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_QuickcastTargetingSpells[] = "NP_QuickcastTargetingSpells";
|
||||
CVarRegister(NP_QuickcastTargetingSpells, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.quickcastTargetingSpells ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_MinBufferTimeMs[] = "NP_MinBufferTimeMs";
|
||||
CVarRegister(NP_MinBufferTimeMs, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
std::to_string(gUserSettings.minBufferTimeMs).c_str(), // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_NonGcdBufferTimeMs[] = "NP_NonGcdBufferTimeMs";
|
||||
CVarRegister(NP_NonGcdBufferTimeMs, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
std::to_string(gUserSettings.nonGcdBufferTimeMs).c_str(), // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_MaxBufferIncreaseMs[] = "NP_MaxBufferIncreaseMs";
|
||||
CVarRegister(NP_MaxBufferIncreaseMs, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
std::to_string(gUserSettings.maxBufferIncreaseMs).c_str(), // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_SpellQueueWindowMs[] = "NP_SpellQueueWindowMs";
|
||||
CVarRegister(NP_SpellQueueWindowMs, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
std::to_string(gUserSettings.spellQueueWindowMs).c_str(), // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_ChannelQueueWindowMs[] = "NP_ChannelQueueWindowMs";
|
||||
CVarRegister(NP_ChannelQueueWindowMs, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
std::to_string(gUserSettings.channelQueueWindowMs).c_str(), // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_TargetingQueueWindowMs[] = "NP_TargetingQueueWindowMs";
|
||||
CVarRegister(NP_TargetingQueueWindowMs, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
std::to_string(gUserSettings.targetingQueueWindowMs).c_str(), // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_CooldownQueueWindowMs[] = "NP_CooldownQueueWindowMs";
|
||||
CVarRegister(NP_CooldownQueueWindowMs, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
std::to_string(gUserSettings.cooldownQueueWindowMs).c_str(), // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_OnSwingBufferCooldownMs[] = "NP_OnSwingBufferCooldownMs";
|
||||
CVarRegister(NP_OnSwingBufferCooldownMs, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
std::to_string(gUserSettings.onSwingBufferCooldownMs).c_str(), // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_ReplaceMatchingNonGcdCategory[] = "NP_ReplaceMatchingNonGcdCategory";
|
||||
CVarRegister(NP_ReplaceMatchingNonGcdCategory, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.replaceMatchingNonGcdCategory ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_OptimizeBufferUsingPacketTimings[] = "NP_OptimizeBufferUsingPacketTimings";
|
||||
CVarRegister(NP_OptimizeBufferUsingPacketTimings, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
gUserSettings.optimizeBufferUsingPacketTimings ? defaultTrue
|
||||
: defaultFalse, // default value address
|
||||
0, // unk1
|
||||
gUserSettings.optimizeBufferUsingPacketTimings
|
||||
? defaultTrue
|
||||
: defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_PreventRightClickTargetChange[] = "NP_PreventRightClickTargetChange";
|
||||
CVarRegister(NP_PreventRightClickTargetChange, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.preventRightClickTargetChange ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_PreventRightClickPvPAttack[] = "NP_PreventRightClickPvPAttack";
|
||||
CVarRegister(NP_PreventRightClickPvPAttack, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.preventRightClickPvPAttack ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_DoubleCastToEndChannelEarly[] = "NP_DoubleCastToEndChannelEarly";
|
||||
CVarRegister(NP_DoubleCastToEndChannelEarly, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.doubleCastToEndChannelEarly ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_QuickcastOnDoubleCast[] = "NP_QuickcastOnDoubleCast";
|
||||
CVarRegister(NP_QuickcastOnDoubleCast, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.quickcastOnDoubleCast ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_SpamProtectionEnabled[] = "NP_SpamProtectionEnabled";
|
||||
CVarRegister(NP_SpamProtectionEnabled, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
gUserSettings.spamProtectionEnabled ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_ChannelLatencyReductionPercentage[] = "NP_ChannelLatencyReductionPercentage";
|
||||
CVarRegister(NP_ChannelLatencyReductionPercentage, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
std::to_string(gUserSettings.channelLatencyReductionPercentage).c_str(), // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_NameplateDistance[] = "NP_NameplateDistance";
|
||||
CVarRegister(NP_NameplateDistance, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
0, // unk1
|
||||
std::to_string(GetNameplateDistance()).c_str(), // use the game's DAT value as the default
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
// update from cvars
|
||||
@@ -1104,10 +1099,10 @@ namespace Nampower {
|
||||
|
||||
// Template function to simplify hook initialization with specific storage
|
||||
template<typename FuncT, typename HookT>
|
||||
std::unique_ptr<hadesmem::PatchDetour<FuncT>>
|
||||
std::unique_ptr<hadesmem::PatchDetour<FuncT> >
|
||||
createHook(const hadesmem::Process &process, Offsets offset, HookT hookFunc) {
|
||||
auto const originalFunc = hadesmem::detail::AliasCast<FuncT>(offset);
|
||||
auto detour = std::make_unique<hadesmem::PatchDetour<FuncT>>(process, originalFunc, hookFunc);
|
||||
auto detour = std::make_unique<hadesmem::PatchDetour<FuncT> >(process, originalFunc, hookFunc);
|
||||
detour->Apply();
|
||||
return detour;
|
||||
}
|
||||
@@ -1116,8 +1111,10 @@ namespace Nampower {
|
||||
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);
|
||||
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);
|
||||
@@ -1144,10 +1141,12 @@ namespace Nampower {
|
||||
&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);
|
||||
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);
|
||||
@@ -1156,13 +1155,14 @@ namespace Nampower {
|
||||
gGetSpellSlotFromLuaDetour = createHook<GetSpellSlotFromLuaT>(process, Offsets::GetSpellSlotFromLua,
|
||||
&GetSpellSlotFromLuaHook);
|
||||
gCGUnit_C_OnAuraRemovedDetour = createHook<CGUnit_C_OnAuraRemovedT>(process, Offsets::CGUnit_C_OnAuraRemoved,
|
||||
&CGUnit_C_OnAuraRemovedHook);
|
||||
&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);
|
||||
&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);
|
||||
&UnitCombatLogUnitDeadHook);
|
||||
}
|
||||
|
||||
void SpellVisualsInitializeHook(hadesmem::PatchDetourBase *detour) {
|
||||
@@ -1172,11 +1172,11 @@ namespace Nampower {
|
||||
initHooks();
|
||||
}
|
||||
|
||||
void addCustomEvent(uint32_t code, char* name) {
|
||||
char ** FrameScript_EventObject_Data = *reinterpret_cast<char ***>(Offsets::Framescript_EventObject_Data);
|
||||
void addCustomEvent(uint32_t code, char *name) {
|
||||
char **FrameScript_EventObject_Data = *reinterpret_cast<char ***>(Offsets::Framescript_EventObject_Data);
|
||||
|
||||
auto SStrDupA = reinterpret_cast<char* (__stdcall *)(char*, char*, int)>(Offsets::SStrDupA);
|
||||
FrameScript_EventObject_Data[code*4] = SStrDupA(name, name, 1308);
|
||||
auto SStrDupA = reinterpret_cast<char* (__stdcall *)(char *, char *, int)>(Offsets::SStrDupA);
|
||||
FrameScript_EventObject_Data[code * 4] = SStrDupA(name, name, 1308);
|
||||
|
||||
DEBUG_LOG("Added custom event code:" << code << " " << name);
|
||||
}
|
||||
@@ -1232,7 +1232,8 @@ namespace Nampower {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
auto const setEventCount = detour->GetTrampolineT<FramescriptSetEventCountT>();
|
||||
|
||||
if (count > 200) {
|
||||
@@ -1333,7 +1334,6 @@ namespace Nampower {
|
||||
|
||||
char getItemIdCooldown[] = "GetItemIdCooldown";
|
||||
RegisterLuaFunction(getItemIdCooldown, reinterpret_cast<uintptr_t *>(Script_GetItemIdCooldown));
|
||||
|
||||
}
|
||||
|
||||
std::once_flag loadFlag;
|
||||
@@ -1344,36 +1344,39 @@ namespace Nampower {
|
||||
const hadesmem::Process process(::GetCurrentProcessId());
|
||||
|
||||
auto const spellVisualsInitOrig = hadesmem::detail::AliasCast<SpellVisualsInitializeT>(
|
||||
Offsets::SpellVisualsInitialize);
|
||||
gSpellVisualsInitDetour = std::make_unique<hadesmem::PatchDetour<SpellVisualsInitializeT >>(process,
|
||||
spellVisualsInitOrig,
|
||||
&SpellVisualsInitializeHook);
|
||||
Offsets::SpellVisualsInitialize);
|
||||
gSpellVisualsInitDetour = std::make_unique<hadesmem::PatchDetour<SpellVisualsInitializeT> >(
|
||||
process,
|
||||
spellVisualsInitOrig,
|
||||
&SpellVisualsInitializeHook);
|
||||
gSpellVisualsInitDetour->Apply();
|
||||
|
||||
auto const loadScriptFunctionsOrig = hadesmem::detail::AliasCast<LoadScriptFunctionsT>(
|
||||
Offsets::LoadScriptFunctions);
|
||||
gLoadScriptFunctionsDetour = std::make_unique<hadesmem::PatchDetour<LoadScriptFunctionsT >>(process,
|
||||
loadScriptFunctionsOrig,
|
||||
&LoadScriptFunctionsHook);
|
||||
Offsets::LoadScriptFunctions);
|
||||
gLoadScriptFunctionsDetour = std::make_unique<hadesmem::PatchDetour<LoadScriptFunctionsT> >(
|
||||
process,
|
||||
loadScriptFunctionsOrig,
|
||||
&LoadScriptFunctionsHook);
|
||||
gLoadScriptFunctionsDetour->Apply();
|
||||
|
||||
auto const createEventsOrig = hadesmem::detail::AliasCast<FrameScript_CreateEventsT>(
|
||||
Offsets::FrameScript_CreateEvents);
|
||||
gCreateEventsDetour = std::make_unique<hadesmem::PatchDetour<FrameScript_CreateEventsT >>(process,
|
||||
createEventsOrig,
|
||||
&FrameScript_CreateEventsHook);
|
||||
Offsets::FrameScript_CreateEvents);
|
||||
gCreateEventsDetour = std::make_unique<hadesmem::PatchDetour<FrameScript_CreateEventsT> >(
|
||||
process,
|
||||
createEventsOrig,
|
||||
&FrameScript_CreateEventsHook);
|
||||
gCreateEventsDetour->Apply();
|
||||
|
||||
auto const setEventCountOrig = hadesmem::detail::AliasCast<FramescriptSetEventCountT>(
|
||||
Offsets::Framescript_SetEventCount);
|
||||
gSetEventCountDetour = std::make_unique<hadesmem::PatchDetour<FramescriptSetEventCountT >>(process,
|
||||
setEventCountOrig,
|
||||
&Framescript_SetEventCountHook);
|
||||
Offsets::Framescript_SetEventCount);
|
||||
gSetEventCountDetour = std::make_unique<hadesmem::PatchDetour<FramescriptSetEventCountT> >(
|
||||
process,
|
||||
setEventCountOrig,
|
||||
&Framescript_SetEventCountHook);
|
||||
gSetEventCountDetour->Apply();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) uint32_t Load() {
|
||||
|
||||
+4
-1
@@ -30,7 +30,7 @@ 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 = 17;
|
||||
constexpr uint32_t MINOR_VERSION = 18;
|
||||
constexpr uint32_t PATCH_VERSION = 0;
|
||||
|
||||
constexpr int32_t LUA_REGISTRYINDEX = -10000;
|
||||
@@ -137,6 +137,9 @@ namespace Nampower {
|
||||
using lua_settopT = void (__fastcall *)(uintptr_t *, int);
|
||||
using lua_newtableT = void (__fastcall *)(uintptr_t *);
|
||||
using lua_settableT = void (__fastcall *)(uintptr_t *, int);
|
||||
using luaL_refT = int (__fastcall *)(uintptr_t *, int);
|
||||
using lua_rawgetiT = void (__fastcall *)(uintptr_t *, int, int);
|
||||
using luaL_unrefT = void (__fastcall *)(uintptr_t *, int, int);
|
||||
|
||||
using Spell_C_CooldownEventTriggeredT = void (__fastcall *)(uint32_t spellId,
|
||||
uint64_t *targetGUID,
|
||||
|
||||
+108
-16
@@ -29,6 +29,19 @@ namespace Nampower {
|
||||
int gScriptPriority = 1;
|
||||
char *queuedScript;
|
||||
|
||||
// Reusable table references to reduce memory allocations
|
||||
static int castInfoTableRef = LUA_REFNIL;
|
||||
static int itemStatsTableRef = LUA_REFNIL;
|
||||
static int unitDataTableRef = LUA_REFNIL;
|
||||
|
||||
// Maps to store separate references for each array field name (for Field functions)
|
||||
static std::unordered_map<std::string, int> itemStatsArrayFieldRefs;
|
||||
static std::unordered_map<std::string, int> unitFieldsArrayFieldRefs;
|
||||
|
||||
// Maps to store separate references for nested array fields (for main table functions)
|
||||
static std::unordered_map<std::string, int> itemStatsNestedArrayRefs;
|
||||
static std::unordered_map<std::string, int> unitFieldsNestedArrayRefs;
|
||||
|
||||
uint32_t Script_GetCurrentCastingInfo(uintptr_t *luaState) {
|
||||
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
|
||||
|
||||
@@ -109,8 +122,12 @@ namespace Nampower {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create new table
|
||||
lua_newtable(luaState);
|
||||
// Get or create reusable table
|
||||
if (castInfoTableRef == LUA_REFNIL) {
|
||||
lua_newtable(luaState);
|
||||
castInfoTableRef = luaL_ref(luaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
lua_rawgeti(luaState, LUA_REGISTRYINDEX, castInfoTableRef);
|
||||
|
||||
// Get current time and calculate offset to convert to WoW time
|
||||
uint32_t currentTime = GetTime();
|
||||
@@ -268,12 +285,18 @@ namespace Nampower {
|
||||
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
|
||||
|
||||
if (!lua_isnumber(luaState, 1)) {
|
||||
lua_error(luaState, "Usage: GetItemStats(itemId)");
|
||||
lua_error(luaState, "Usage: GetItemStats(itemId, [copy])");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t itemId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
|
||||
|
||||
// Check for optional copy parameter
|
||||
bool useCopy = false;
|
||||
if (lua_isnumber(luaState, 2)) {
|
||||
useCopy = static_cast<int>(lua_tonumber(luaState, 2)) != 0;
|
||||
}
|
||||
|
||||
// Get from cache
|
||||
game::ItemStats_C *item = GetItemStats(itemId);
|
||||
if (!item) {
|
||||
@@ -281,8 +304,16 @@ namespace Nampower {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create new table
|
||||
lua_newtable(luaState);
|
||||
// Create new table or get reusable table based on copy parameter
|
||||
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);
|
||||
}
|
||||
|
||||
// Push all simple fields using descriptors
|
||||
PushFieldsToLua(luaState, item, itemStatsFields, itemStatsFieldsCount);
|
||||
@@ -294,8 +325,12 @@ namespace Nampower {
|
||||
PushTableValue(luaState, const_cast<char *>("description"),
|
||||
item->m_description ? item->m_description : const_cast<char *>(""));
|
||||
|
||||
// Push all array fields using descriptors
|
||||
PushArrayFieldsToLua(luaState, item, itemStatsArrayFields, itemStatsArrayFieldsCount);
|
||||
// Push all array fields using descriptors with or without references based on copy parameter
|
||||
if (useCopy) {
|
||||
PushArrayFieldsToLua(luaState, item, itemStatsArrayFields, itemStatsArrayFieldsCount);
|
||||
} else {
|
||||
PushArrayFieldsToLuaWithRefs(luaState, item, itemStatsArrayFields, itemStatsArrayFieldsCount, itemStatsNestedArrayRefs);
|
||||
}
|
||||
|
||||
return 1; // Return the table
|
||||
}
|
||||
@@ -304,7 +339,7 @@ namespace Nampower {
|
||||
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
|
||||
|
||||
if (!lua_isnumber(luaState, 1) || !lua_isstring(luaState, 2)) {
|
||||
lua_error(luaState, "Usage: GetItemStatsField(itemId, fieldName)");
|
||||
lua_error(luaState, "Usage: GetItemStatsField(itemId, fieldName, [copy])");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -313,6 +348,12 @@ namespace Nampower {
|
||||
uint32_t itemId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
|
||||
const char *fieldName = lua_tostring(luaState, 2);
|
||||
|
||||
// Check for optional copy parameter
|
||||
bool useCopy = false;
|
||||
if (lua_isnumber(luaState, 3)) {
|
||||
useCopy = static_cast<int>(lua_tonumber(luaState, 3)) != 0;
|
||||
}
|
||||
|
||||
// Get from cache
|
||||
game::ItemStats_C *item = GetItemStats(itemId);
|
||||
if (!item) {
|
||||
@@ -354,7 +395,20 @@ namespace Nampower {
|
||||
if (arrayIt != itemStatsArrayFieldMap.end()) {
|
||||
size_t i = arrayIt->second;
|
||||
const auto &field = itemStatsArrayFields[i];
|
||||
lua_newtable(luaState);
|
||||
|
||||
// Create new table or get reusable table based on copy parameter
|
||||
if (useCopy) {
|
||||
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]);
|
||||
}
|
||||
|
||||
const char *fieldPtr = reinterpret_cast<const char *>(item) + field.offset;
|
||||
|
||||
@@ -404,11 +458,18 @@ namespace Nampower {
|
||||
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
|
||||
|
||||
if (!lua_isstring(luaState, 1)) {
|
||||
lua_error(luaState, "Usage: GetUnitData(unitToken) - unitToken can be 'player', 'target', 'pet', etc., or a GUID string");
|
||||
lua_error(luaState, "Usage: GetUnitData(unitToken, [copy]) - unitToken can be 'player', 'target', 'pet', etc., or a GUID string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *unitToken = lua_tostring(luaState, 1);
|
||||
|
||||
// Check for optional copy parameter
|
||||
bool useCopy = false;
|
||||
if (lua_isnumber(luaState, 2)) {
|
||||
useCopy = static_cast<int>(lua_tonumber(luaState, 2)) != 0;
|
||||
}
|
||||
|
||||
uint64_t guid = GetUnitGuidFromString(unitToken);
|
||||
|
||||
if (guid == 0) {
|
||||
@@ -430,14 +491,26 @@ namespace Nampower {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create new table
|
||||
lua_newtable(luaState);
|
||||
// Create new table or get reusable table based on copy parameter
|
||||
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);
|
||||
}
|
||||
|
||||
// Push all simple fields using descriptors
|
||||
PushFieldsToLua(luaState, unitFields, unitFieldsFields, unitFieldsFieldsCount);
|
||||
|
||||
// Push all array fields using descriptors
|
||||
PushArrayFieldsToLua(luaState, unitFields, unitFieldsArrayFields, unitFieldsArrayFieldsCount);
|
||||
// Push all array fields using descriptors with or without references based on copy parameter
|
||||
if (useCopy) {
|
||||
PushArrayFieldsToLua(luaState, unitFields, unitFieldsArrayFields, unitFieldsArrayFieldsCount);
|
||||
} else {
|
||||
PushArrayFieldsToLuaWithRefs(luaState, unitFields, unitFieldsArrayFields, unitFieldsArrayFieldsCount, unitFieldsNestedArrayRefs);
|
||||
}
|
||||
|
||||
return 1; // Return the table
|
||||
}
|
||||
@@ -446,7 +519,7 @@ namespace Nampower {
|
||||
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
|
||||
|
||||
if (!lua_isstring(luaState, 1) || !lua_isstring(luaState, 2)) {
|
||||
lua_error(luaState, "Usage: GetUnitField(unitToken, fieldName) - unitToken can be 'player', 'target', 'pet', etc., or a GUID string");
|
||||
lua_error(luaState, "Usage: GetUnitField(unitToken, fieldName, [copy]) - unitToken can be 'player', 'target', 'pet', etc., or a GUID string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -455,6 +528,12 @@ namespace Nampower {
|
||||
const char *unitToken = lua_tostring(luaState, 1);
|
||||
const char *fieldName = lua_tostring(luaState, 2);
|
||||
|
||||
// Check for optional copy parameter
|
||||
bool useCopy = false;
|
||||
if (lua_isnumber(luaState, 3)) {
|
||||
useCopy = static_cast<int>(lua_tonumber(luaState, 3)) != 0;
|
||||
}
|
||||
|
||||
uint64_t guid = GetUnitGuidFromString(unitToken);
|
||||
|
||||
if (guid == 0) {
|
||||
@@ -505,7 +584,20 @@ namespace Nampower {
|
||||
if (arrayIt != unitFieldsArrayFieldMap.end()) {
|
||||
size_t i = arrayIt->second;
|
||||
const auto &field = unitFieldsArrayFields[i];
|
||||
lua_newtable(luaState);
|
||||
|
||||
// Create new table or get reusable table based on copy parameter
|
||||
if (useCopy) {
|
||||
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]);
|
||||
}
|
||||
|
||||
const char *fieldPtr = reinterpret_cast<const char *>(unitFields) + field.offset;
|
||||
|
||||
|
||||
@@ -160,8 +160,11 @@ enum class Offsets : std::uint32_t {
|
||||
lua_newtable = 0x006F3C90,
|
||||
lua_settable = 0x006F3E20,
|
||||
lua_pushboolean = 0x006F39F0,
|
||||
lua_rawseti = 0x006F3EA0,
|
||||
lua_rawseti = 0x006f3f60,
|
||||
lua_rawgeti = 0x006f3bc0,
|
||||
lua_gettop = 0x006F3070,
|
||||
luaL_ref = 0x006F5310,
|
||||
luaL_unref = 0x006F5400,
|
||||
|
||||
|
||||
CGInputControlGetActive = 0XBE1148,
|
||||
|
||||
@@ -10,6 +10,15 @@
|
||||
#include <cstring>
|
||||
|
||||
namespace Nampower {
|
||||
// Reusable table references to reduce memory allocations
|
||||
static int spellRecTableRef = LUA_REFNIL;
|
||||
|
||||
// Map to store separate references for each array field name (for Field function)
|
||||
static std::unordered_map<std::string, int> spellRecArrayFieldRefs;
|
||||
|
||||
// Map to store separate references for nested array fields (for main table function)
|
||||
static std::unordered_map<std::string, int> spellRecNestedArrayRefs;
|
||||
|
||||
uint32_t Script_CastSpellByNameNoQueue(uintptr_t *luaState) {
|
||||
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
|
||||
|
||||
@@ -265,12 +274,18 @@ namespace Nampower {
|
||||
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
|
||||
|
||||
if (!lua_isnumber(luaState, 1)) {
|
||||
lua_error(luaState, "Usage: GetSpellRec(spellId)");
|
||||
lua_error(luaState, "Usage: GetSpellRec(spellId, [copy])");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t spellId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
|
||||
|
||||
// Check for optional copy parameter
|
||||
bool useCopy = false;
|
||||
if (lua_isnumber(luaState, 2)) {
|
||||
useCopy = static_cast<int>(lua_tonumber(luaState, 2)) != 0;
|
||||
}
|
||||
|
||||
// Get spell info
|
||||
auto spell = game::GetSpellInfo(spellId);
|
||||
if (!spell) {
|
||||
@@ -278,8 +293,16 @@ namespace Nampower {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create new table
|
||||
lua_newtable(luaState);
|
||||
// Create new table or get reusable table based on copy parameter
|
||||
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);
|
||||
}
|
||||
|
||||
// Push all simple fields using descriptors
|
||||
PushFieldsToLua(luaState, spell, spellRecFields, spellRecFieldsCount);
|
||||
@@ -294,8 +317,12 @@ namespace Nampower {
|
||||
? const_cast<char *>(reinterpret_cast<const char *>(spell->Rank[language]))
|
||||
: const_cast<char *>(""));
|
||||
|
||||
// Push all array fields using descriptors
|
||||
PushArrayFieldsToLua(luaState, spell, spellRecArrayFields, spellRecArrayFieldsCount);
|
||||
// Push all array fields using descriptors with or without references based on copy parameter
|
||||
if (useCopy) {
|
||||
PushArrayFieldsToLua(luaState, spell, spellRecArrayFields, spellRecArrayFieldsCount);
|
||||
} else {
|
||||
PushArrayFieldsToLuaWithRefs(luaState, spell, spellRecArrayFields, spellRecArrayFieldsCount, spellRecNestedArrayRefs);
|
||||
}
|
||||
|
||||
return 1; // Return the table
|
||||
}
|
||||
@@ -304,7 +331,7 @@ namespace Nampower {
|
||||
luaState = GetLuaStatePtr(); // pcall leads to corrupted lua state pointer on added scripts, not sure why
|
||||
|
||||
if (!lua_isnumber(luaState, 1) || !lua_isstring(luaState, 2)) {
|
||||
lua_error(luaState, "Usage: GetSpellRecField(spellId, fieldName)");
|
||||
lua_error(luaState, "Usage: GetSpellRecField(spellId, fieldName, [copy])");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -313,6 +340,12 @@ namespace Nampower {
|
||||
uint32_t spellId = static_cast<uint32_t>(lua_tonumber(luaState, 1));
|
||||
const char *fieldName = lua_tostring(luaState, 2);
|
||||
|
||||
// Check for optional copy parameter
|
||||
bool useCopy = false;
|
||||
if (lua_isnumber(luaState, 3)) {
|
||||
useCopy = static_cast<int>(lua_tonumber(luaState, 3)) != 0;
|
||||
}
|
||||
|
||||
// Get spell info
|
||||
auto spell = game::GetSpellInfo(spellId);
|
||||
if (!spell) {
|
||||
@@ -355,7 +388,20 @@ namespace Nampower {
|
||||
if (arrayIt != spellRecArrayFieldMap.end()) {
|
||||
size_t i = arrayIt->second;
|
||||
const auto &field = spellRecArrayFields[i];
|
||||
lua_newtable(luaState);
|
||||
|
||||
// Create new table or get reusable table based on copy parameter
|
||||
if (useCopy) {
|
||||
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]);
|
||||
}
|
||||
|
||||
const char *fieldPtr = reinterpret_cast<const char *>(spell) + field.offset;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user