+-- Inspect.lua
+local _;
+local next, print = next, print;
+local format = string.format;
+local InCombatLockdown = InCombatLockdown;
+local CTimerAfter = C_Timer.After;
+local IsInGroup, IsInRaid = IsInGroup, IsInRaid;
+local CheckInteractDistance = CheckInteractDistance;
+local GetTime, UnitGUID, UnitName = GetTime, UnitGUID, UnitName;
+local CanInspect, NotifyInspect, ClearInspectPlayer = CanInspect, NotifyInspect, ClearInspectPlayer;
+local GetInventoryItemLink, GetInventoryItemID = GetInventoryItemLink, GetInventoryItemID;
+local GetTalentInfo, GetInspectSpecialization = GetTalentInfo, GetInspectSpecialization;
+local INVSLOT_MAINHAND, INVSLOT_WRIST = INVSLOT_MAINHAND, INVSLOT_WRIST;
+
+local cache = {};
+local pending = {};
+local inspecting = nil;
+local inspectui = nil;
+local frame = CreateFrame("Frame", "OmaInspect");
+frame:Hide();
+OmaInspect = {};
+
+local redoGuid = nil;
+local function redo()
+ if redoGuid and inspecting == redoGuid then
+ print("hit redo timeout, putting back on pending");
+ pending[redoGuid] = true;
+ inspecting = nil;
+ redoGuid = nil;
+ if not inspectui then ClearInspectPlayer() end
+ end
+end
+
+local function inspect(id)
+ local guid = UnitGUID(id);
+ if not guid then return end
+ if InCombatLockdown() then
+ pending[guid] = true;
+ elseif not inspectui then
+ -- not necessary, but there's too many issues with inspect,
+ -- try to hope being nearby makes it more likely to work
+ -- no need to inspect people not in range before pull anyway
+ if CheckInteractDistance(id, 1) then
+ if not inspecting then
+ inspecting = guid;
+ print("Sending inspect", UnitName(id));
+ NotifyInspect(id);
+ redoGuid = guid;
+ CTimerAfter(20, redo);
+ else
+ pending[guid] = true;
+ end
+ else
+ pending[guid] = true;
+ end
+ else
+ pending[guid] = true;
+ end
+end
+
+hooksecurefunc("InspectUnit", function()
+ inspectui = true;
+end);
+hooksecurefunc("NotifyInspect", function(id)
+ if inspecting ~= UnitGUID(id) then
+ inspectui = true;
+ end
+end);
+hooksecurefunc("ClearInspectPlayer", function()
+ inspectui = nil;
+end);
+
+local function tick()
+ -- make sure pending inspects get done at some point
+ if not InCombatLockdown() then
+ local guid, _ = next(pending);
+ if guid and cache[guid] and cache[guid].id then
+ pending[guid] = nil;
+ inspect(cache[guid].id);
+ end
+ end
+ CTimerAfter(2, tick);
+end
+
+function OmaInspect.Request(guid, id, callback, needItems, force)
+ if not id or not CanInspect(id) then return false end
+ if not guid or UnitGUID(id) ~= guid then return false end
+
+ if not cache[guid] then cache[guid] = {} end
+ local cached = cache[guid];
+ if not cached.time then cached.time = 0 end
+ cached.id = id;
+ cached.cb = callback;
+ cached.needItems = needItems;
+ local elapsed = GetTime() - cached.time;
+ if force or (not needItems and (not cached.talent ~= nil or elapsed > 60)) or
+ (needItems and (not cached.weapon or elapsed > 60)) then
+ if not pending[guid] or inspecting ~= guid then -- don't send multiple inspects
+ inspect(id);
+ end
+ else
+ cached.cb(guid, cached.spec, cached.talent, cached.weapon, cached.wrist);
+ end
+ return true;
+end
+
+local function inspectReady(guid)
+ if not guid or inspectui then return end
+ local cached = cache[guid];
+ if cached and cached.id and UnitGUID(cached.id) == guid then
+ local time = GetTime();
+ local id = cached.id;
+ inspecting = nil;
+ redoGuid = nil;
+ if InCombatLockdown() and not inspectui then
+ pending[guid] = true;
+ ClearInspectPlayer();
+ else
+ if CanInspect(id) then
+ if time - cached.time > 60 then -- refresh >1min
+ -- new inspect
+ cached.time = time;
+ if needItems then
+ cached.weapon = GetInventoryItemLink(id, INVSLOT_MAINHAND);
+ cached.wrist = GetInventoryItemID(id, INVSLOT_WRIST);
+ end
+ cached.spec = GetInspectSpecialization(id);
+ local _, _, _, selected = GetTalentInfo(6, 2, 1, true, id);
+ cached.talent = selected;
+ end
+ end
+ ClearInspectPlayer();
+ if (cached.needItems and cached.weapon) or
+ (not cached.needItems and cached.talent ~= nil) then
+ print("Got inspect done", UnitName(id));
+ cached.cb(guid, cached.spec, cached.talent, cached.weapon, cached.wrist);
+ else
+ pending[guid] = true;
+ end
+ end
+ end
+end
+
+local function updateIds()
+ local size = 0;
+ local prefix = "solo";
+ if IsInGroup() then
+ if IsInRaid() then
+ size = 40;
+ prefix = "raid";
+ else
+ size = 4;
+ prefix = "party";
+ end
+ end
+ for i = 1,size do
+ local id = format("%s%i", prefix, i);
+ local guid = UnitGUID(id);
+ if cache[guid] then cache[guid].id = id end
+ end
+end
+
+local function create()
+ frame:UnregisterAllEvents();
+ frame:SetScript("OnEvent", function(self, event, guid)
+ if event == "INSPECT_READY" then
+ inspectReady(guid);
+ elseif event == "GROUP_ROSTER_UPDATE" then
+ updateIds();
+ end
+ end);
+ frame:RegisterEvent("INSPECT_READY");
+ frame:RegisterEvent("GROUP_ROSTER_UPDATE");
+ tick();
+end
+
+frame:RegisterEvent("PLAYER_LOGIN");
+frame:SetScript("OnEvent", function(self, event)
+ if event == "PLAYER_LOGIN" then
+ return create();
+ end
+end);