mirror of
https://github.com/brues-code/nampower.git
synced 2026-10-03 12:10:00 +00:00
add spam protection cvar, prevent right click pvp attack, attempt to fix/log crashes on launch
This commit is contained in:
@@ -88,8 +88,12 @@ 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_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_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.
|
||||
|
||||
@@ -152,4 +152,40 @@ namespace game {
|
||||
|
||||
return unitFields->target;
|
||||
}
|
||||
|
||||
bool UnitIsPvpFlagged(uintptr_t *unit) {
|
||||
if (!unit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *unitFields = *reinterpret_cast<UnitFields **>(unit + 68);
|
||||
|
||||
if (unitFields == nullptr) {
|
||||
// we don't have attribute info.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto flags = unitFields->flags;
|
||||
return (flags & UNIT_FLAG_PVP);
|
||||
}
|
||||
|
||||
bool UnitIsInCombat(uintptr_t *unit) {
|
||||
if (!unit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *unitFields = *reinterpret_cast<UnitFields **>(unit + 68);
|
||||
|
||||
if (unitFields == nullptr) {
|
||||
// we don't have attribute info.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto flags = unitFields->flags;
|
||||
if ((flags & UNIT_FLAG_IN_COMBAT) != 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1190,6 +1190,45 @@ namespace game {
|
||||
|
||||
};//Size=0x0010
|
||||
|
||||
enum UnitFlags {
|
||||
UNIT_FLAG_NONE = 0x00000000,
|
||||
UNIT_FLAG_UNK_0 = 0x00000001, // Movement checks disabled, likely paired with loss of client control packet.
|
||||
UNIT_FLAG_SPAWNING = 0x00000002, // not attackable
|
||||
UNIT_FLAG_DISABLE_MOVE = 0x00000004,
|
||||
UNIT_FLAG_PLAYER_CONTROLLED = 0x00000008, // players, pets, totems, guardians, companions, charms, any units associated with players
|
||||
UNIT_FLAG_PET_RENAME = 0x00000010, // Old pet rename: moved to UNIT_FIELD_BYTES_2,2 in TBC+
|
||||
UNIT_FLAG_PET_ABANDON = 0x00000020, // Old pet abandon: moved to UNIT_FIELD_BYTES_2,2 in TBC+
|
||||
UNIT_FLAG_UNK_6 = 0x00000040,
|
||||
UNIT_FLAG_IMMUNE_TO_PLAYER = 0x00000100, // Target is immune to players
|
||||
UNIT_FLAG_IMMUNE_TO_NPC = 0x00000200, // Target is immune to creatures
|
||||
UNIT_FLAG_PVP = 0x00001000,
|
||||
UNIT_FLAG_SILENCED = 0x00002000, // silenced, 2.1.1
|
||||
UNIT_FLAG_UNK_14 = 0x00004000,
|
||||
UNIT_FLAG_USE_SWIM_ANIMATION = 0x00008000,
|
||||
UNIT_FLAG_NON_ATTACKABLE_2 = 0x00010000, // removes attackable icon, if on yourself, cannot assist self but can cast TARGET_UNIT_CASTER spells - added by SPELL_AURA_MOD_UNATTACKABLE
|
||||
UNIT_FLAG_PACIFIED = 0x00020000,
|
||||
UNIT_FLAG_STUNNED = 0x00040000, // Unit is a subject to stun, turn and strafe movement disabled
|
||||
UNIT_FLAG_IN_COMBAT = 0x00080000,
|
||||
UNIT_FLAG_TAXI_FLIGHT = 0x00100000, // Unit is on taxi, paired with a duplicate loss of client control packet (likely a legacy serverside hack). Disables any spellcasts not allowed in taxi flight client-side.
|
||||
UNIT_FLAG_CONFUSED = 0x00400000, // Unit is a subject to confused movement, movement checks disabled, paired with loss of client control packet.
|
||||
UNIT_FLAG_FLEEING = 0x00800000, // Unit is a subject to fleeing movement, movement checks disabled, paired with loss of client control packet.
|
||||
UNIT_FLAG_POSSESSED = 0x01000000, // Unit is under remote control by another unit, movement checks disabled, paired with loss of client control packet. New master is allowed to use melee attack and can't select this unit via mouse in the world (as if it was own character).
|
||||
UNIT_FLAG_NOT_SELECTABLE = 0x02000000,
|
||||
UNIT_FLAG_SKINNABLE = 0x04000000,
|
||||
UNIT_FLAG_AURAS_VISIBLE = 0x08000000, // magic detect
|
||||
UNIT_FLAG_SHEATHE = 0x40000000,
|
||||
UNIT_FLAG_IMMUNE = 0x80000000, // Immune to damage
|
||||
|
||||
// [-ZERO] TBC enumerations [?]
|
||||
UNIT_FLAG_NOT_ATTACKABLE_1 = 0x00000080, // ?? (UNIT_FLAG_PLAYER_CONTROLLED | UNIT_FLAG_NOT_ATTACKABLE_1) is NON_PVP_ATTACKABLE
|
||||
UNIT_FLAG_LOOTING = 0x00000400, // loot animation
|
||||
UNIT_FLAG_PET_IN_COMBAT = 0x00000800, // in combat?, 2.0.8
|
||||
UNIT_FLAG_DISARMED = 0x00200000, // disable melee spells casting..., "Required melee weapon" added to melee spells tooltip.
|
||||
|
||||
UNIT_FLAG_UNK_28 = 0x10000000,
|
||||
UNIT_FLAG_UNK_29 = 0x20000000, // used in Feing Death spell
|
||||
};
|
||||
|
||||
typedef struct UnitFields {
|
||||
uint64_t charm; // Size:2
|
||||
uint64_t summon; // Size:2
|
||||
@@ -1293,4 +1332,7 @@ namespace game {
|
||||
|
||||
uint64_t UnitGetTargetGuid(uintptr_t *unit);
|
||||
|
||||
bool UnitIsPvpFlagged(uintptr_t *unit);
|
||||
|
||||
bool UnitIsInCombat(uintptr_t *unit);
|
||||
}
|
||||
+135
-33
@@ -45,6 +45,8 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
#include <windows.h>
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE, uint32_t, void *);
|
||||
|
||||
@@ -155,8 +157,8 @@ namespace Nampower {
|
||||
function(code, "Unused");
|
||||
}
|
||||
|
||||
uintptr_t* GetLuaStatePtr() {
|
||||
typedef uintptr_t* (__fastcall* GETCONTEXT)(void);
|
||||
uintptr_t *GetLuaStatePtr() {
|
||||
typedef uintptr_t *(__fastcall *GETCONTEXT)(void);
|
||||
static auto p_GetContext = reinterpret_cast<GETCONTEXT>(0x7040D0);
|
||||
return p_GetContext();
|
||||
}
|
||||
@@ -478,12 +480,22 @@ namespace Nampower {
|
||||
|
||||
// combat check from Script_UnitAffectingCombat
|
||||
// only prevent right click if in combat
|
||||
if (unit && ((*(uint32_t *) (*(int32_t *) (unit + 0x110) + 0xa0) >> 0x13 & 1) != 0)) {
|
||||
if (unit && game::UnitIsInCombat(unit)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gUserSettings.preventRightClickPvPAttack) {
|
||||
// check if clicking player
|
||||
auto playerUnit = game::ClntObjMgrObjectPtr(game::TYPEMASK_PLAYER, objectGUID);
|
||||
|
||||
if (playerUnit && game::UnitIsPvpFlagged(playerUnit)) {
|
||||
// check if they have pvp enabled
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return onSpriteRightClick(objectGUID);
|
||||
}
|
||||
|
||||
@@ -543,10 +555,18 @@ namespace Nampower {
|
||||
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_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);
|
||||
@@ -624,19 +644,43 @@ namespace Nampower {
|
||||
}
|
||||
}
|
||||
|
||||
bool isFileInUse(const char *filename) {
|
||||
HANDLE file = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
|
||||
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_SHARING_VIOLATION || error == ERROR_LOCK_VIOLATION) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
CloseHandle(file);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool safeRemove(const char *filename) {
|
||||
if (isFileInUse(filename)) {
|
||||
return false;
|
||||
}
|
||||
return remove(filename) == 0;
|
||||
}
|
||||
|
||||
bool safeRename(const char *oldname, const char *newname) {
|
||||
if (isFileInUse(oldname) || isFileInUse(newname)) {
|
||||
return false;
|
||||
}
|
||||
return rename(oldname, newname) == 0;
|
||||
}
|
||||
|
||||
void loadConfig() {
|
||||
gStartTime = static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch()).count());
|
||||
|
||||
try {
|
||||
// remove/rename previous logs
|
||||
remove("nampower_debug.log.3");
|
||||
rename("nampower_debug.log.2", "nampower_debug.log.3");
|
||||
rename("nampower_debug.log.1", "nampower_debug.log.2");
|
||||
rename("nampower_debug.log", "nampower_debug.log.1");
|
||||
} catch (...) {
|
||||
// ignore any exceptions during log rotation
|
||||
}
|
||||
// remove/rename previous logs
|
||||
safeRemove("nampower_debug.log.3");
|
||||
safeRename("nampower_debug.log.2", "nampower_debug.log.3");
|
||||
safeRename("nampower_debug.log.1", "nampower_debug.log.2");
|
||||
safeRename("nampower_debug.log", "nampower_debug.log.1");
|
||||
|
||||
|
||||
// open new log file
|
||||
@@ -660,9 +704,12 @@ namespace Nampower {
|
||||
gUserSettings.optimizeBufferUsingPacketTimings = false;
|
||||
|
||||
gUserSettings.preventRightClickTargetChange = false;
|
||||
gUserSettings.preventRightClickPvPAttack = true;
|
||||
|
||||
gUserSettings.doubleCastToEndChannelEarly = false;
|
||||
|
||||
gUserSettings.spamProtectionEnabled = true;
|
||||
|
||||
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;
|
||||
@@ -885,6 +932,16 @@ namespace Nampower {
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_PreventRightClickPvPAttack[] = "NP_PreventRightClickPvPAttack";
|
||||
CVarRegister(NP_PreventRightClickPvPAttack, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
gUserSettings.preventRightClickPvPAttack ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_DoubleCastToEndChannelEarly[] = "NP_DoubleCastToEndChannelEarly";
|
||||
CVarRegister(NP_DoubleCastToEndChannelEarly, // name
|
||||
nullptr, // help
|
||||
@@ -895,6 +952,16 @@ namespace Nampower {
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_SpamProtectionEnabled[] = "NP_SpamProtectionEnabled";
|
||||
CVarRegister(NP_SpamProtectionEnabled, // name
|
||||
nullptr, // help
|
||||
0, // unk1
|
||||
gUserSettings.spamProtectionEnabled ? defaultTrue : defaultFalse, // default value address
|
||||
nullptr, // callback
|
||||
1, // category
|
||||
0, // unk2
|
||||
0); // unk3
|
||||
|
||||
char NP_ChannelLatencyReductionPercentage[] = "NP_ChannelLatencyReductionPercentage";
|
||||
CVarRegister(NP_ChannelLatencyReductionPercentage, // name
|
||||
nullptr, // help
|
||||
@@ -932,8 +999,12 @@ namespace Nampower {
|
||||
|
||||
loadUserVar("NP_PreventRightClickTargetChange");
|
||||
|
||||
loadUserVar("NP_PreventRightClickPvPAttack");
|
||||
|
||||
loadUserVar("NP_DoubleCastToEndChannelEarly");
|
||||
|
||||
loadUserVar("NP_SpamProtectionEnabled");
|
||||
|
||||
loadUserVar("NP_MinBufferTimeMs");
|
||||
loadUserVar("NP_NonGcdBufferTimeMs");
|
||||
loadUserVar("NP_MaxBufferIncreaseMs");
|
||||
@@ -975,7 +1046,8 @@ namespace Nampower {
|
||||
|
||||
// Template function to simplify hook initialization with specific storage
|
||||
template<typename FuncT, typename HookT>
|
||||
std::unique_ptr<hadesmem::PatchDetour<FuncT>> createHook(const hadesmem::Process& process, Offsets offset, HookT hookFunc) {
|
||||
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);
|
||||
detour->Apply();
|
||||
@@ -991,30 +1063,50 @@ namespace Nampower {
|
||||
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);
|
||||
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);
|
||||
gCastSpellByNameNoQueueDetour = createHook<LuaScriptT>(process, Offsets::Script_CastSpellByNameNoQueue, Script_CastSpellByNameNoQueue);
|
||||
gQueueSpellByNameDetour = createHook<LuaScriptT>(process, Offsets::Script_QueueSpellByName, Script_QueueSpellByName);
|
||||
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);
|
||||
gCastSpellByNameNoQueueDetour = createHook<LuaScriptT>(process, Offsets::Script_CastSpellByNameNoQueue,
|
||||
Script_CastSpellByNameNoQueue);
|
||||
gQueueSpellByNameDetour = createHook<LuaScriptT>(process, Offsets::Script_QueueSpellByName,
|
||||
Script_QueueSpellByName);
|
||||
qQueueScriptDetour = createHook<LuaScriptT>(process, Offsets::Script_QueueScript, Script_QueueScript);
|
||||
gIsSpellInRangeDetour = createHook<LuaScriptT>(process, Offsets::Script_IsSpellInRange, Script_IsSpellInRange);
|
||||
gIsSpellUsableDetour = createHook<LuaScriptT>(process, Offsets::Script_IsSpellUsable, Script_IsSpellUsable);
|
||||
gGetCurrentCastingInfoDetour = createHook<LuaScriptT>(process, Offsets::Script_GetCurrentCastingInfo, Script_GetCurrentCastingInfo);
|
||||
gGetSpellIdForNameDetour = createHook<LuaScriptT>(process, Offsets::Script_GetSpellIdForName, Script_GetSpellIdForName);
|
||||
gGetSpellNameAndRankForIdDetour = createHook<LuaScriptT>(process, Offsets::Script_GetSpellNameAndRankForId, Script_GetSpellNameAndRankForId);
|
||||
gGetSpellSlotAndTypeForNameDetour = createHook<LuaScriptT>(process, Offsets::Script_GetSpellSlotTypeIdForName, Script_GetSpellSlotTypeIdForName);
|
||||
gOnSpriteRightClickDetour = createHook<OnSpriteRightClickT>(process, Offsets::OnSpriteRightClick, OnSpriteRightClickHook);
|
||||
gChannelStopCastingNextTickDetour = createHook<LuaScriptT>(process, Offsets::Script_ChannelStopCastingNextTick, Script_ChannelStopCastingNextTick);
|
||||
gGetNampowerVersionDetour = createHook<LuaScriptT>(process, Offsets::Script_GetNampowerVersion, Script_GetNampowerVersion);
|
||||
gGetCurrentCastingInfoDetour = createHook<LuaScriptT>(process, Offsets::Script_GetCurrentCastingInfo,
|
||||
Script_GetCurrentCastingInfo);
|
||||
gGetSpellIdForNameDetour = createHook<LuaScriptT>(process, Offsets::Script_GetSpellIdForName,
|
||||
Script_GetSpellIdForName);
|
||||
gGetSpellNameAndRankForIdDetour = createHook<LuaScriptT>(process, Offsets::Script_GetSpellNameAndRankForId,
|
||||
Script_GetSpellNameAndRankForId);
|
||||
gGetSpellSlotAndTypeForNameDetour = createHook<LuaScriptT>(process, Offsets::Script_GetSpellSlotTypeIdForName,
|
||||
Script_GetSpellSlotTypeIdForName);
|
||||
gOnSpriteRightClickDetour = createHook<OnSpriteRightClickT>(process, Offsets::OnSpriteRightClick,
|
||||
OnSpriteRightClickHook);
|
||||
gChannelStopCastingNextTickDetour = createHook<LuaScriptT>(process, Offsets::Script_ChannelStopCastingNextTick,
|
||||
Script_ChannelStopCastingNextTick);
|
||||
gGetNampowerVersionDetour = createHook<LuaScriptT>(process, Offsets::Script_GetNampowerVersion,
|
||||
Script_GetNampowerVersion);
|
||||
gGetItemLevelDetour = createHook<LuaScriptT>(process, Offsets::Script_GetItemLevel, Script_GetItemLevel);
|
||||
gIEndSceneDetour = createHook<ISceneEndT>(process, Offsets::ISceneEndPtr, &ISceneEndHook);
|
||||
}
|
||||
@@ -1119,6 +1211,16 @@ namespace Nampower {
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) uint32_t Load() {
|
||||
Nampower::load();
|
||||
try {
|
||||
Nampower::load();
|
||||
} catch (const std::exception &e) {
|
||||
std::string errorMsg = "Exception in Nampower::load(): ";
|
||||
errorMsg += e.what();
|
||||
MessageBoxA(nullptr, errorMsg.c_str(), "Nampower Error", MB_OK | MB_ICONERROR);
|
||||
return EXIT_FAILURE;
|
||||
} catch (...) {
|
||||
MessageBoxA(nullptr, "Unknown exception in Nampower::load()", "Nampower Error", MB_OK | MB_ICONERROR);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
+5
-4
@@ -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 = 10;
|
||||
constexpr uint32_t PATCH_VERSION = 16;
|
||||
constexpr uint32_t MINOR_VERSION = 11;
|
||||
constexpr uint32_t PATCH_VERSION = 0;
|
||||
|
||||
constexpr int32_t LUA_REGISTRYINDEX = -10000;
|
||||
constexpr int32_t LUA_GLOBALSINDEX = -10001;
|
||||
@@ -110,7 +110,7 @@ namespace Nampower {
|
||||
using LuaCallT = void (__fastcall *)(const char *code, const char *unused);
|
||||
using LuaScriptT = uint32_t (__fastcall *)(uintptr_t *luaState);
|
||||
using GetGUIDFromNameT = std::uint64_t (__fastcall *)(const char *);
|
||||
using GetUnitFromNameT = uintptr_t (__fastcall *)(const char *);
|
||||
using GetUnitFromNameT = uintptr_t *(__fastcall *)(const char *);
|
||||
using lua_gettableT = void (__fastcall *)(uintptr_t *luaState, int globalsIndex);
|
||||
using lua_isstringT = bool (__fastcall *)(uintptr_t *, int);
|
||||
using lua_isnumberT = bool (__fastcall *)(uintptr_t *, int);
|
||||
@@ -131,7 +131,8 @@ namespace Nampower {
|
||||
using SpellVisualsInitializeT = void (__stdcall *)(void);
|
||||
|
||||
using PlaySpellVisual = void (__stdcall *)(int **param_1, void *param_2, int param_3, void **param_4);
|
||||
using CGUnit_C_ClearCastingSpellT = void (__thiscall *)(uintptr_t *unit, uint32_t param_1, int param_2, int param_3);
|
||||
using CGUnit_C_ClearCastingSpellT = void (__thiscall *)(uintptr_t *unit, uint32_t param_1, int param_2,
|
||||
int param_3);
|
||||
using CGUnit_C_ClearSpellEffectT = void (__thiscall *)(uintptr_t *unit, uint32_t param_1, int param_2);
|
||||
|
||||
using GetBuffByIndexT = uintptr_t *(__fastcall *)(int index);
|
||||
|
||||
+13
-10
@@ -521,20 +521,23 @@ namespace Nampower {
|
||||
// if cast in the last second and still waiting for server result or succeeded
|
||||
// otherwise can break cooldown in the client and cause unnecessary errors
|
||||
if (castTime == 0 || spell->Attributes & game::SPELL_ATTR_DISABLED_WHILE_ACTIVE) {
|
||||
auto castParams = gCastHistory.findNewestWaitingForServerSpellId(spellId);
|
||||
if (castParams &&
|
||||
currentTime - castParams->castStartTimeMs < 500) {
|
||||
DEBUG_LOG("Ignoring " << spellName
|
||||
<< " cast still waiting for server result for the same spell");
|
||||
return false;
|
||||
} else {
|
||||
castParams = gCastHistory.findNewestSuccessfulSpellId(spellId);
|
||||
// check if spam protection is enabled
|
||||
if(gUserSettings.spamProtectionEnabled) {
|
||||
auto castParams = gCastHistory.findNewestWaitingForServerSpellId(spellId);
|
||||
if (castParams &&
|
||||
castParams->guid == guid &&
|
||||
currentTime - castParams->castStartTimeMs < 500) {
|
||||
DEBUG_LOG("Ignoring " << spellName
|
||||
<< " cast recently succeeded for the same spell and target");
|
||||
<< " cast still waiting for server result for the same spell");
|
||||
return false;
|
||||
} else {
|
||||
castParams = gCastHistory.findNewestSuccessfulSpellId(spellId);
|
||||
if (castParams &&
|
||||
castParams->guid == guid &&
|
||||
currentTime - castParams->castStartTimeMs < 500) {
|
||||
DEBUG_LOG("Ignoring " << spellName
|
||||
<< " cast recently succeeded for the same spell and target");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,12 @@ struct UserSettings {
|
||||
bool optimizeBufferUsingPacketTimings;
|
||||
|
||||
bool preventRightClickTargetChange;
|
||||
bool preventRightClickPvPAttack;
|
||||
|
||||
bool doubleCastToEndChannelEarly;
|
||||
|
||||
bool spamProtectionEnabled;
|
||||
|
||||
uint32_t spellQueueWindowMs;
|
||||
uint32_t onSwingBufferCooldownMs;
|
||||
uint32_t channelQueueWindowMs;
|
||||
|
||||
Reference in New Issue
Block a user