Merge pull request #16 from Dusk-92/test/aoe-loot-classicapi-cleanup
Make AoE Loot authoritative across autoloot systems
This commit is contained in:
@@ -50,6 +50,9 @@ API.containeritems = type(_G.C_Container) == "table"
|
|||||||
API.containeriteminfo = type(_G.C_Container) == "table"
|
API.containeriteminfo = type(_G.C_Container) == "table"
|
||||||
and type(_G.C_Container.GetContainerItemInfo) == "function"
|
and type(_G.C_Container.GetContainerItemInfo) == "function"
|
||||||
|
|
||||||
|
API.containeropenable = type(_G.C_Container) == "table"
|
||||||
|
and type(_G.C_Container.IsContainerItemOpenable) == "function"
|
||||||
|
|
||||||
API.items = type(_G.C_Item) == "table"
|
API.items = type(_G.C_Item) == "table"
|
||||||
API.iteminfo = API.items and type(_G.C_Item.GetItemInfo) == "function"
|
API.iteminfo = API.items and type(_G.C_Item.GetItemInfo) == "function"
|
||||||
API.iteminfoinstant = API.items
|
API.iteminfoinstant = API.items
|
||||||
@@ -119,6 +122,11 @@ API.loothistoryevents = API.loothistory and API.eventutils
|
|||||||
and _G.C_EventUtils.IsEventValid("LOOT_HISTORY_FULL_UPDATE")
|
and _G.C_EventUtils.IsEventValid("LOOT_HISTORY_FULL_UPDATE")
|
||||||
API.lootrollitemid = type(_G.GetLootRollItemID) == "function"
|
API.lootrollitemid = type(_G.GetLootRollItemID) == "function"
|
||||||
|
|
||||||
|
API.aoeloot = type(_G.C_Loot) == "table"
|
||||||
|
and type(_G.C_Loot.GetNearbyLootableUnits) == "function"
|
||||||
|
and type(_G.C_Loot.IsScanInProgress) == "function"
|
||||||
|
and type(_G.C_Loot.LootAllCorpses) == "function"
|
||||||
|
|
||||||
API.overridebindings = type(_G.SetOverrideBindingClick) == "function"
|
API.overridebindings = type(_G.SetOverrideBindingClick) == "function"
|
||||||
and type(_G.ClearOverrideBindings) == "function"
|
and type(_G.ClearOverrideBindings) == "function"
|
||||||
|
|
||||||
@@ -380,6 +388,30 @@ API.GetContainerNumFreeSlots = function(bag)
|
|||||||
return 0, 0
|
return 0, 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
API.IsContainerItemOpenable = function(bag, slot)
|
||||||
|
if API.containeropenable then
|
||||||
|
return _G.C_Container.IsContainerItemOpenable(bag, slot)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
API.GetNearbyLootableUnits = function()
|
||||||
|
if API.aoeloot then
|
||||||
|
return _G.C_Loot.GetNearbyLootableUnits()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
API.IsLootScanInProgress = function()
|
||||||
|
return API.aoeloot and _G.C_Loot.IsScanInProgress() or false
|
||||||
|
end
|
||||||
|
|
||||||
|
API.LootAllCorpses = function(maxCount)
|
||||||
|
if API.aoeloot then
|
||||||
|
if maxCount then return _G.C_Loot.LootAllCorpses(maxCount) end
|
||||||
|
return _G.C_Loot.LootAllCorpses()
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
-- ClassicAPI updates its own left/right modifier bitmap before firing
|
-- ClassicAPI updates its own left/right modifier bitmap before firing
|
||||||
-- MODIFIER_STATE_CHANGED. Prefer that state over vanilla's merged Win32 key
|
-- MODIFIER_STATE_CHANGED. Prefer that state over vanilla's merged Win32 key
|
||||||
-- state when the richer ClassicAPI functions are available.
|
-- state when the richer ClassicAPI functions are available.
|
||||||
|
|||||||
+57
-71
@@ -1,6 +1,7 @@
|
|||||||
-- Adapted from AoELoot by Sandrea / ChatGPT for ShaguTweaks-ClassicAPI.
|
-- Adapted from AoELoot by Sandrea / ChatGPT for ShaguTweaks-ClassicAPI.
|
||||||
|
|
||||||
local T = ShaguTweaks.T
|
local T = ShaguTweaks.T
|
||||||
|
local API = ShaguTweaks.API
|
||||||
|
|
||||||
local module = ShaguTweaks:register({
|
local module = ShaguTweaks:register({
|
||||||
title = T["AoE Loot"],
|
title = T["AoE Loot"],
|
||||||
@@ -11,15 +12,24 @@ local module = ShaguTweaks:register({
|
|||||||
})
|
})
|
||||||
|
|
||||||
module.enable = function(self)
|
module.enable = function(self)
|
||||||
|
-- AoE Loot relies entirely on ClassicAPI's native corpse walker,
|
||||||
|
-- container classification and timer. Do not keep partial legacy behavior
|
||||||
|
-- when those capabilities are unavailable.
|
||||||
|
if not API or not API.aoeloot or not API.containeropenable or not API.timer then return end
|
||||||
|
|
||||||
local frame = CreateFrame("Frame", "ShaguTweaksAoELoot")
|
local frame = CreateFrame("Frame", "ShaguTweaksAoELoot")
|
||||||
local pending = false
|
local pending = false
|
||||||
local releaseDeadline = 0
|
|
||||||
local containerLootDeadline = 0
|
local containerLootDeadline = 0
|
||||||
|
local takeoverGeneration = 0
|
||||||
|
local TAKEOVER_DELAY = 0.3
|
||||||
|
|
||||||
|
local function CancelTakeover()
|
||||||
|
takeoverGeneration = takeoverGeneration + 1
|
||||||
|
pending = false
|
||||||
|
end
|
||||||
|
|
||||||
local function TrackContainerUse(bag, slot)
|
local function TrackContainerUse(bag, slot)
|
||||||
if not C_Container or not C_Container.IsContainerItemOpenable then return end
|
local isOpenable, canOpen = API.IsContainerItemOpenable(bag, slot)
|
||||||
|
|
||||||
local isOpenable, canOpen = C_Container.IsContainerItemOpenable(bag, slot)
|
|
||||||
if isOpenable and canOpen then
|
if isOpenable and canOpen then
|
||||||
-- LOOT_OPENED is also fired by clams, lockboxes and similar bag items.
|
-- LOOT_OPENED is also fired by clams, lockboxes and similar bag items.
|
||||||
-- Mark that session before UseContainerItem runs so it remains under the
|
-- Mark that session before UseContainerItem runs so it remains under the
|
||||||
@@ -39,97 +49,73 @@ module.enable = function(self)
|
|||||||
|
|
||||||
local function CanStartAoELoot()
|
local function CanStartAoELoot()
|
||||||
if IsMasterLootActive() then return false end
|
if IsMasterLootActive() then return false end
|
||||||
if not C_Loot or not C_Loot.LootAllCorpses then return false end
|
if API.IsLootScanInProgress() then return false end
|
||||||
|
|
||||||
if C_Loot.IsScanInProgress and C_Loot.IsScanInProgress() then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function HasNearbyLootableCorpse()
|
local function HasNearbyLootableCorpse()
|
||||||
-- Older ClassicAPI builds may not expose the query yet. Keep AoE Loot
|
local units = API.GetNearbyLootableUnits()
|
||||||
-- functional there; the container hook above still protects bag items.
|
|
||||||
if not C_Loot or not C_Loot.GetNearbyLootableUnits then return true end
|
|
||||||
|
|
||||||
local units = C_Loot.GetNearbyLootableUnits()
|
|
||||||
return type(units) == "table" and table.getn(units) > 0
|
return type(units) == "table" and table.getn(units) > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local function StartAoELoot()
|
local function StartAoELoot(generation)
|
||||||
-- Defer for one frame so the normal loot session can close cleanly.
|
if generation ~= takeoverGeneration or not pending then return end
|
||||||
frame:SetScript("OnUpdate", nil)
|
|
||||||
pending = false
|
pending = false
|
||||||
releaseDeadline = 0
|
|
||||||
|
|
||||||
if CanStartAoELoot() then
|
if CanStartAoELoot() then
|
||||||
C_Loot.LootAllCorpses()
|
API.LootAllCorpses()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function QueueAoELoot()
|
local function TakeOverLootSession()
|
||||||
releaseDeadline = 0
|
-- AoE Loot owns corpse sessions while enabled. Close the normal client
|
||||||
frame:SetScript("OnUpdate", StartAoELoot)
|
-- window immediately so Vanilla autoloot, SuperAPI SetAutoloot modes and
|
||||||
end
|
-- quickloot-patched clients cannot keep control of the session.
|
||||||
|
takeoverGeneration = takeoverGeneration + 1
|
||||||
|
local generation = takeoverGeneration
|
||||||
|
pending = true
|
||||||
|
CloseLoot()
|
||||||
|
|
||||||
local function WaitForLootRelease()
|
-- Native autoloot may already have emitted loot packets before LOOT_OPENED
|
||||||
-- Native Auto Loot can finish before this module receives LOOT_OPENED.
|
-- reaches Lua. ClassicAPI's own loot test uses the same 0.3s settling
|
||||||
-- In that case LOOT_CLOSED has already passed, so use the empty session
|
-- window between loot operations; after it expires the native corpse walker
|
||||||
-- as a fallback and queue the ClassicAPI walk on the following frame.
|
-- becomes the sole owner of all remaining nearby corpse loot.
|
||||||
if pending and (not GetNumLootItems or GetNumLootItems() == 0) then
|
C_Timer.After(TAKEOVER_DELAY, function()
|
||||||
QueueAoELoot()
|
StartAoELoot(generation)
|
||||||
elseif pending and GetTime() >= releaseDeadline then
|
end)
|
||||||
-- Never leave a per-frame waiter behind if the native loot session
|
|
||||||
-- cannot finish, for example because every inventory bag is full.
|
|
||||||
pending = false
|
|
||||||
releaseDeadline = 0
|
|
||||||
frame:SetScript("OnUpdate", nil)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
frame:RegisterEvent("LOOT_OPENED")
|
frame:RegisterEvent("LOOT_OPENED")
|
||||||
frame:RegisterEvent("LOOT_CLOSED")
|
|
||||||
|
|
||||||
frame:SetScript("OnEvent", function()
|
frame:SetScript("OnEvent", function()
|
||||||
if event == "LOOT_OPENED" then
|
if event ~= "LOOT_OPENED" then return end
|
||||||
-- Inventory containers use the same loot events as corpses. Let the
|
|
||||||
-- normal client finish them instead of closing their loot session.
|
|
||||||
if containerLootDeadline > 0 then
|
|
||||||
local isContainerLoot = GetTime() <= containerLootDeadline
|
|
||||||
containerLootDeadline = 0
|
|
||||||
if isContainerLoot then return end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- The master looter must keep the normal window to inspect and assign loot.
|
-- Inventory containers use the same loot event as corpses. Let the normal
|
||||||
if IsMasterLootActive() then
|
-- client finish them instead of treating them as an AoE-loot trigger.
|
||||||
pending = false
|
if containerLootDeadline > 0 then
|
||||||
releaseDeadline = 0
|
local isContainerLoot = GetTime() <= containerLootDeadline
|
||||||
frame:SetScript("OnUpdate", nil)
|
containerLootDeadline = 0
|
||||||
|
if isContainerLoot then
|
||||||
|
CancelTakeover()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Chests, fishing nodes and other non-corpse sources also emit
|
-- The master looter must keep the normal window to inspect and assign loot.
|
||||||
-- LOOT_OPENED. AoE Loot only has work to do when ClassicAPI can actually
|
if IsMasterLootActive() then
|
||||||
-- see at least one nearby lootable unit.
|
CancelTakeover()
|
||||||
if not HasNearbyLootableCorpse() then return end
|
|
||||||
|
|
||||||
if pending or not CanStartAoELoot() then return end
|
|
||||||
|
|
||||||
pending = true
|
|
||||||
releaseDeadline = GetTime() + 3
|
|
||||||
frame:SetScript("OnUpdate", WaitForLootRelease)
|
|
||||||
|
|
||||||
-- Close the normal session so ClassicAPI can take over. The temporary
|
|
||||||
-- waiter also handles clients whose native Auto Loot already completed
|
|
||||||
-- and fired LOOT_CLOSED before this module received LOOT_OPENED.
|
|
||||||
CloseLoot()
|
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if event == "LOOT_CLOSED" and pending then
|
-- Chests, fishing nodes and other non-corpse sources also emit LOOT_OPENED.
|
||||||
QueueAoELoot()
|
-- Only take over when ClassicAPI can see at least one nearby lootable unit.
|
||||||
end
|
if not HasNearbyLootableCorpse() then return end
|
||||||
|
|
||||||
|
-- A queued takeover already owns this interaction. ClassicAPI suppresses
|
||||||
|
-- its own LOOT_OPENED/LOOT_CLOSED events while walking corpses, so no
|
||||||
|
-- additional session needs to be stacked here.
|
||||||
|
if pending then return end
|
||||||
|
|
||||||
|
TakeOverLootSession()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user