local ____lualib = require("lualib_bundle") local __TS__Class = ____lualib.__TS__Class local Map = ____lualib.Map local __TS__New = ____lualib.__TS__New local __TS__ArrayIsArray = ____lualib.__TS__ArrayIsArray local __TS__TypeOf = ____lualib.__TS__TypeOf local __TS__ObjectKeys = ____lualib.__TS__ObjectKeys local __TS__ArrayJoin = ____lualib.__TS__ArrayJoin local __TS__ArrayForEach = ____lualib.__TS__ArrayForEach local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter local __TS__ArraySort = ____lualib.__TS__ArraySort local __TS__ObjectValues = ____lualib.__TS__ObjectValues local __TS__ArraySome = ____lualib.__TS__ArraySome local __TS__ArrayPushArray = ____lualib.__TS__ArrayPushArray local __TS__ArrayMap = ____lualib.__TS__ArrayMap local Set = ____lualib.Set local __TS__ArrayIndexOf = ____lualib.__TS__ArrayIndexOf local ____exports = {} local ____server_config = require("server_config") local SERVER_CONFIG = ____server_config.SERVER_CONFIG local ____api_helper = require("api_helper") local setApiHeaders = ____api_helper.setApiHeaders local setApiHeadersLong = ____api_helper.setApiHeadersLong local ____store_manager = require("store_manager") local StoreManager = ____store_manager.StoreManager local ____hero_list_table = require("tables.hero_list_table") local HERO_LIST_TABLE = ____hero_list_table.HERO_LIST_TABLE local function rawPrintFn(____, ...) _G:print(...) end local ENABLE_VERBOSE_MINI_PROFILE_LOGS = false local ____print = ENABLE_VERBOSE_MINI_PROFILE_LOGS and rawPrintFn or (function(____, ...) return nil end) ____exports.MiniProfileServer = __TS__Class() local MiniProfileServer = ____exports.MiniProfileServer MiniProfileServer.name = "MiniProfileServer" MiniProfileServer.____file_path = "scripts/vscripts/mini_profile_server.lua" function MiniProfileServer.prototype.____constructor(self) self.serverUrl = SERVER_CONFIG.API_URL self.grantedProfileRewardsInSession = __TS__New(Map) self.grantedHeroRankRewardsInSession = __TS__New(Map) self.profileLevelRewards = { {level = 5, freeCurrency = 100}, {level = 10, freeCurrency = 200}, {level = 15, freeCurrency = 350}, {level = 20, freeCurrency = 500}, {level = 25, freeCurrency = 700}, {level = 30, freeCurrency = 900}, {level = 40, freeCurrency = 1400}, {level = 50, freeCurrency = 2000}, {level = 75, freeCurrency = 3500}, {level = 100, freeCurrency = 5000}, {level = 150, freeCurrency = 5500}, {level = 200, freeCurrency = 6000}, {level = 300, freeCurrency = 7000}, {level = 400, freeCurrency = 8000}, {level = 500, freeCurrency = 9000}, {level = 600, freeCurrency = 10000}, {level = 700, freeCurrency = 11000}, {level = 800, freeCurrency = 12500}, {level = 900, freeCurrency = 14000}, {level = 1000, freeCurrency = 16000} } self:setupEventListeners() end function MiniProfileServer.getInstance(self) if not ____exports.MiniProfileServer.instance then ____exports.MiniProfileServer.instance = __TS__New(____exports.MiniProfileServer) end return ____exports.MiniProfileServer.instance end function MiniProfileServer.prototype.setupEventListeners(self) CustomGameEventManager:RegisterListener( "request_player_profile", function(source, event) local playerId = event.PlayerID local playerName = event.player_name local requestedSteamId = event.steam_id local requestedSteamId64 = event.steam_id_64 local steamId local steamId64 if requestedSteamId and requestedSteamId ~= "" then steamId = tostring(requestedSteamId) if requestedSteamId64 and requestedSteamId64 ~= "" and requestedSteamId64 ~= "null" then steamId64 = tostring(requestedSteamId64) local steamIdStr = tostring(steamId) local steamIdPrefix = string.sub(steamIdStr, 1, 7) if string.len(steamIdStr) > 10 and steamIdPrefix == "7656119" then local base64Str = "76561197960265728" local steamId64Str = steamIdStr local accountId = self:subtractBigInts(steamId64Str, base64Str) steamId = accountId ____print(nil, (("[MiniProfileServer] Using provided Steam ID64: " .. steamId64) .. ", converted to Account ID: ") .. steamId) else ____print(nil, (("[MiniProfileServer] Using provided Steam ID32: " .. steamId) .. ", Steam ID64: ") .. steamId64) end else local steamIdStr = tostring(steamId) local steamIdPrefix = string.sub(steamIdStr, 1, 7) if string.len(steamIdStr) > 10 and steamIdPrefix == "7656119" then steamId64 = steamIdStr local base64Str = "76561197960265728" local accountId = self:subtractBigInts(steamIdStr, base64Str) steamId = accountId ____print(nil, (("[MiniProfileServer] Steam ID64 detected: " .. steamId64) .. ", converted to Account ID: ") .. steamId) else local accountIdNum = tonumber(steamId) if accountIdNum then local base64Str = "76561197960265728" local accountIdStr = tostring(accountIdNum) local steamId64Str = self:addBigInts(accountIdStr, base64Str) steamId64 = steamId64Str ____print(nil, (("[MiniProfileServer] Account ID detected: " .. steamId) .. ", converted to Steam ID64: ") .. steamId64) else if playerId ~= -1 and PlayerResource:GetPlayer(playerId) then steamId64 = tostring(PlayerResource:GetSteamID(playerId)) else steamId64 = steamId end end end end else steamId = tostring(PlayerResource:GetSteamAccountID(playerId)) steamId64 = tostring(PlayerResource:GetSteamID(playerId)) end local requestingPlayer = EntIndexToHScript(source) local requestingPlayerId = requestingPlayer ~= nil and requestingPlayer ~= nil and requestingPlayer:GetPlayerID() or playerId local requesterSteamId = tostring(PlayerResource:GetSteamAccountID(requestingPlayerId)) local isOwnProfileRequest = requesterSteamId == steamId self:loadPlayerProfileFromServer( requestingPlayerId, steamId, playerName, steamId64, isOwnProfileRequest ) end ) CustomGameEventManager:RegisterListener( "request_match_players", function(source, event) local requestingPlayer = EntIndexToHScript(source) if not requestingPlayer then return end local matchIdRaw = event.match_id or event.game_id or event.id local matchId = tonumber(tostring(matchIdRaw)) or 0 local rowId = tonumber(tostring(event.row_id or 0)) or 0 local steamId = tostring(event.steam_id or "") if matchId <= 0 then CustomGameEventManager:Send_ServerToPlayer(requestingPlayer, "match_players_data", {error = "Некорректный ID матча", match_id = 0, players = {}}) return end self:loadMatchPlayersFromServer(requestingPlayer, matchId, rowId, steamId) end ) CustomGameEventManager:RegisterListener( "request_store_currency", function(source, event) local playerId = event.PlayerID if playerId == nil or playerId == nil or not PlayerResource:IsValidPlayerID(playerId) then return end self:syncHeroRankRewardsForPlayer(playerId) end ) end function MiniProfileServer.prototype.syncHeroRankRewardsForPlayer(self, playerId) local steamId = tostring(PlayerResource:GetSteamAccountID(playerId)) if not steamId or steamId == "0" then return end self:loadHeroAchievementsForProfile( steamId, playerId, true, function(____, _heroAchievementsObject, grantedNow) local grantedCount = #self:normalizeArrayLike(grantedNow) if grantedCount > 0 then ____print( nil, (("[MiniProfileServer] Store-trigger reward sync: player=" .. tostring(playerId)) .. ", granted=") .. tostring(grantedCount) ) end end ) end function MiniProfileServer.prototype.createPlayerProfile(self, playerId, steamId, playerName) local request = CreateHTTPRequestScriptVM("POST", self.serverUrl .. "/player") setApiHeadersLong(nil, request) request:SetHTTPRequestRawPostBody( "application/json", json.encode({steam_id = steamId, player_name = playerName}) ) request:Send(function(result) local player = PlayerResource:GetPlayer(playerId) if not player then return end if result.StatusCode >= 200 and result.StatusCode < 300 then do pcall(function() local decoded = {json.decode(result.Body)} local responseData = nil if __TS__ArrayIsArray(decoded) and #decoded > 0 then responseData = decoded[1] elseif decoded and type(decoded) == "table" then responseData = decoded end if responseData then StoreManager:getInstance():handleLoginPlayerApiResponse(playerId, responseData) end end) end self:loadPlayerProfileFromServer(playerId, steamId, playerName) else CustomGameEventManager:Send_ServerToPlayer(player, "player_profile_data", {error = "Не удалось создать профиль", steam_id = steamId, player_name = playerName}) end end) end function MiniProfileServer.prototype.loadPlayerProfileFromServer(self, playerId, steamId, playerName, steamId64, shouldGrantLevelRewards) if shouldGrantLevelRewards == nil then shouldGrantLevelRewards = false end local steamIdStr = tostring(steamId) local steamIdNum = tonumber(steamIdStr) if steamIdNum and steamIdNum > 1000000000000 then local base64 = 76561197960265730 local accountId = math.floor(steamIdNum - base64) steamIdStr = tostring(accountId) ____print(nil, (("[MiniProfileServer] Converted 64-bit Steam ID " .. steamId) .. " to 32-bit Account ID ") .. steamIdStr) end ____print(nil, (("[MiniProfileServer] Загрузка профиля: steam_id=" .. steamIdStr) .. ", player=") .. playerName) local request = CreateHTTPRequestScriptVM("GET", (self.serverUrl .. "/player/") .. steamIdStr) setApiHeaders(nil, request) request:Send(function(result) do local function ____catch(____error) local player = PlayerResource:GetPlayer(playerId) if player then CustomGameEventManager:Send_ServerToPlayer(player, "player_profile_data", {error = "Ошибка обработки данных", steam_id = steamId, player_name = playerName}) end end local ____try, ____hasReturned, ____returnValue = pcall(function() local player = PlayerResource:GetPlayer(playerId) if not player then return true end if result.StatusCode == 0 then CustomGameEventManager:Send_ServerToPlayer(player, "player_profile_data", {error = "Сервер недоступен", steam_id = steamId, player_name = playerName}) return true end if result.StatusCode >= 200 and result.StatusCode < 300 then do local function ____catch(e) ____print( nil, "[MiniProfileServer] Ошибка обработки данных профиля: " .. tostring(e) ) CustomGameEventManager:Send_ServerToPlayer(player, "player_profile_data", {error = "Ошибка обработки данных профиля", steam_id = steamId, player_name = playerName}) end local ____try, ____hasReturned, ____returnValue = pcall(function() local responseBodyStr = tostring(result.Body or "") local responseBodyPreview = string.len(responseBodyStr) > 1000 and string.sub(responseBodyStr, 1, 1000) .. "... [truncated]" or responseBodyStr ____print(nil, "[MiniProfileServer] Response Body (preview): " .. responseBodyPreview) local responseData = self:decodeJsonSafe(result.Body) if responseData == nil then ____print( nil, "[MiniProfileServer] Ошибка JSON профиля: body_length=" .. tostring(string.len(responseBodyStr)) ) CustomGameEventManager:Send_ServerToPlayer(player, "player_profile_data", {error = "Ошибка парсинга JSON", steam_id = steamId, player_name = playerName}) return true end local responseDataAny = responseData ____print( nil, (("[MiniProfileServer] Decoded response type: " .. __TS__TypeOf(responseData)) .. ", isArray: ") .. tostring(__TS__ArrayIsArray(responseData)) ) ____print( nil, "[MiniProfileServer] Decoded response keys: " .. (type(responseData) == "table" and __TS__ArrayJoin( __TS__ObjectKeys(responseData), ", " ) or "N/A") ) local data = nil local responseItems = {} local topLevelObjects = {} if responseDataAny and type(responseDataAny) == "table" then for k in pairs(responseDataAny) do local v = responseDataAny[k] if v and type(v) == "table" then topLevelObjects[#topLevelObjects + 1] = v end end end local looksLikeProfilePayload = responseDataAny and type(responseDataAny) == "table" and (responseDataAny.profile ~= nil or responseDataAny.stats ~= nil or responseDataAny.recentGames ~= nil or responseDataAny.recent_games ~= nil or responseDataAny.games ~= nil or responseDataAny.history ~= nil) if looksLikeProfilePayload then data = responseDataAny ____print(nil, "[MiniProfileServer] Using profile payload object directly") elseif __TS__ArrayIsArray(responseDataAny) then local reconstructed = {} local reconstructedCount = 0 __TS__ArrayForEach( topLevelObjects, function(____, obj) local objAny = obj local keyNamed = tostring(objAny.key or "") local valueNamed = objAny.value local keyIndexed = tostring(objAny[1] or objAny["1"] or "") local ____temp_0 if objAny[2] ~= nil then ____temp_0 = objAny[2] else ____temp_0 = objAny["2"] end local valueIndexed = ____temp_0 local finalKey = keyNamed ~= "" and keyNamed or keyIndexed local ____temp_1 if keyNamed ~= "" then ____temp_1 = valueNamed else ____temp_1 = valueIndexed end local finalValue = ____temp_1 if finalKey ~= "" and finalValue ~= nil then reconstructed[finalKey] = finalValue reconstructedCount = reconstructedCount + 1 end end ) if reconstructedCount > 0 then data = reconstructed ____print( nil, "[MiniProfileServer] Reconstructed object from key/value pairs, keys=" .. table.concat( __TS__ObjectKeys(reconstructed), ", " ) ) elseif #topLevelObjects > 0 then local sample = topLevelObjects[1] local sampleKeys = {} for k in pairs(sample) do sampleKeys[#sampleKeys + 1] = tostring(k) end local ____temp_10 = ("[MiniProfileServer] array-like sample keys=" .. table.concat(sampleKeys, ", ")) .. " " local ____tostring_5 = tostring local ____opt_result_4 if sample ~= nil then ____opt_result_4 = sample.key end local ____tostring_5_result_9 = ____tostring_5(____opt_result_4) local ____opt_result_8 if sample ~= nil then ____opt_result_8 = sample.value end local ____temp_27 = ____temp_10 .. ((("key=" .. ____tostring_5_result_9) .. " value_type=") .. __TS__TypeOf(____opt_result_8)) .. " " local ____tostring_18 = tostring local ____opt_result_13 if sample ~= nil then ____opt_result_13 = sample[1] end local ____opt_result_13_17 = ____opt_result_13 if not ____opt_result_13_17 then local ____opt_result_16 if sample ~= nil then ____opt_result_16 = sample["1"] end ____opt_result_13_17 = ____opt_result_16 end local ____tostring_18_result_26 = ____tostring_18(____opt_result_13_17) local ____opt_result_21 if sample ~= nil then ____opt_result_21 = sample[2] end local ____opt_result_21_25 = ____opt_result_21 if ____opt_result_21_25 == nil then local ____opt_result_24 if sample ~= nil then ____opt_result_24 = sample["2"] end ____opt_result_21_25 = ____opt_result_24 end ____print( nil, ____temp_27 .. (("idx1=" .. ____tostring_18_result_26) .. " idx2_type=") .. __TS__TypeOf(____opt_result_21_25) ) end if not data then for ____, obj in ipairs(topLevelObjects) do if obj and type(obj) == "table" and (obj.profile ~= nil or obj.stats ~= nil or obj.recentGames ~= nil or obj.recent_games ~= nil or obj.games ~= nil or obj.history ~= nil) then data = obj ____print(nil, "[MiniProfileServer] Found payload object inside array-like response") break end end end if not data then responseItems = self:normalizeArrayLike(responseDataAny) if #responseItems > 0 then data = responseItems[1] ____print( nil, "[MiniProfileServer] Using array-like response, items=" .. tostring(#responseItems) ) end end elseif responseDataAny and type(responseDataAny) == "table" and responseDataAny.value ~= nil then data = responseDataAny.value ____print(nil, "[MiniProfileServer] Using responseData.value as data") elseif responseDataAny and type(responseDataAny) == "table" then data = responseDataAny ____print(nil, "[MiniProfileServer] Using object directly as data") else ____print(nil, "[MiniProfileServer] Failed to decode response") CustomGameEventManager:Send_ServerToPlayer(player, "player_profile_data", {error = "Ошибка декодирования данных", steam_id = steamId, player_name = playerName}) return true end if data then local function collectObjectKeys(____, obj) local keys = {} if not obj or type(obj) ~= "table" then return keys end for key in pairs(obj) do keys[#keys + 1] = tostring(key) end return keys end if not data or type(data) ~= "table" then for ____, item in ipairs(responseItems) do if item and type(item) == "table" then data = item break end end end if not data or type(data) ~= "table" then ____print(nil, "[MiniProfileServer] ❌ Некорректный формат данных профиля (data is not object)") CustomGameEventManager:Send_ServerToPlayer(player, "player_profile_data", {error = "Некорректный формат данных профиля", steam_id = steamId, player_name = playerName}) return true end ____print( nil, "[MiniProfileServer] Data keys: " .. table.concat( collectObjectKeys(nil, data), ", " ) ) ____print( nil, "[MiniProfileServer] data.recentGames exists: " .. tostring(data.recentGames ~= nil) ) ____print( nil, (("[MiniProfileServer] data.recentGames type: " .. __TS__TypeOf(data.recentGames)) .. ", isArray: ") .. tostring(__TS__ArrayIsArray(data.recentGames)) ) if data.recentGames then local ____Array_isArray_result_28 if __TS__ArrayIsArray(data.recentGames) then ____Array_isArray_result_28 = data.recentGames.length else ____Array_isArray_result_28 = "N/A" end ____print( nil, "[MiniProfileServer] data.recentGames length: " .. tostring(____Array_isArray_result_28) ) end local profileData = data.profile or data if #responseItems > 0 then for ____, item in ipairs(responseItems) do if item and type(item) == "table" and item.profile and type(item.profile) == "table" then profileData = item.profile break end end end local nameFromDB = profileData.name or playerName local ____tostring_32 = tostring local ____opt_result_31 if profileData ~= nil then ____opt_result_31 = profileData.name end local ____tostring_32_result_37 = ____tostring_32(____opt_result_31) local ____tostring_36 = tostring local ____opt_result_35 if profileData ~= nil then ____opt_result_35 = profileData.level end local ____temp_47 = ((("[MiniProfileServer] profileData name=" .. ____tostring_32_result_37) .. " level=") .. ____tostring_36(____opt_result_35)) .. " " local ____tostring_41 = tostring local ____opt_result_40 if profileData ~= nil then ____opt_result_40 = profileData.free_currency end local ____tostring_41_result_46 = ____tostring_41(____opt_result_40) local ____tostring_45 = tostring local ____opt_result_44 if profileData ~= nil then ____opt_result_44 = profileData.donate_currency end ____print( nil, ____temp_47 .. (("free_currency=" .. ____tostring_41_result_46) .. " donate_currency=") .. ____tostring_45(____opt_result_44) ) local grantedLevelRewardsNow = {} if shouldGrantLevelRewards then do local function ____catch(grantError) ____print( nil, "[MiniProfileServer] Ошибка выдачи наград профиля: " .. tostring(grantError) ) grantedLevelRewardsNow = {} end local ____try, ____hasReturned = pcall(function() local profileLevel = tonumber(profileData.level) or 1 grantedLevelRewardsNow = self:grantPendingProfileLevelRewards(playerId, profileLevel) end) if not ____try then ____catch(____hasReturned) end end end local grantedLevelRewardsObject = {} __TS__ArrayForEach( grantedLevelRewardsNow, function(____, reward, index) grantedLevelRewardsObject[tostring(index)] = reward end ) local recentGames = data.recentGames or data.recent_games or data.games or data.history or data.match_history or data.stats and (data.stats.recentGames or data.stats.recent_games or data.stats.games or data.stats.history) or data.profile and (data.profile.recentGames or data.profile.recent_games or data.profile.games or data.profile.history or data.profile.match_history) local function collectObjectValues(____, obj) local out = {} if not obj or type(obj) ~= "table" then return out end for key in pairs(obj) do out[#out + 1] = obj[key] end return out end local isRecentGamesEmptyObject = recentGames and type(recentGames) == "table" and not __TS__ArrayIsArray(recentGames) and #collectObjectKeys(nil, recentGames) == 0 if (not recentGames or isRecentGamesEmptyObject) and #responseItems > 0 then for ____, item in ipairs(responseItems) do do if not item or type(item) ~= "table" then goto __continue93 end local candidate = item.recentGames or item.recent_games or item.games or item.history or item.match_history or item.stats and (item.stats.recentGames or item.stats.recent_games or item.stats.games or item.stats.history) or item.profile and (item.profile.recentGames or item.profile.recent_games or item.profile.games or item.profile.history or item.profile.match_history) if not candidate then goto __continue93 end if __TS__ArrayIsArray(candidate) then if #collectObjectValues(nil, candidate) > 0 then recentGames = candidate break end elseif type(candidate) == "table" and #collectObjectKeys(nil, candidate) > 0 then recentGames = candidate break end end ::__continue93:: end end local extractGamesArray extractGamesArray = function(____, source) if not source then return {} end if type(source) == "string" then do local function ____catch(e) return true, {} end local ____try, ____hasReturned, ____returnValue = pcall(function() local decoded = {json.decode(source)} return true, extractGamesArray(nil, decoded) end) if not ____try then ____hasReturned, ____returnValue = ____catch(____hasReturned) end if ____hasReturned then return ____returnValue end end end if __TS__ArrayIsArray(source) then local values = collectObjectValues(nil, source) if #values > 0 then return __TS__ArrayFilter( values, function(____, item) return item and type(item) == "table" end ) end return {} end if type(source) == "table" then local directValues = __TS__ArrayFilter( collectObjectValues(nil, source), function(____, item) return item and type(item) == "table" end ) if #directValues > 0 then return directValues end local nested = source.items or source.data or source.rows or source.matches or source.history or source.recentGames or source.recent_games if nested then return extractGamesArray(nil, nested) end end return {} end local gamesExtracted = extractGamesArray(nil, recentGames) do local function ____catch(sortError) ____print( nil, "[MiniProfileServer] Не удалось отсортировать recentGames: " .. tostring(sortError) ) end local ____try, ____hasReturned = pcall(function() if type(Date) == "function" then __TS__ArraySort( gamesExtracted, function(____, a, b) local dateA = __TS__New(Date, a.game_start or a.gameStart or a.created_at or 0):getTime() local dateB = __TS__New(Date, b.game_start or b.gameStart or b.created_at or 0):getTime() return dateB - dateA end ) end end) if not ____try then ____catch(____hasReturned) end end recentGames = gamesExtracted ____print( nil, "[MiniProfileServer] Extracted games: " .. tostring(#gamesExtracted) ) ____print( nil, (("[MiniProfileServer] Profile loaded for " .. tostring(nameFromDB)) .. ", recentGames count: ") .. tostring(__TS__ArrayIsArray(recentGames) and #recentGames or "not an array") ) ____print( nil, (("[MiniProfileServer] recentGames type: " .. __TS__TypeOf(recentGames)) .. ", isArray: ") .. tostring(__TS__ArrayIsArray(recentGames)) ) if not recentGames or type(recentGames) == "table" and #collectObjectKeys(nil, recentGames) == 0 then ____print( nil, (("[MiniProfileServer] recentGames пустой. Data keys=" .. table.concat( collectObjectKeys(nil, data), ", " )) .. ", profile keys=") .. (profileData and type(profileData) == "table" and table.concat( collectObjectKeys(nil, profileData), ", " ) or "N/A") ) end local gamesToSend = {} if __TS__ArrayIsArray(recentGames) then gamesToSend = self:normalizeArrayLike(recentGames) elseif recentGames and type(recentGames) == "table" then gamesToSend = __TS__ArrayFilter( collectObjectValues(nil, recentGames), function(____, item) return item and type(item) == "table" end ) end if #gamesToSend == 0 then ____print(nil, "[MiniProfileServer] recentGames пустой в /player. Пробуем fallback /player/:id/history") self:loadRecentGamesFallback( player, steamIdStr, profileData, data.stats or data, nameFromDB, steamId64 or steamId, grantedLevelRewardsObject ) return true end self:loadHeroAchievementsForProfile( steamIdStr, playerId, shouldGrantLevelRewards, function(____, heroAchievementsObject, grantedHeroRankRewardsObject) self:sendProfileToClient( player, profileData, data.stats or data, gamesToSend, steamId, nameFromDB, steamId64 or steamId, grantedLevelRewardsObject, heroAchievementsObject, grantedHeroRankRewardsObject ) end ) end end) if not ____try then ____hasReturned, ____returnValue = ____catch(____hasReturned) end if ____hasReturned then return true, ____returnValue end end elseif result.StatusCode == 404 then self:createPlayerProfile(playerId, steamId, playerName) else CustomGameEventManager:Send_ServerToPlayer( player, "player_profile_data", { error = "Ошибка сервера: " .. tostring(result.StatusCode), steam_id = steamId, player_name = playerName } ) end end) if not ____try then ____hasReturned, ____returnValue = ____catch(____hasReturned) end if ____hasReturned then return ____returnValue end end end) end function MiniProfileServer.prototype.normalizeArrayLike(self, input) if not input then return {} end local function hasGameFields(____, obj) if not obj or type(obj) ~= "table" then return false end return not not (obj.hero or obj.hero_name or obj.heroName or obj.result or obj.match_result or obj.difficulty or obj.difficulty_name or obj.mode) end local unwrapKnownContainers unwrapKnownContainers = function(____, value) if not value or type(value) ~= "table" then return value end local containerKeys = { "history", "recentGames", "games", "items", "rows", "data", "result", "payload" } for ____, key in ipairs(containerKeys) do local nested = value[key] if nested and type(nested) == "table" then if key == "data" and type(nested) == "table" then local deep = unwrapKnownContainers(nil, nested) if deep ~= nested or __TS__ArrayIsArray(deep) then return deep end end if __TS__ArrayIsArray(nested) then return nested end if hasGameFields(nil, nested) then return {nested} end local nestedValues = __TS__ArrayFilter( __TS__ObjectValues(nested), function(____, v) return v and type(v) == "table" end ) if #nestedValues > 0 then return nested end end end return value end local unwrapped = unwrapKnownContainers(nil, input) if unwrapped ~= input then return self:normalizeArrayLike(unwrapped) end if __TS__ArrayIsArray(input) then local arr = input local len = #arr if type(len) == "number" and len > 0 then if __TS__ArraySome( arr, function(____, item) return hasGameFields(nil, item) end ) then return __TS__ArrayFilter( arr, function(____, item) return item and type(item) == "table" end ) end local expanded = {} __TS__ArrayForEach( arr, function(____, item) local normalized = self:normalizeArrayLike(item) if #normalized > 0 then __TS__ArrayPushArray(expanded, normalized) end end ) if #expanded > 0 then return expanded end return __TS__ArrayFilter( arr, function(____, item) return item and type(item) == "table" end ) end end local numericEntries = {} local otherValues = {} if type(input) == "table" then for key in pairs(input) do if not input.hasOwnProperty or rawget(input, key) ~= nil then local value = input[key] local numericKey = tonumber(tostring(key)) if numericKey ~= nil and numericKey ~= nil then numericEntries[#numericEntries + 1] = {idx = numericKey, value = value} else otherValues[#otherValues + 1] = value end end end end if #numericEntries > 0 then __TS__ArraySort( numericEntries, function(____, a, b) return a.idx - b.idx end ) return __TS__ArrayFilter( __TS__ArrayMap( numericEntries, function(____, entry) return entry.value end ), function(____, item) return item and type(item) == "table" end ) end if hasGameFields(nil, input) then return {input} end local flattened = {} __TS__ArrayForEach( __TS__ArrayFilter( otherValues, function(____, item) return item and type(item) == "table" end ), function(____, item) local normalized = self:normalizeArrayLike(item) if #normalized > 0 then __TS__ArrayPushArray(flattened, normalized) else flattened[#flattened + 1] = item end end ) return flattened end function MiniProfileServer.prototype.loadRecentGamesFallback(self, player, steamId, profileData, statsData, playerName, steamId64, grantedLevelRewardsObject) if grantedLevelRewardsObject == nil then grantedLevelRewardsObject = {} end local fallbackRequest = CreateHTTPRequestScriptVM("GET", ((self.serverUrl .. "/player/") .. steamId) .. "/history?limit=10&offset=0") setApiHeaders(nil, fallbackRequest) fallbackRequest:Send(function(result) if result.StatusCode >= 200 and result.StatusCode < 300 then do local function ____catch(e) ____print(nil, "[MiniProfileServer] Fallback history parse error") end local ____try, ____hasReturned, ____returnValue = pcall(function() local decoded = {json.decode(result.Body)} local games = self:normalizeArrayLike(decoded) ____print( nil, ("[MiniProfileServer] Fallback history loaded: " .. tostring(#games)) .. " games" ) self:loadHeroAchievementsForProfile( steamId, player:GetPlayerID(), false, function(____, heroAchievementsObject, grantedHeroRankRewardsObject) self:sendProfileToClient( player, profileData, statsData, games, steamId, playerName, steamId64, grantedLevelRewardsObject, heroAchievementsObject, grantedHeroRankRewardsObject ) end ) return true end) if not ____try then ____hasReturned, ____returnValue = ____catch(____hasReturned) end if ____hasReturned then return ____returnValue end end else ____print( nil, "[MiniProfileServer] Fallback history HTTP " .. tostring(result.StatusCode) ) end self:loadHeroAchievementsForProfile( steamId, player:GetPlayerID(), false, function(____, heroAchievementsObject, grantedHeroRankRewardsObject) self:sendProfileToClient( player, profileData, statsData, {}, steamId, playerName, steamId64, grantedLevelRewardsObject, heroAchievementsObject, grantedHeroRankRewardsObject ) end ) end) end function MiniProfileServer.prototype.sendProfileToClient(self, player, profileData, statsData, gamesToSend, steamId, playerName, steamId64, grantedLevelRewardsObject, heroAchievementsObject, grantedHeroRankRewardsObject) if grantedLevelRewardsObject == nil then grantedLevelRewardsObject = {} end if heroAchievementsObject == nil then heroAchievementsObject = {} end if grantedHeroRankRewardsObject == nil then grantedHeroRankRewardsObject = {} end ____print( nil, (("[MiniProfileServer] Профиль отправлен: games=" .. tostring(#gamesToSend)) .. ", steam64=") .. steamId64 ) local gamesObject = {} __TS__ArrayForEach( gamesToSend, function(____, game, index) gamesObject[tostring(index)] = game end ) CustomGameEventManager:Send_ServerToPlayer(player, "player_profile_data", { profile = profileData, stats = statsData, recentGames = gamesObject, steam_id = steamId, player_name = playerName, player_steamid = steamId64, profile_level_rewards_granted = grantedLevelRewardsObject, hero_achievements = heroAchievementsObject, hero_rank_rewards_granted = grantedHeroRankRewardsObject }) end function MiniProfileServer.prototype.loadHeroAchievementsForProfile(self, steamId, playerId, shouldGrantRankRewards, callback) local allHeroes = self:getAllAvailableHeroes(playerId) local request = CreateHTTPRequestScriptVM("GET", ((self.serverUrl .. "/player/") .. steamId) .. "/history?limit=5000&offset=0") setApiHeaders(nil, request) request:Send(function(result) ____print( nil, (("[MiniProfileServer] /history status=" .. tostring(result.StatusCode)) .. " steam_id=") .. steamId ) if result.StatusCode < 200 or result.StatusCode >= 300 then callback( nil, self:buildHeroAchievementsObject(allHeroes, {}), {} ) return end do local function ____catch(e) callback( nil, self:buildHeroAchievementsObject(allHeroes, {}), {} ) end local ____try, ____hasReturned = pcall(function() local decoded = self:decodeJsonSafe(result.Body) local games = self:normalizeArrayLike(decoded) ____print( nil, "[MiniProfileServer] history entries=" .. tostring(#games) ) do local i = 0 while i < math.min(5, #games) do local g = games[i + 1] local ____i_60 = i local ____tostring_59 = tostring local ____opt_result_50 if g ~= nil then ____opt_result_50 = g.hero end local ____opt_result_50_54 = ____opt_result_50 if not ____opt_result_50_54 then local ____opt_result_53 if g ~= nil then ____opt_result_53 = g.hero_name end ____opt_result_50_54 = ____opt_result_53 end local ____opt_result_50_54_58 = ____opt_result_50_54 if not ____opt_result_50_54_58 then local ____opt_result_57 if g ~= nil then ____opt_result_57 = g.heroName end ____opt_result_50_54_58 = ____opt_result_57 end local ____temp_69 = (("[MiniProfileServer] raw[" .. tostring(____i_60)) .. "] hero=") .. ____tostring_59(____opt_result_50_54_58 or "") local ____tostring_68 = tostring local ____opt_result_63 if g ~= nil then ____opt_result_63 = g.result end local ____opt_result_63_67 = ____opt_result_63 if not ____opt_result_63_67 then local ____opt_result_66 if g ~= nil then ____opt_result_66 = g.match_result end ____opt_result_63_67 = ____opt_result_66 end local ____temp_74 = ____temp_69 .. " result=" .. ____tostring_68(____opt_result_63_67 or "") local ____tostring_73 = tostring local ____opt_result_72 if g ~= nil then ____opt_result_72 = g.is_win end local ____temp_91 = ____temp_74 .. " is_win=" .. ____tostring_73(____opt_result_72) local ____tostring_90 = tostring local ____opt_result_77 if g ~= nil then ____opt_result_77 = g.difficulty end local ____opt_result_77_81 = ____opt_result_77 if not ____opt_result_77_81 then local ____opt_result_80 if g ~= nil then ____opt_result_80 = g.difficulty_name end ____opt_result_77_81 = ____opt_result_80 end local ____opt_result_77_81_85 = ____opt_result_77_81 if not ____opt_result_77_81_85 then local ____opt_result_84 if g ~= nil then ____opt_result_84 = g.mode end ____opt_result_77_81_85 = ____opt_result_84 end local ____opt_result_77_81_85_89 = ____opt_result_77_81_85 if not ____opt_result_77_81_85_89 then local ____opt_result_88 if g ~= nil then ____opt_result_88 = g.game_mode end ____opt_result_77_81_85_89 = ____opt_result_88 end ____print( nil, ____temp_91 .. " difficulty=" .. ____tostring_90(____opt_result_77_81_85_89 or "") ) i = i + 1 end end local aggregated = self:aggregateHeroAchievements(games) local heroAchievementsObject = self:buildHeroAchievementsObject(allHeroes, aggregated) local grantedHeroRankRewardsObject = {} if shouldGrantRankRewards then grantedHeroRankRewardsObject = self:grantPendingHeroRankRewards(playerId, heroAchievementsObject) end callback(nil, heroAchievementsObject, grantedHeroRankRewardsObject) end) if not ____try then ____catch(____hasReturned) end end end) end function MiniProfileServer.prototype.getAllAvailableHeroes(self, playerId) local heroes = {} local storeManager = StoreManager:getInstance() local enabledHeroes = self:getEnabledHeroesFromHeroList() for heroName in pairs(enabledHeroes) do do local heroInfo = HERO_LIST_TABLE[heroName] local isDonateHero = (heroInfo and heroInfo.isDonate) == true if isDonateHero and not storeManager:hasUnlockedHero( playerId, tostring(heroName), heroInfo.storeItemId ) then goto __continue185 end heroes[#heroes + 1] = tostring(heroName) end ::__continue185:: end __TS__ArraySort( heroes, function(____, a, b) return a < b and -1 or (a > b and 1 or 0) end ) return heroes end function MiniProfileServer.prototype.getEnabledHeroesFromHeroList(self) local enabledHeroes = {} local rawKv = LoadKeyValues("scripts/npc/herolist.txt") local ____temp_96 = rawKv and rawKv.CustomHeroList if ____temp_96 == nil then ____temp_96 = rawKv end local heroList = ____temp_96 if heroList then for heroName in pairs(heroList) do local count = tonumber(tostring(heroList[heroName])) or 0 if count > 0 or count == -1 then enabledHeroes[tostring(heroName)] = true end end end if #__TS__ObjectKeys(enabledHeroes) == 0 then for heroName in pairs(HERO_LIST_TABLE) do enabledHeroes[tostring(heroName)] = true end end return enabledHeroes end function MiniProfileServer.prototype.aggregateHeroAchievements(self, games) local stats = {} local enabledHeroes = self:getEnabledHeroesFromHeroList() local function normalizeDifficultyKey(____, rawDifficulty) local key = string.lower(tostring(rawDifficulty or "normal")) if key == "easy" or key == "difficulty_easy" or key == "лёгкая" or key == "легкая" then return "easy" end if key == "normal" or key == "difficulty_normal" or key == "обычная" or key == "normal_mode" then return "normal" end if key == "hard" or key == "difficulty_hard" or key == "сложная" then return "hard" end if key == "impossible" or key == "difficulty_impossible" or key == "невозможная" or key == "imposible" then return "impossible" end if key == "death_sentence" or key == "difficulty_death_sentence" or key == "смертельный приговор" or key == "deathsentence" then return "death_sentence" end return "normal" end local function getRankByDifficulty(____, difficulty) local key = normalizeDifficultyKey(nil, difficulty) if key == "easy" then return 1 end if key == "normal" then return 3 end if key == "hard" then return 6 end if key == "impossible" then return 8 end if key == "death_sentence" then return 10 end return 0 end local function isWinResult(____, game) local ____opt_result_99 if game ~= nil then ____opt_result_99 = game.is_win end local directWin = ____opt_result_99 if directWin == true or directWin == 1 or tostring(directWin) == "1" then return true end local ____tonumber_103 = tonumber local ____opt_result_102 if game ~= nil then ____opt_result_102 = game.result end local numericResult = ____tonumber_103(____opt_result_102) if numericResult == 1 then return true end local ____tostring_111 = tostring local ____opt_result_106 if game ~= nil then ____opt_result_106 = game.result end local ____opt_result_106_110 = ____opt_result_106 if not ____opt_result_106_110 then local ____opt_result_109 if game ~= nil then ____opt_result_109 = game.match_result end ____opt_result_106_110 = ____opt_result_109 end local key = string.lower(____tostring_111(____opt_result_106_110 or "")) return key == "win" or key == "victory" or key == "won" or key == "radiant_win" or key == "dire_win" or key == "success" end local function normalizeHeroName(____, rawHero) local base = tostring(rawHero or "") if base == "" then return "" end if string.sub(base, 1, 14) == "npc_dota_hero_" then return base end local normalized = "npc_dota_hero_" .. base if enabledHeroes[normalized] ~= nil then return normalized end return base end __TS__ArrayForEach( games, function(____, game, index) if not game or type(game) ~= "table" then return end local hero = normalizeHeroName(nil, game.hero or game.hero_name or game.heroName) if hero == "" or string.sub(hero, 1, 14) ~= "npc_dota_hero_" then return end if not (enabledHeroes[hero] ~= nil) then return end if not (stats[hero] ~= nil) then stats[hero] = {games = 0, wins = 0, impossibleWins = 0, bestRank = 0} end local heroStats = stats[hero] heroStats.games = heroStats.games + 1 local difficulty = normalizeDifficultyKey(nil, game.difficulty or game.difficulty_name or game.mode or game.game_mode) local win = isWinResult(nil, game) if index < 8 then local ____temp_125 = (((((("[MiniProfileServer] normalized[" .. tostring(index)) .. "] hero=") .. hero) .. " difficulty=") .. difficulty) .. " win=") .. tostring(win) local ____tostring_119 = tostring local ____opt_result_114 if game ~= nil then ____opt_result_114 = game.result end local ____opt_result_114_118 = ____opt_result_114 if not ____opt_result_114_118 then local ____opt_result_117 if game ~= nil then ____opt_result_117 = game.match_result end ____opt_result_114_118 = ____opt_result_117 end local ____tostring_119_result_124 = ____tostring_119(____opt_result_114_118 or "") local ____tostring_123 = tostring local ____opt_result_122 if game ~= nil then ____opt_result_122 = game.is_win end ____print( nil, ____temp_125 .. ((" raw_result=" .. ____tostring_119_result_124) .. " raw_is_win=") .. ____tostring_123(____opt_result_122) ) end if win then heroStats.wins = heroStats.wins + 1 heroStats.bestRank = math.max( heroStats.bestRank, getRankByDifficulty(nil, difficulty) ) if difficulty == "impossible" then heroStats.impossibleWins = heroStats.impossibleWins + 1 end end end ) local keys = __TS__ObjectKeys(stats) ____print( nil, "[MiniProfileServer] aggregated heroes=" .. tostring(#keys) ) __TS__ArrayForEach( keys, function(____, heroName, idx) if idx >= 8 then return end local s = stats[heroName] ____print( nil, ((((("[MiniProfileServer] stats[" .. heroName) .. "] games=") .. tostring(s.games)) .. " wins=") .. tostring(s.wins)) .. ((" best_rank=" .. tostring(s.bestRank)) .. " impossible_wins=") .. tostring(s.impossibleWins) ) end ) return stats end function MiniProfileServer.prototype.buildHeroAchievementsObject(self, allHeroes, aggregated) local out = {} __TS__ArrayForEach( allHeroes, function(____, heroName, index) local heroStats = aggregated[heroName] or ({games = 0, wins = 0, impossibleWins = 0, bestRank = 0}) local games = heroStats.games local wins = heroStats.wins local impossibleWins = heroStats.impossibleWins local winRate = games > 0 and math.floor(wins / games * 1000) / 10 or 0 out[tostring(index)] = { hero = heroName, games = games, wins = wins, win_rate = winRate, best_rank = heroStats.bestRank, impossible_wins = impossibleWins } end ) return out end function MiniProfileServer.prototype.getHeroRankRewardAmount(self, tier) if tier == "rank1" then return 100 end if tier == "rank3" then return 200 end if tier == "rank6" then return 400 end if tier == "rank8a" then return 800 end if tier == "rank8b" then return 1200 end if tier == "rank8c" then return 2000 end return 0 end function MiniProfileServer.prototype.getHeroAchievementTier(self, bestRank, impossibleWins) if bestRank >= 8 then if impossibleWins >= 100 then return "rank8c" end if impossibleWins >= 10 then return "rank8b" end return "rank8a" end if bestRank >= 6 then return "rank6" end if bestRank >= 3 then return "rank3" end if bestRank >= 1 then return "rank1" end return "rank0" end function MiniProfileServer.prototype.grantPendingHeroRankRewards(self, playerId, heroAchievementsObject) local storeManager = StoreManager:getInstance() if not self.grantedHeroRankRewardsInSession:has(playerId) then self.grantedHeroRankRewardsInSession:set( playerId, __TS__New(Set) ) end local sessionGranted = self.grantedHeroRankRewardsInSession:get(playerId) local grantedNow = {} local rewardsToCheck = { "rank1", "rank3", "rank6", "rank8a", "rank8b", "rank8c" } local achievementsArray = self:normalizeArrayLike(heroAchievementsObject) local grantedIndex = 0 __TS__ArrayForEach( achievementsArray, function(____, entry) local hero = tostring(entry.hero or "") if hero == "" then return end local bestRank = tonumber(entry.best_rank) or 0 local impossibleWins = tonumber(entry.impossible_wins) or 0 local currentTier = self:getHeroAchievementTier(bestRank, impossibleWins) local currentTierIndex = __TS__ArrayIndexOf(rewardsToCheck, currentTier) if currentTierIndex < 0 then return end do local i = 0 while i <= currentTierIndex do do local tier = rewardsToCheck[i + 1] local amount = self:getHeroRankRewardAmount(tier) if amount <= 0 then goto __continue248 end local rewardItemId = (("hero_rank_reward_" .. hero) .. "_") .. tier if sessionGranted:has(rewardItemId) then ____print(nil, "[MiniProfileServer] reward skip (session) " .. rewardItemId) goto __continue248 end if storeManager:hasPurchasedItem(playerId, rewardItemId) then ____print(nil, "[MiniProfileServer] reward skip (already purchased) " .. rewardItemId) sessionGranted:add(rewardItemId) goto __continue248 end local added = storeManager:addFreeCurrency(playerId, amount) if not added then ____print( nil, (("[MiniProfileServer] reward addFreeCurrency failed " .. rewardItemId) .. " amount=") .. tostring(amount) ) goto __continue248 end storeManager:savePurchaseToServer(playerId, rewardItemId, "hero_rank_reward") ____print( nil, (("[MiniProfileServer] reward granted " .. rewardItemId) .. " amount=") .. tostring(amount) ) sessionGranted:add(rewardItemId) grantedNow[tostring(grantedIndex)] = {hero = hero, tier = tier, freeCurrency = amount} grantedIndex = grantedIndex + 1 end ::__continue248:: i = i + 1 end end end ) return grantedNow end function MiniProfileServer.prototype.loadMatchPlayersFromServer(self, player, matchId, rowId, steamId) if rowId == nil then rowId = 0 end if steamId == nil then steamId = "" end local idsToTry = {} local function addId(____, value) if value > 0 and __TS__ArrayIndexOf(idsToTry, value) == -1 then idsToTry[#idsToTry + 1] = value end end addId(nil, matchId) addId(nil, rowId) local endpoints = {} __TS__ArrayForEach( idsToTry, function(____, id) endpoints[#endpoints + 1] = ((self.serverUrl .. "/game/") .. tostring(id)) .. "/players" end ) if steamId ~= "" then __TS__ArrayForEach( idsToTry, function(____, id) endpoints[#endpoints + 1] = ((((self.serverUrl .. "/player/") .. steamId) .. "/history?match_id=") .. tostring(id)) .. "&limit=10&offset=0" endpoints[#endpoints + 1] = ((((self.serverUrl .. "/player/") .. steamId) .. "/history?game_id=") .. tostring(id)) .. "&limit=10&offset=0" endpoints[#endpoints + 1] = ((((self.serverUrl .. "/player/") .. steamId) .. "/history?id=") .. tostring(id)) .. "&limit=10&offset=0" end ) end local function collectObjectValues(____, obj) local out = {} if not obj or type(obj) ~= "table" then return out end for key in pairs(obj) do out[#out + 1] = obj[key] end return out end local extractPlayers extractPlayers = function(____, source) if not source then return {} end if __TS__ArrayIsArray(source) then local normalizedArray = __TS__ArrayFilter( self:normalizeArrayLike(source), function(____, item) return item and type(item) == "table" end ) local playersFromParty = {} __TS__ArrayForEach( normalizedArray, function(____, item) local nestedParty = item.party_players or item.partyPlayers or item.players or item.participants or item.match_players if nestedParty then local nested = extractPlayers(nil, nestedParty) __TS__ArrayForEach( nested, function(____, p) local ____temp_126 = #playersFromParty + 1 playersFromParty[____temp_126] = p return ____temp_126 end ) end end ) if #playersFromParty > 0 then return playersFromParty end return normalizedArray end if type(source) == "table" then local directPlayers = source.players or source.participants or source.match_players or source.party_players or source.partyPlayers or source.items or source.rows or source.data if directPlayers then return extractPlayers(nil, directPlayers) end return __TS__ArrayFilter( collectObjectValues(nil, source), function(____, item) return item and type(item) == "table" end ) end return {} end local tryRequest tryRequest = function(____, index) if index >= #endpoints then CustomGameEventManager:Send_ServerToPlayer(player, "match_players_data", {error = "Не удалось загрузить участников матча", match_id = matchId, players = {}}) return end local request = CreateHTTPRequestScriptVM("GET", endpoints[index + 1]) setApiHeaders(nil, request) request:Send(function(result) if result.StatusCode < 200 or result.StatusCode >= 300 then ____print( nil, (("[MiniProfileServer] match players endpoint failed: " .. endpoints[index + 1]) .. " status=") .. tostring(result.StatusCode) ) tryRequest(nil, index + 1) return end local decoded = self:decodeJsonSafe(result.Body) if decoded == nil then ____print(nil, "[MiniProfileServer] match players decode failed: " .. endpoints[index + 1]) tryRequest(nil, index + 1) return end local players = extractPlayers(nil, decoded) if #players == 0 and index < #endpoints - 1 then ____print(nil, ("[MiniProfileServer] Endpoint " .. endpoints[index + 1]) .. " returned 0 players, trying next") tryRequest(nil, index + 1) return end local playersObject = {} __TS__ArrayForEach( players, function(____, item, idx) playersObject[tostring(idx)] = item end ) CustomGameEventManager:Send_ServerToPlayer(player, "match_players_data", {match_id = matchId, players = playersObject}) end) end tryRequest(nil, 0) end function MiniProfileServer.prototype.addBigInts(self, a, b) local maxLen = math.max( string.len(a), string.len(b) ) a = string.rep( "0", maxLen - string.len(a) ) .. a b = string.rep( "0", maxLen - string.len(b) ) .. b local result = "" local carry = 0 do local i = maxLen while i >= 1 do local digitA = tonumber(string.sub(a, i, i)) or 0 local digitB = tonumber(string.sub(b, i, i)) or 0 local sum = digitA + digitB + carry result = tostring(sum % 10) .. result carry = math.floor(sum / 10) i = i - 1 end end if carry > 0 then result = tostring(carry) .. result end return result end function MiniProfileServer.prototype.subtractBigInts(self, a, b) local maxLen = math.max( string.len(a), string.len(b) ) a = string.rep( "0", maxLen - string.len(a) ) .. a b = string.rep( "0", maxLen - string.len(b) ) .. b local result = "" local borrow = 0 do local i = maxLen while i >= 1 do local digitA = tonumber(string.sub(a, i, i)) or 0 local digitB = tonumber(string.sub(b, i, i)) or 0 local diff = digitA - digitB - borrow if diff < 0 then diff = diff + 10 borrow = 1 else borrow = 0 end result = tostring(diff) .. result i = i - 1 end end result = (string.gsub(result, "^0+", "")) if result == "" then result = "0" end return result end function MiniProfileServer.prototype.decodeJsonSafe(self, rawBody) do local function ____catch(e) local body = tostring(rawBody) local firstObj = {string.find(body, "{", 1, true)} local firstArr = {string.find(body, "[", 1, true)} local first = nil if firstObj ~= nil and firstArr ~= nil then first = math.min(firstObj[1], firstArr[1]) elseif firstObj ~= nil then first = firstObj[1] elseif firstArr ~= nil then first = firstArr[1] end if first == nil then return true, nil end local lastObj = {string.find(body, "}", -1, true)} local lastArr = {string.find(body, "]", -1, true)} local last = nil if lastObj ~= nil and lastArr ~= nil then last = math.max(lastObj[1], lastArr[1]) elseif lastObj ~= nil then last = lastObj[1] elseif lastArr ~= nil then last = lastArr[1] end if last == nil or last < first then return true, nil end local sliced = string.sub(body, first, last) do local function ____catch(e2) return true, nil end local ____try, ____hasReturned, ____returnValue = pcall(function() return true, {json.decode(sliced)} end) if not ____try then ____hasReturned, ____returnValue = ____catch(____hasReturned) end if ____hasReturned then return true, ____returnValue end end end local ____try, ____hasReturned, ____returnValue = pcall(function() return true, {json.decode(rawBody)} end) if not ____try then ____hasReturned, ____returnValue = ____catch(____hasReturned) end if ____hasReturned then return ____returnValue end end end function MiniProfileServer.prototype.grantPendingProfileLevelRewards(self, playerId, profileLevel) if profileLevel <= 0 then return {} end local storeManager = StoreManager:getInstance() if not self.grantedProfileRewardsInSession:has(playerId) then self.grantedProfileRewardsInSession:set( playerId, __TS__New(Set) ) end local sessionGrantedSet = self.grantedProfileRewardsInSession:get(playerId) local grantedNow = {} __TS__ArrayForEach( self.profileLevelRewards, function(____, reward) if reward.level > profileLevel then return end local rewardItemId = "profile_level_reward_" .. tostring(reward.level) if sessionGrantedSet:has(rewardItemId) then return end if storeManager:hasPurchasedItem(playerId, rewardItemId) then sessionGrantedSet:add(rewardItemId) return end local added = storeManager:addFreeCurrency(playerId, reward.freeCurrency) if not added then return end storeManager:savePurchaseToServer(playerId, rewardItemId, "profile_level_reward") sessionGrantedSet:add(rewardItemId) grantedNow[#grantedNow + 1] = {level = reward.level, freeCurrency = reward.freeCurrency} ____print( nil, (((("[MiniProfileServer] Выдана награда за уровень " .. tostring(reward.level)) .. ": +") .. tostring(reward.freeCurrency)) .. " осколков игроку ") .. tostring(playerId) ) end ) return grantedNow end if IsServer() then (function() Timers:CreateTimer( 1, function() do local function ____catch(____error) return true, nil end local ____try, ____hasReturned, ____returnValue = pcall(function() local miniProfileServer = ____exports.MiniProfileServer:getInstance() return true, nil end) if not ____try then ____hasReturned, ____returnValue = ____catch(____hasReturned) end if ____hasReturned then return ____returnValue end end end ) end)(nil) end return ____exports