Skip to content

Commit af04eb3

Browse files
authored
Fix weighted trade result parsing for 3.29 (#9996)
* Fix weighted trade result parsing for 3.29 * Support flattened trade stat options * Preserve legacy trade option matching
1 parent c98330d commit af04eb3

4 files changed

Lines changed: 113 additions & 6 deletions

File tree

spec/System/TestTradeHelpers_spec.lua

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@ describe("TradeHelpers trade hash matching", function()
2121
end)
2222

2323
describe("findTradeIdOption", function()
24-
it("matches a '#'-valued option and returns its value", function()
24+
it("matches a flattened option stat and returns its value", function()
25+
local tradeId, value = tradeHelpers.findTradeIdOption(
26+
"Passive skills in radius of Elemental Overload can be Allocated without being connected to your tree",
27+
"explicit")
28+
assert.equal("explicit.stat_2422708892", tradeId)
29+
assert.equal(22088, value)
30+
end)
31+
32+
it("matches a legacy '#'-valued option and returns its value", function()
2533
local tradeId, value = tradeHelpers.findTradeIdOption("Grants Level 20 Summon Bestial Snake Skill",
2634
"explicit")
2735
assert.equal("explicit.stat_2878779644", tradeId)

spec/System/TestTradeQueryRequests_spec.lua

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
describe("TradeQueryRequests", function()
2+
local dkjson = require "dkjson"
23
local mock_limiter = {
34
NextRequestTime = function()
45
return os.time()
@@ -192,6 +193,51 @@ Strict-Transport-Security: max-age=63115200; includeSubDomains; preload]]
192193
end)
193194
end)
194195

196+
describe("FetchResultBlock", function()
197+
it("reads weighted sums from current and legacy pseudo mods", function()
198+
local function makeTradeEntry(id, pseudoMods)
199+
return {
200+
id = id,
201+
listing = {
202+
price = { amount = 1, currency = "chaos", type = "~price" },
203+
whisper = "hi",
204+
account = { name = "seller" },
205+
},
206+
item = {
207+
extended = { text = "VGVzdCBJdGVt" },
208+
pseudoMods = pseudoMods,
209+
},
210+
}
211+
end
212+
local response = dkjson.encode({
213+
result = {
214+
makeTradeEntry("current", { { description = "Sum: 178", domain = "pseudo", hash = "stat.statgroup.0" } }),
215+
makeTradeEntry("legacy", { "Sum: 42" }),
216+
makeTradeEntry("empty", { }),
217+
},
218+
})
219+
local fetchedItems
220+
local callbackError
221+
requests.requestQueue.fetch = { }
222+
requests:FetchResultBlock("test", function(items, errMsg)
223+
fetchedItems = items
224+
callbackError = errMsg
225+
end)
226+
227+
local request = table.remove(requests.requestQueue.fetch, 1)
228+
request.callback(response)
229+
230+
local itemsById = { }
231+
for _, item in ipairs(fetchedItems) do
232+
itemsById[item.id] = item
233+
end
234+
assert.is_nil(callbackError)
235+
assert.are.equal("178", itemsById.current.weight)
236+
assert.are.equal("42", itemsById.legacy.weight)
237+
assert.are.equal("0", itemsById.empty.weight)
238+
end)
239+
end)
240+
195241
describe("FetchResults", function()
196242
-- Pass: Fetches exactly 10 from 11, in 1 block
197243
-- Fail: Fetches wrong count/blocks, indicating batch limit violation, triggering rate limits

src/Classes/TradeHelpers.lua

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,27 +79,74 @@ end
7979

8080
local _optionTradeStatMap
8181

82+
-- These option stats are still needed for legacy items, but are no longer
83+
-- included in the trade API's 3.29 stats response.
84+
local legacyOptionTradeStats = {
85+
{
86+
type = "explicit",
87+
id = "explicit.stat_2878779644",
88+
text = "Grants Level 20 Summon Bestial # Skill",
89+
options = {
90+
{ id = 1, text = "rhoa" },
91+
{ id = 2, text = "ursa" },
92+
{ id = 3, text = "snake" },
93+
},
94+
},
95+
{
96+
type = "explicit",
97+
id = "explicit.stat_3642528642",
98+
text = "Only affects Passives in # Ring",
99+
options = {
100+
{ id = 1, text = "small" },
101+
{ id = 2, text = "medium" },
102+
{ id = 3, text = "large" },
103+
{ id = 4, text = "very large" },
104+
{ id = 5, text = "massive" },
105+
},
106+
},
107+
}
108+
82109
---@param tradeStats table table of data from https://www.pathofexile.com/api/trade2/data/stats
83110
---@return table optionTradeStatMap table containing helper data for matching trade option filters
84111
local function getOptionTradeStatMap(tradeStats)
85112
if _optionTradeStatMap then return _optionTradeStatMap end
86-
local optionTradeStatMap = {}
113+
local optionTradeStatMap = {
114+
exact = {},
115+
patterns = {},
116+
}
87117
for _, cat in ipairs(tradeStats) do
88118
if cat.id == "enchant" or cat.id == "explicit" or cat.id == "implicit" then
89119
for _, entry in ipairs(cat.entries) do
90-
if entry.option and entry.text:match("#") then
120+
local tradeId, optionId = entry.id:match("^(.-)|(.+)$")
121+
if tradeId and optionId then
122+
-- The 3.29 trade API expands option stats into one entry per option,
123+
-- with the option value appended to the stat ID.
124+
local matchKey = entry.text:gsub(" Passage", ""):lower()
125+
optionTradeStatMap.exact[cat.id .. "\0" .. matchKey] = {
126+
tradeId = tradeId,
127+
value = tonumber(optionId) or optionId,
128+
}
129+
elseif entry.option and entry.text:match("#") then
91130
-- pob parses the passage part as a separate mod line, which
92131
-- causes trouble
93132
local matchKey = entry.text:gsub("#", "(.*)"):gsub(" Passage", ""):lower()
94133
-- make options lowercase
95134
for _, option in ipairs(entry.option.options) do
96135
option.text = option.text and option.text:lower()
97136
end
98-
optionTradeStatMap[matchKey] = { type = cat.id, options = entry.option.options, tradeId = entry.id }
137+
optionTradeStatMap.patterns[matchKey] = { type = cat.id, options = entry.option.options, tradeId = entry.id }
99138
end
100139
end
101140
end
102141
end
142+
for _, entry in ipairs(legacyOptionTradeStats) do
143+
local matchKey = entry.text:gsub("#", "(.*)"):lower()
144+
optionTradeStatMap.patterns[matchKey] = optionTradeStatMap.patterns[matchKey] or {
145+
type = entry.type,
146+
options = entry.options,
147+
tradeId = entry.id,
148+
}
149+
end
103150

104151
_optionTradeStatMap = optionTradeStatMap
105152
return _optionTradeStatMap
@@ -165,7 +212,11 @@ function M.findTradeIdOption(modLine, modType)
165212

166213
-- reformat double-line cluster enchants
167214
modLine = modLine:gsub(".added small passive skills grant: ", " ")
168-
for pat, entry in pairs(optionTradeStatMap) do
215+
local exactEntry = optionTradeStatMap.exact[modType .. "\0" .. modLine]
216+
if exactEntry then
217+
return exactEntry.tradeId, exactEntry.value
218+
end
219+
for pat, entry in pairs(optionTradeStatMap.patterns) do
169220
local match = modLine:match(pat)
170221
if entry.type == modType and match then
171222
for _, option in ipairs(entry.options) do

src/Classes/TradeQueryRequests.lua

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,14 +290,16 @@ function TradeQueryRequestsClass:FetchResultBlock(url, callback)
290290
end
291291
local items = {}
292292
for _, trade_entry in pairs(response.result) do
293+
local pseudoMod = trade_entry.item.pseudoMods and trade_entry.item.pseudoMods[1]
294+
local pseudoModLine = pseudoMod and (pseudoMod.description or pseudoMod)
293295
table.insert(items, {
294296
amount = trade_entry.listing.price.amount,
295297
currency = trade_entry.listing.price.currency,
296298
priceType = trade_entry.listing.price.type,
297299
item_string = escapeGGGString(common.base64.decode(trade_entry.item.extended.text)),
298300
whisper = trade_entry.listing.whisper,
299301
trader = trade_entry.listing.account.name,
300-
weight = trade_entry.item.pseudoMods and trade_entry.item.pseudoMods[1]:match("Sum: (.+)") or "0",
302+
weight = pseudoModLine and pseudoModLine:match("Sum: (.+)") or "0",
301303
id = trade_entry.id
302304
})
303305
end

0 commit comments

Comments
 (0)