Skip to content

Commit 37b9f93

Browse files
committed
Cache targeted radius jewel tooltip comparisons
Avoid rebuilding radius-jewel comparison specs for repeated targeted tooltip hovers and skip limited-unique socket outputs that will not be shown. Preserve full multi-slot tooltip behavior when slot-only tooltips are disabled. Related local follow-up to PR 9746.
1 parent c6483fa commit 37b9f93

3 files changed

Lines changed: 154 additions & 19 deletions

File tree

spec/System/TestRadiusJewelStatDiff_spec.lua

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,35 @@ local function setupAllocatedSocket()
122122
return spec, socketNode
123123
end
124124

125+
local function setupAllocatedSockets(count)
126+
local spec = build.spec
127+
local sockets = { }
128+
local sortedSockets = { }
129+
for _, node in pairs(spec.nodes) do
130+
if node.isJewelSocket then
131+
sortedSockets[#sortedSockets + 1] = node
132+
end
133+
end
134+
table.sort(sortedSockets, function(a, b)
135+
return a.id < b.id
136+
end)
137+
for _, socketNode in ipairs(sortedSockets) do
138+
if allocatePathToNode(spec, socketNode) then
139+
sockets[#sockets + 1] = socketNode
140+
if #sockets >= count then
141+
break
142+
end
143+
end
144+
end
145+
if #sockets < count then
146+
pending("Could not allocate the requested number of jewel sockets for this tree layout")
147+
return spec, sockets
148+
end
149+
spec:BuildAllDependsAndPaths()
150+
runCallback("OnFrame")
151+
return spec, sockets
152+
end
153+
125154
local function rebuildBuild()
126155
build.buildFlag = true
127156
runCallback("OnFrame")
@@ -597,4 +626,73 @@ describe("TestRadiusJewelStatDiff", function()
597626
"tooltip should contain a 'Removing this item' comparison header")
598627
end)
599628

629+
it("AddItemTooltip avoids rebuilding unused limited-unique socket comparisons without a target slot", function()
630+
local spec, sockets = setupAllocatedSockets(2)
631+
632+
local item = newThreadOfHope()
633+
item.limit = 1
634+
equipJewelInSocket(item, sockets[1])
635+
spec:BuildAllDependsAndPaths()
636+
runCallback("OnFrame")
637+
638+
local specClass = getmetatable(spec)
639+
local originalBuildAllDependsAndPaths = specClass.BuildAllDependsAndPaths
640+
local rebuilds = 0
641+
specClass.BuildAllDependsAndPaths = function(self, ...)
642+
rebuilds = rebuilds + 1
643+
return originalBuildAllDependsAndPaths(self, ...)
644+
end
645+
646+
local ok, err = pcall(function()
647+
local tooltip = new("Tooltip")
648+
build.itemsTab:AddItemTooltip(tooltip, item)
649+
end)
650+
specClass.BuildAllDependsAndPaths = originalBuildAllDependsAndPaths
651+
if not ok then
652+
error(err)
653+
end
654+
655+
assert.are.equals(1, rebuilds,
656+
"limited unique radius jewels should rebuild only the same-unique slot that will be displayed")
657+
end)
658+
659+
it("AddItemTooltip reuses targeted radius jewel comparison specs until output changes", function()
660+
local spec, sockets = setupAllocatedSockets(2)
661+
662+
local item = newCustomLeapJewel("Cached Leap")
663+
local slot = equipJewelInSocket(item, sockets[1])
664+
spec:BuildAllDependsAndPaths()
665+
runCallback("OnFrame")
666+
667+
local originalSlotOnlyTooltips = main.slotOnlyTooltips
668+
main.slotOnlyTooltips = true
669+
local specClass = getmetatable(spec)
670+
local originalBuildAllDependsAndPaths = specClass.BuildAllDependsAndPaths
671+
local rebuilds = 0
672+
specClass.BuildAllDependsAndPaths = function(self, ...)
673+
rebuilds = rebuilds + 1
674+
return originalBuildAllDependsAndPaths(self, ...)
675+
end
676+
677+
local ok, err = pcall(function()
678+
local tooltip = new("Tooltip")
679+
build.itemsTab:AddItemTooltip(tooltip, item, slot)
680+
tooltip = new("Tooltip")
681+
build.itemsTab:AddItemTooltip(tooltip, item, slot)
682+
assert.are.equals(1, rebuilds,
683+
"targeted radius jewel hover should reuse its cached comparison spec")
684+
685+
build.outputRevision = build.outputRevision + 1
686+
tooltip = new("Tooltip")
687+
build.itemsTab:AddItemTooltip(tooltip, item, slot)
688+
assert.are.equals(2, rebuilds,
689+
"targeted radius jewel comparison spec cache should reset when output changes")
690+
end)
691+
specClass.BuildAllDependsAndPaths = originalBuildAllDependsAndPaths
692+
main.slotOnlyTooltips = originalSlotOnlyTooltips
693+
if not ok then
694+
error(err)
695+
end
696+
end)
697+
600698
end)

src/Classes/CompareTab.lua

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3727,6 +3727,7 @@ function CompareTabClass:DrawItems(vp, compareEntry, inputEvents)
37273727
local hoverX, hoverY = 0, 0
37283728
local hoverW, hoverH = 0, 0
37293729
local hoverItemsTab = nil
3730+
local hoverSlotName = nil
37303731

37313732
-- Track item copy button clicks
37323733
local clickedCopySlot = nil
@@ -3808,6 +3809,7 @@ function CompareTabClass:DrawItems(vp, compareEntry, inputEvents)
38083809
if rowHoverItem then
38093810
hoverItem = rowHoverItem
38103811
hoverItemsTab = rowHoverItemsTab
3812+
hoverSlotName = pHover and equipSlotName or cHover and copySlotName or nil
38113813
hoverX, hoverY = rowHoverX, rowHoverY
38123814
hoverW, hoverH = rowHoverW, rowHoverH
38133815
end
@@ -3890,8 +3892,10 @@ function CompareTabClass:DrawItems(vp, compareEntry, inputEvents)
38903892
SetViewport()
38913893
local maxTooltipWidth = m_min(600, m_max(260, vp.width - 24))
38923894
if hoverItem and hoverItemsTab then
3893-
self.itemTooltip:Clear()
3894-
hoverItemsTab:AddItemTooltip(self.itemTooltip, hoverItem, nil, nil, maxTooltipWidth)
3895+
local hoverBuild = hoverItemsTab.build
3896+
if self.itemTooltip:CheckForUpdate(hoverItemsTab, hoverItem, hoverSlotName, maxTooltipWidth, main.slotOnlyTooltips, launch.devModeAlt, hoverBuild and hoverBuild.outputRevision) then
3897+
hoverItemsTab:AddItemTooltip(self.itemTooltip, hoverItem, hoverSlotName, nil, maxTooltipWidth)
3898+
end
38953899
SetDrawLayer(nil, 100)
38963900
self.itemTooltip:Draw(vp.x + hoverX, vp.y + checkboxOffset + hoverY, hoverW, hoverH, vp)
38973901
SetDrawLayer(nil, 0)

src/Classes/ItemsTab.lua

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3874,12 +3874,33 @@ local function cloneSpecForJewelComparison(spec)
38743874
return specCopy
38753875
end
38763876

3877-
local function buildSpecForJewelComparison(itemsTab, compareSlot, replacementItem)
3877+
local function buildSpecForJewelComparison(itemsTab, compareSlot, replacementItem, useCache)
38783878
local tempItemId
3879+
local replacementItemId = replacementItem and replacementItem.id
3880+
local replacementItemIsStored = replacementItemId and itemsTab.items[replacementItemId] == replacementItem
3881+
local canCache = useCache and (not replacementItem or replacementItemIsStored)
3882+
local cacheKey
3883+
local cache
3884+
if canCache then
3885+
local outputRevision = itemsTab.build and itemsTab.build.outputRevision or 0
3886+
cache = itemsTab.targetedJewelComparisonSpecCache
3887+
if not cache or cache.outputRevision ~= outputRevision then
3888+
cache = {
3889+
outputRevision = outputRevision,
3890+
specs = { },
3891+
}
3892+
itemsTab.targetedJewelComparisonSpecCache = cache
3893+
end
3894+
cacheKey = tostring(compareSlot.nodeId) .. ":" .. tostring(replacementItemId or "")
3895+
if cache.specs[cacheKey] then
3896+
return cache.specs[cacheKey]
3897+
end
3898+
end
3899+
38793900
local spec = cloneSpecForJewelComparison(itemsTab.build.spec)
38803901
if replacementItem then
3881-
if replacementItem.id and itemsTab.items[replacementItem.id] == replacementItem then
3882-
spec.jewels[compareSlot.nodeId] = replacementItem.id
3902+
if replacementItemIsStored then
3903+
spec.jewels[compareSlot.nodeId] = replacementItemId
38833904
else
38843905
tempItemId = -1
38853906
while itemsTab.items[tempItemId] do
@@ -3901,6 +3922,9 @@ local function buildSpecForJewelComparison(itemsTab, compareSlot, replacementIte
39013922
if not ok then
39023923
error(err, 0)
39033924
end
3925+
if cacheKey then
3926+
cache.specs[cacheKey] = spec
3927+
end
39043928
return spec
39053929
end
39063930

@@ -4537,18 +4561,18 @@ function ItemsTabClass:AddItemTooltip(tooltip, item, slot, dbMode, maxWidth)
45374561

45384562
tooltip:AddLine(14, colorCodes.TIP .. "Tip: Press Ctrl+D to disable the display of stat differences.")
45394563

4540-
local function getReplacedItemAndOutput(compareSlot)
4541-
local selItem = self.items[compareSlot.selItemId]
4564+
local function getReplacedItemAndOutput(compareSlot, selItem, useJewelComparisonSpecCache)
4565+
selItem = selItem or self.items[compareSlot.selItemId]
45424566
local override = { repSlotName = compareSlot.slotName, repItem = item ~= selItem and item or nil }
45434567
if compareSlot.nodeId and (itemChangesPassiveTreeRadius(selItem) or itemChangesPassiveTreeRadius(item)) then
4544-
override.spec = buildSpecForJewelComparison(self, compareSlot, override.repItem)
4568+
override.spec = buildSpecForJewelComparison(self, compareSlot, override.repItem, useJewelComparisonSpecCache)
45454569
end
45464570
local output = calcFunc(override)
45474571
return selItem, output
45484572
end
4549-
local function addCompareForSlot(compareSlot, selItem, output)
4573+
local function addCompareForSlot(compareSlot, selItem, output, useJewelComparisonSpecCache)
45504574
if not selItem or not output then
4551-
selItem, output = getReplacedItemAndOutput(compareSlot)
4575+
selItem, output = getReplacedItemAndOutput(compareSlot, nil, useJewelComparisonSpecCache)
45524576
end
45534577
local header
45544578
if item == selItem then
@@ -4561,29 +4585,38 @@ function ItemsTabClass:AddItemTooltip(tooltip, item, slot, dbMode, maxWidth)
45614585

45624586
-- if we have a specific slot to compare to, and the user has "Show
45634587
-- tooltips only for affected slots" checked, we can just compare that
4564-
-- one slot
4588+
-- one slot.
4589+
local compareOnlySlot = type(slot) ~= "string" and slot or self.slots[slot]
45654590
if main.slotOnlyTooltips and slot then
4566-
slot = type(slot) ~= "string" and slot or self.slots[slot]
4567-
if slot then addCompareForSlot(slot) end
4591+
if compareOnlySlot then addCompareForSlot(compareOnlySlot, nil, nil, true) end
45684592
return
45694593
end
45704594

4571-
4572-
local slots = {}
45734595
local isUnique = item.rarity == "UNIQUE" or item.rarity == "RELIC"
45744596
local currentSameUniqueCount = 0
4597+
local slotCandidates = {}
45754598
for _, compareSlot in ipairs(compareSlots) do
4576-
local selItem, output = getReplacedItemAndOutput(compareSlot)
4599+
local selItem = self.items[compareSlot.selItemId]
45774600
local isSameUnique = isUnique and selItem and item.name == selItem.name
45784601
if isUnique and isSameUnique and item.limit then
45794602
currentSameUniqueCount = currentSameUniqueCount + 1
45804603
end
4581-
table.insert(slots,
4582-
{ selItem = selItem, output = output, compareSlot = compareSlot, isSameUnique = isSameUnique })
4604+
table.insert(slotCandidates,
4605+
{ selItem = selItem, compareSlot = compareSlot, isSameUnique = isSameUnique })
4606+
end
4607+
local isLimitedUniqueAtLimit = (isUnique and item.limit and currentSameUniqueCount == item.limit) or false
4608+
4609+
local slots = {}
4610+
for _, slotEntry in ipairs(slotCandidates) do
4611+
if not isLimitedUniqueAtLimit or slotEntry.isSameUnique then
4612+
local _, output = getReplacedItemAndOutput(slotEntry.compareSlot, slotEntry.selItem)
4613+
slotEntry.output = output
4614+
table.insert(slots, slotEntry)
4615+
end
45834616
end
45844617

45854618
-- limited uniques: only compare to slots with the same item if more don't fit
4586-
if currentSameUniqueCount == item.limit then
4619+
if isLimitedUniqueAtLimit then
45874620
for _, slotEntry in ipairs(slots) do
45884621
if slotEntry.isSameUnique then
45894622
addCompareForSlot(slotEntry.compareSlot, slotEntry.selItem, slotEntry.output)

0 commit comments

Comments
 (0)