72b73c4dd6
Allows the game client to make HTTP API calls from a listen server (local lobby) instead of requiring a Steam dedicated server. CreateHTTPRequestScriptVM has the exact same API signature but works in both dedicated server and listen server contexts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1162 lines
49 KiB
Lua
1162 lines
49 KiB
Lua
local ____lualib = require("lualib_bundle")
|
|
local __TS__Class = ____lualib.__TS__Class
|
|
local __TS__New = ____lualib.__TS__New
|
|
local __TS__ArrayIsArray = ____lualib.__TS__ArrayIsArray
|
|
local __TS__ArrayMap = ____lualib.__TS__ArrayMap
|
|
local __TS__StringTrim = ____lualib.__TS__StringTrim
|
|
local __TS__StringSplit = ____lualib.__TS__StringSplit
|
|
local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter
|
|
local __TS__ObjectValues = ____lualib.__TS__ObjectValues
|
|
local __TS__StringSubstring = ____lualib.__TS__StringSubstring
|
|
local __TS__ObjectKeys = ____lualib.__TS__ObjectKeys
|
|
local __TS__TypeOf = ____lualib.__TS__TypeOf
|
|
local __TS__Number = ____lualib.__TS__Number
|
|
local Set = ____lualib.Set
|
|
local __TS__ArraySome = ____lualib.__TS__ArraySome
|
|
local __TS__Decorate = ____lualib.__TS__Decorate
|
|
local ____exports = {}
|
|
local ____tstl_2Dutils = require("lib.tstl-utils")
|
|
local reloadable = ____tstl_2Dutils.reloadable
|
|
local ____api_helper = require("api_helper")
|
|
local setApiHeaders = ____api_helper.setApiHeaders
|
|
local ____server_config = require("server_config")
|
|
local SERVER_CONFIG = ____server_config.SERVER_CONFIG
|
|
local ____ArsenalManager = require("arsenal.ArsenalManager")
|
|
local ArsenalManager = ____ArsenalManager.ArsenalManager
|
|
local ____store_manager = require("store_manager")
|
|
local StoreManager = ____store_manager.StoreManager
|
|
local LOG_PREFIX = "[MarketplaceManager]"
|
|
--- Вкл. шумные print (API, рефреш, слоты). По умолчанию выкл.
|
|
local MARKETPLACE_VERBOSE_LOG = false
|
|
--- Отдельно: разбор истории продаж / NetTable (вкл. при отладке пустой истории).
|
|
local MARKETPLACE_SALES_DEBUG_LOG = false
|
|
local function marketplaceLog(self, message)
|
|
if MARKETPLACE_VERBOSE_LOG then
|
|
print(message)
|
|
end
|
|
end
|
|
local function salesHistoryDebugLog(self, message)
|
|
if MARKETPLACE_SALES_DEBUG_LOG then
|
|
print((LOG_PREFIX .. "[sales] ") .. message)
|
|
end
|
|
end
|
|
local MARKET_MIN_PRICE_FREE = 5000
|
|
--- Слоты активных лотов на игрока (без донат-расширения).
|
|
local MARKET_BASE_SLOTS_LIMIT = 8
|
|
local MARKET_MAX_SLOTS_LIMIT = 8
|
|
____exports.MarketplaceManagerClass = __TS__Class()
|
|
local MarketplaceManagerClass = ____exports.MarketplaceManagerClass
|
|
MarketplaceManagerClass.name = "MarketplaceManagerClass"
|
|
MarketplaceManagerClass.____file_path = "scripts/vscripts/arsenal/MarketplaceManager.lua"
|
|
function MarketplaceManagerClass.prototype.____constructor(self)
|
|
self.marketBuyInFlightByPlayer = {}
|
|
self.marketCreateInFlightByPlayer = {}
|
|
end
|
|
function MarketplaceManagerClass.getInstance(self)
|
|
if not ____exports.MarketplaceManagerClass._instance then
|
|
____exports.MarketplaceManagerClass._instance = __TS__New(____exports.MarketplaceManagerClass)
|
|
end
|
|
return ____exports.MarketplaceManagerClass._instance
|
|
end
|
|
function MarketplaceManagerClass.prototype.initialize(self)
|
|
if not IsServer() then
|
|
return
|
|
end
|
|
self:registerListeners()
|
|
marketplaceLog(nil, LOG_PREFIX .. " initialized")
|
|
end
|
|
function MarketplaceManagerClass.prototype.registerListeners(self)
|
|
CustomGameEventManager:RegisterListener(
|
|
"arsenal_market_refresh",
|
|
function(_src, data)
|
|
local playerId = self:resolvePlayerId(data)
|
|
if playerId == nil then
|
|
return
|
|
end
|
|
local stats = self:parseStatKeys(data.stats)
|
|
self:refreshForPlayer(playerId, stats, false)
|
|
end
|
|
)
|
|
CustomGameEventManager:RegisterListener(
|
|
"arsenal_market_create",
|
|
function(_src, data)
|
|
local playerId = self:resolvePlayerId(data)
|
|
if playerId == nil then
|
|
return
|
|
end
|
|
local instanceId = tostring(data.instance_id or "")
|
|
local priceFree = math.max(
|
|
1,
|
|
math.floor(tonumber(data.price_free) or 0)
|
|
)
|
|
self:createListing(playerId, instanceId, priceFree)
|
|
end
|
|
)
|
|
CustomGameEventManager:RegisterListener(
|
|
"arsenal_market_buy",
|
|
function(_src, data)
|
|
local playerId = self:resolvePlayerId(data)
|
|
if playerId == nil then
|
|
return
|
|
end
|
|
local listingId = tostring(data.listing_id or "")
|
|
self:buyListing(playerId, listingId)
|
|
end
|
|
)
|
|
CustomGameEventManager:RegisterListener(
|
|
"arsenal_market_cancel",
|
|
function(_src, data)
|
|
local playerId = self:resolvePlayerId(data)
|
|
if playerId == nil then
|
|
return
|
|
end
|
|
local listingId = tostring(data.listing_id or "")
|
|
self:cancelListing(playerId, listingId)
|
|
end
|
|
)
|
|
end
|
|
function MarketplaceManagerClass.prototype.resolvePlayerId(self, data)
|
|
local ____opt_result_2
|
|
if data ~= nil then
|
|
____opt_result_2 = data.PlayerID
|
|
end
|
|
local ____opt_result_2_6 = ____opt_result_2
|
|
if ____opt_result_2_6 == nil then
|
|
local ____opt_result_5
|
|
if data ~= nil then
|
|
____opt_result_5 = data.playerId
|
|
end
|
|
____opt_result_2_6 = ____opt_result_5
|
|
end
|
|
local ____opt_result_2_6_10 = ____opt_result_2_6
|
|
if ____opt_result_2_6_10 == nil then
|
|
local ____opt_result_9
|
|
if data ~= nil then
|
|
____opt_result_9 = data.playerID
|
|
end
|
|
____opt_result_2_6_10 = ____opt_result_9
|
|
end
|
|
local raw = ____opt_result_2_6_10
|
|
if raw == nil or raw == nil then
|
|
return nil
|
|
end
|
|
local n = tonumber(tostring(raw))
|
|
if n == nil or n < 0 then
|
|
return nil
|
|
end
|
|
return n
|
|
end
|
|
function MarketplaceManagerClass.prototype.parseStatKeys(self, raw)
|
|
if not raw then
|
|
return {}
|
|
end
|
|
if __TS__ArrayIsArray(raw) then
|
|
return __TS__ArrayMap(
|
|
raw,
|
|
function(____, x) return tostring(x) end
|
|
)
|
|
end
|
|
if type(raw) == "string" then
|
|
return __TS__ArrayFilter(
|
|
__TS__ArrayMap(
|
|
__TS__StringSplit(raw, ","),
|
|
function(____, x) return __TS__StringTrim(tostring(x)) end
|
|
),
|
|
function(____, x) return #x > 0 end
|
|
)
|
|
end
|
|
if type(raw) == "table" then
|
|
return __TS__ArrayMap(
|
|
__TS__ObjectValues(raw),
|
|
function(____, x) return tostring(x) end
|
|
)
|
|
end
|
|
return {}
|
|
end
|
|
function MarketplaceManagerClass.prototype.getSteamId(self, playerId)
|
|
local steamId = PlayerResource:GetSteamAccountID(playerId)
|
|
if not steamId or steamId <= 0 then
|
|
return nil
|
|
end
|
|
return steamId
|
|
end
|
|
function MarketplaceManagerClass.prototype.sendResult(self, playerId, success, messageToken, op)
|
|
marketplaceLog(
|
|
nil,
|
|
(((((((LOG_PREFIX .. " result player=") .. tostring(playerId)) .. " ok=") .. tostring(success)) .. " msg=") .. messageToken) .. " op=") .. (op or "none")
|
|
)
|
|
local player = PlayerResource:GetPlayer(playerId)
|
|
if not player then
|
|
return
|
|
end
|
|
local payload = {success = success, message = messageToken}
|
|
if op ~= nil then
|
|
payload.op = op
|
|
end
|
|
CustomGameEventManager:Send_ServerToPlayer(player, "arsenal_market_result", payload)
|
|
end
|
|
function MarketplaceManagerClass.prototype.callApi(self, method, url, body, cb)
|
|
marketplaceLog(
|
|
nil,
|
|
(((((LOG_PREFIX .. " api -> ") .. method) .. " ") .. url) .. " body=") .. (body and json.encode(body) or "{}")
|
|
)
|
|
local req = CreateHTTPRequestScriptVM(method, url)
|
|
setApiHeaders(nil, req)
|
|
if method == "POST" or method == "PUT" then
|
|
req:SetHTTPRequestRawPostBody(
|
|
"application/json",
|
|
json.encode(body or ({}))
|
|
)
|
|
end
|
|
req:Send(function(result)
|
|
local ok = result.StatusCode >= 200 and result.StatusCode < 300
|
|
local payload = nil
|
|
if result.Body and #result.Body > 0 then
|
|
local decoded = {json.decode(result.Body)}
|
|
if decoded and type(decoded) == "table" then
|
|
payload = decoded
|
|
end
|
|
end
|
|
local bodySize = type(result.Body) == "string" and #result.Body or 0
|
|
marketplaceLog(
|
|
nil,
|
|
(((((((((LOG_PREFIX .. " api <- ") .. method) .. " ") .. url) .. " code=") .. tostring(result.StatusCode)) .. " ok=") .. tostring(ok)) .. " bodySize=") .. tostring(bodySize)
|
|
)
|
|
if result.Body and #result.Body > 0 then
|
|
local preview = #result.Body > 220 and __TS__StringSubstring(result.Body, 0, 220) .. "..." or result.Body
|
|
marketplaceLog(nil, (LOG_PREFIX .. " api body preview=") .. preview)
|
|
end
|
|
if payload and type(payload) == "table" then
|
|
local sampleItems = payload.items
|
|
if sampleItems and __TS__ArrayIsArray(sampleItems) then
|
|
marketplaceLog(
|
|
nil,
|
|
(LOG_PREFIX .. " api payload items=") .. tostring(#sampleItems)
|
|
)
|
|
else
|
|
local keys = table.concat(
|
|
__TS__ObjectKeys(payload),
|
|
","
|
|
)
|
|
marketplaceLog(nil, ((LOG_PREFIX .. " api payload keys=[") .. keys) .. "]")
|
|
end
|
|
end
|
|
if MARKETPLACE_SALES_DEBUG_LOG and (string.find(url, "arsenal_market/sales", nil, true) or 0) - 1 >= 0 then
|
|
local rawBody = type(result.Body) == "string" and result.Body or ""
|
|
local preview = #rawBody <= 0 and "(empty body)" or (#rawBody > 380 and __TS__StringSubstring(rawBody, 0, 380) .. "..." or rawBody)
|
|
salesHistoryDebugLog(
|
|
nil,
|
|
(((((("HTTP GET sales code=" .. tostring(result.StatusCode)) .. " ok=") .. tostring(ok)) .. " bodyLen=") .. tostring(bodySize)) .. " preview=") .. preview
|
|
)
|
|
end
|
|
if cb ~= nil then
|
|
cb(nil, ok, payload)
|
|
end
|
|
end)
|
|
end
|
|
function MarketplaceManagerClass.prototype.unwrapPayload(self, payload)
|
|
if not payload or type(payload) ~= "table" then
|
|
return payload
|
|
end
|
|
if __TS__ArrayIsArray(payload) then
|
|
for ____, part in ipairs(payload) do
|
|
do
|
|
if not part or type(part) ~= "table" then
|
|
goto __continue50
|
|
end
|
|
if __TS__ArrayIsArray(part) then
|
|
return part
|
|
end
|
|
if part.items ~= nil or part.listings ~= nil or part.data ~= nil then
|
|
return part
|
|
end
|
|
end
|
|
::__continue50::
|
|
end
|
|
end
|
|
return payload
|
|
end
|
|
function MarketplaceManagerClass.prototype.extractListingsFromPayload(self, payload)
|
|
local p = self:unwrapPayload(payload)
|
|
if not p or type(p) ~= "table" then
|
|
return {}
|
|
end
|
|
if __TS__ArrayIsArray(p) then
|
|
return p
|
|
end
|
|
local direct = p.items
|
|
if __TS__ArrayIsArray(direct) then
|
|
return direct
|
|
end
|
|
local listings = p.listings
|
|
if __TS__ArrayIsArray(listings) then
|
|
return listings
|
|
end
|
|
local data = p.data
|
|
if __TS__ArrayIsArray(data) then
|
|
return data
|
|
end
|
|
if data and type(data) == "table" then
|
|
local di = data.items
|
|
if __TS__ArrayIsArray(di) then
|
|
return di
|
|
end
|
|
local dl = data.listings
|
|
if __TS__ArrayIsArray(dl) then
|
|
return dl
|
|
end
|
|
end
|
|
return {}
|
|
end
|
|
function MarketplaceManagerClass.prototype.extractSalesHistoryFromPayload(self, payload)
|
|
local function pickRowsArray(____, node)
|
|
if not node or type(node) ~= "table" then
|
|
return {rows = {}, source = "empty_node"}
|
|
end
|
|
if __TS__ArrayIsArray(node) then
|
|
return {rows = node, source = "nested_array"}
|
|
end
|
|
local o = node
|
|
for ____, k in ipairs({
|
|
"items",
|
|
"sales",
|
|
"sales_history",
|
|
"history",
|
|
"rows"
|
|
}) do
|
|
local v = o[k]
|
|
if __TS__ArrayIsArray(v) then
|
|
return {rows = v, source = "object." .. k}
|
|
end
|
|
end
|
|
local data = o.data
|
|
if __TS__ArrayIsArray(data) then
|
|
return {rows = data, source = "object.data_array"}
|
|
end
|
|
if data and type(data) == "table" then
|
|
local ____data_items_13 = data.items
|
|
if ____data_items_13 == nil then
|
|
____data_items_13 = data.sales
|
|
end
|
|
local di = ____data_items_13
|
|
if __TS__ArrayIsArray(di) then
|
|
return {rows = di, source = "object.data.items_or_sales"}
|
|
end
|
|
end
|
|
return {rows = {}, source = "object_no_array"}
|
|
end
|
|
local rawType = (payload == nil or payload == nil) and "null" or __TS__TypeOf(payload)
|
|
local p = self:unwrapPayload(payload)
|
|
local unwrappedType = (p == nil or p == nil) and "null" or __TS__TypeOf(p)
|
|
local shape = "none"
|
|
local rows = {}
|
|
if not p then
|
|
salesHistoryDebugLog(nil, ("extract: rawType=" .. rawType) .. " unwrapped=null → 0 rows")
|
|
return {}
|
|
end
|
|
if __TS__ArrayIsArray(p) then
|
|
rows = p
|
|
shape = "unwrap_array"
|
|
elseif type(p) == "table" then
|
|
local picked = pickRowsArray(nil, p)
|
|
rows = picked.rows
|
|
shape = picked.source
|
|
else
|
|
salesHistoryDebugLog(nil, ((("extract: rawType=" .. rawType) .. " unwrapped=") .. unwrappedType) .. " → 0 rows (not object/array)")
|
|
return {}
|
|
end
|
|
local out = {}
|
|
for ____, row in ipairs(rows) do
|
|
do
|
|
if not row or type(row) ~= "table" then
|
|
goto __continue78
|
|
end
|
|
local ____math_max_17 = math.max
|
|
local ____math_floor_16 = math.floor
|
|
local ____row_price_free_14 = row.price_free
|
|
if ____row_price_free_14 == nil then
|
|
____row_price_free_14 = row.priceFree
|
|
end
|
|
local ____row_price_free_14_15 = ____row_price_free_14
|
|
if ____row_price_free_14_15 == nil then
|
|
____row_price_free_14_15 = 0
|
|
end
|
|
local price = ____math_max_17(
|
|
0,
|
|
____math_floor_16(__TS__Number(____row_price_free_14_15))
|
|
)
|
|
local ____math_max_21 = math.max
|
|
local ____math_floor_20 = math.floor
|
|
local ____row_commission_free_18 = row.commission_free
|
|
if ____row_commission_free_18 == nil then
|
|
____row_commission_free_18 = row.commissionFree
|
|
end
|
|
local ____row_commission_free_18_19 = ____row_commission_free_18
|
|
if ____row_commission_free_18_19 == nil then
|
|
____row_commission_free_18_19 = 0
|
|
end
|
|
local commission = ____math_max_21(
|
|
0,
|
|
____math_floor_20(__TS__Number(____row_commission_free_18_19))
|
|
)
|
|
local ____math_max_25 = math.max
|
|
local ____math_floor_24 = math.floor
|
|
local ____row_seller_received_free_22 = row.seller_received_free
|
|
if ____row_seller_received_free_22 == nil then
|
|
____row_seller_received_free_22 = row.sellerReceivedFree
|
|
end
|
|
local ____row_seller_received_free_22_23 = ____row_seller_received_free_22
|
|
if ____row_seller_received_free_22_23 == nil then
|
|
____row_seller_received_free_22_23 = 0
|
|
end
|
|
local received = ____math_max_25(
|
|
0,
|
|
____math_floor_24(__TS__Number(____row_seller_received_free_22_23))
|
|
)
|
|
local ____tostring_28 = tostring
|
|
local ____row_listing_id_26 = row.listing_id
|
|
if ____row_listing_id_26 == nil then
|
|
____row_listing_id_26 = row.listingId
|
|
end
|
|
local ____row_listing_id_26_27 = ____row_listing_id_26
|
|
if ____row_listing_id_26_27 == nil then
|
|
____row_listing_id_26_27 = ""
|
|
end
|
|
local ____tostring_28_result_42 = ____tostring_28(____row_listing_id_26_27)
|
|
local ____tostring_31 = tostring
|
|
local ____row_item_name_29 = row.item_name
|
|
if ____row_item_name_29 == nil then
|
|
____row_item_name_29 = row.itemName
|
|
end
|
|
local ____row_item_name_29_30 = ____row_item_name_29
|
|
if ____row_item_name_29_30 == nil then
|
|
____row_item_name_29_30 = ""
|
|
end
|
|
local ____tostring_31_result_43 = ____tostring_31(____row_item_name_29_30)
|
|
local ____tostring_33 = tostring
|
|
local ____row_quality_32 = row.quality
|
|
if ____row_quality_32 == nil then
|
|
____row_quality_32 = "common"
|
|
end
|
|
local ____tostring_33_result_44 = ____tostring_33(____row_quality_32)
|
|
local ____math_floor_36 = math.floor
|
|
local ____row_buyer_steam_id_34 = row.buyer_steam_id
|
|
if ____row_buyer_steam_id_34 == nil then
|
|
____row_buyer_steam_id_34 = row.buyerSteamId
|
|
end
|
|
local ____row_buyer_steam_id_34_35 = ____row_buyer_steam_id_34
|
|
if ____row_buyer_steam_id_34_35 == nil then
|
|
____row_buyer_steam_id_34_35 = 0
|
|
end
|
|
local ____math_floor_36_result_45 = ____math_floor_36(__TS__Number(____row_buyer_steam_id_34_35))
|
|
local ____tostring_39 = tostring
|
|
local ____row_buyer_name_37 = row.buyer_name
|
|
if ____row_buyer_name_37 == nil then
|
|
____row_buyer_name_37 = row.buyerName
|
|
end
|
|
local ____row_buyer_name_37_38 = ____row_buyer_name_37
|
|
if ____row_buyer_name_37_38 == nil then
|
|
____row_buyer_name_37_38 = ""
|
|
end
|
|
local ____tostring_39_result_46 = ____tostring_39(____row_buyer_name_37_38)
|
|
local ____temp_47 = received > 0 and received or math.max(0, price - commission)
|
|
local ____row_sold_at_40 = row.sold_at
|
|
if ____row_sold_at_40 == nil then
|
|
____row_sold_at_40 = row.soldAt
|
|
end
|
|
local ____row_sold_at_40_41 = ____row_sold_at_40
|
|
if ____row_sold_at_40_41 == nil then
|
|
____row_sold_at_40_41 = row.updated_at
|
|
end
|
|
out[#out + 1] = {
|
|
listing_id = ____tostring_28_result_42,
|
|
item_name = ____tostring_31_result_43,
|
|
quality = ____tostring_33_result_44,
|
|
price_free = price,
|
|
buyer_steam_id = ____math_floor_36_result_45,
|
|
buyer_name = ____tostring_39_result_46,
|
|
commission_free = commission,
|
|
seller_received_free = ____temp_47,
|
|
sold_at = ____row_sold_at_40_41
|
|
}
|
|
end
|
|
::__continue78::
|
|
end
|
|
local first = #out > 0 and out[1] or nil
|
|
salesHistoryDebugLog(
|
|
nil,
|
|
(((((((((("extract: rawType=" .. rawType) .. " unwrapped=") .. unwrappedType) .. " shape=") .. shape) .. " rawRows=") .. tostring(#rows)) .. " normalized=") .. tostring(#out)) .. " firstItem=") .. (first and tostring(first.item_name) or "-")
|
|
)
|
|
return out
|
|
end
|
|
function MarketplaceManagerClass.prototype.extractInventoryInstancesFromPayload(self, payload)
|
|
local visited = __TS__New(Set)
|
|
local walk
|
|
walk = function(____, node, depth)
|
|
if not node or type(node) ~= "table" then
|
|
return nil
|
|
end
|
|
if visited:has(node) then
|
|
return nil
|
|
end
|
|
visited:add(node)
|
|
if depth > 6 then
|
|
return nil
|
|
end
|
|
local directInstances = node.instances
|
|
if directInstances and type(directInstances) == "table" then
|
|
return directInstances
|
|
end
|
|
local ai = node.arsenal_inventory
|
|
if ai and type(ai) == "table" and ai.instances and type(ai.instances) == "table" then
|
|
return ai.instances
|
|
end
|
|
local d = node.data
|
|
if d and type(d) == "table" then
|
|
local fromData = walk(nil, d, depth + 1)
|
|
if fromData then
|
|
return fromData
|
|
end
|
|
end
|
|
if __TS__ArrayIsArray(node) then
|
|
for ____, part in ipairs(node) do
|
|
local found = walk(nil, part, depth + 1)
|
|
if found then
|
|
return found
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
for k in pairs(node) do
|
|
do
|
|
local v = node[k]
|
|
if not v or type(v) ~= "table" then
|
|
goto __continue94
|
|
end
|
|
local found = walk(nil, v, depth + 1)
|
|
if found then
|
|
return found
|
|
end
|
|
end
|
|
::__continue94::
|
|
end
|
|
return nil
|
|
end
|
|
return walk(nil, payload, 0) or ({})
|
|
end
|
|
function MarketplaceManagerClass.prototype.collectCreateCandidateIds(self, localInstanceId, owned, localInstances, apiInstances)
|
|
local out = {}
|
|
local seen = {}
|
|
local function push(____, v)
|
|
if v == nil or v == nil then
|
|
return
|
|
end
|
|
local s = tostring(v)
|
|
if not s or #s <= 0 then
|
|
return
|
|
end
|
|
if seen[s] then
|
|
return
|
|
end
|
|
seen[s] = true
|
|
out[#out + 1] = type(v) == "number" and v or s
|
|
end
|
|
push(
|
|
nil,
|
|
__TS__Number(owned.globalSerial or 0) > 0 and __TS__Number(owned.globalSerial or 0) or nil
|
|
)
|
|
push(
|
|
nil,
|
|
__TS__Number(owned.serial or 0) > 0 and __TS__Number(owned.serial or 0) or nil
|
|
)
|
|
push(nil, localInstanceId)
|
|
push(nil, owned.instanceId)
|
|
push(nil, owned.instance_id)
|
|
local function scanBag(____, bag)
|
|
for key in pairs(bag) do
|
|
local row = bag[key]
|
|
local ____tostring_56 = tostring
|
|
local ____opt_result_50
|
|
if row ~= nil then
|
|
____opt_result_50 = row.instanceId
|
|
end
|
|
local ____opt_result_50_54 = ____opt_result_50
|
|
if ____opt_result_50_54 == nil then
|
|
local ____opt_result_53
|
|
if row ~= nil then
|
|
____opt_result_53 = row.instance_id
|
|
end
|
|
____opt_result_50_54 = ____opt_result_53
|
|
end
|
|
local ____opt_result_50_54_55 = ____opt_result_50_54
|
|
if ____opt_result_50_54_55 == nil then
|
|
____opt_result_50_54_55 = ""
|
|
end
|
|
local rowInstance = ____tostring_56(____opt_result_50_54_55)
|
|
local ____opt_result_59
|
|
if row ~= nil then
|
|
____opt_result_59 = row.globalSerial
|
|
end
|
|
local ____opt_result_59_63 = ____opt_result_59
|
|
if ____opt_result_59_63 == nil then
|
|
local ____opt_result_62
|
|
if row ~= nil then
|
|
____opt_result_62 = row.global_serial
|
|
end
|
|
____opt_result_59_63 = ____opt_result_62
|
|
end
|
|
local ____opt_result_59_63_64 = ____opt_result_59_63
|
|
if ____opt_result_59_63_64 == nil then
|
|
____opt_result_59_63_64 = 0
|
|
end
|
|
local rowGlobal = __TS__Number(____opt_result_59_63_64)
|
|
local ____opt_result_67
|
|
if row ~= nil then
|
|
____opt_result_67 = row.serial
|
|
end
|
|
local ____opt_result_67_68 = ____opt_result_67
|
|
if ____opt_result_67_68 == nil then
|
|
____opt_result_67_68 = 0
|
|
end
|
|
local rowSerial = __TS__Number(____opt_result_67_68)
|
|
local sameInstance = #rowInstance > 0 and rowInstance == localInstanceId
|
|
local sameGlobal = __TS__Number(owned.globalSerial or 0) > 0 and rowGlobal > 0 and rowGlobal == __TS__Number(owned.globalSerial or 0)
|
|
local sameSerial = __TS__Number(owned.serial or 0) > 0 and rowSerial > 0 and rowSerial == __TS__Number(owned.serial or 0)
|
|
if sameInstance or sameGlobal or sameSerial then
|
|
push(nil, key)
|
|
push(nil, rowInstance)
|
|
if rowGlobal > 0 then
|
|
push(nil, rowGlobal)
|
|
end
|
|
if rowSerial > 0 then
|
|
push(nil, rowSerial)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
scanBag(nil, localInstances)
|
|
scanBag(nil, apiInstances)
|
|
return out
|
|
end
|
|
function MarketplaceManagerClass.prototype.extractSlotsFromPayload(self, payload, myListingsCount)
|
|
local p = self:unwrapPayload(payload)
|
|
if not p or type(p) ~= "table" then
|
|
return {slots_limit = MARKET_BASE_SLOTS_LIMIT, slots_used = myListingsCount}
|
|
end
|
|
local ____temp_69
|
|
if p.data and type(p.data) == "table" then
|
|
____temp_69 = p.data
|
|
else
|
|
____temp_69 = p
|
|
end
|
|
local data = ____temp_69
|
|
local ____data_slots_limit_70 = data.slots_limit
|
|
if ____data_slots_limit_70 == nil then
|
|
____data_slots_limit_70 = data.market_slots_limit
|
|
end
|
|
local ____data_slots_limit_70_71 = ____data_slots_limit_70
|
|
if ____data_slots_limit_70_71 == nil then
|
|
____data_slots_limit_70_71 = MARKET_BASE_SLOTS_LIMIT
|
|
end
|
|
local rawLimit = __TS__Number(____data_slots_limit_70_71)
|
|
local ____data_slots_used_72 = data.slots_used
|
|
if ____data_slots_used_72 == nil then
|
|
____data_slots_used_72 = data.market_slots_used
|
|
end
|
|
local ____data_slots_used_72_73 = ____data_slots_used_72
|
|
if ____data_slots_used_72_73 == nil then
|
|
____data_slots_used_72_73 = myListingsCount
|
|
end
|
|
local rawUsed = __TS__Number(____data_slots_used_72_73)
|
|
return {
|
|
slots_limit = math.max(
|
|
MARKET_BASE_SLOTS_LIMIT,
|
|
math.min(
|
|
MARKET_MAX_SLOTS_LIMIT,
|
|
math.floor(rawLimit or MARKET_BASE_SLOTS_LIMIT)
|
|
)
|
|
),
|
|
slots_used = math.max(
|
|
0,
|
|
math.floor(rawUsed or myListingsCount)
|
|
)
|
|
}
|
|
end
|
|
function MarketplaceManagerClass.prototype.setMarketTables(self, playerId, publicListings, myListings, slots, selectedStats, salesHistory)
|
|
marketplaceLog(
|
|
nil,
|
|
((((((((((((((LOG_PREFIX .. " set tables player=") .. tostring(playerId)) .. " public=") .. tostring(#publicListings)) .. " my=") .. tostring(#myListings)) .. " sales=") .. tostring(#salesHistory)) .. " slots=") .. tostring(slots.slots_used or #myListings)) .. "/") .. tostring(slots.slots_limit or MARKET_BASE_SLOTS_LIMIT)) .. " stats=[") .. table.concat(selectedStats, ",")) .. "]"
|
|
)
|
|
local statKeysSet = {}
|
|
for ____, row in ipairs(publicListings) do
|
|
for ____, k in ipairs(row.stat_keys or ({})) do
|
|
if k and #k > 0 then
|
|
statKeysSet[k] = true
|
|
end
|
|
end
|
|
for ____, p in ipairs(row.stats_snapshot or ({})) do
|
|
local k = tostring(p.key or "")
|
|
if #k > 0 then
|
|
statKeysSet[k] = true
|
|
end
|
|
end
|
|
end
|
|
CustomNetTables:SetTableValue(
|
|
"arsenal_market",
|
|
"listings_public",
|
|
{
|
|
listings = publicListings,
|
|
stat_keys = __TS__ObjectKeys(statKeysSet),
|
|
selected_stats = selectedStats,
|
|
ts = GameRules:GetGameTime()
|
|
}
|
|
)
|
|
local salesJsonEncoded = json.encode(salesHistory)
|
|
salesHistoryDebugLog(
|
|
nil,
|
|
(((((("setMarketTables pid=" .. tostring(playerId)) .. " sales=") .. tostring(#salesHistory)) .. " sales_json_chars=") .. tostring(#salesJsonEncoded)) .. " my=") .. tostring(#myListings)
|
|
)
|
|
CustomNetTables:SetTableValue(
|
|
"arsenal_market",
|
|
tostring(playerId),
|
|
{
|
|
my_listings = myListings,
|
|
sales_history_json = salesJsonEncoded,
|
|
slots_limit = slots.slots_limit or MARKET_BASE_SLOTS_LIMIT,
|
|
slots_used = slots.slots_used or #myListings,
|
|
ts = GameRules:GetGameTime()
|
|
}
|
|
)
|
|
end
|
|
function MarketplaceManagerClass.prototype.refreshForAllConnectedPlayers(self)
|
|
do
|
|
local pid = 0
|
|
while pid < DOTA_MAX_PLAYERS do
|
|
do
|
|
if not PlayerResource:IsValidPlayerID(pid) then
|
|
goto __continue121
|
|
end
|
|
local playerId = pid
|
|
local player = PlayerResource:GetPlayer(playerId)
|
|
if not player then
|
|
goto __continue121
|
|
end
|
|
self:refreshForPlayer(playerId, {}, true)
|
|
end
|
|
::__continue121::
|
|
pid = pid + 1
|
|
end
|
|
end
|
|
end
|
|
function MarketplaceManagerClass.prototype.refreshForPlayer(self, playerId, selectedStats, silentOnError)
|
|
local steamId = self:getSteamId(playerId)
|
|
if not steamId then
|
|
return
|
|
end
|
|
marketplaceLog(
|
|
nil,
|
|
(((((((LOG_PREFIX .. " refresh player=") .. tostring(playerId)) .. " steam=") .. tostring(steamId)) .. " stats=[") .. table.concat(selectedStats, ",")) .. "] silent=") .. tostring(silentOnError)
|
|
)
|
|
local statsQuery = #selectedStats > 0 and "?stats=" .. table.concat(selectedStats, ",") or ""
|
|
self:callApi(
|
|
"GET",
|
|
(SERVER_CONFIG.API_URL .. "/arsenal_market/listings") .. statsQuery,
|
|
nil,
|
|
function(____, okPub, pubPayload)
|
|
self:callApi(
|
|
"GET",
|
|
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arsenal_market/my_listings",
|
|
nil,
|
|
function(____, okMine, minePayload)
|
|
self:callApi(
|
|
"GET",
|
|
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arsenal_market/slots",
|
|
nil,
|
|
function(____, okSlots, slotsPayload)
|
|
self:callApi(
|
|
"GET",
|
|
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arsenal_market/sales",
|
|
nil,
|
|
function(____, okSales, salesPayload)
|
|
local publicListings = okPub and self:extractListingsFromPayload(pubPayload) or ({})
|
|
local myListings = okMine and self:extractListingsFromPayload(minePayload) or ({})
|
|
local slots = okSlots and self:extractSlotsFromPayload(slotsPayload, #myListings) or ({slots_limit = MARKET_BASE_SLOTS_LIMIT, slots_used = #myListings})
|
|
salesHistoryDebugLog(
|
|
nil,
|
|
(((((("GET sales player=" .. tostring(playerId)) .. " steam=") .. tostring(steamId)) .. " ok=") .. tostring(okSales)) .. " payloadType=") .. ((salesPayload == nil or salesPayload == nil) and "null" or __TS__TypeOf(salesPayload))
|
|
)
|
|
local salesHistory = okSales and self:extractSalesHistoryFromPayload(salesPayload) or ({})
|
|
salesHistoryDebugLog(
|
|
nil,
|
|
"GET sales → normalized=" .. tostring(#salesHistory)
|
|
)
|
|
self:setMarketTables(
|
|
playerId,
|
|
publicListings,
|
|
myListings,
|
|
slots,
|
|
selectedStats,
|
|
salesHistory
|
|
)
|
|
if (not okPub or not okMine or not okSlots) and not silentOnError then
|
|
self:sendResult(playerId, false, "#store_marketplace_error_fetch", "refresh")
|
|
end
|
|
end
|
|
)
|
|
end
|
|
)
|
|
end
|
|
)
|
|
end
|
|
)
|
|
end
|
|
function MarketplaceManagerClass.prototype.createListing(self, playerId, instanceId, priceFree)
|
|
marketplaceLog(
|
|
nil,
|
|
(((((LOG_PREFIX .. " create req player=") .. tostring(playerId)) .. " instance=") .. instanceId) .. " price=") .. tostring(priceFree)
|
|
)
|
|
if not instanceId or priceFree < MARKET_MIN_PRICE_FREE then
|
|
self:sendResult(playerId, false, "#store_marketplace_error_min_price", "create")
|
|
return
|
|
end
|
|
local steamId = self:getSteamId(playerId)
|
|
if not steamId then
|
|
return
|
|
end
|
|
local owned = ArsenalManager:getInventoryInstance(playerId, instanceId)
|
|
if not owned then
|
|
self:sendResult(playerId, false, "#arsenal_item_not_owned", "create")
|
|
return
|
|
end
|
|
marketplaceLog(
|
|
nil,
|
|
(((((((((((LOG_PREFIX .. " create owned local instanceId=") .. tostring(owned.instanceId or "")) .. " serial=") .. tostring(owned.serial or 0)) .. " globalSerial=") .. tostring(owned.globalSerial or 0)) .. " item=") .. tostring(owned.itemName or "")) .. " quality=") .. tostring(owned.quality or "")) .. " lvl=") .. tostring(owned.upgradeLevel or 0)
|
|
)
|
|
if ArsenalManager:isInstanceTradeLocked(playerId, instanceId) then
|
|
self:sendResult(playerId, false, "#store_marketplace_error_locked_item", "create")
|
|
return
|
|
end
|
|
local itemLevel = math.floor(__TS__Number(owned.upgradeLevel or 0))
|
|
if itemLevel < 1 then
|
|
self:sendResult(playerId, false, "#store_marketplace_error_min_level_1", "create")
|
|
return
|
|
end
|
|
local pidKey = playerId
|
|
if self.marketCreateInFlightByPlayer[pidKey] then
|
|
self:sendResult(playerId, false, "#store_marketplace_error_create_in_progress", "create")
|
|
return
|
|
end
|
|
self.marketCreateInFlightByPlayer[pidKey] = true
|
|
local function clearCreateFlight()
|
|
self.marketCreateInFlightByPlayer[pidKey] = false
|
|
end
|
|
local inventoryPayload = ArsenalManager:buildInventoryPayloadForMarket(playerId)
|
|
local payloadInstances = inventoryPayload.instances or ({})
|
|
marketplaceLog(
|
|
nil,
|
|
(LOG_PREFIX .. " create local payload instancesCount=") .. tostring(#__TS__ObjectKeys(payloadInstances))
|
|
)
|
|
local localRow = payloadInstances[instanceId]
|
|
if localRow then
|
|
marketplaceLog(
|
|
nil,
|
|
(((((((((LOG_PREFIX .. " create local payload hit key=") .. instanceId) .. " row.instanceId=") .. tostring(localRow.instanceId or "")) .. " row.instance_id=") .. tostring(localRow.instance_id or "")) .. " row.global_serial=") .. tostring(localRow.global_serial or 0)) .. " row.serial=") .. tostring(localRow.serial or 0)
|
|
)
|
|
else
|
|
marketplaceLog(nil, (LOG_PREFIX .. " create local payload miss key=") .. instanceId)
|
|
end
|
|
self:callApi(
|
|
"PUT",
|
|
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arsenal_inventory",
|
|
{arsenal_inventory = inventoryPayload},
|
|
function(____, _okSync)
|
|
self:callApi(
|
|
"GET",
|
|
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arsenal_inventory",
|
|
nil,
|
|
function(____, _okInv, invPayload)
|
|
local apiInstances = self:extractInventoryInstancesFromPayload(invPayload)
|
|
marketplaceLog(
|
|
nil,
|
|
(LOG_PREFIX .. " create api inventory instancesCount=") .. tostring(#__TS__ObjectKeys(apiInstances))
|
|
)
|
|
local byLocalKey = apiInstances[instanceId]
|
|
if byLocalKey then
|
|
marketplaceLog(
|
|
nil,
|
|
(((((((((LOG_PREFIX .. " create api hit localKey=") .. instanceId) .. " row.instanceId=") .. tostring(byLocalKey.instanceId or "")) .. " row.instance_id=") .. tostring(byLocalKey.instance_id or "")) .. " row.global_serial=") .. tostring(byLocalKey.global_serial or 0)) .. " row.serial=") .. tostring(byLocalKey.serial or 0)
|
|
)
|
|
else
|
|
marketplaceLog(nil, (LOG_PREFIX .. " create api miss localKey=") .. instanceId)
|
|
end
|
|
local candidateIds = self:collectCreateCandidateIds(instanceId, owned, payloadInstances, apiInstances)
|
|
marketplaceLog(
|
|
nil,
|
|
((LOG_PREFIX .. " create candidates=[") .. table.concat(
|
|
__TS__ArrayMap(
|
|
candidateIds,
|
|
function(____, x) return tostring(x) end
|
|
),
|
|
","
|
|
)) .. "]"
|
|
)
|
|
self:callApi(
|
|
"GET",
|
|
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arsenal_market/slots",
|
|
nil,
|
|
function(____, okSlots, slotsPayload)
|
|
if not okSlots then
|
|
clearCreateFlight(nil)
|
|
self:sendResult(playerId, false, "#store_marketplace_error_fetch", "create")
|
|
return
|
|
end
|
|
local ____math_max_79 = math.max
|
|
local ____math_min_78 = math.min
|
|
local ____math_floor_77 = math.floor
|
|
local ____opt_result_76
|
|
if slotsPayload ~= nil then
|
|
____opt_result_76 = slotsPayload.slots_limit
|
|
end
|
|
local slotsLimit = ____math_max_79(
|
|
MARKET_BASE_SLOTS_LIMIT,
|
|
____math_min_78(
|
|
MARKET_MAX_SLOTS_LIMIT,
|
|
____math_floor_77(__TS__Number(____opt_result_76 or MARKET_BASE_SLOTS_LIMIT))
|
|
)
|
|
)
|
|
local ____math_max_84 = math.max
|
|
local ____math_floor_83 = math.floor
|
|
local ____opt_result_82
|
|
if slotsPayload ~= nil then
|
|
____opt_result_82 = slotsPayload.slots_used
|
|
end
|
|
local slotsUsed = ____math_max_84(
|
|
0,
|
|
____math_floor_83(__TS__Number(____opt_result_82 or 0))
|
|
)
|
|
if slotsUsed >= slotsLimit then
|
|
clearCreateFlight(nil)
|
|
self:sendResult(playerId, false, "#store_marketplace_error_slots_full", "create")
|
|
return
|
|
end
|
|
local createUrl = ((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arsenal_market/create"
|
|
local function buildCreateBody(____, primaryInstanceId)
|
|
return {
|
|
instance_id = primaryInstanceId,
|
|
instanceId = instanceId,
|
|
item_instance_id = primaryInstanceId,
|
|
itemInstanceId = instanceId,
|
|
serial = __TS__Number(owned.serial or 0),
|
|
global_serial = __TS__Number(owned.globalSerial or 0),
|
|
globalSerial = __TS__Number(owned.globalSerial or 0),
|
|
item_name = tostring(owned.itemName or ""),
|
|
itemName = tostring(owned.itemName or ""),
|
|
quality = tostring(owned.quality or ""),
|
|
upgrade_level = __TS__Number(owned.upgradeLevel or 0),
|
|
upgradeLevel = __TS__Number(owned.upgradeLevel or 0),
|
|
price_free = priceFree,
|
|
priceFree = priceFree,
|
|
request_id = tostring(DoUniqueString("market_create")),
|
|
requestId = tostring(DoUniqueString("market_create_alt"))
|
|
}
|
|
end
|
|
local function onCreateSuccess()
|
|
ArsenalManager:removeInventoryInstanceForMarket(playerId, instanceId)
|
|
clearCreateFlight(nil)
|
|
ArsenalManager:loadFromServer(playerId)
|
|
self:refreshForPlayer(playerId, {}, true)
|
|
self:sendResult(playerId, true, "#store_marketplace_success_create", "create")
|
|
end
|
|
local tryCreateByIndex
|
|
tryCreateByIndex = function(____, idx)
|
|
if idx >= #candidateIds then
|
|
clearCreateFlight(nil)
|
|
self:sendResult(playerId, false, "#store_marketplace_error_create", "create")
|
|
return
|
|
end
|
|
local currentId = candidateIds[idx + 1]
|
|
marketplaceLog(
|
|
nil,
|
|
(((LOG_PREFIX .. " create try idx=") .. tostring(idx)) .. " candidate=") .. tostring(currentId)
|
|
)
|
|
self:callApi(
|
|
"POST",
|
|
createUrl,
|
|
buildCreateBody(nil, currentId),
|
|
function(____, okTry, payloadTry)
|
|
if not okTry then
|
|
local ____tostring_93 = tostring
|
|
local ____opt_result_87
|
|
if payloadTry ~= nil then
|
|
____opt_result_87 = payloadTry.error
|
|
end
|
|
local ____opt_result_87_91 = ____opt_result_87
|
|
if ____opt_result_87_91 == nil then
|
|
local ____opt_result_90
|
|
if payloadTry ~= nil then
|
|
____opt_result_90 = payloadTry.message
|
|
end
|
|
____opt_result_87_91 = ____opt_result_90
|
|
end
|
|
local ____opt_result_87_91_92 = ____opt_result_87_91
|
|
if ____opt_result_87_91_92 == nil then
|
|
____opt_result_87_91_92 = ""
|
|
end
|
|
local err = ____tostring_93(____opt_result_87_91_92)
|
|
marketplaceLog(
|
|
nil,
|
|
((((((LOG_PREFIX .. " create try fail idx=") .. tostring(idx)) .. " candidate=") .. tostring(currentId)) .. " err=\"") .. err) .. "\""
|
|
)
|
|
if idx + 1 < #candidateIds then
|
|
tryCreateByIndex(nil, idx + 1)
|
|
return
|
|
end
|
|
clearCreateFlight(nil)
|
|
self:sendResult(playerId, false, "#store_marketplace_error_create", "create")
|
|
return
|
|
end
|
|
marketplaceLog(
|
|
nil,
|
|
(((LOG_PREFIX .. " create try success idx=") .. tostring(idx)) .. " candidate=") .. tostring(currentId)
|
|
)
|
|
onCreateSuccess(nil)
|
|
end
|
|
)
|
|
end
|
|
tryCreateByIndex(nil, 0)
|
|
end
|
|
)
|
|
end
|
|
)
|
|
end
|
|
)
|
|
end
|
|
function MarketplaceManagerClass.prototype.buyListing(self, playerId, listingId)
|
|
marketplaceLog(
|
|
nil,
|
|
(((LOG_PREFIX .. " buy req player=") .. tostring(playerId)) .. " listing=") .. listingId
|
|
)
|
|
if not listingId then
|
|
self:sendResult(playerId, false, "#store_marketplace_error_invalid_data", "buy")
|
|
return
|
|
end
|
|
local steamId = self:getSteamId(playerId)
|
|
if not steamId then
|
|
return
|
|
end
|
|
local pidKey = playerId
|
|
if self.marketBuyInFlightByPlayer[pidKey] then
|
|
self:sendResult(playerId, false, "#store_marketplace_error_buy_in_progress", "buy")
|
|
return
|
|
end
|
|
self.marketBuyInFlightByPlayer[pidKey] = true
|
|
local function clearBuyFlight()
|
|
self.marketBuyInFlightByPlayer[pidKey] = false
|
|
end
|
|
self:callApi(
|
|
"GET",
|
|
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arsenal_market/my_listings",
|
|
nil,
|
|
function(____, okMine, minePayload)
|
|
if okMine then
|
|
local ownListings = self:extractListingsFromPayload(minePayload)
|
|
local isOwn = __TS__ArraySome(
|
|
ownListings,
|
|
function(____, x) return tostring(x.listing_id or "") == listingId end
|
|
)
|
|
if isOwn then
|
|
clearBuyFlight(nil)
|
|
self:sendResult(playerId, false, "#store_marketplace_error_buy", "buy")
|
|
return
|
|
end
|
|
end
|
|
self:callApi(
|
|
"POST",
|
|
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arsenal_market/buy",
|
|
{
|
|
listing_id = listingId,
|
|
request_id = tostring(DoUniqueString("market_buy"))
|
|
},
|
|
function(____, ok, payload)
|
|
clearBuyFlight(nil)
|
|
if not ok then
|
|
self:sendResult(playerId, false, "#store_marketplace_error_buy", "buy")
|
|
return
|
|
end
|
|
ArsenalManager:loadFromServer(playerId)
|
|
StoreManager:getInstance():loadCurrencyFromServer(playerId)
|
|
self:refreshForPlayer(playerId, {}, true)
|
|
local ____opt_result_96
|
|
if payload ~= nil then
|
|
____opt_result_96 = payload.seller_steam_id
|
|
end
|
|
local sellerSteamId = __TS__Number(____opt_result_96 or 0)
|
|
if sellerSteamId > 0 then
|
|
local sellerPid = self:findConnectedPlayerBySteamId(sellerSteamId)
|
|
if sellerPid ~= nil then
|
|
ArsenalManager:loadFromServer(sellerPid)
|
|
StoreManager:getInstance():loadCurrencyFromServer(sellerPid)
|
|
self:refreshForPlayer(sellerPid, {}, true)
|
|
end
|
|
end
|
|
self:refreshForAllConnectedPlayers()
|
|
self:sendResult(playerId, true, "#store_marketplace_success_buy", "buy")
|
|
end
|
|
)
|
|
end
|
|
)
|
|
end
|
|
function MarketplaceManagerClass.prototype.cancelListing(self, playerId, listingId)
|
|
marketplaceLog(
|
|
nil,
|
|
(((LOG_PREFIX .. " cancel req player=") .. tostring(playerId)) .. " listing=") .. listingId
|
|
)
|
|
if not listingId then
|
|
self:sendResult(playerId, false, "#store_marketplace_error_invalid_data", "cancel")
|
|
return
|
|
end
|
|
local steamId = self:getSteamId(playerId)
|
|
if not steamId then
|
|
return
|
|
end
|
|
self:callApi(
|
|
"POST",
|
|
((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arsenal_market/cancel",
|
|
{
|
|
listing_id = listingId,
|
|
request_id = tostring(DoUniqueString("market_cancel"))
|
|
},
|
|
function(____, ok)
|
|
if not ok then
|
|
self:sendResult(playerId, false, "#store_marketplace_error_cancel", "cancel")
|
|
return
|
|
end
|
|
ArsenalManager:loadFromServer(playerId)
|
|
self:refreshForPlayer(playerId, {}, true)
|
|
self:sendResult(playerId, true, "#store_marketplace_success_cancel", "cancel")
|
|
end
|
|
)
|
|
end
|
|
function MarketplaceManagerClass.prototype.findConnectedPlayerBySteamId(self, steamId)
|
|
do
|
|
local pid = 0
|
|
while pid < DOTA_MAX_PLAYERS do
|
|
do
|
|
if not PlayerResource:IsValidPlayerID(pid) then
|
|
goto __continue175
|
|
end
|
|
if PlayerResource:GetSteamAccountID(pid) == steamId then
|
|
return pid
|
|
end
|
|
end
|
|
::__continue175::
|
|
pid = pid + 1
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
MarketplaceManagerClass = __TS__Decorate(MarketplaceManagerClass, MarketplaceManagerClass, {reloadable}, {kind = "class", name = "MarketplaceManagerClass"})
|
|
____exports.MarketplaceManagerClass = MarketplaceManagerClass
|
|
____exports.MarketplaceManager = ____exports.MarketplaceManagerClass:getInstance()
|
|
return ____exports
|