Skip to content

Commit 845364a

Browse files
vaisestLocalIdentity
andauthored
Buy similar: fix mod matching and improve search workflow (#1942)
* port compatible trader tool changes from pob1 * Fix corrupted mods being fractured mods in trade mod generation * Fix radius jewel weight generation * Regenerate QueryMods.lua * convert trade tool mod weight generation to use tradeHash * wip: change poesessid to bearer token * Cleanup: remove extra logout button and fix poeapi comments * Fix trader crash when rate limited on startup * Use https://poe.ninja/poe2/api/economy/exchange/current/overview for currency rates * Fix poe.ninja tests * Fix trader section anchor * Adjust price scaling factor due to things being in divs (still an abitrary number) * Clarify price options and rate limit waits, and use Retry-After for rate limiting waits if possible * rate limiting pls work * Fix perfect essences not appearing in generated weights, and regenerate querymods.lua * Fix tradehashes for radius jewels * Improve rate limit countdown to prevent simplegraphic suspension problems, and to show it on non-429 rate limit. (429 issue solved on GGG's side) * Fix debug print causing crash, and remove extra debug print * disable wiping trader controls to fix crash when it is closed and a search tries to add results to controls * remove whisper for instant buyout items * make cspell happy * Fix currency conversion button not being updated after reopening trader panel * Avoid useless search in "search for" button * fix api error on invalid token * disable reuseaddr * Remove error code on login and fix hanging item slot controls in tradequery * Fix QueryMods.lua generation. Change soulcores.lua to export trade hashes in a similar format as previous mod export changes. * Add note about trade hashes * Clear authorization on 403 to fix outdated scope in trader * Use enum in mods.lua and format it * Fix typo in mods.lua * Remove forgotten debug prints * Fix trade hash generation * add note about radius jewel mods * Fix rune weight generation and regenerate QueryMods.lua * Port buy similar improvements from pob1 and improve mod matching * Fix timeless jewel searching (completely useless) * Fix error handling on oauth login * Spacing --------- Co-authored-by: LocalIdentity <localidentity2@gmail.com>
1 parent 6589172 commit 845364a

8 files changed

Lines changed: 6791 additions & 6670 deletions

src/Classes/CompareBuySimilar.lua

Lines changed: 96 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,7 @@ for i, entry in ipairs(LISTED_STATUS_OPTIONS) do
3030
LISTED_STATUS_LABELS[i] = entry.label
3131
end
3232

33-
-- Helper: create a numeric EditControl without +/- spinner buttons
34-
local function newPlainNumericEdit(anchor, rect, init, prompt, limit)
35-
local ctrl = new("EditControl", anchor, rect, init, prompt, "%D", limit)
36-
-- Remove the +/- spinner buttons that "%D" filter triggers
37-
ctrl.isNumeric = false
38-
if ctrl.controls then
39-
if ctrl.controls.buttonDown then ctrl.controls.buttonDown.shown = false end
40-
if ctrl.controls.buttonUp then ctrl.controls.buttonUp.shown = false end
41-
end
42-
return ctrl
43-
end
33+
4434

4535
-- Build the trade search URL based on popup selections
4636
local function buildURL(item, slotName, controls, modEntries, defenceEntries, isUnique)
@@ -139,24 +129,30 @@ local function buildURL(item, slotName, controls, modEntries, defenceEntries, is
139129
for i, entry in ipairs(modEntries) do
140130
local prefix = "mod" .. i
141131
if entry.tradeId and controls[prefix .. "Check"] and controls[prefix .. "Check"].state then
142-
local minVal = tonumber(controls[prefix .. "Min"].buf)
143-
local maxVal = tonumber(controls[prefix .. "Max"].buf)
144132
local filter = { id = entry.tradeId }
145-
local value = {}
146-
if minVal then
147-
value.min = minVal
148-
end
149-
if maxVal then
150-
value.max = maxVal
151-
end
152-
if entry.invert then
153-
value.min, value.max = value.max, value.min
154-
value.min = value.min and -value.min
155-
value.max = value.max and -value.max
156-
end
157-
if next(value) then
158-
filter.value = value
133+
if entry.isOption then
134+
filter.value = { min = entry.value, max = entry.value }
135+
elseif entry.value then
136+
local minVal = tonumber(controls[prefix .. "Min"].buf)
137+
138+
local maxVal = tonumber(controls[prefix .. "Max"].buf)
139+
local value = {}
140+
if minVal then
141+
value.min = minVal
142+
end
143+
if maxVal then
144+
value.max = maxVal
145+
end
146+
if entry.invert then
147+
value.min, value.max = value.max, value.min
148+
value.min = value.min and -value.min
149+
value.max = value.max and -value.max
150+
end
151+
if next(value) then
152+
filter.value = value
153+
end
159154
end
155+
160156
t_insert(queryTable.query.stats[1].filters, filter)
161157
end
162158
end
@@ -187,6 +183,7 @@ function M.openPopup(item, slotName, primaryBuild)
187183

188184
local isUnique = item.rarity == "UNIQUE" or item.rarity == "RELIC"
189185
local controls = {}
186+
local uri = ""
190187
local rowHeight = 24
191188
local popupWidth = 700
192189
local leftMargin = 20
@@ -199,29 +196,38 @@ function M.openPopup(item, slotName, primaryBuild)
199196
-- Collect mod entries with trade IDs
200197
local modEntries = {}
201198
local modTypeSources = {
202-
{ list = item.enchantModLines, type = "enchant" },
199+
{ list = item.enchantModLines, type = "enchant" },
203200
{ list = item.implicitModLines, type = "implicit" },
204201
{ list = item.explicitModLines, type = "explicit" },
205202
}
206203
for _, source in ipairs(modTypeSources) do
207204
if source.list then
208205
for _, modLine in ipairs(source.list) do
209206
if item:CheckModLineVariant(modLine) then
207+
local modLine = copyTable(modLine)
208+
-- remove unsupported data. the formatting of unsupported
209+
-- mods is confusing here
210+
modLine.extra = nil
210211
local formatted = itemLib.formatModLine(modLine)
211-
formatted = formatted and formatted:gsub(" %^8%(Not supported in PoB yet%)", "")
212212
if formatted then
213213
-- Use range-resolved text for matching
214-
local resolvedLine = (modLine.range and itemLib.applyRange(modLine.line, modLine.range, modLine.valueScalar)) or modLine.line
215-
local tradeHash = tradeHelpers.findTradeHash(item, resolvedLine, source.type, modLine.desecrated)
216-
local identifier = tradeHash and string.format("%s.stat_%s", source.type, tradeHash)
217-
local value = tradeHelpers.modLineValue(resolvedLine)
214+
local resolvedLine = (modLine.range and itemLib.applyRange(modLine.line, modLine.range, modLine.valueScalar)) or
215+
modLine.line
216+
local tradeHash, identifier, value = tradeHelpers.findTradeHash(item, resolvedLine, source.type, modLine.desecrated)
217+
local isOption = not not identifier
218+
if not identifier then
219+
identifier = tradeHash and string.format("%s.stat_%s", source.type, tradeHash)
220+
value = tradeHelpers.modLineValue(resolvedLine)
221+
end
222+
local invert = (not isOption) and tradeHelpers.shouldBeInverted(identifier, resolvedLine, source.type)
218223
t_insert(modEntries, {
219224
line = modLine.line,
220-
formatted = formatted:gsub("%^x%x%x%x%x%x%x", ""):gsub("%^%x", ""), -- strip color codes
225+
formatted = formatted,
221226
tradeId = identifier,
222227
value = value,
223-
modType = source.type,
224-
invert = tradeHelpers.shouldBeInverted(identifier, resolvedLine, source.type)
228+
isOption = isOption,
229+
type = source.type,
230+
invert = invert,
225231
})
226232
end
227233
end
@@ -319,6 +325,23 @@ function M.openPopup(item, slotName, primaryBuild)
319325
fetchLeaguesForRealm("poe2")
320326
ctrlY = ctrlY + rowHeight + 4
321327

328+
local function rebuildUrl()
329+
local result = buildURL(item, slotName, controls, modEntries, defenceEntries, isUnique)
330+
uri = result
331+
end
332+
333+
-- Helper: create a numeric EditControl without +/- spinner buttons, and
334+
-- with a preset changeFunc
335+
local function newPlainNumericEdit(anchor, rect, init, prompt, limit)
336+
local ctrl = new("EditControl", anchor, rect, init, prompt, "%D", limit, rebuildUrl)
337+
-- Remove the +/- spinner buttons that "%D" filter triggers
338+
ctrl.isNumeric = false
339+
if ctrl.controls then
340+
if ctrl.controls.buttonDown then ctrl.controls.buttonDown.shown = false end
341+
if ctrl.controls.buttonUp then ctrl.controls.buttonUp.shown = false end
342+
end
343+
return ctrl
344+
end
322345
if isUnique then
323346
-- Unique item name label
324347
controls.nameLabel = new("LabelControl", nil, {0, ctrlY, 0, 16}, "^x" .. (colorCodes[item.rarity] or "FFFFFF"):gsub("%^x","") .. item.name)
@@ -330,7 +353,7 @@ function M.openPopup(item, slotName, primaryBuild)
330353
ctrlY = ctrlY + rowHeight
331354

332355
-- Base type checkbox
333-
controls.baseTypeCheck = new("CheckBoxControl", nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", nil, nil)
356+
controls.baseTypeCheck = new("CheckBoxControl", nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", rebuildUrl)
334357
controls.baseTypeLabel = new("LabelControl", {"LEFT", controls.baseTypeCheck, "RIGHT"}, {4, 0, 0, 16}, "^7Use specific base: " .. (item.baseName or "Unknown"))
335358
ctrlY = ctrlY + rowHeight
336359

@@ -344,7 +367,7 @@ function M.openPopup(item, slotName, primaryBuild)
344367
-- Defence stat rows
345368
for i, def in ipairs(defenceEntries) do
346369
local prefix = "def" .. i
347-
controls[prefix .. "Check"] = new("CheckBoxControl", nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", nil, nil)
370+
controls[prefix .. "Check"] = new("CheckBoxControl", nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", rebuildUrl)
348371
controls[prefix .. "Label"] = new("LabelControl", {"LEFT", controls[prefix .. "Check"], "RIGHT"}, {4, 0, 0, 16}, "^7" .. def.label)
349372
controls[prefix .. "Min"] = newPlainNumericEdit(nil, {minFieldX - popupWidth/2, ctrlY, fieldW, fieldH}, tostring(m_floor(def.value)), "Min", 6)
350373
controls[prefix .. "Max"] = newPlainNumericEdit(nil, {maxFieldX - popupWidth/2, ctrlY, fieldW, fieldH}, "", "Max", 6)
@@ -358,51 +381,55 @@ function M.openPopup(item, slotName, primaryBuild)
358381
end
359382

360383
-- Mod rows
384+
local prevType
361385
for i, entry in ipairs(modEntries) do
386+
-- add extra row to separate e.g. implicits
387+
if prevType and prevType ~= entry.type then
388+
ctrlY = ctrlY + rowHeight
389+
end
390+
prevType = entry.type
362391
local prefix = "mod" .. i
363392
local canSearch = entry.tradeId ~= nil
364-
controls[prefix .. "Check"] = new("CheckBoxControl", nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", nil, nil)
393+
controls[prefix .. "Check"] = new("CheckBoxControl", nil, {-popupWidth/2 + leftMargin + checkboxSize/2, ctrlY, checkboxSize}, "", rebuildUrl)
365394
controls[prefix .. "Check"].enabled = function() return canSearch end
366395
-- Truncate long mod text to fit
396+
--- @type string
367397
local displayText = entry.formatted
368-
if #displayText > 45 then
369-
displayText = displayText:sub(1, 42) .. "..."
370-
end
371-
controls[prefix .. "Label"] = new("LabelControl", {"LEFT", controls[prefix .. "Check"], "RIGHT"}, {4, 0, 0, 16}, (canSearch and "^7" or "^8") .. displayText)
372-
controls[prefix .. "Min"] = newPlainNumericEdit(nil, {minFieldX - popupWidth/2, ctrlY, fieldW, fieldH}, entry.value ~= 0 and tostring(m_floor(entry.value)) or "", "Min", 8)
373-
controls[prefix .. "Max"] = newPlainNumericEdit(nil, {maxFieldX - popupWidth/2, ctrlY, fieldW, fieldH}, "", "Max", 8)
398+
local colorCodeLength = displayText:match("(%^x%x%x%x%x%x%x)") or displayText:gsub("(%^%x)", "") or ""
374399
if not canSearch then
375-
controls[prefix .. "Min"].enabled = function() return false end
376-
controls[prefix .. "Max"].enabled = function() return false end
400+
-- strip color codes and replace with gray
401+
displayText = "^8" .. displayText:gsub("%^x%x%x%x%x%x%x", ""):gsub("%^%x", "")
402+
end
403+
if #displayText > (#colorCodeLength + 60) then
404+
displayText = displayText:sub(1, #colorCodeLength + 54) .. "..."
405+
end
406+
407+
controls[prefix .. "Label"] = new("LabelControl", { "LEFT", controls[prefix .. "Check"], "RIGHT" }, { 4, 0, 0, 16 },
408+
displayText)
409+
-- when the trade site has a dropdown for the value, we opt to disable
410+
-- the inputs as they are numeric
411+
if not (entry.isOption or entry.needsExactValue) and entry.value then
412+
controls[prefix .. "Min"] = newPlainNumericEdit(nil, {minFieldX - popupWidth/2, ctrlY, fieldW, fieldH}, entry.value ~= 0 and tostring(m_floor(entry.value)) or "", "Min", 8)
413+
controls[prefix .. "Max"] = newPlainNumericEdit(nil, {maxFieldX - popupWidth/2, ctrlY, fieldW, fieldH}, "", "Max", 8)
414+
if not canSearch then
415+
controls[prefix .. "Min"].enabled = function() return false end
416+
controls[prefix .. "Max"].enabled = function() return false end
417+
end
377418
end
378419
ctrlY = ctrlY + rowHeight
379420
end
380421

381422
-- Search button
382423
ctrlY = ctrlY + 8
383-
controls.search = new("ButtonControl", nil, {0, ctrlY, 110, 20}, "Generate URL", function()
384-
local success, result = pcall(function()
385-
return buildURL(item, slotName, controls, modEntries, defenceEntries, isUnique)
386-
end)
387-
if success and result then
388-
controls.uri:SetText(result, true)
389-
elseif not success then
390-
controls.uri:SetText("Error: " .. tostring(result), true)
391-
else
392-
controls.uri:SetText("Error: could not determine league", true)
393-
end
394-
end)
395-
ctrlY = ctrlY + rowHeight + 4
396-
397-
-- URL field
398-
controls.uri = new("EditControl", nil, {-30, ctrlY, popupWidth - 100, fieldH}, "", nil, "^%C\t\n")
399-
controls.uri:SetPlaceholder("Press 'Generate URL' then Ctrl+Click to open")
400-
controls.uri.tooltipFunc = function(tooltip)
401-
tooltip:Clear()
402-
if controls.uri.buf and controls.uri.buf ~= "" then
403-
tooltip:AddLine(16, "^7Ctrl + Click to open in web browser")
404-
end
424+
controls.search = new("ButtonControl", nil, {0, ctrlY, 110, 20}, "Open URL", function()
425+
Copy(uri)
426+
OpenURL(uri)
427+
end, nil)
428+
controls.search.tooltipText = "The URL is also copied to the clipboard."
429+
controls.search.enabled = function()
430+
return uri and uri ~= ""
405431
end
432+
406433
controls.close = new("ButtonControl", nil, {popupWidth/2 - 50, ctrlY, 60, 20}, "Close", function()
407434
main:ClosePopup()
408435
end)

src/Classes/ImportTab.lua

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ local ImportTabClass = newClass("ImportTab", "ControlHost", "Control", function(
132132
end)
133133
self.controls.enablePartyExportBuffs = new("CheckBoxControl", {"LEFT",self.controls.generateCode,"RIGHT"}, {100, 0, 18}, "Export Support", function(state)
134134
self.build.partyTab.enableExportBuffs = state
135-
self.build.buildFlag = true
135+
self.build.buildFlag = true
136136
end, "This is for party play, to export support character, it enables the exporting of auras, curses and modifiers to the enemy", false)
137137
self.controls.generateCodeOut = new("EditControl", {"TOPLEFT",self.controls.generateCodeLabel,"BOTTOMLEFT"}, {0, 8, 250, 20}, "", "Code", "%Z")
138138
self.controls.generateCodeOut.enabled = function()
@@ -406,7 +406,7 @@ function ImportTabClass:Save(xml)
406406
xml.attrib.importLink = self.build.importLink
407407
end
408408
-- Gets rid of erroneous, potentially infinitely nested full base64 XML stored as an import link
409-
xml.attrib.importLink = (xml.attrib.importLink and xml.attrib.importLink:len() < 100) and xml.attrib.importLink or nil
409+
xml.attrib.importLink = (xml.attrib.importLink and xml.attrib.importLink:len() < 100) and xml.attrib.importLink or nil
410410
end
411411

412412
function ImportTabClass:Draw(viewPort, inputEvents)
@@ -438,7 +438,7 @@ function ImportTabClass:DownloadCharacterList()
438438
-- normal league and ruthless league (Sanctum, Ruthless Sanctum)
439439
return "Standard"
440440
end
441-
end
441+
end
442442

443443
self.charImportMode = "DOWNLOADCHARLIST"
444444
self.charImportStatus = "Retrieving character list..."
@@ -785,7 +785,7 @@ function ImportTabClass:ImportPassiveTreeAndJewels(charData)
785785
local resistancePenaltyIndex = 7
786786
if self.build.Act then -- Estimate resistance penalty setting based on act progression estimate
787787
if type(self.build.Act) == "string" and self.build.Act == "Endgame" then resistancePenaltyIndex = 7
788-
elseif type(self.build.Act) == "number" then
788+
elseif type(self.build.Act) == "number" then
789789
if self.build.Act > 6 then resistancePenaltyIndex = 7
790790
elseif self.build.Act < 1 then resistancePenaltyIndex = 1
791791
else resistancePenaltyIndex = self.build.Act end

0 commit comments

Comments
 (0)