Updates for 11.2 ? LUA Error since PrePatch
Niyuni opened this issue · 3 comments
433x QuestPlates/QuestPlates.lua:113: attempt to call field 'SurfaceArgs' (a nil value)
[string "@QuestPlates/QuestPlates.lua"]:113: in function GetQuestProgress' [string "@QuestPlates/QuestPlates.lua"]:260: in function <QuestPlates/QuestPlates.lua:247> [string "@QuestPlates/QuestPlates.lua"]:326: in function
?'
[string "@QuestPlates/semlib/eve.lua"]:15: in function <QuestPlates/semlib/eve.lua:12>
[string "@QuestPlates/semlib/SemlarPlates.lua"]:61: in function `?'
[string "@QuestPlates/semlib/eve.lua"]:15: in function <QuestPlates/semlib/eve.lua:12>
Locals:
unitID = "nameplate1"
tooltipData =
dataInstanceID = 5650
type = 2
guid = "Creature-0-4245-2552-212-223657-00004883F4"
lines =
}
healthGUID = "Creature-0-4245-2552-212-223657-00004883F4"
}
progressGlob = nil
questType = nil
objectiveCount = 0
questTexture = nil
questLogIndex = nil
questID = nil
(for index) = 3
(for limit) = 5
(for step) = 1
i = 3
line =
leftColor =
}
type = 0
leftText = "Elementar"
}
(*temporary) = nil
(*temporary) =
leftColor =
}
type = 0
leftText = "Elementar"
}
(*temporary) = "attempt to call field 'SurfaceArgs' (a nil value)"
ActiveWorldQuests =
}
OurName = "Niyuni"
Here's your fix.
Event Handling:
The PLAYER_LOGIN
, QUEST_ACCEPTED
, QUEST_REMOVED
, and QUEST_WATCH_LIST_CHANGED
events correctly update the ActiveWorldQuests
table and trigger updates to quest progress.
Tooltip Processing:
The GetQuestProgress
function safely handles the tooltip data and includes a fallback if TooltipUtil.SurfaceArgs
is unavailable. This ensures no errors occur during the tooltip parsing.
Quest Icon Management:
The UpdateQuestIcon
function is responsible for updating the quest icons on nameplates based on the current quest progress, handling various quest states, and ensuring the correct visuals are displayed.
Re-anchoring and Loading:
The ADDON_LOADED
event re-anchors the quest icons when the addon is loaded, ensuring the visual settings are applied.
-- QuestPlates.lua
-- ICON SETTINGS
QuestPlateSettings = {
AnchorPoint = 'RIGHT', -- Point of icon to anchor to nameplate (CENTER, LEFT, RIGHT, TOP, BOTTOM)
RelativeTo = 'LEFT', -- Point of nameplate to anchor icon to (CENTER, LEFT, RIGHT, TOP, BOTTOM)
OffsetX = 0, -- Horizontal offset for icon (from anchor point)
OffsetY = 0, -- Vertical offset for icon
IconScale = 1, -- Scale for icon
}
local addonName, addon = ...
local E = addon:Eve()
local TextureAtlases = {
['item'] = 'Banker', -- bag icon, you have to loot something for this quest
}
local ActiveWorldQuests = {}
do
function E:PLAYER_LOGIN()
local uiMapID = C_Map.GetBestMapForUnit('player')
if uiMapID then
for _, task in pairs(C_TaskQuest.GetQuestsForPlayerByMapID(uiMapID) or {}) do
if task.inProgress then
local questID = task.questId
local questName = C_TaskQuest.GetQuestInfoByQuestID(questID)
if questName then
ActiveWorldQuests[questName] = questID
end
end
end
end
end
function E:QUEST_ACCEPTED(questLogIndex, questID, ...)
if questID and C_QuestLog.IsQuestTask(questID) then
local questName = C_TaskQuest.GetQuestInfoByQuestID(questID)
if questName then
ActiveWorldQuests[questName] = questID
end
end
E:UNIT_QUEST_LOG_CHANGED()
end
function E:QUEST_REMOVED(questID)
local questName = C_TaskQuest.GetQuestInfoByQuestID(questID)
if questName and ActiveWorldQuests[questName] then
ActiveWorldQuests[questName] = nil
end
E:UNIT_QUEST_LOG_CHANGED()
end
function E:QUEST_WATCH_LIST_CHANGED(questID, added)
E:QUEST_ACCEPTED(nil, questID)
end
end
local OurName = UnitName('player')
QuestLogIndex = {}
function GetQuestProgress(unitID)
if not C_QuestLog.UnitIsRelatedToActiveQuest(unitID) then return end
local tooltipData = C_TooltipInfo.GetUnit(unitID)
local progressGlob
local questType
local objectiveCount = 0
local questLogIndex
local questID
for i = 3, #tooltipData.lines do
local line = tooltipData.lines[i]
-- Check if TooltipUtil.SurfaceArgs exists
if TooltipUtil and TooltipUtil.SurfaceArgs then
TooltipUtil.SurfaceArgs(line)
else
-- Fallback logic if SurfaceArgs is not available
end
if line.type == 17 and line.id then
local text, objectiveType, finished = GetQuestObjectiveInfo(line.id, 1, false)
questID = questID or line.id or text and ActiveWorldQuests[text]
local playerName = ""
local progressText = text
local isQuestText = not not progressText
if playerName and playerName ~= '' and playerName ~= OurName then
if not questType then
questType = 2
end
else
if isQuestText then
local x, y = strmatch(progressText, '(%d+)/(%d+)')
if x and y then
local numLeft = y - x
if numLeft > objectiveCount then
objectiveCount = numLeft
end
else
local progress = tonumber(strmatch(progressText, '([%d%.]+)%%'))
if progress and progress <= 100 then
local questType = 3
return text, questType, ceil(100 - progress), questID
end
end
if not x or (x and y and x ~= y) then
progressGlob = progressGlob and progressGlob .. '\n' .. progressText or progressText
end
elseif ActiveWorldQuests[text] then
local progress = C_TaskQuest.GetQuestProgressBarInfo(questID)
if progress then
local questType = 3
return text, questType, ceil(100 - progress), questID
end
elseif QuestLogIndex[text] then
questLogIndex = QuestLogIndex[text]
end
end
end
end
return progressGlob, progressGlob and 1 or questType, objectiveCount, questLogIndex, questID
end
local QuestPlates = {} -- [plate] = f
function E:OnNewPlate(f, plate)
local frame = CreateFrame('frame', nil, f)
frame:Hide()
frame:SetAllPoints(f)
QuestPlates[plate] = frame
local icon = frame:CreateTexture(nil, nil, nil, 0)
icon:SetSize(28, 22)
icon:SetTexture('Interface/QuestFrame/AutoQuest-Parts')
icon:SetTexCoord(0.30273438, 0.41992188, 0.015625, 0.953125)
icon:SetPoint(QuestPlateSettings.AnchorPoint or 'RIGHT', frame, QuestPlateSettings.RelativeTo or 'LEFT', (QuestPlateSettings.OffsetX or 0) / (QuestPlateSettings.IconScale or 1), (QuestPlateSettings.OffsetY or 0) / (QuestPlateSettings.IconScale or 1))
frame:SetScale(QuestPlateSettings.IconScale or 1)
frame.jellybean = icon
local itemTexture = frame:CreateTexture(nil, nil, nil, 1)
itemTexture:SetPoint('TOPRIGHT', icon, 'BOTTOMLEFT', 12, 12)
itemTexture:SetSize(16, 16)
itemTexture:SetMask('Interface/CharacterFrame/TempPortraitAlphaMask')
itemTexture:Hide()
frame.itemTexture = itemTexture
-- Loot icon, display if mob needs to be looted for quest item
local lootIcon = frame:CreateTexture(nil, nil, nil, 1)
lootIcon:SetAtlas('Banker')
lootIcon:SetSize(16, 16)
lootIcon:SetPoint('TOPLEFT', icon, 'BOTTOMRIGHT', -12, 12)
lootIcon:Hide()
frame.lootIcon = lootIcon
local iconText = frame:CreateFontString(nil, 'OVERLAY', 'SystemFont_Outline_Small')
iconText:SetPoint('CENTER', icon, 0.8, 0)
iconText:SetShadowOffset(1, -1)
--iconText:SetText(math.random(22))
iconText:SetTextColor(1,.82,0)
frame.iconText = iconText
-- todo: add setting for displaying quest text again
local questText = frame:CreateFontString(nil, 'BACKGROUND', 'GameFontWhiteSmall')
questText:SetPoint('TOP', frame, 'BOTTOM')
questText:SetShadowOffset(1, -1)
questText:Hide()
frame.questText = questText
local qmark = frame:CreateTexture(nil, 'OVERLAY')
qmark:SetSize(28, 28)
qmark:SetPoint('CENTER', icon)
qmark:SetTexture('Interface/WorldMap/UI-WorldMap-QuestIcon')
qmark:SetTexCoord(0, 0.56, 0.5, 1)
qmark:SetAlpha(0)
local duration = 1
local group = qmark:CreateAnimationGroup()
local alpha = group:CreateAnimation('Alpha')
alpha:SetOrder(1)
alpha:SetFromAlpha(0)
alpha:SetToAlpha(1)
alpha:SetDuration(0)
local translation = group:CreateAnimation('Translation')
translation:SetOrder(1)
translation:SetOffset(0, 20)
translation:SetDuration(duration)
translation:SetSmoothing('OUT')
local alpha2 = group:CreateAnimation('Alpha')
alpha2:SetOrder(1)
alpha2:SetFromAlpha(1)
alpha2:SetToAlpha(0)
alpha2:SetDuration(duration)
alpha2:SetSmoothing('OUT')
frame.ani = group
frame:HookScript('OnShow', function(self)
group:Play()
end)
end
local function UpdateQuestIcon(plate, unitID)
local Q = QuestPlates[plate]
local unitID = unitID or addon:GetUnitForPlate(plate)
if not Q then return end
local scenarioName, currentStage, numStages, flags, _, _, _, xp, money, scenarioType, _, textureKitID = C_Scenario.GetInfo()
local inChallengeMode = (scenarioType == LE_SCENARIO_TYPE_CHALLENGE_MODE)
local guid = UnitGUID(unitID)
if inChallengeMode and guid then -- C_MythicPlus.IsMythicPlusActive() and guid then
Q:Hide()
return
end
local progressGlob, questType, objectiveCount, questLogIndex, questID = GetQuestProgress(unitID)
if progressGlob and questType ~= 2 then
Q.questText:SetText(progressGlob or '')
if questType == 3 then -- todo: progress bar
Q.iconText:SetText(objectiveCount > 0 and objectiveCount or '?')
else
Q.iconText:SetText(objectiveCount > 0 and objectiveCount or '?')
end
if questType == 1 then
Q.jellybean:SetDesaturated(false)
Q.iconText:SetTextColor(1, .82, 0)
elseif questType == 2 then
Q.jellybean:SetDesaturated(true)
Q.iconText:SetTextColor(1, 1, 1)
elseif questType == 3 then
Q.jellybean:SetDesaturated(false)
Q.iconText:SetTextColor(0.2, 1, 1)
end
Q.itemTexture:Hide()
Q.lootIcon:Hide()
if questLogIndex or questID then
if questID then
for i = 1, 10 do
local text, objectiveType, finished = GetQuestObjectiveInfo(questID, i, false)
if not text then break end
if not finished and (objectiveType == 'item' or objectiveType == 'object') then
Q.lootIcon:Show()
end
end
else
local info = C_QuestLog.GetInfo(questLogIndex)
if info then
for i = 1, GetNumQuestLeaderBoards(questLogIndex) or 0 do
local text, objectiveType, finished = GetQuestObjectiveInfo(info.questID, i, false)
if not finished and (objectiveType == 'item' or objectiveType == 'object') then
Q.lootIcon:Show()
end
end
end
end
if questLogIndex then
local link, itemTexture, charges, showItemWhenComplete = GetQuestLogSpecialItemInfo(questLogIndex)
if link and itemTexture then
Q.itemTexture:SetTexture(itemTexture)
Q.itemTexture:Show()
else
Q.itemTexture:Hide()
end
end
end
if not Q:IsVisible() then
Q.ani:Stop()
Q:Show()
Q.ani:Play()
end
--Q:Show()
else
Q:Hide()
end
end
function E:OnPlateShow(f, plate, unitID)
UpdateQuestIcon(plate, unitID)
end
QuestObjectiveStrings = {}
local function CacheQuestIndexes()
wipe(QuestLogIndex)
for i = 1, C_QuestLog.GetNumQuestLogEntries() do
-- for i = 1, GetNumQuestLogEntries() do if not select(4,GetQuestLogTitle(i)) and select(11,GetQuestLogTitle(i)) then QuestLogPushQuest(i) end end
local info = C_QuestLog.GetInfo(i)
if info and not info.isHeader then
QuestLogIndex[info.title] = i
for objectiveID = 1, GetNumQuestLeaderBoards(i) or 0 do
local objectiveText, objectiveType, finished, numFulfilled, numRequired = GetQuestObjectiveInfo(info.questID, objectiveID, false)
if objectiveText then
QuestObjectiveStrings[ info.title .. objectiveText ] = {info.questID, objectiveID}
end
end
end
end
for plate, f in pairs(addon:GetActiveNameplates()) do
UpdateQuestIcon(plate, f._unitID)
end
end
function E:UNIT_QUEST_LOG_CHANGED(unitID)
if unitID == 'player' then
CacheQuestIndexes()
else
for plate in pairs(addon:GetActiveNameplates()) do
UpdateQuestIcon(plate)
end
end
end
function E:QUEST_LOG_UPDATE()
CacheQuestIndexes()
end
E:UnregisterEvent('QUEST_LOG_UPDATE')
function E:PLAYER_LEAVING_WORLD()
E:UnregisterEvent('QUEST_LOG_UPDATE')
end
function E:PLAYER_ENTERING_WORLD()
E:RegisterEvent('QUEST_LOG_UPDATE')
end
-- Reanchor any existing nameplate icons after settings load
function E:ADDON_LOADED(loadedAddon)
if loadedAddon == addonName then
for plate, f in pairs(addon:GetAllNameplates()) do
local frame = QuestPlates[plate]
if frame then
frame.jellybean:ClearAllPoints()
frame.jellybean:SetPoint(QuestPlateSettings.AnchorPoint or 'RIGHT', frame, QuestPlateSettings.RelativeTo or 'LEFT', (QuestPlateSettings.OffsetX or 0) / (QuestPlateSettings.IconScale or 1), (QuestPlateSettings.OffsetY or 0) / (QuestPlateSettings.IconScale or 1))
frame:SetScale(QuestPlateSettings.IconScale or 1)
end
end
self:UnregisterEvent("ADDON_LOADED")
end
end
Here's a proper release tag with updated code for TWW.
https://github.com/donniedice/QuestPlates/releases/tag/v2.0.0
I've submitted pull request to merge my fork.. dude hasn't touched his github in over a year.