@@ -2657,30 +2657,35 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories
26572657 t_insert (pGroups , cGroup )
26582658 self .primaryBuild .buildFlag = true
26592659
2660- -- Get a fresh calculator with the added group
2661- local gemCalcFunc , gemCalcBase = self .calcs .getMiscCalculator (self .primaryBuild )
2662- local impact = self :CalculatePowerStat (powerStat , gemCalcBase , calcBase )
2660+ -- Get a fresh calculator with the added group (pcall to guarantee cleanup)
2661+ local ok , gemCalcFunc , gemCalcBase = pcall (self .calcs .getMiscCalculator , self .calcs , self .primaryBuild )
26632662
2664- -- Remove the temporarily added group
2663+ -- Always remove the temporarily added group
26652664 t_remove (pGroups )
26662665 self .primaryBuild .buildFlag = true
26672666
2668- local impactStr , impactVal , combinedImpactStr , impactPercent = formatImpact (impact )
2669- local label = self :GetSocketGroupLabel (cGroup )
2667+ if not ok then
2668+ -- gemCalcFunc contains the error message on failure; skip this group
2669+ ConPrintf (" Compare power (gem): %s" , tostring (gemCalcFunc ))
2670+ else
2671+ local impact = self :CalculatePowerStat (powerStat , gemCalcBase , calcBase )
2672+ local impactStr , impactVal , combinedImpactStr , impactPercent = formatImpact (impact )
2673+ local label = self :GetSocketGroupLabel (cGroup )
26702674
2671- t_insert (results , {
2672- category = " Gem" ,
2673- categoryColor = colorCodes .GEM ,
2674- nameColor = colorCodes .GEM ,
2675- name = label ,
2676- impact = impactVal ,
2677- impactStr = impactStr ,
2678- impactPercent = impactPercent ,
2679- combinedImpactStr = combinedImpactStr ,
2680- pathDist = nil ,
2681- perPoint = nil ,
2682- perPointStr = nil ,
2683- })
2675+ t_insert (results , {
2676+ category = " Gem" ,
2677+ categoryColor = colorCodes .GEM ,
2678+ nameColor = colorCodes .GEM ,
2679+ name = label ,
2680+ impact = impactVal ,
2681+ impactStr = impactStr ,
2682+ impactPercent = impactPercent ,
2683+ combinedImpactStr = combinedImpactStr ,
2684+ pathDist = nil ,
2685+ perPoint = nil ,
2686+ perPointStr = nil ,
2687+ })
2688+ end
26842689 end
26852690 processed = processed + 1
26862691 if coroutine.running () and GetTime () - start > 100 then
@@ -2715,43 +2720,48 @@ function CompareTabClass:ComparePowerBuilder(compareEntry, powerStat, categories
27152720 -- Apply compare build's config value
27162721 pInput [varData .var ] = cVal
27172722
2718- -- Rebuild the mod list with the new config value
2719- self .primaryBuild .configTab :BuildModList ()
2720- self .primaryBuild .buildFlag = true
2721-
2722- -- Get a fresh calculator with the changed config
2723- local cfgCalcFunc , cfgCalcBase = self .calcs .getMiscCalculator (self .primaryBuild )
2724- local impact = self :CalculatePowerStat (powerStat , cfgCalcBase , calcBase )
2723+ -- Rebuild and calculate (pcall to guarantee restore on error)
2724+ local ok , cfgCalcFunc , cfgCalcBase = pcall (function ()
2725+ self .primaryBuild .configTab :BuildModList ()
2726+ self .primaryBuild .buildFlag = true
2727+ return self .calcs .getMiscCalculator (self .primaryBuild )
2728+ end )
27252729
2726- -- Restore original value
2730+ -- Always restore original value
27272731 pInput [varData .var ] = savedVal
27282732 self .primaryBuild .configTab :BuildModList ()
27292733 self .primaryBuild .buildFlag = true
27302734
2731- local impactStr , impactVal , combinedImpactStr , impactPercent = formatImpact (impact )
2732-
2733- -- Only include configs with non-zero impact
2734- if impactVal ~= 0 then
2735- -- Build display name with value change description
2736- local displayName = varData .label or varData .var
2737- displayName = displayName :gsub (" :$" , " " )
2738-
2739- local pDisplay = stripColors (self :FormatConfigValue (varData , pVal ))
2740- local cDisplay = stripColors (self :FormatConfigValue (varData , cVal ))
2741-
2742- t_insert (results , {
2743- category = " Config" ,
2744- categoryColor = colorCodes .FRACTURED ,
2745- nameColor = " ^7" ,
2746- name = displayName .. " (" .. pDisplay .. " -> " .. cDisplay .. " )" ,
2747- impact = impactVal ,
2748- impactStr = impactStr ,
2749- impactPercent = impactPercent ,
2750- combinedImpactStr = combinedImpactStr ,
2751- pathDist = nil ,
2752- perPoint = nil ,
2753- perPointStr = nil ,
2754- })
2735+ if not ok then
2736+ -- cfgCalcFunc contains the error message on failure; skip this config
2737+ ConPrintf (" Compare power (config): %s" , tostring (cfgCalcFunc ))
2738+ else
2739+ local impact = self :CalculatePowerStat (powerStat , cfgCalcBase , calcBase )
2740+ local impactStr , impactVal , combinedImpactStr , impactPercent = formatImpact (impact )
2741+
2742+ -- Only include configs with non-zero impact
2743+ if impactVal ~= 0 then
2744+ -- Build display name with value change description
2745+ local displayName = varData .label or varData .var
2746+ displayName = displayName :gsub (" :$" , " " )
2747+
2748+ local pDisplay = stripColors (self :FormatConfigValue (varData , pVal ))
2749+ local cDisplay = stripColors (self :FormatConfigValue (varData , cVal ))
2750+
2751+ t_insert (results , {
2752+ category = " Config" ,
2753+ categoryColor = colorCodes .FRACTURED ,
2754+ nameColor = " ^7" ,
2755+ name = displayName .. " (" .. pDisplay .. " -> " .. cDisplay .. " )" ,
2756+ impact = impactVal ,
2757+ impactStr = impactStr ,
2758+ impactPercent = impactPercent ,
2759+ combinedImpactStr = combinedImpactStr ,
2760+ pathDist = nil ,
2761+ perPoint = nil ,
2762+ perPointStr = nil ,
2763+ })
2764+ end
27552765 end
27562766
27572767 processed = processed + 1
0 commit comments