@@ -53,6 +53,7 @@ local GemSelectClass = newClass("GemSelectControl", "EditControl", function(self
5353 lifeReservationPercent = " LifePercent" ,
5454 }
5555 self .imbuedSelect = imbued
56+ self .dpsBuildFlag = false
5657end )
5758
5859function GemSelectClass :CalcOutputWithThisGem (calcFunc , gemData , useFullDPS )
@@ -168,11 +169,12 @@ function GemSelectClass:BuildList(buf)
168169 t_remove (tagsList , 1 )
169170
170171 -- Search for gem name using increasingly broad search patterns
172+ local lowerSearch = searchTerm :lower ()
171173 local patternList = {
172- " ^ " .. searchTerm : lower () .. " $" , -- Exact match
173- " ^" .. searchTerm : lower () :gsub (" %a" , " %0%%l+" ) .. " $" , -- Simple abbreviation ("CtF" -> "Cold to Fire")
174- " ^ " .. searchTerm : lower () , -- Starts with
175- searchTerm : lower () , -- Contains
174+ " ^ " .. lowerSearch .. " $" , -- Exact match
175+ " ^" .. lowerSearch :gsub (" %a" , " %0%%l+" ) .. " $" , -- Simple abbreviation ("CtF" -> "Cold to Fire")
176+ " ^ " .. lowerSearch , -- Starts with
177+ lowerSearch , -- Contains
176178 }
177179 for i , pattern in ipairs (patternList ) do
178180 local matchList = { }
@@ -340,44 +342,90 @@ function GemSelectClass:UpdateSortCache()
340342 -- Check for nil because some fields may not be populated, default to 0
341343 local baseDPS = (dpsField == " FullDPS" and calcBase [dpsField ] ~= nil and calcBase [dpsField ]) or (calcBase .Minion and calcBase .Minion .CombinedDPS ) or (calcBase [dpsField ] ~= nil and calcBase [dpsField ]) or 0
342344
345+ sortCache .calcFunc = calcFunc
346+ sortCache .useFullDPS = useFullDPS
347+ sortCache .baseDPS = baseDPS
348+ sortCache .dpsField = dpsField
349+ sortCache .pendingGems = { }
350+
343351 for gemId , gemData in pairs (self .gems ) do
344352 sortCache .dps [gemId ] = baseDPS
345- -- Ignore gems that don't support the active skill
353+ -- Gems that support the active skill or have global effects need DPS calc
346354 if sortCache .canSupport [gemId ] or (gemData .grantedEffect .hasGlobalEffect and not gemData .grantedEffect .support ) then
347- local output = self :CalcOutputWithThisGem (calcFunc , gemData , useFullDPS )
348- -- Check for nil because some fields may not be populated, default to 0
349- sortCache .dps [gemId ] = (dpsField == " FullDPS" and output [dpsField ] ~= nil and output [dpsField ]) or (output .Minion and output .Minion .CombinedDPS ) or (output [dpsField ] ~= nil and output [dpsField ]) or 0
350- end
351- -- Color based on the DPS
352- if sortCache .dps [gemId ] > baseDPS then
353- sortCache .dpsColor [gemId ] = " ^x228866"
354- elseif sortCache .dps [gemId ] < baseDPS then
355- sortCache .dpsColor [gemId ] = " ^xFF4422"
356- else
357- sortCache .dpsColor [gemId ] = " ^xFFFF66"
355+ sortCache .pendingGems [# sortCache .pendingGems + 1 ] = gemId
358356 end
357+ -- Neutral color until DPS is computed
358+ sortCache .dpsColor [gemId ] = " "
359359 end
360360
361- -- ConPrintf("Gem Selector time: %d ms", GetTime() - start)
361+ self . dpsBuildFlag = true
362362end
363363
364364function GemSelectClass :SortGemList (gemList )
365365 local sortCache = self .sortCache
366+ local gems = self .gems
367+ -- cache names to avoid repeated table lookups in comparator
368+ local names = {}
369+ for _ , gemId in ipairs (gemList ) do
370+ local gem = gems [gemId ]
371+ names [gemId ] = gem and gem .name or gemId
372+ end
366373 t_sort (gemList , function (a , b )
367374 if sortCache .canSupport [a ] == sortCache .canSupport [b ] then
368375 if self .skillsTab .sortGemsByDPS and sortCache .dps [a ] ~= sortCache .dps [b ] then
369376 return sortCache .dps [a ] > sortCache .dps [b ]
370377 else
371- local nameA = (self .gems [a ] and self .gems [a ].name ) or a
372- local nameB = (self .gems [b ] and self .gems [b ].name ) or b
373- return nameA < nameB
378+ return names [a ] < names [b ]
374379 end
375380 else
376381 return sortCache .canSupport [a ]
377382 end
378383 end )
379384end
380385
386+ function GemSelectClass :DPSBuilder ()
387+ local sortCache = self .sortCache
388+ if not sortCache or not sortCache .pendingGems then return end
389+
390+ local pending = sortCache .pendingGems
391+ local calcFunc = sortCache .calcFunc
392+ local useFullDPS = sortCache .useFullDPS
393+ local baseDPS = sortCache .baseDPS
394+ local dpsField = sortCache .dpsField
395+ local start = GetTime ()
396+
397+ for index , gemId in ipairs (pending ) do
398+ local gemData = self .gems [gemId ]
399+ if gemData then
400+ local output = self :CalcOutputWithThisGem (calcFunc , gemData , useFullDPS )
401+ sortCache .dps [gemId ] = (dpsField == " FullDPS" and output [dpsField ] ~= nil and output [dpsField ]) or (output .Minion and output .Minion .CombinedDPS ) or (output [dpsField ] ~= nil and output [dpsField ]) or 0
402+ if sortCache .dps [gemId ] > baseDPS then
403+ sortCache .dpsColor [gemId ] = " ^x228866"
404+ elseif sortCache .dps [gemId ] < baseDPS then
405+ sortCache .dpsColor [gemId ] = " ^xFF4422"
406+ else
407+ sortCache .dpsColor [gemId ] = " ^xFFFF66"
408+ end
409+ end
410+ local now = GetTime ()
411+ if now - start > 50 then
412+ if # self .searchStr == 0 then
413+ self :SortGemList (self .list )
414+ end
415+ if self .dpsBuilderCallback then
416+ self .dpsBuilderCallback (m_floor (index /# pending * 100 ))
417+ end
418+ coroutine.yield ()
419+ start = now
420+ end
421+ end
422+
423+ if # self .searchStr == 0 then
424+ self :SortGemList (self .list )
425+ end
426+ sortCache .pendingGems = nil
427+ end
428+
381429function GemSelectClass :UpdateGem (setText , addUndo , focusLost )
382430 local gemId = self .list [m_max (self .selIndex , 1 )]
383431 -- don't process unless the buffer equals an actual gem, whether typed, clicked, or navigated with arrows
@@ -428,6 +476,24 @@ function GemSelectClass:IsMouseOver()
428476end
429477
430478function GemSelectClass :Draw (viewPort , noTooltip )
479+ self .sortPercentage = self .sortPercentage or " "
480+ if self .dpsBuildFlag then
481+ self .dpsBuildFlag = false
482+ self .dpsBuilder = coroutine.create (self .DPSBuilder )
483+ self .dpsBuilderCallback = function (percentage )
484+ self .sortPercentage = (" %d%%" ):format (percentage )
485+ end
486+ end
487+ if self .dpsBuilder then
488+ local res , errMsg = coroutine.resume (self .dpsBuilder , self )
489+ if launch .devMode and not res then
490+ error (errMsg )
491+ end
492+ if coroutine.status (self .dpsBuilder ) == " dead" then
493+ self .dpsBuilder = nil
494+ end
495+ end
496+
431497 self .EditControl :Draw (viewPort , noTooltip and not self .forceTooltip )
432498 local x , y = self :GetPos ()
433499 local width , height = self :GetSize ()
@@ -446,6 +512,10 @@ function GemSelectClass:Draw(viewPort, noTooltip)
446512 end
447513 if self .dropped then
448514 SetDrawLayer (nil , 5 )
515+ if self .dpsBuilder then
516+ SetDrawColor (0.75 , 0.75 , 0.75 )
517+ DrawString (x + width - 4 , y , " RIGHT_X" , height - 2 , " VAR" , " Sorting " .. self .sortPercentage )
518+ end
449519 local cursorX , cursorY = GetCursorPos ()
450520 self .hoverSel = mOverComp == " DROP" and math.floor ((cursorY - y - height + scrollBar .offset ) / (height - 4 )) + 1
451521 if self .hoverSel and not self .gems [self .list [self .hoverSel ]] then
@@ -475,10 +545,10 @@ function GemSelectClass:Draw(viewPort, noTooltip)
475545 local gemText = gemData and gemData .name or " <No matches>"
476546 DrawString (0 , y , " LEFT" , height - 4 , " VAR" , gemText )
477547 if gemData then
478- if gemData .grantedEffect .support and self .sortCache .canSupport [gemId ] then
548+ if gemData .grantedEffect .support and self .sortCache .canSupport [gemId ] and self . sortCache . dpsColor [ gemId ] ~= " " then
479549 SetDrawColor (self .sortCache .dpsColor [gemId ])
480550 main :DrawCheckMark (width - 4 - height / 2 - (scrollBar .enabled and 18 or 0 ), y + (height - 4 ) / 2 , (height - 4 ) * 0.8 )
481- elseif gemData .grantedEffect .hasGlobalEffect then
551+ elseif gemData .grantedEffect .hasGlobalEffect and self . sortCache . dpsColor [ gemId ] ~= " " then
482552 SetDrawColor (self .sortCache .dpsColor [gemId ])
483553 DrawString (width - 4 - height / 2 - (scrollBar .enabled and 18 or 0 ), y - 2 , " CENTER_X" , height , " VAR" , " +" )
484554 end
@@ -487,14 +557,23 @@ function GemSelectClass:Draw(viewPort, noTooltip)
487557 SetViewport ()
488558 self :DrawControls (viewPort , (noTooltip and not self .forceTooltip ) and self )
489559 if self .hoverSel then
490- local calcFunc , calcBase = self .skillsTab .build .calcsTab :GetMiscCalculator (self .build )
491- if calcFunc then
492- self .tooltip :Clear ()
493- local gemData = self .gems [self .list [self .hoverSel ]]
494- local output = self :CalcOutputWithThisGem (calcFunc , gemData , self .skillsTab .sortGemsByDPSField == " FullDPS" )
495- local gemInstance = {
560+ -- Debounce hover
561+ if self .hoverSel == self .lastHoverSel then
562+ self .hoverFrameCount = (self .hoverFrameCount or 0 ) + 1
563+ else
564+ self .lastHoverSel = self .hoverSel
565+ self .hoverFrameCount = 0
566+ end
567+ if self .hoverFrameCount >= 2 then
568+ local calcFunc , calcBase = self .skillsTab .build .calcsTab :GetMiscCalculator (self .build )
569+ if calcFunc then
570+ self .tooltip :Clear ()
571+ local gemData = self .gems [self .list [self .hoverSel ]]
572+ local output = self :CalcOutputWithThisGem (calcFunc , gemData , self .skillsTab .sortGemsByDPSField == " FullDPS" )
573+ local gemInstance = {
496574 level = self .skillsTab :ProcessGemLevel (gemData , self .imbuedSelect ),
497575 quality = self .skillsTab .defaultGemQuality or 0 ,
576+ qualityId = " Default" ,
498577 count = 1 ,
499578 enabled = true ,
500579 enableGlobal1 = true ,
@@ -505,11 +584,15 @@ function GemSelectClass:Draw(viewPort, noTooltip)
505584 displayEffect = nil ,
506585 gemData = gemData
507586 }
508- self :AddGemTooltip (gemInstance )
509- self .tooltip :AddSeparator (10 )
510- self .skillsTab .build :AddStatComparesToTooltip (self .tooltip , calcBase , output , " ^7Selecting this gem will give you:" )
511- self .tooltip :Draw (x , y + height + 2 + (self .hoverSel - 1 ) * (height - 4 ) - scrollBar .offset , width , height - 4 , viewPort )
587+ self :AddGemTooltip (gemInstance )
588+ self .tooltip :AddSeparator (10 )
589+ self .skillsTab .build :AddStatComparesToTooltip (self .tooltip , calcBase , output , " ^7Selecting this gem will give you:" )
590+ self .tooltip :Draw (x , y + height + 2 + (self .hoverSel - 1 ) * (height - 4 ) - scrollBar .offset , width , height - 4 , viewPort )
591+ end
512592 end
593+ else
594+ self .lastHoverSel = nil
595+ self .hoverFrameCount = 0
513596 end
514597 SetDrawLayer (nil , 0 )
515598 else
0 commit comments