Files
Dota-Zombie-Invasion/scripts/vscripts/battle_pass_server.lua
T
2026-05-29 15:11:31 +07:00

2192 lines
96 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local Map = ____lualib.Map
local __TS__New = ____lualib.__TS__New
local Set = ____lualib.Set
local __TS__Iterator = ____lualib.__TS__Iterator
local __TS__ArrayForEach = ____lualib.__TS__ArrayForEach
local __TS__ArrayFind = ____lualib.__TS__ArrayFind
local __TS__Number = ____lualib.__TS__Number
local __TS__NumberIsFinite = ____lualib.__TS__NumberIsFinite
local __TS__ArrayIsArray = ____lualib.__TS__ArrayIsArray
local __TS__ObjectKeys = ____lualib.__TS__ObjectKeys
local __TS__ArrayMap = ____lualib.__TS__ArrayMap
local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter
local ____exports = {}
local ____match_end_combat_stats = require("match_end_combat_stats")
local MatchEndCombatStats = ____match_end_combat_stats.MatchEndCombatStats
local ____server_config = require("server_config")
local SERVER_CONFIG = ____server_config.SERVER_CONFIG
local ____api_helper = require("api_helper")
local encodeApiBody = ____api_helper.encodeApiBody
local setApiHeaders = ____api_helper.setApiHeaders
local setApiHeadersLong = ____api_helper.setApiHeadersLong
local ____chat_wheel_grant = require("chat_wheel_grant")
local grantChatWheelSoundFromBattlePass = ____chat_wheel_grant.grantChatWheelSoundFromBattlePass
local ____store_manager = require("store_manager")
local StoreManager = ____store_manager.StoreManager
local ____player_info = require("player_info")
local PlayerInfo = ____player_info.PlayerInfo
local ____battle_pass_duplicate_compensation = require("battle_pass_duplicate_compensation")
local getBpDuplicateCompensationByStoreItemId = ____battle_pass_duplicate_compensation.getBpDuplicateCompensationByStoreItemId
local ____WaveManager = require("WaveManager")
local WaveManager = ____WaveManager.WaveManager
local ____QuestSystem = require("quests.QuestSystem")
local QuestEvents = ____QuestSystem.QuestEvents
local ENABLE_VERBOSE_BATTLE_PASS_SERVER_LOGS = true
local function rawPrintFn(____, ...)
_G:print(...)
end
local ____print = ENABLE_VERBOSE_BATTLE_PASS_SERVER_LOGS and rawPrintFn or (function(____, ...) return nil end)
--- Число из ответа API / тела события (VScript).
local function parseApiNumber(self, v)
if v == nil or v == nil then
return 0
end
local n = tonumber(tostring(v))
return n ~= nil and n ~= nil and n or 0
end
--- Булевы поля из API (1 / "true" и т.д.)
local function apiJsonBool(self, v)
return v == true or v == 1 or v == "1" or v == "true"
end
____exports.BattlePassServer = __TS__Class()
local BattlePassServer = ____exports.BattlePassServer
BattlePassServer.name = "BattlePassServer"
BattlePassServer.____file_path = "scripts/vscripts/battle_pass_server.lua"
function BattlePassServer.prototype.____constructor(self)
self.serverUrl = SERVER_CONFIG.API_URL
self.playerQuestState = __TS__New(Map)
self.bpServerSnapshotByPlayer = __TS__New(Map)
self:setupEventListeners()
self:setupQuestTracking()
self:setupPlayerConnectionHandlers()
____print(nil, "[BattlePassServer] Инициализирован")
end
function BattlePassServer.getInstance(self)
if not ____exports.BattlePassServer.instance then
____exports.BattlePassServer.instance = __TS__New(____exports.BattlePassServer)
end
return ____exports.BattlePassServer.instance
end
function BattlePassServer.prototype.rememberBattlePassSnapshot(self, playerId, level, experience, hasPremium)
local prev = self.bpServerSnapshotByPlayer:get(playerId)
local ____temp_3
if hasPremium ~= nil then
____temp_3 = hasPremium
else
local ____temp_2 = prev and prev.has_premium
if ____temp_2 == nil then
____temp_2 = false
end
____temp_3 = ____temp_2
end
local hp = ____temp_3
self.bpServerSnapshotByPlayer:set(playerId, {level = level, experience = experience, has_premium = hp})
end
function BattlePassServer.prototype.getBattlePassSnapshotForMatchEnd(self, playerId)
local s = self.bpServerSnapshotByPlayer:get(playerId)
if s then
return {level = s.level, experience = s.experience, has_premium = s.has_premium}
end
return {level = 1, experience = 0, has_premium = false}
end
function BattlePassServer.prototype.getNpcQuestsCompletedForPlayer(self, playerId)
local state = self.playerQuestState:get(playerId)
return state and state.npcQuestsCompleted or 0
end
function BattlePassServer.prototype.getTotalHealToAlliesForPlayer(self, playerId)
return MatchEndCombatStats:getInstance():getHealToAlliesSum(playerId)
end
function BattlePassServer.prototype.pickDecodedJsonRoot(self, decoded, rootKeys)
if not decoded or type(decoded) ~= "table" then
return decoded
end
for ____, key in ipairs(rootKeys) do
local v = decoded[key]
if v ~= nil and v ~= nil then
return decoded
end
end
for ____, idx in ipairs({1, 0}) do
local inner = decoded[idx]
if inner and type(inner) == "table" then
for ____, key in ipairs(rootKeys) do
local v = inner[key]
if v ~= nil and v ~= nil then
return inner
end
end
end
end
return decoded
end
function BattlePassServer.prototype.setupPlayerConnectionHandlers(self)
ListenToGameEvent(
"player_connect_full",
function(event)
local playerId = event.PlayerID
if playerId ~= nil and playerId >= 0 then
Timers:CreateTimer(
2,
function()
if PlayerResource:IsValidPlayer(playerId) and not PlayerResource:IsFakeClient(playerId) then
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
____print(
nil,
((("[BattlePassServer] Автоматическая загрузка квестов для игрока " .. tostring(playerId)) .. " (Steam ID: ") .. steamId) .. ")"
)
self:loadQuests(playerId, steamId)
____print(
nil,
"[BattlePassServer] Предзагрузка данных Battle Pass для игрока " .. tostring(playerId)
)
self:loadBattlePassData(playerId, steamId)
end
return nil
end
)
end
end,
nil
)
ListenToGameEvent(
"npc_spawned",
function(event)
local unitIndex = event.entindex
if unitIndex == nil or unitIndex == nil then
return
end
local unit = EntIndexToHScript(unitIndex)
if unit and unit:IsRealHero() then
local playerId = unit:GetPlayerOwnerID()
if playerId >= 0 and not PlayerResource:IsFakeClient(playerId) then
self:onHeroSelected(
playerId,
unit:GetUnitName()
)
Timers:CreateTimer(
1,
function()
local state = self.playerQuestState:get(playerId)
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
if not state or not state.questsLoaded then
____print(
nil,
((("[BattlePassServer] Автоматическая загрузка квестов при спавне героя для игрока " .. tostring(playerId)) .. " (Steam ID: ") .. steamId) .. ")"
)
self:loadQuests(playerId, steamId)
end
if not self.bpServerSnapshotByPlayer:has(playerId) then
____print(
nil,
"[BattlePassServer] Догрузка Battle Pass при спавне героя для игрока " .. tostring(playerId)
)
self:loadBattlePassData(playerId, steamId)
end
return nil
end
)
end
end
end,
nil
)
end
function BattlePassServer.prototype.setupQuestTracking(self)
ListenToGameEvent(
"entity_killed",
function(event)
local killedIndex = event.entindex_killed
if killedIndex == nil or killedIndex == nil then
return
end
local killedUnit = EntIndexToHScript(killedIndex)
if not killedUnit then
return
end
local killerIndex = event.entindex_attacker
local ____temp_6
if killerIndex == nil or killerIndex == nil then
____temp_6 = nil
else
____temp_6 = EntIndexToHScript(killerIndex)
end
local killerEnt = ____temp_6
if not killerEnt then
return
end
local hero
local killerHasIsRealHero = killerEnt.IsRealHero ~= nil
if killerHasIsRealHero and killerEnt:IsRealHero() then
hero = killerEnt
else
local ____opt_7 = killerEnt.GetOwner
local owner = ____opt_7 and ____opt_7(killerEnt)
local ____opt_result_11
if owner ~= nil then
____opt_result_11 = owner.IsRealHero
end
local ownerHasIsRealHero = ____opt_result_11 ~= nil
if owner and ownerHasIsRealHero and owner:IsRealHero() then
hero = owner
end
end
if not hero then
return
end
local playerId = hero:GetPlayerOwnerID()
if playerId < 0 then
return
end
local team = killedUnit:GetTeamNumber()
if team == DOTA_TEAM_NEUTRALS or team == DOTA_TEAM_BADGUYS then
local state = self:getOrCreateQuestState(playerId)
state.killCount = state.killCount + 1
self:syncPlayerQuestProgress(playerId)
end
end,
nil
)
Timers:CreateTimer(
5,
function()
do
local function ____catch(e)
____print(
nil,
"[BattlePassServer] Не удалось подписаться на OnWaveEnd: " .. tostring(e)
)
end
local ____try, ____hasReturned = pcall(function()
WaveManager:getInstance():OnWaveEnd(function(____, info)
do
local i = 0
while i < PlayerResource:GetPlayerCount() do
do
if not PlayerResource:IsValidPlayer(i) or PlayerResource:IsFakeClient(i) then
goto __continue52
end
local state = self:getOrCreateQuestState(i)
state.wavesCompleted = info.waveIndex
self:syncPlayerQuestProgress(i)
end
::__continue52::
i = i + 1
end
end
end)
____print(nil, "[BattlePassServer] Зарегистрирован OnWaveEnd для квестов")
end)
if not ____try then
____catch(____hasReturned)
end
end
return nil
end
)
QuestEvents:OnQuestCompleted(function(____, data)
local questId = data.questId or ""
____print(
nil,
"[BattlePassServer] OnQuestCompleted: questId=" .. tostring(questId)
)
do
local i = 0
while i < PlayerResource:GetPlayerCount() do
do
if not PlayerResource:IsValidPlayer(i) or PlayerResource:IsFakeClient(i) then
goto __continue56
end
local state = self:getOrCreateQuestState(i)
state.npcQuestsCompleted = state.npcQuestsCompleted + 1
local canSync = state.questsLoaded and #state.quests > 0
if not canSync then
____print(
nil,
((("[BattlePassServer] Квесты ещё не загружены для игрока " .. tostring(i)) .. ", прогресс сохранён (npcQuestsCompleted=") .. tostring(state.npcQuestsCompleted)) .. ")"
)
Timers:CreateTimer(
3,
function()
self:syncPlayerQuestProgress(i)
return nil
end
)
end
self:syncPlayerQuestProgress(i)
end
::__continue56::
i = i + 1
end
end
end)
ListenToGameEvent(
"entity_killed",
function(event)
local killedIndex = event.entindex_killed
if killedIndex == nil or killedIndex == nil then
return
end
local killed = EntIndexToHScript(killedIndex)
local ____temp_14 = not killed
if not ____temp_14 then
local ____this_13
____this_13 = killed
local ____opt_12 = ____this_13.IsRealHero
if ____opt_12 ~= nil then
____opt_12 = ____opt_12(____this_13)
end
____temp_14 = not ____opt_12
end
if ____temp_14 then
return
end
local playerId = killed:GetPlayerOwnerID()
if playerId < 0 then
return
end
local state = self:getOrCreateQuestState(playerId)
state.lastDeathTime = GameRules:GetGameTime()
self:syncPlayerQuestProgress(playerId)
end,
nil
)
ListenToGameEvent(
"dota_item_picked_up",
function(event)
local heroIndex = event.HeroEntityIndex
local itemIndex = event.ItemEntityIndex
if heroIndex == nil or heroIndex == nil then
return
end
if itemIndex == nil or itemIndex == nil then
return
end
local hero = EntIndexToHScript(heroIndex)
local item = EntIndexToHScript(itemIndex)
if not hero or not item or not hero:IsRealHero() then
return
end
local playerId = hero:GetPlayerOwnerID()
if playerId < 0 then
return
end
local itemName = item:GetAbilityName()
local state = self:getOrCreateQuestState(playerId)
state.collectedItems[itemName] = (state.collectedItems[itemName] or 0) + 1
self:syncPlayerQuestProgress(playerId)
end,
nil
)
CustomGameEventManager:RegisterListener(
"cooking_claim_dish",
function(_, event)
local ____event_playerID_15 = event.playerID
if ____event_playerID_15 == nil then
____event_playerID_15 = event.PlayerID
end
local playerId = ____event_playerID_15
if playerId == nil or playerId < 0 then
return
end
local result = event.result
local state = self:getOrCreateQuestState(playerId)
state.cookingCompleted = state.cookingCompleted + 1
if result == "item_grilled_meat" then
state.cookGrilledMeat = 1
end
self:syncPlayerQuestProgress(playerId)
end
)
CustomGameEventManager:RegisterListener(
"cooking_start",
function(_, event)
local ____event_PlayerID_16 = event.PlayerID
if ____event_PlayerID_16 == nil then
____event_PlayerID_16 = event.playerID
end
local playerId = ____event_PlayerID_16
if playerId == nil or playerId < 0 then
return
end
local state = self:getOrCreateQuestState(playerId)
state.campfireUses = state.campfireUses + 1
self:syncPlayerQuestProgress(playerId)
end
)
Timers:CreateTimer(
15,
function()
self:syncAllQuestProgress()
return 30
end
)
____print(nil, "[BattlePassServer] Квест-трекинг инициализирован")
end
function BattlePassServer.prototype.getOrCreateQuestState(self, playerId)
local state = self.playerQuestState:get(playerId)
if not state then
state = {
quests = {},
killCount = 0,
blackShopBuys = 0,
blackShopBuysByQuality = {},
npcQuestsCompleted = 0,
npcQuestsByNpc = {},
wavesCompleted = 0,
gameStartTime = GameRules:GetGameTime(),
lastSyncTime = 0,
questsLoaded = false,
cookingCompleted = 0,
cookGrilledMeat = 0,
campfireUses = 0,
tipsGiven = 0,
lastDeathTime = 0,
collectedItems = {},
heroesPlayed = __TS__New(Set)
}
self.playerQuestState:set(playerId, state)
end
return state
end
function BattlePassServer.prototype.onTipped(self, playerId)
local state = self:getOrCreateQuestState(playerId)
state.tipsGiven = state.tipsGiven + 1
self:syncPlayerQuestProgress(playerId)
end
function BattlePassServer.prototype.onHealAlly(self, healerPlayerId, amount)
MatchEndCombatStats:getInstance():addHealToAllies(healerPlayerId, amount)
self:syncPlayerQuestProgress(healerPlayerId)
end
function BattlePassServer.prototype.onHeroSelected(self, playerId, heroName)
local state = self:getOrCreateQuestState(playerId)
state.heroesPlayed:add(heroName)
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
local request = CreateHTTPRequest("POST", ((self.serverUrl .. "/battlepass/") .. steamId) .. "/hero-played")
setApiHeaders(nil, request)
request:SetHTTPRequestRawPostBody(
"application/json",
json.encode({hero_name = heroName})
)
request:Send(function()
end)
self:syncPlayerQuestProgress(playerId)
end
function BattlePassServer.prototype.onBlackShopPurchase(self, playerId, quality)
local state = self:getOrCreateQuestState(playerId)
state.blackShopBuys = state.blackShopBuys + 1
if quality then
local q = string.lower(quality)
state.blackShopBuysByQuality[q] = (state.blackShopBuysByQuality[q] or 0) + 1
end
self:syncPlayerQuestProgress(playerId)
end
function BattlePassServer.prototype.getQuestProgress(self, playerId, quest)
local state = self.playerQuestState:get(playerId)
if not state then
return 0
end
repeat
local ____switch85 = quest.type
local ____cond85 = ____switch85 == "kill_zombies"
if ____cond85 then
return state.killCount
end
____cond85 = ____cond85 or ____switch85 == "survive_time"
if ____cond85 then
return math.floor(GameRules:GetGameTime() - state.gameStartTime)
end
____cond85 = ____cond85 or ____switch85 == "buy_black_shop"
if ____cond85 then
return state.blackShopBuys
end
____cond85 = ____cond85 or ____switch85 == "buy_black_shop_quality"
if ____cond85 then
do
local q = string.lower(quest.quality or "")
return q ~= "" and (state.blackShopBuysByQuality[q] or 0) or 0
end
end
____cond85 = ____cond85 or ____switch85 == "complete_npc_quest"
if ____cond85 then
return state.npcQuestsCompleted
end
____cond85 = ____cond85 or ____switch85 == "complete_npc_quest_npc"
if ____cond85 then
do
local npc = quest.npc or ""
return npc ~= "" and (state.npcQuestsByNpc[npc] or 0) or 0
end
end
____cond85 = ____cond85 or ____switch85 == "earn_gold"
if ____cond85 then
do
do
local function ____catch(e)
return true, 0
end
local ____try, ____hasReturned, ____returnValue = pcall(function()
return true, PlayerResource:GetTotalEarnedGold(playerId)
end)
if not ____try then
____hasReturned, ____returnValue = ____catch(____hasReturned)
end
if ____hasReturned then
return ____returnValue
end
end
end
end
____cond85 = ____cond85 or ____switch85 == "hero_level"
if ____cond85 then
do
local hero = PlayerResource:GetSelectedHeroEntity(playerId)
if hero then
return hero:GetLevel()
end
return 0
end
end
____cond85 = ____cond85 or ____switch85 == "survive_waves"
if ____cond85 then
return state.wavesCompleted
end
____cond85 = ____cond85 or ____switch85 == "complete_cooking"
if ____cond85 then
return state.cookingCompleted
end
____cond85 = ____cond85 or ____switch85 == "cook_grilled_meat"
if ____cond85 then
return state.cookGrilledMeat
end
____cond85 = ____cond85 or ____switch85 == "use_campfire"
if ____cond85 then
return state.campfireUses
end
____cond85 = ____cond85 or ____switch85 == "tip_teammate"
if ____cond85 then
return state.tipsGiven
end
____cond85 = ____cond85 or ____switch85 == "no_death"
if ____cond85 then
do
if state.lastDeathTime > 0 then
return 0
end
return math.floor(GameRules:GetGameTime() - state.gameStartTime)
end
end
____cond85 = ____cond85 or ____switch85 == "heal_ally"
if ____cond85 then
return MatchEndCombatStats:getInstance():getHealToAlliesSum(playerId)
end
____cond85 = ____cond85 or ____switch85 == "deal_damage"
if ____cond85 then
return MatchEndCombatStats:getInstance():getOutgoingDamageSum(playerId)
end
____cond85 = ____cond85 or ____switch85 == "collect_item"
if ____cond85 then
do
local item = quest.target_item or ""
return item ~= "" and (state.collectedItems[item] or 0) or 0
end
end
____cond85 = ____cond85 or ____switch85 == "play_different_hero"
if ____cond85 then
return math.max(state.heroesPlayed.size, quest.progress or 0)
end
do
return 0
end
until true
end
function BattlePassServer.prototype.syncPlayerQuestProgress(self, playerId)
local state = self.playerQuestState:get(playerId)
if not state or not state.questsLoaded or #state.quests == 0 then
return
end
if not PlayerResource:IsValidPlayer(playerId) or PlayerResource:IsFakeClient(playerId) then
return
end
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
local anyUpdated = false
for ____, quest in ipairs(state.quests) do
do
if quest.claimed then
goto __continue99
end
local currentProgress = self:getQuestProgress(playerId, quest)
local newProgress = math.min(currentProgress, quest.target)
local newCompleted = newProgress >= quest.target
local wasCompleted = quest.completed
if newProgress ~= quest.progress or newCompleted ~= quest.completed then
quest.progress = newProgress
quest.completed = newCompleted
anyUpdated = true
self:syncQuestProgressToApi(steamId, quest.quest_id, newProgress)
if quest.completed and not wasCompleted then
____print(nil, ("[BattlePassServer] Квест " .. quest.quest_id) .. " выполнен, автоматически забираем...")
self:claimQuest(playerId, steamId, quest.quest_id)
end
end
end
::__continue99::
end
if anyUpdated then
self:sendQuestsToClient(playerId, state.quests)
end
end
function BattlePassServer.prototype.syncAllQuestProgress(self)
for ____, ____value in __TS__Iterator(self.playerQuestState) do
local playerId = ____value[1]
local state = ____value[2]
do
if not state.questsLoaded or #state.quests == 0 then
goto __continue106
end
if not PlayerResource:IsValidPlayer(playerId) or PlayerResource:IsFakeClient(playerId) then
goto __continue106
end
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
local anyUpdated = false
for ____, quest in ipairs(state.quests) do
do
if quest.claimed then
goto __continue109
end
local currentProgress = self:getQuestProgress(playerId, quest)
local newProgress = math.min(currentProgress, quest.target)
local newCompleted = newProgress >= quest.target
local wasCompleted = quest.completed
if newProgress ~= quest.progress or newCompleted ~= quest.completed then
quest.progress = newProgress
quest.completed = newCompleted
anyUpdated = true
self:syncQuestProgressToApi(steamId, quest.quest_id, newProgress)
if quest.completed and not wasCompleted then
____print(nil, ("[BattlePassServer] Квест " .. quest.quest_id) .. " выполнен, автоматически забираем...")
self:claimQuest(playerId, steamId, quest.quest_id)
end
end
end
::__continue109::
end
if anyUpdated then
self:sendQuestsToClient(playerId, state.quests)
end
end
::__continue106::
end
end
function BattlePassServer.prototype.syncQuestProgressToApi(self, steamId, questId, progress)
local request = CreateHTTPRequest("POST", ((self.serverUrl .. "/battlepass/") .. steamId) .. "/quests/progress")
setApiHeaders(nil, request)
request:SetHTTPRequestRawPostBody(
"application/json",
json.encode({quest_id = questId, progress = progress})
)
request:Send(function(result)
if result.StatusCode >= 200 and result.StatusCode < 300 then
do
pcall(function()
local decoded = {json.decode(result.Body)}
local data = self:pickDecodedJsonRoot(decoded, {"success", "completed", "progress"})
if data and apiJsonBool(nil, data.completed) then
____print(
nil,
((("[BattlePassServer] Квест " .. questId) .. " стал выполненным (прогресс: ") .. tostring(progress)) .. ")"
)
end
end)
end
else
____print(
nil,
(("[BattlePassServer] Ошибка синхронизации квеста " .. questId) .. ": ") .. tostring(result.StatusCode)
)
end
end)
end
function BattlePassServer.prototype.sendQuestsToClient(self, playerId, quests)
local player = PlayerResource:GetPlayer(playerId)
if not player then
return
end
local questsObject = {}
__TS__ArrayForEach(
quests,
function(____, q, idx)
questsObject[tostring(idx)] = {
quest_id = q.quest_id,
type = q.type,
name = q.name,
description = q.description,
progress = q.progress,
target = q.target,
completed = q.completed and 1 or 0,
claimed = q.claimed and 1 or 0,
reward_exp = q.reward_exp,
reward_free_currency = q.reward_free_currency or 0
}
end
)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_quests_data", {quests = questsObject})
end
function BattlePassServer.prototype.loadQuests(self, playerId, steamId)
____print(
nil,
((("[BattlePassServer] Запрос квестов для " .. steamId) .. " (playerId: ") .. tostring(playerId)) .. ")"
)
local request = CreateHTTPRequest("GET", ((self.serverUrl .. "/battlepass/") .. steamId) .. "/quests")
setApiHeaders(nil, request)
request:Send(function(result)
local player = PlayerResource:GetPlayer(playerId)
if not player then
____print(
nil,
("[BattlePassServer] Игрок " .. tostring(playerId)) .. " не найден при получении квестов"
)
return
end
if result.StatusCode == 0 then
____print(nil, "[BattlePassServer] Сервер недоступен (StatusCode=0) для квестов")
return
end
if result.StatusCode >= 200 and result.StatusCode < 300 then
do
local function ____catch(e)
____print(
nil,
"[BattlePassServer] Ошибка парсинга квестов: " .. tostring(e)
)
____print(
nil,
"[BattlePassServer] Тело ответа: " .. tostring(result.Body)
)
end
local ____try, ____hasReturned = pcall(function()
local decoded = {json.decode(result.Body)}
____print(
nil,
"[BattlePassServer] Ответ API квестов (raw): " .. tostring(result.Body)
)
local data = self:pickDecodedJsonRoot(decoded, {"quests"})
____print(
nil,
"[BattlePassServer] Финальные данные: " .. json.encode(data)
)
local questsData = nil
if data and type(data) == "table" then
if data.quests ~= nil and data.quests ~= nil then
questsData = data.quests
____print(nil, "[BattlePassServer] ✓ Найдено через .quests")
elseif data.quests ~= nil and data.quests ~= nil then
questsData = data.quests
____print(nil, "[BattlePassServer] ✓ Найдено через [\"quests\"]")
end
end
if questsData == nil or questsData == nil then
____print(nil, "[BattlePassServer] ⚠️ quests не найдено в data")
end
local questsArray = {}
if questsData ~= nil and questsData ~= nil then
local rawQuests = {}
local index = 1
while true do
do
local item = questsData[index]
if item == nil or item == nil then
if index == 1 then
index = 0
goto __continue136
end
break
end
rawQuests[#rawQuests + 1] = item
index = index + 1
end
::__continue136::
end
if #rawQuests == 0 and type(questsData) == "table" then
for key in pairs(questsData) do
local item = questsData[key]
if item and type(item) == "table" then
rawQuests[#rawQuests + 1] = item
end
end
end
____print(
nil,
("[BattlePassServer] Получено " .. tostring(#rawQuests)) .. " квестов из API"
)
for ____, q in ipairs(rawQuests) do
if q and type(q) == "table" then
local questObj = {
quest_id = q.quest_id or "",
type = q.type or "unknown",
name = q.name or q.quest_id or "",
description = q.description or "",
progress = q.progress or 0,
target = q.target or 1,
completed = apiJsonBool(nil, q.completed),
claimed = apiJsonBool(nil, q.claimed),
reward_exp = q.reward_exp or 0,
reward_free_currency = q.reward_free_currency or 0
}
if q.quality then
questObj.quality = q.quality
end
if q.npc then
questObj.npc = q.npc
end
if q.target_item then
questObj.target_item = q.target_item
end
questsArray[#questsArray + 1] = questObj
end
end
else
____print(nil, "[BattlePassServer] ⚠️ questsData пусто или null после всех попыток")
end
local state = self:getOrCreateQuestState(playerId)
state.quests = questsArray
state.questsLoaded = true
for ____, quest in ipairs(state.quests) do
do
if quest.claimed then
goto __continue150
end
local currentProgress = self:getQuestProgress(playerId, quest)
local newProgress = math.min(currentProgress, quest.target)
local newCompleted = newProgress >= quest.target
local wasCompleted = quest.completed
if newProgress > quest.progress or newCompleted ~= quest.completed then
quest.progress = newProgress
quest.completed = newCompleted
self:syncQuestProgressToApi(steamId, quest.quest_id, newProgress)
end
if quest.completed and not quest.claimed then
____print(nil, ("[BattlePassServer] Квест " .. quest.quest_id) .. " уже выполнен, автоматически забираем...")
self:claimQuest(playerId, steamId, quest.quest_id)
end
end
::__continue150::
end
____print(
nil,
(("[BattlePassServer] Загружено " .. tostring(#questsArray)) .. " квестов для ") .. steamId
)
self:sendQuestsToClient(playerId, state.quests)
Timers:CreateTimer(
0.5,
function()
self:syncPlayerQuestProgress(playerId)
return nil
end
)
end)
if not ____try then
____catch(____hasReturned)
end
end
else
____print(
nil,
"[BattlePassServer] Ошибка загрузки квестов: " .. tostring(result.StatusCode)
)
____print(
nil,
"[BattlePassServer] Тело ответа: " .. tostring(result.Body)
)
end
end)
end
function BattlePassServer.prototype.claimQuest(self, playerId, steamId, questId)
____print(
nil,
(((("[BattlePassServer] claimQuest: playerId=" .. tostring(playerId)) .. ", steamId=") .. steamId) .. ", questId=") .. questId
)
local state = self.playerQuestState:get(playerId)
if not state then
____print(
nil,
"[BattlePassServer] ⚠️ Состояние квестов не найдено для playerId=" .. tostring(playerId)
)
return
end
local quest = __TS__ArrayFind(
state.quests,
function(____, q) return q.quest_id == questId end
)
if not quest then
____print(nil, ("[BattlePassServer] ⚠️ Квест " .. questId) .. " не найден в локальном состоянии")
local player = PlayerResource:GetPlayer(playerId)
if player then
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_quest_claim_result", {success = false, error = "Задание не найдено"})
end
return
end
____print(
nil,
(((((("[BattlePassServer] Квест найден: completed=" .. tostring(quest.completed)) .. ", claimed=") .. tostring(quest.claimed)) .. ", progress=") .. tostring(quest.progress)) .. "/") .. tostring(quest.target)
)
if not quest.completed or quest.claimed then
____print(
nil,
(("[BattlePassServer] ⚠️ Квест не может быть забран: completed=" .. tostring(quest.completed)) .. ", claimed=") .. tostring(quest.claimed)
)
local player = PlayerResource:GetPlayer(playerId)
if player then
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_quest_claim_result", {success = false, error = "Задание не выполнено или уже забрано"})
end
return
end
____print(nil, "[BattlePassServer] Отправляем запрос на клейм квеста " .. questId)
local request = CreateHTTPRequest("POST", ((self.serverUrl .. "/battlepass/") .. steamId) .. "/quests/claim")
setApiHeadersLong(nil, request)
request:SetHTTPRequestRawPostBody(
"application/json",
json.encode({quest_id = questId})
)
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
local function ____catch(e)
____print(
nil,
"[BattlePassServer] Ошибка парсинга claim квеста: " .. tostring(e)
)
____print(
nil,
"[BattlePassServer] Тело ответа: " .. tostring(result.Body)
)
end
local ____try, ____hasReturned = pcall(function()
local decoded = {json.decode(result.Body)}
____print(
nil,
"[BattlePassServer] Ответ claim квеста (raw): " .. tostring(result.Body)
)
local data = self:pickDecodedJsonRoot(decoded, {"success", "reward_exp", "quest_id", "new_level"})
____print(
nil,
"[BattlePassServer] Данные claim: " .. json.encode(data)
)
quest.claimed = true
local rewardExpNum = __TS__Number(data.reward_exp)
local rewardExp = __TS__NumberIsFinite(rewardExpNum) and rewardExpNum or 0
local rewardFreeNum = __TS__Number(data.reward_free_currency)
local rewardFreeCurrency = __TS__NumberIsFinite(rewardFreeNum) and rewardFreeNum or 0
local newLevelNum = __TS__Number(data.new_level)
local newLevel = __TS__NumberIsFinite(newLevelNum) and newLevelNum or 0
local newExpNum = __TS__Number(data.new_experience)
local newExp = __TS__NumberIsFinite(newExpNum) and newExpNum or 0
____print(
nil,
(((((((("[BattlePassServer] Квест " .. questId) .. " забран для ") .. steamId) .. ", +") .. tostring(rewardExp)) .. " BP XP, новый уровень: ") .. tostring(newLevel)) .. ", новый опыт: ") .. tostring(newExp)
)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_quest_claim_result", {
success = true,
quest_id = questId,
reward_exp = rewardExp,
reward_free_currency = rewardFreeCurrency,
new_level = newLevel,
new_experience = newExp
})
self:sendQuestsToClient(playerId, state.quests)
____print(nil, "[BattlePassServer] Перезагружаем данные BP после клейма квеста...")
self:loadBattlePassData(playerId, steamId)
end)
if not ____try then
____catch(____hasReturned)
end
end
else
local errorMsg = "Ошибка: " .. tostring(result.StatusCode)
____print(
nil,
"[BattlePassServer] Ошибка клейма квеста: StatusCode=" .. tostring(result.StatusCode)
)
____print(
nil,
"[BattlePassServer] Тело ответа: " .. tostring(result.Body)
)
do
local function ____catch(e)
____print(
nil,
"[BattlePassServer] Ошибка парсинга ответа об ошибке: " .. tostring(e)
)
end
local ____try, ____hasReturned = pcall(function()
local body = {json.decode(result.Body)}
local errorBody = body
if body and type(body) == "table" and body[1] ~= nil then
errorBody = body[1]
end
if errorBody and errorBody.error then
errorMsg = errorBody.error
____print(nil, "[BattlePassServer] Сообщение об ошибке: " .. errorMsg)
end
end)
if not ____try then
____catch(____hasReturned)
end
end
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_quest_claim_result", {success = false, error = errorMsg})
end
end)
end
function BattlePassServer.prototype.setupEventListeners(self)
CustomGameEventManager:RegisterListener(
"request_battle_pass",
function(source, event)
local playerId = event.PlayerID
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
____print(
nil,
(("[BattlePassServer] Запрос данных Battle Pass для игрока " .. tostring(playerId)) .. ", Steam ID: ") .. steamId
)
self:loadBattlePassData(playerId, steamId)
end
)
CustomGameEventManager:RegisterListener(
"battle_pass_claim_reward",
function(source, event)
local playerId = event.PlayerID
local level = event.level
local rawPrem = event.is_premium
local isPremium = rawPrem == 1 or rawPrem == true or rawPrem == "1"
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
____print(
nil,
(((("[BattlePassServer] Запрос на забор награды уровня " .. tostring(level)) .. " (premium: ") .. tostring(isPremium)) .. ") для игрока ") .. tostring(playerId)
)
self:claimReward(playerId, steamId, level, isPremium)
end
)
CustomGameEventManager:RegisterListener(
"buy_battle_pass_premium",
function(source, event)
local playerId = event.PlayerID
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
____print(
nil,
"[BattlePassServer] Запрос на покупку Battle Pass Premium для игрока " .. tostring(playerId)
)
self:buyPremium(playerId, steamId)
end
)
CustomGameEventManager:RegisterListener(
"claim_all_battle_pass_rewards",
function(source, event)
local playerId = event.PlayerID
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
____print(
nil,
"[BattlePassServer] Запрос на забор ВСЕХ наград для игрока " .. tostring(playerId)
)
self:claimAllRewards(playerId, steamId)
end
)
CustomGameEventManager:RegisterListener(
"request_battle_pass_quests",
function(source, event)
local playerId = event.PlayerID
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
____print(
nil,
"[BattlePassServer] Запрос квестов для игрока " .. tostring(playerId)
)
self:loadQuests(playerId, steamId)
end
)
CustomGameEventManager:RegisterListener(
"claim_battle_pass_quest",
function(source, event)
local playerId = event.PlayerID
local questId = event.quest_id
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
____print(
nil,
(("[BattlePassServer] Клейм квеста " .. questId) .. " для игрока ") .. tostring(playerId)
)
self:claimQuest(playerId, steamId, questId)
end
)
end
function BattlePassServer.prototype.loadBattlePassData(self, playerId, steamId)
local request = CreateHTTPRequest("GET", (self.serverUrl .. "/battlepass/") .. steamId)
setApiHeaders(nil, request)
request:Send(function(result)
do
local function ____catch(____error)
____print(
nil,
"[BattlePassServer] Ошибка обработки ответа: " .. tostring(____error)
)
local player = PlayerResource:GetPlayer(playerId)
if player then
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_data", {error = "Ошибка обработки данных"})
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
____print(nil, "[BattlePassServer] Сервер недоступен (StatusCode=0)")
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_data", {error = "Сервер недоступен"})
return true
end
if result.StatusCode >= 200 and result.StatusCode < 300 then
do
local function ____catch(e)
____print(
nil,
"[BattlePassServer] Ошибка парсинга JSON: " .. tostring(e)
)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_data", {error = "Ошибка парсинга данных"})
end
local ____try, ____hasReturned = pcall(function()
local responseData = {json.decode(result.Body)}
local data = nil
if __TS__ArrayIsArray(responseData) and #responseData > 0 then
data = responseData[1]
elseif responseData and type(responseData) == "table" then
data = responseData
end
if data then
local claimedRewards = data.claimed_rewards or ({})
local claimedObject = {}
if __TS__ArrayIsArray(claimedRewards) then
__TS__ArrayForEach(
claimedRewards,
function(____, level, index)
claimedObject[tostring(index)] = level
end
)
elseif type(claimedRewards) == "table" then
for key in pairs(claimedRewards) do
if rawget(claimedRewards, key) ~= nil then
claimedObject[key] = claimedRewards[key]
end
end
end
local claimedPremiumRewards = data.claimed_premium_rewards or ({})
local claimedPremiumObject = {}
if __TS__ArrayIsArray(claimedPremiumRewards) then
__TS__ArrayForEach(
claimedPremiumRewards,
function(____, level, index)
claimedPremiumObject[tostring(index)] = level
end
)
elseif type(claimedPremiumRewards) == "table" then
for key in pairs(claimedPremiumRewards) do
if rawget(claimedPremiumRewards, key) ~= nil then
claimedPremiumObject[key] = claimedPremiumRewards[key]
end
end
end
____print(
nil,
(((((((("[BattlePassServer] Данные загружены: level=" .. tostring(data.level)) .. ", exp=") .. tostring(data.experience)) .. ", claimed=") .. tostring(#__TS__ObjectKeys(claimedObject))) .. ", premium=") .. tostring(data.has_premium)) .. ", claimed_premium=") .. tostring(#__TS__ObjectKeys(claimedPremiumObject))
)
self:rememberBattlePassSnapshot(
playerId,
parseApiNumber(nil, data.level),
parseApiNumber(nil, data.experience),
apiJsonBool(nil, data.has_premium)
)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_data", {
level = data.level or 0,
experience = data.experience or 0,
claimed_rewards = claimedObject,
has_premium = data.has_premium and 1 or 0,
claimed_premium_rewards = claimedPremiumObject
})
else
____print(nil, "[BattlePassServer] Данные не найдены, создаем новый Battle Pass для " .. steamId)
self:createBattlePass(playerId, steamId)
end
end)
if not ____try then
____catch(____hasReturned)
end
end
elseif result.StatusCode == 404 then
____print(nil, "[BattlePassServer] 404 - создаем новый Battle Pass для " .. steamId)
self:createBattlePass(playerId, steamId)
else
____print(
nil,
"[BattlePassServer] Ошибка сервера: " .. tostring(result.StatusCode)
)
CustomGameEventManager:Send_ServerToPlayer(
player,
"battle_pass_data",
{error = "Ошибка сервера: " .. tostring(result.StatusCode)}
)
end
end)
if not ____try then
____hasReturned, ____returnValue = ____catch(____hasReturned)
end
if ____hasReturned then
return ____returnValue
end
end
end)
end
function BattlePassServer.prototype.createBattlePass(self, playerId, steamId, afterCreate)
local request = CreateHTTPRequest("POST", self.serverUrl .. "/battlepass")
setApiHeadersLong(nil, request)
request:SetHTTPRequestRawPostBody(
"application/json",
encodeApiBody(nil, {
steam_id = steamId,
level = 0,
experience = 0,
claimed_rewards = {},
has_premium = false,
claimed_premium_rewards = {}
})
)
request:Send(function(result)
local player = PlayerResource:GetPlayer(playerId)
if not player then
if afterCreate then
afterCreate(nil, false)
end
return
end
if result.StatusCode >= 200 and result.StatusCode < 300 then
____print(nil, "[BattlePassServer] Battle Pass создан на сервере для " .. steamId)
self:rememberBattlePassSnapshot(playerId, 0, 0, false)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_data", {
level = 0,
experience = 0,
claimed_rewards = {},
has_premium = 0,
claimed_premium_rewards = {}
})
if afterCreate then
afterCreate(nil, true)
end
else
____print(
nil,
"[BattlePassServer] Ошибка создания Battle Pass: " .. tostring(result.StatusCode)
)
CustomGameEventManager:Send_ServerToPlayer(
player,
"battle_pass_data",
{error = "Ошибка создания Battle Pass: " .. tostring(result.StatusCode)}
)
if afterCreate then
afterCreate(nil, false)
end
end
end)
end
function BattlePassServer.prototype.claimReward(self, playerId, steamId, level, isPremium)
if isPremium == nil then
isPremium = false
end
local endpoint = isPremium and "claim-premium" or "claim"
local request = CreateHTTPRequest("POST", (((self.serverUrl .. "/battlepass/") .. steamId) .. "/") .. endpoint)
setApiHeadersLong(nil, request)
request:SetHTTPRequestRawPostBody(
"application/json",
json.encode({steam_id = steamId, level = level, is_premium = isPremium})
)
request:Send(function(result)
local player = PlayerResource:GetPlayer(playerId)
if not player then
return
end
if result.StatusCode >= 200 and result.StatusCode < 300 then
____print(
nil,
(((("[BattlePassServer] Награда уровня " .. tostring(level)) .. " (premium: ") .. tostring(isPremium)) .. ") забрана для ") .. steamId
)
local rCfg = self:getRewardForLevel(level, isPremium)
local expF = 0
local expD = 0
if (rCfg and rCfg.type) == "free_currency" then
expF = rCfg.amount or 0
end
if (rCfg and rCfg.type) == "donate_currency" then
expD = rCfg.amount or 0
end
local ____temp_21 = self:parseCurrencyGrantedFromClaimResponse(tostring(result.Body))
local apiFree = ____temp_21.apiFree
local apiDonate = ____temp_21.apiDonate
local hasField = ____temp_21.hasField
if hasField and (expF > 0 or expD > 0) then
self:syncBattlePassShopCurrencyIfUnderGranted(
playerId,
apiFree,
apiDonate,
expF,
expD,
(("одиночный claim ур." .. tostring(level)) .. " prem=") .. tostring(isPremium)
)
elseif not hasField and (expF > 0 or expD > 0) then
rawPrintFn(
nil,
((((("[BattlePassServer] В ответе claim нет currency_granted — начисляю осколки через /currency/give: free=" .. tostring(expF)) .. " donate=") .. tostring(expD)) .. " (ур.") .. tostring(level)) .. ")"
)
self:grantShopCurrencyViaApi(
playerId,
expF,
expD,
((("[BattlePassServer] Валюта БП (нет поля API): +" .. tostring(expF)) .. " free, +") .. tostring(expD)) .. " donate"
)
end
self:grantRewardInGame(playerId, level, isPremium)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_claim_result", {success = true, level = level, is_premium = isPremium and 1 or 0})
else
local errorMsg = "Ошибка: " .. tostring(result.StatusCode)
do
pcall(function()
local body = {json.decode(result.Body)}
if body and body.error then
errorMsg = body.error
end
end)
end
____print(nil, "[BattlePassServer] Ошибка забора награды: " .. errorMsg)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_claim_result", {success = false, level = level, error = errorMsg})
end
end)
end
function BattlePassServer.battlePassFreeShardsPerLevel(self, level)
return level * 250
end
function BattlePassServer.battlePassDustForLevel(self, level)
return level * 200
end
function BattlePassServer.isDustLevel(self, level, isPremium)
local list = isPremium and ____exports.BattlePassServer.BP_PREMIUM_DUST_LEVELS or ____exports.BattlePassServer.BP_FREE_DUST_LEVELS
for ____, l in ipairs(list) do
if l == level then
return true
end
end
return false
end
function BattlePassServer.isPackLevel(self, level, isPremium)
local list = isPremium and ____exports.BattlePassServer.BP_PREMIUM_PACK_LEVELS or ____exports.BattlePassServer.BP_FREE_PACK_LEVELS
for ____, l in ipairs(list) do
if l == level then
return true
end
end
return false
end
function BattlePassServer.buildFreeRewardsConfig(self)
local cfg = {}
do
local lvl = 1
while lvl <= 50 do
if ____exports.BattlePassServer:isDustLevel(lvl, false) then
cfg[lvl] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(lvl)
}
elseif ____exports.BattlePassServer:isPackLevel(lvl, false) then
cfg[lvl] = {type = "arcade_pack_standard", amount = 1}
else
cfg[lvl] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(lvl)
}
end
lvl = lvl + 1
end
end
return cfg
end
function BattlePassServer.prototype.getRewardForLevel(self, lvl, isPremium)
if isPremium == nil then
isPremium = false
end
local config = isPremium and ____exports.BattlePassServer.PREMIUM_REWARDS_CONFIG or ____exports.BattlePassServer.REWARDS_CONFIG
local reward = config[lvl]
if reward == nil or reward == nil then
return nil
end
return reward
end
function BattlePassServer.prototype.findCurrencyGrantedInDecoded(self, decoded)
if not decoded or type(decoded) ~= "table" then
return nil
end
local candidates = {decoded}
local z = decoded
if z[0] and type(z[0]) == "table" then
candidates[#candidates + 1] = z[0]
end
if z[1] and type(z[1]) == "table" then
candidates[#candidates + 1] = z[1]
end
for ____, obj in ipairs(candidates) do
local cg = obj.currency_granted
if cg ~= nil and cg ~= nil and type(cg) == "table" then
return {
free = parseApiNumber(nil, cg.free_currency),
donate = parseApiNumber(nil, cg.donate_currency)
}
end
end
return nil
end
function BattlePassServer.prototype.parseCurrencyGrantedFromClaimResponse(self, body)
do
local ____try, ____hasReturned, ____returnValue = pcall(function()
local decoded = {json.decode(body)}
local found = self:findCurrencyGrantedInDecoded(decoded)
if found then
return true, {apiFree = found.free, apiDonate = found.donate, hasField = true}
end
end)
if ____try and ____hasReturned then
return ____returnValue
end
end
return {apiFree = 0, apiDonate = 0, hasField = false}
end
function BattlePassServer.prototype.sumExpectedShopCurrencyForLevels(self, freeLevels, premiumLevels)
local free = 0
local donate = 0
for ____, lvl in ipairs(freeLevels) do
local r = self:getRewardForLevel(lvl, false)
if (r and r.type) == "free_currency" then
free = free + (r.amount or 0)
end
end
for ____, lvl in ipairs(premiumLevels) do
local r = self:getRewardForLevel(lvl, true)
if (r and r.type) == "free_currency" then
free = free + (r.amount or 0)
end
if (r and r.type) == "donate_currency" then
donate = donate + (r.amount or 0)
end
end
return {free = free, donate = donate}
end
function BattlePassServer.prototype.syncBattlePassShopCurrencyIfUnderGranted(self, playerId, apiFree, apiDonate, expectedFree, expectedDonate, logCtx)
local needFree = math.max(0, expectedFree - (apiFree or 0))
local needDonate = math.max(0, expectedDonate - (apiDonate or 0))
if needFree <= 0 and needDonate <= 0 then
return false
end
rawPrintFn(
nil,
(((((((((((("[BattlePassServer] " .. logCtx) .. ": API free=") .. tostring(apiFree)) .. " donate=") .. tostring(apiDonate)) .. ", ожидалось free=") .. tostring(expectedFree)) .. " donate=") .. tostring(expectedDonate)) .. " → доначисление give +") .. tostring(needFree)) .. "/+") .. tostring(needDonate)
)
self:grantShopCurrencyViaApi(
playerId,
needFree,
needDonate,
((((("[BattlePassServer] Доначисление валюты БП (" .. logCtx) .. "): +") .. tostring(needFree)) .. " free, +") .. tostring(needDonate)) .. " donate"
)
return true
end
function BattlePassServer.prototype.grantShopCurrencyViaApi(self, playerId, freeAmount, donateAmount, logSuccess, dustAmount, arcadePackStandard, arcadePackPremium)
if dustAmount == nil then
dustAmount = 0
end
if arcadePackStandard == nil then
arcadePackStandard = 0
end
if arcadePackPremium == nil then
arcadePackPremium = 0
end
StoreManager:getInstance():grantShopExtrasViaApi(playerId, {
freeAmount = freeAmount,
donateAmount = donateAmount,
dustAmount = dustAmount,
arcadePackStandard = arcadePackStandard,
arcadePackPremium = arcadePackPremium
}, logSuccess)
end
function BattlePassServer.prototype.playerAlreadyOwnsChatWheelSound(self, playerId, soundId)
local info = PlayerInfo:GetPlayerInfo(playerId)
local sw = info and info.sounds_wheel
if sw and sw[soundId] then
return true
end
return StoreManager:getInstance():hasPurchasedItem(playerId, "chat_wheel_sound_" .. soundId)
end
function BattlePassServer.prototype.grantRewardInGame(self, playerId, level, isPremium)
if isPremium == nil then
isPremium = false
end
local reward = self:getRewardForLevel(level, isPremium)
if not reward then
____print(
nil,
((("[BattlePassServer] Уровень " .. tostring(level)) .. " (premium: ") .. tostring(isPremium)) .. ") не имеет награды"
)
return
end
if not PlayerResource:IsValidPlayer(playerId) or not PlayerResource:GetPlayer(playerId) then
____print(
nil,
(("[BattlePassServer] Слот " .. tostring(playerId)) .. " не валиден — пропуск выдачи награды уровня ") .. tostring(level)
)
return
end
local storeMgr = StoreManager:getInstance()
repeat
local ____switch272 = reward.type
local cardId, cardStoreId, itemName, itemSteamId, purchaseRequest, effectId
local ____cond272 = ____switch272 == "free_currency" or ____switch272 == "donate_currency" or ____switch272 == "dust_currency" or ____switch272 == "arcade_pack_standard" or ____switch272 == "arcade_pack_premium"
if ____cond272 then
____print(
nil,
((((("[BattlePassServer] Пропуск " .. reward.type) .. " уровня ") .. tostring(level)) .. " (premium=") .. tostring(isPremium)) .. ") — уже начислено на сервере при клейме"
)
break
end
____cond272 = ____cond272 or ____switch272 == "card"
if ____cond272 then
cardId = reward.card_id
if cardId == nil or cardId == nil then
____print(
nil,
"[BattlePassServer] Ошибка: card_id не указан для карты на уровне " .. tostring(level)
)
break
end
cardStoreId = "card_data_" .. tostring(cardId)
if storeMgr:hasPurchasedCardById(playerId, cardId) then
local comp = getBpDuplicateCompensationByStoreItemId(nil, cardStoreId)
if comp.free_currency > 0 or comp.donate_currency > 0 then
self:grantShopCurrencyViaApi(
playerId,
comp.free_currency,
comp.donate_currency,
((((((("[BattlePassServer] Дубликат карты " .. cardStoreId) .. " (ур. ") .. tostring(level)) .. "): компенсация +") .. tostring(comp.free_currency)) .. " free, +") .. tostring(comp.donate_currency)) .. " donate"
)
else
____print(nil, ("[BattlePassServer] Дубликат " .. cardStoreId) .. ", нет компенсации в battle_pass_duplicate_compensation.ts")
end
break
end
storeMgr:registerCardFromBattlePass(playerId, cardId)
____print(
nil,
(("[BattlePassServer] Карта " .. tostring(cardId)) .. " добавлена через StoreManager для игрока ") .. tostring(playerId)
)
break
end
____cond272 = ____cond272 or ____switch272 == "item"
if ____cond272 then
itemName = reward.item_name
if not itemName then
____print(
nil,
"[BattlePassServer] Ошибка: item_name не указан для предмета на уровне " .. tostring(level)
)
break
end
if storeMgr:hasPurchasedItem(playerId, itemName) then
local comp = getBpDuplicateCompensationByStoreItemId(nil, itemName)
if comp.free_currency > 0 or comp.donate_currency > 0 then
self:grantShopCurrencyViaApi(
playerId,
comp.free_currency,
comp.donate_currency,
((((((("[BattlePassServer] Дубликат предмета " .. itemName) .. " (ур. ") .. tostring(level)) .. "): компенсация +") .. tostring(comp.free_currency)) .. " free, +") .. tostring(comp.donate_currency)) .. " donate"
)
else
____print(nil, ("[BattlePassServer] Дубликат " .. itemName) .. ", нет компенсации в battle_pass_duplicate_compensation.ts")
end
break
end
itemSteamId = tostring(PlayerResource:GetSteamAccountID(playerId))
purchaseRequest = CreateHTTPRequest("POST", ((self.serverUrl .. "/player/") .. itemSteamId) .. "/purchases")
setApiHeaders(nil, purchaseRequest)
purchaseRequest:SetHTTPRequestRawPostBody(
"application/json",
json.encode({item_id = itemName, item_category = "items", card_id = nil})
)
purchaseRequest:Send(function(purchaseResult)
if purchaseResult.StatusCode >= 200 and purchaseResult.StatusCode < 300 then
____print(
nil,
((((("[BattlePassServer] Предмет " .. itemName) .. " добавлен в покупки игрока ") .. tostring(playerId)) .. " (Steam ID: ") .. itemSteamId) .. ")"
)
else
____print(
nil,
"[BattlePassServer] Ошибка добавления предмета в покупки: " .. tostring(purchaseResult.StatusCode)
)
____print(
nil,
"[BattlePassServer] Тело ответа: " .. tostring(purchaseResult.Body)
)
end
end)
break
end
____cond272 = ____cond272 or ____switch272 == "effect"
if ____cond272 then
effectId = reward.effect_id
if effectId then
if storeMgr:hasPurchasedItem(playerId, effectId) then
local comp = getBpDuplicateCompensationByStoreItemId(nil, effectId)
if comp.free_currency > 0 or comp.donate_currency > 0 then
self:grantShopCurrencyViaApi(
playerId,
comp.free_currency,
comp.donate_currency,
((((((("[BattlePassServer] Дубликат эффекта " .. effectId) .. " (ур. ") .. tostring(level)) .. "): компенсация +") .. tostring(comp.free_currency)) .. " free, +") .. tostring(comp.donate_currency)) .. " donate"
)
else
____print(nil, ("[BattlePassServer] Дубликат " .. effectId) .. ", нет компенсации в battle_pass_duplicate_compensation.ts")
end
break
end
local effectSteamId = tostring(PlayerResource:GetSteamAccountID(playerId))
local effectPurchaseRequest = CreateHTTPRequest("POST", ((self.serverUrl .. "/player/") .. effectSteamId) .. "/purchases")
setApiHeaders(nil, effectPurchaseRequest)
effectPurchaseRequest:SetHTTPRequestRawPostBody(
"application/json",
json.encode({item_id = effectId, item_category = "effects", card_id = nil})
)
effectPurchaseRequest:Send(function(effectPurchaseResult)
if effectPurchaseResult.StatusCode >= 200 and effectPurchaseResult.StatusCode < 300 then
____print(
nil,
((((("[BattlePassServer] Эффект " .. effectId) .. " добавлен в покупки игрока ") .. tostring(playerId)) .. " (Steam ID: ") .. effectSteamId) .. ")"
)
else
____print(
nil,
"[BattlePassServer] Ошибка добавления эффекта в покупки: " .. tostring(effectPurchaseResult.StatusCode)
)
____print(
nil,
"[BattlePassServer] Тело ответа: " .. tostring(effectPurchaseResult.Body)
)
end
end)
end
break
end
____cond272 = ____cond272 or ____switch272 == "chat_wheel_sound"
if ____cond272 then
do
local sid = reward.sound_id
if not sid then
____print(
nil,
"[BattlePassServer] Ошибка: sound_id не указан для chat_wheel_sound на уровне " .. tostring(level)
)
break
end
if self:playerAlreadyOwnsChatWheelSound(playerId, sid) then
local cwItemId = "chat_wheel_sound_" .. sid
local comp = getBpDuplicateCompensationByStoreItemId(nil, cwItemId)
if comp.free_currency > 0 or comp.donate_currency > 0 then
self:grantShopCurrencyViaApi(
playerId,
comp.free_currency,
comp.donate_currency,
((((((("[BattlePassServer] Дубликат звука " .. cwItemId) .. " (ур. ") .. tostring(level)) .. "): компенсация +") .. tostring(comp.free_currency)) .. " free, +") .. tostring(comp.donate_currency)) .. " donate"
)
else
____print(nil, ("[BattlePassServer] Дубликат " .. cwItemId) .. ", нет компенсации в battle_pass_duplicate_compensation.ts")
end
break
end
grantChatWheelSoundFromBattlePass(nil, playerId, sid)
break
end
end
until true
end
function BattlePassServer.prototype.claimAllRewards(self, playerId, steamId)
local request = CreateHTTPRequest("POST", ((self.serverUrl .. "/battlepass/") .. steamId) .. "/claim-all")
setApiHeadersLong(nil, request)
request:SetHTTPRequestRawPostBody(
"application/json",
json.encode({steam_id = steamId})
)
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
local function ____catch(e)
____print(
nil,
"[BattlePassServer] Ошибка парсинга claim-all: " .. tostring(e)
)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_claim_result", {success = false, error = "Ошибка обработки данных"})
end
local ____try, ____hasReturned = pcall(function()
local decoded = {json.decode(result.Body)}
local responseData = self:pickDecodedJsonRoot(decoded, {"success", "free_levels", "premium_levels"})
local ____opt_result_30
if responseData ~= nil then
____opt_result_30 = responseData.free_levels
end
local flRaw = ____opt_result_30
local ____opt_result_33
if responseData ~= nil then
____opt_result_33 = responseData.premium_levels
end
local plRaw = ____opt_result_33
local freeLevels = __TS__ArrayIsArray(flRaw) and __TS__ArrayFilter(
__TS__ArrayMap(
flRaw,
function(____, v) return parseApiNumber(nil, v) end
),
function(____, n) return n >= 1 end
) or ({})
local premiumLevels = __TS__ArrayIsArray(plRaw) and __TS__ArrayFilter(
__TS__ArrayMap(
plRaw,
function(____, v) return parseApiNumber(nil, v) end
),
function(____, n) return n >= 1 end
) or ({})
____print(
nil,
(((("[BattlePassServer] Забрано " .. tostring(#freeLevels)) .. " бесплатных + ") .. tostring(#premiumLevels)) .. " премиум наград для ") .. steamId
)
local ____temp_34 = self:sumExpectedShopCurrencyForLevels(freeLevels, premiumLevels)
local expF = ____temp_34.free
local expD = ____temp_34.donate
local ____temp_35 = self:parseCurrencyGrantedFromClaimResponse(tostring(result.Body))
local apiFree = ____temp_35.apiFree
local apiDonate = ____temp_35.apiDonate
local hasField = ____temp_35.hasField
if hasField and (expF > 0 or expD > 0) then
self:syncBattlePassShopCurrencyIfUnderGranted(
playerId,
apiFree,
apiDonate,
expF,
expD,
((("claim-all (" .. tostring(#freeLevels)) .. "+") .. tostring(#premiumLevels)) .. " ур.)"
)
elseif not hasField and (expF > 0 or expD > 0) then
rawPrintFn(
nil,
(("[BattlePassServer] claim-all: нет currency_granted в ответе — give free=" .. tostring(expF)) .. " donate=") .. tostring(expD)
)
self:grantShopCurrencyViaApi(
playerId,
expF,
expD,
((("[BattlePassServer] Валюта БП claim-all (нет поля API): +" .. tostring(expF)) .. " free, +") .. tostring(expD)) .. " donate"
)
end
for ____, lvl in ipairs(freeLevels) do
self:grantRewardInGame(playerId, lvl, false)
end
for ____, lvl in ipairs(premiumLevels) do
self:grantRewardInGame(playerId, lvl, true)
end
local freeObject = {}
__TS__ArrayForEach(
freeLevels,
function(____, lvl, idx)
freeObject[tostring(idx)] = lvl
end
)
local premiumObject = {}
__TS__ArrayForEach(
premiumLevels,
function(____, lvl, idx)
premiumObject[tostring(idx)] = lvl
end
)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_claim_result", {success = true, claimed_levels = freeObject, claimed_premium_levels = premiumObject})
end)
if not ____try then
____catch(____hasReturned)
end
end
else
local errorMsg = "Ошибка: " .. tostring(result.StatusCode)
do
pcall(function()
local body = {json.decode(result.Body)}
if body and body.error then
errorMsg = body.error
end
end)
end
____print(nil, "[BattlePassServer] Ошибка забора всех наград: " .. errorMsg)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_claim_result", {success = false, error = errorMsg})
end
end)
end
function BattlePassServer.prototype.buyPremium(self, playerId, steamId)
local request = CreateHTTPRequest("POST", ((self.serverUrl .. "/battlepass/") .. steamId) .. "/buy-premium")
setApiHeadersLong(nil, request)
request:SetHTTPRequestRawPostBody(
"application/json",
json.encode({steam_id = steamId, cost = 1000})
)
request:Send(function(result)
local player = PlayerResource:GetPlayer(playerId)
if not player then
return
end
if result.StatusCode >= 200 and result.StatusCode < 300 then
____print(nil, "[BattlePassServer] Battle Pass Premium куплен для " .. steamId)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_buy_result", {success = true})
self:loadBattlePassData(playerId, steamId)
else
local code = result.StatusCode
local errorMsg = "Ошибка: " .. tostring(code)
local ____tostring_37 = tostring
local ____result_Body_36 = result.Body
if ____result_Body_36 == nil then
____result_Body_36 = ""
end
local rawBody = ____tostring_37(____result_Body_36)
if rawBody ~= "" then
do
pcall(function()
local decoded = {json.decode(rawBody)}
local body = self:pickDecodedJsonRoot(decoded, {"error"})
if body and body.error ~= nil and body.error ~= nil and tostring(body.error) ~= "" then
errorMsg = tostring(body.error)
end
end)
end
end
____print(
nil,
((("[BattlePassServer] Ошибка покупки Premium: " .. errorMsg) .. " (HTTP ") .. tostring(code)) .. ")"
)
CustomGameEventManager:Send_ServerToPlayer(player, "battle_pass_buy_result", {success = false, error = errorMsg})
end
end)
end
function BattlePassServer.prototype.addExperience(self, playerId, amount)
self:sendAddExpRequest(playerId, amount, false)
end
function BattlePassServer.prototype.sendAddExpRequest(self, playerId, amount, alreadyRetriedAfterCreate)
local expAdd = math.max(
0,
math.floor(amount)
)
if expAdd <= 0 then
return
end
local steamId = tostring(PlayerResource:GetSteamAccountID(playerId))
____print(
nil,
((((("[BattlePassServer] Добавляем " .. tostring(expAdd)) .. " опыта Battle Pass игроку ") .. tostring(playerId)) .. " (Steam ID: ") .. steamId) .. ")"
)
local request = CreateHTTPRequest("POST", ((self.serverUrl .. "/battlepass/") .. steamId) .. "/addexp")
setApiHeadersLong(nil, request)
request:SetHTTPRequestRawPostBody(
"application/json",
encodeApiBody(nil, {steam_id = steamId, experience = expAdd})
)
request:Send(function(result)
if result.StatusCode >= 200 and result.StatusCode < 300 then
do
local function ____catch(e)
____print(nil, "[BattlePassServer] Опыт добавлен для " .. steamId)
end
local ____try, ____hasReturned = pcall(function()
local responseData = {json.decode(result.Body)}
local levelUp = responseData.level_up == true
____print(
nil,
(((((("[BattlePassServer] Опыт добавлен для " .. steamId) .. ". Новый уровень: ") .. tostring(responseData.level)) .. ", опыт: ") .. tostring(responseData.experience)) .. ", level_up: ") .. tostring(levelUp)
)
if responseData.level ~= nil and responseData.experience ~= nil then
self:rememberBattlePassSnapshot(
playerId,
parseApiNumber(nil, responseData.level),
parseApiNumber(nil, responseData.experience)
)
end
end)
if not ____try then
____catch(____hasReturned)
end
end
self:loadBattlePassData(playerId, steamId)
elseif result.StatusCode == 404 and not alreadyRetriedAfterCreate then
____print(nil, "[BattlePassServer] addexp 404 (нет battle_pass) — создаём запись и повторяем начисление")
self:createBattlePass(
playerId,
steamId,
function(____, ok)
if ok then
self:sendAddExpRequest(playerId, expAdd, true)
else
____print(nil, "[BattlePassServer] Не удалось создать Battle Pass — опыт за матч не начислен")
end
end
)
else
local bodyStr = result.Body ~= nil and tostring(result.Body) or ""
____print(
nil,
(("[BattlePassServer] Ошибка добавления опыта: HTTP " .. tostring(result.StatusCode)) .. " body=") .. bodyStr
)
end
end)
end
BattlePassServer.REWARD_AMOUNTS = {DONATE_CURRENCY = {
LEVEL_1 = 100,
LEVEL_11 = 100,
LEVEL_21 = 100,
LEVEL_31 = 100,
LEVEL_41 = 100
}, ITEM_AMOUNT = 1, EFFECT_AMOUNT = 1, CARD_AMOUNT = 1}
BattlePassServer.BP_FREE_DUST_LEVELS = {
3,
8,
13,
18,
23,
28,
33,
38,
43,
48
}
BattlePassServer.BP_FREE_PACK_LEVELS = {
10,
20,
30,
40,
50
}
BattlePassServer.BP_PREMIUM_DUST_LEVELS = {
2,
6,
13,
16,
22,
26,
32,
36,
42,
47
}
BattlePassServer.BP_PREMIUM_PACK_LEVELS = {
3,
9,
23,
33,
48
}
BattlePassServer.REWARDS_CONFIG = ____exports.BattlePassServer:buildFreeRewardsConfig()
BattlePassServer.PREMIUM_REWARDS_CONFIG = {
[1] = {type = "donate_currency", amount = ____exports.BattlePassServer.REWARD_AMOUNTS.DONATE_CURRENCY.LEVEL_1},
[2] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(2)
},
[3] = {type = "arcade_pack_premium", amount = 1},
[4] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(4)
},
[5] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(5)
},
[6] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(6)
},
[7] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(7)
},
[8] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(8)
},
[9] = {type = "arcade_pack_premium", amount = 1},
[10] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(10)
},
[11] = {type = "donate_currency", amount = ____exports.BattlePassServer.REWARD_AMOUNTS.DONATE_CURRENCY.LEVEL_11},
[12] = {type = "effect", amount = ____exports.BattlePassServer.REWARD_AMOUNTS.EFFECT_AMOUNT, effect_id = "skin_effect_bp_diretide_emblem"},
[13] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(13)
},
[14] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(14)
},
[15] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(15)
},
[16] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(16)
},
[17] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(17)
},
[18] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(18)
},
[19] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(19)
},
[20] = {type = "effect", amount = ____exports.BattlePassServer.REWARD_AMOUNTS.EFFECT_AMOUNT, effect_id = "skin_effect_bp_diretide_emblem_v1"},
[21] = {type = "donate_currency", amount = ____exports.BattlePassServer.REWARD_AMOUNTS.DONATE_CURRENCY.LEVEL_21},
[22] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(22)
},
[23] = {type = "arcade_pack_premium", amount = 1},
[24] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(24)
},
[25] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(25)
},
[26] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(26)
},
[27] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(27)
},
[28] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(28)
},
[29] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(29)
},
[30] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(30)
},
[31] = {type = "donate_currency", amount = ____exports.BattlePassServer.REWARD_AMOUNTS.DONATE_CURRENCY.LEVEL_31},
[32] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(32)
},
[33] = {type = "arcade_pack_premium", amount = 1},
[34] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(34)
},
[35] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(35)
},
[36] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(36)
},
[37] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(37)
},
[38] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(38)
},
[39] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(39)
},
[40] = {type = "item", amount = ____exports.BattlePassServer.REWARD_AMOUNTS.ITEM_AMOUNT, item_name = "hero_spectre"},
[41] = {type = "donate_currency", amount = ____exports.BattlePassServer.REWARD_AMOUNTS.DONATE_CURRENCY.LEVEL_41},
[42] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(42)
},
[43] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(43)
},
[44] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(44)
},
[45] = {type = "effect", amount = ____exports.BattlePassServer.REWARD_AMOUNTS.EFFECT_AMOUNT, effect_id = "skin_effect_bp_diretide_emblem_v3"},
[46] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(46)
},
[47] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(47)
},
[48] = {type = "arcade_pack_premium", amount = 1},
[49] = {
type = "dust_currency",
amount = ____exports.BattlePassServer:battlePassDustForLevel(49)
},
[50] = {
type = "free_currency",
amount = ____exports.BattlePassServer:battlePassFreeShardsPerLevel(50)
}
}
if IsServer() then
(function()
Timers:CreateTimer(
2,
function()
do
local function ____catch(____error)
____print(
nil,
"[BattlePassServer] Ошибка инициализации: " .. tostring(____error)
)
return true, nil
end
local ____try, ____hasReturned, ____returnValue = pcall(function()
local battlePassServer = ____exports.BattlePassServer:getInstance()
____print(nil, "[BattlePassServer] Успешно инициализирован")
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