聊天重做前缓存

This commit is contained in:
rucky
2026-04-09 09:46:47 +08:00
parent 6e18269bfd
commit e915bbd74a
39 changed files with 8501 additions and 2308 deletions

View File

@@ -1148,11 +1148,9 @@ end
-- unit under the mouse cursor without changing current target.
--
-- Strategy:
-- UseAction hook: temporarily TargetUnit(moUnit) before the real UseAction,
-- then restore previous target afterwards. This preserves the hardware
-- event callstack so the client doesn't reject the action.
-- CastSpellByName hook (SuperWoW): pass moUnit as 2nd arg directly.
-- CastSpellByName hook (no SuperWoW): same target-swap trick.
-- Temporarily try the mouseover unit first while preserving the original
-- target. If the spell cannot resolve on mouseover, stop the pending target
-- mode, restore the original target, and retry there.
--------------------------------------------------------------------------------
local mouseoverCastEnabled = false
local origUseAction = nil
@@ -1176,6 +1174,70 @@ local function GetMouseoverUnit()
return nil
end
local function CaptureTargetState()
local hadTarget = UnitExists("target")
return {
hadTarget = hadTarget,
name = hadTarget and UnitName("target") or nil,
}
end
local function RestoreTargetState(state)
if not state then return end
if state.hadTarget and state.name then
TargetLastTarget()
if not UnitExists("target") or UnitName("target") ~= state.name then
TargetByName(state.name, true)
end
else
ClearTarget()
end
end
local function ResolvePendingSpellTarget(unit)
if not (SpellIsTargeting and SpellIsTargeting()) then
return true
end
if unit then
if SpellCanTargetUnit then
if SpellCanTargetUnit(unit) then
SpellTargetUnit(unit)
end
else
SpellTargetUnit(unit)
end
end
if SpellIsTargeting and SpellIsTargeting() then
return false
end
return true
end
local function TryActionOnUnit(unit, action, cursor, onSelf)
if not unit then return false end
if not (UnitIsUnit and UnitExists("target") and UnitIsUnit(unit, "target")) then
TargetUnit(unit)
end
origUseAction(action, cursor, onSelf)
return ResolvePendingSpellTarget(unit)
end
local function TryCastSpellOnUnit(unit, spell)
if not unit then return false end
if not (UnitIsUnit and UnitExists("target") and UnitIsUnit(unit, "target")) then
TargetUnit(unit)
end
origCastSpellByName(spell)
return ResolvePendingSpellTarget(unit)
end
local function MouseoverUseAction(action, cursor, onSelf)
-- Don't interfere: picking up action, or re-entrant call
if cursor == 1 or inMouseoverAction then
@@ -1187,42 +1249,24 @@ local function MouseoverUseAction(action, cursor, onSelf)
return origUseAction(action, cursor, onSelf)
end
-- Skip if mouseover IS current target (no swap needed)
if UnitIsUnit and UnitExists("target") and UnitIsUnit(moUnit, "target") then
return origUseAction(action, cursor, onSelf)
end
local prevTarget = CaptureTargetState()
-- Remember current target state
local hadTarget = UnitExists("target")
local prevTargetName = hadTarget and UnitName("target") or nil
-- Temporarily target the mouseover unit
inMouseoverAction = true
TargetUnit(moUnit)
local castOnMouseover = TryActionOnUnit(moUnit, action, cursor, onSelf)
-- Execute the real UseAction on the now-targeted mouseover unit
origUseAction(action, cursor, onSelf)
-- Handle ground-targeted spells (Blizzard, Flamestrike, etc.)
if SpellIsTargeting and SpellIsTargeting() then
SpellTargetUnit(moUnit)
end
if SpellIsTargeting and SpellIsTargeting() then
if not castOnMouseover and SpellIsTargeting and SpellIsTargeting() then
SpellStopTargeting()
end
-- Restore previous target
if hadTarget and prevTargetName then
-- Target back the previous unit
TargetLastTarget()
-- Verify restoration worked
if not UnitExists("target") or UnitName("target") ~= prevTargetName then
-- TargetLastTarget failed, try by name
TargetByName(prevTargetName, true)
RestoreTargetState(prevTarget)
if not castOnMouseover and prevTarget.hadTarget then
origUseAction(action, cursor, onSelf)
if SpellIsTargeting and SpellIsTargeting() then
if not ResolvePendingSpellTarget("target") then
SpellStopTargeting()
end
end
else
-- Had no target before, clear
ClearTarget()
end
inMouseoverAction = false
@@ -1244,43 +1288,26 @@ local function MouseoverCastSpellByName(spell, arg2)
return origCastSpellByName(spell)
end
-- SuperWoW: direct unit parameter, no target swap needed
if SUPERWOW_VERSION then
origCastSpellByName(spell, moUnit)
if SpellIsTargeting and SpellIsTargeting() then
SpellTargetUnit(moUnit)
end
if SpellIsTargeting and SpellIsTargeting() then
SpellStopTargeting()
end
return
end
local prevTarget = CaptureTargetState()
-- No SuperWoW: target-swap
local hadTarget = UnitExists("target")
local prevTargetName = hadTarget and UnitName("target") or nil
inMouseoverAction = true
local castOnMouseover = TryCastSpellOnUnit(moUnit, spell)
if not (hadTarget and UnitIsUnit and UnitIsUnit(moUnit, "target")) then
TargetUnit(moUnit)
end
origCastSpellByName(spell)
if SpellIsTargeting and SpellIsTargeting() then
SpellTargetUnit("target")
end
if SpellIsTargeting and SpellIsTargeting() then
if not castOnMouseover and SpellIsTargeting and SpellIsTargeting() then
SpellStopTargeting()
end
if hadTarget and prevTargetName then
TargetLastTarget()
if not UnitExists("target") or UnitName("target") ~= prevTargetName then
TargetByName(prevTargetName, true)
RestoreTargetState(prevTarget)
if not castOnMouseover and prevTarget.hadTarget then
origCastSpellByName(spell)
if SpellIsTargeting and SpellIsTargeting() then
if not ResolvePendingSpellTarget("target") then
SpellStopTargeting()
end
end
elseif not hadTarget then
ClearTarget()
end
inMouseoverAction = false
end
local function InitMouseoverCast()