6d95836d11
Empty Russian and Chinese locale files so English is used regardless of client language. Translate all CustomGameEventManager error messages, SendCustomMessage calls, and deck/card UI strings to English. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2192 lines
95 KiB
Lua
2192 lines
95 KiB
Lua
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 = CreateHTTPRequestScriptVM("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 = CreateHTTPRequestScriptVM("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 = CreateHTTPRequestScriptVM("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 = "Quest not found"})
|
||
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 = "Quest not completed or already claimed"})
|
||
end
|
||
return
|
||
end
|
||
____print(nil, "[BattlePassServer] Отправляем запрос на клейм квеста " .. questId)
|
||
local request = CreateHTTPRequestScriptVM("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 = "Error: " .. 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 = CreateHTTPRequestScriptVM("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 = "Data processing 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 = "Server unavailable"})
|
||
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 = "Data parsing 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 = "Server 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 = CreateHTTPRequestScriptVM("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 = "Failed to create 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 = CreateHTTPRequestScriptVM("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 = "Error: " .. 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 = CreateHTTPRequestScriptVM("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 = CreateHTTPRequestScriptVM("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 = CreateHTTPRequestScriptVM("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 = "Data processing 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 = "Error: " .. 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 = CreateHTTPRequestScriptVM("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 = "Error: " .. 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 = CreateHTTPRequestScriptVM("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
|