Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion spec/System/TestTradeHelpers_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,15 @@ describe("TradeHelpers trade hash matching", function()
end)

describe("findTradeIdOption", function()
it("matches a '#'-valued option and returns its value", function()
it("matches a flattened option stat and returns its value", function()
local tradeId, value = tradeHelpers.findTradeIdOption(
"Passive skills in radius of Elemental Overload can be Allocated without being connected to your tree",
"explicit")
assert.equal("explicit.stat_2422708892", tradeId)
assert.equal(22088, value)
end)

it("matches a legacy '#'-valued option and returns its value", function()
local tradeId, value = tradeHelpers.findTradeIdOption("Grants Level 20 Summon Bestial Snake Skill",
"explicit")
assert.equal("explicit.stat_2878779644", tradeId)
Expand Down
46 changes: 46 additions & 0 deletions spec/System/TestTradeQueryRequests_spec.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
describe("TradeQueryRequests", function()
local dkjson = require "dkjson"
local mock_limiter = {
NextRequestTime = function()
return os.time()
Expand Down Expand Up @@ -192,6 +193,51 @@ Strict-Transport-Security: max-age=63115200; includeSubDomains; preload]]
end)
end)

describe("FetchResultBlock", function()
it("reads weighted sums from current and legacy pseudo mods", function()
local function makeTradeEntry(id, pseudoMods)
return {
id = id,
listing = {
price = { amount = 1, currency = "chaos", type = "~price" },
whisper = "hi",
account = { name = "seller" },
},
item = {
extended = { text = "VGVzdCBJdGVt" },
pseudoMods = pseudoMods,
},
}
end
local response = dkjson.encode({
result = {
makeTradeEntry("current", { { description = "Sum: 178", domain = "pseudo", hash = "stat.statgroup.0" } }),
makeTradeEntry("legacy", { "Sum: 42" }),
makeTradeEntry("empty", { }),
},
})
local fetchedItems
local callbackError
requests.requestQueue.fetch = { }
requests:FetchResultBlock("test", function(items, errMsg)
fetchedItems = items
callbackError = errMsg
end)

local request = table.remove(requests.requestQueue.fetch, 1)
request.callback(response)

local itemsById = { }
for _, item in ipairs(fetchedItems) do
itemsById[item.id] = item
end
assert.is_nil(callbackError)
assert.are.equal("178", itemsById.current.weight)
assert.are.equal("42", itemsById.legacy.weight)
assert.are.equal("0", itemsById.empty.weight)
end)
end)

describe("FetchResults", function()
-- Pass: Fetches exactly 10 from 11, in 1 block
-- Fail: Fetches wrong count/blocks, indicating batch limit violation, triggering rate limits
Expand Down
59 changes: 55 additions & 4 deletions src/Classes/TradeHelpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,74 @@ end

local _optionTradeStatMap

-- These option stats are still needed for legacy items, but are no longer
-- included in the trade API's 3.29 stats response.
local legacyOptionTradeStats = {
{
type = "explicit",
id = "explicit.stat_2878779644",
text = "Grants Level 20 Summon Bestial # Skill",
options = {
{ id = 1, text = "rhoa" },
{ id = 2, text = "ursa" },
{ id = 3, text = "snake" },
},
},
{
type = "explicit",
id = "explicit.stat_3642528642",
text = "Only affects Passives in # Ring",
options = {
{ id = 1, text = "small" },
{ id = 2, text = "medium" },
{ id = 3, text = "large" },
{ id = 4, text = "very large" },
{ id = 5, text = "massive" },
},
},
}

---@param tradeStats table table of data from https://www.pathofexile.com/api/trade2/data/stats
---@return table optionTradeStatMap table containing helper data for matching trade option filters
local function getOptionTradeStatMap(tradeStats)
if _optionTradeStatMap then return _optionTradeStatMap end
local optionTradeStatMap = {}
local optionTradeStatMap = {
exact = {},
patterns = {},
}
for _, cat in ipairs(tradeStats) do
if cat.id == "enchant" or cat.id == "explicit" or cat.id == "implicit" then
for _, entry in ipairs(cat.entries) do
if entry.option and entry.text:match("#") then
local tradeId, optionId = entry.id:match("^(.-)|(.+)$")
if tradeId and optionId then
-- The 3.29 trade API expands option stats into one entry per option,
-- with the option value appended to the stat ID.
local matchKey = entry.text:gsub(" Passage", ""):lower()
optionTradeStatMap.exact[cat.id .. "\0" .. matchKey] = {
tradeId = tradeId,
value = tonumber(optionId) or optionId,
}
elseif entry.option and entry.text:match("#") then
-- pob parses the passage part as a separate mod line, which
-- causes trouble
local matchKey = entry.text:gsub("#", "(.*)"):gsub(" Passage", ""):lower()
-- make options lowercase
for _, option in ipairs(entry.option.options) do
option.text = option.text and option.text:lower()
end
optionTradeStatMap[matchKey] = { type = cat.id, options = entry.option.options, tradeId = entry.id }
optionTradeStatMap.patterns[matchKey] = { type = cat.id, options = entry.option.options, tradeId = entry.id }
end
end
end
end
for _, entry in ipairs(legacyOptionTradeStats) do
local matchKey = entry.text:gsub("#", "(.*)"):lower()
optionTradeStatMap.patterns[matchKey] = optionTradeStatMap.patterns[matchKey] or {
type = entry.type,
options = entry.options,
tradeId = entry.id,
}
end

_optionTradeStatMap = optionTradeStatMap
return _optionTradeStatMap
Expand Down Expand Up @@ -165,7 +212,11 @@ function M.findTradeIdOption(modLine, modType)

-- reformat double-line cluster enchants
modLine = modLine:gsub(".added small passive skills grant: ", " ")
for pat, entry in pairs(optionTradeStatMap) do
local exactEntry = optionTradeStatMap.exact[modType .. "\0" .. modLine]
if exactEntry then
return exactEntry.tradeId, exactEntry.value
end
for pat, entry in pairs(optionTradeStatMap.patterns) do
local match = modLine:match(pat)
if entry.type == modType and match then
for _, option in ipairs(entry.options) do
Expand Down
4 changes: 3 additions & 1 deletion src/Classes/TradeQueryRequests.lua
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,16 @@ function TradeQueryRequestsClass:FetchResultBlock(url, callback)
end
local items = {}
for _, trade_entry in pairs(response.result) do
local pseudoMod = trade_entry.item.pseudoMods and trade_entry.item.pseudoMods[1]
local pseudoModLine = pseudoMod and (pseudoMod.description or pseudoMod)
table.insert(items, {
amount = trade_entry.listing.price.amount,
currency = trade_entry.listing.price.currency,
priceType = trade_entry.listing.price.type,
item_string = escapeGGGString(common.base64.decode(trade_entry.item.extended.text)),
whisper = trade_entry.listing.whisper,
trader = trade_entry.listing.account.name,
weight = trade_entry.item.pseudoMods and trade_entry.item.pseudoMods[1]:match("Sum: (.+)") or "0",
weight = pseudoModLine and pseudoModLine:match("Sum: (.+)") or "0",
id = trade_entry.id
})
end
Expand Down
Loading