local skynet = require "skynet" local battleCore = require "battle.battleCore" local battleLog = require "battle.battleLog" local battleCode = require "battle.battleCode" local battleDefine = require "battle.battleDefine" local nodeMgr = require "nodeMgr" local httpc = require "http.httpc" local md5 = require "md5" local machine = require "machine" local code = require "code" local util_user = require "utils.util_user" local gameConst = require("const.gameConst") local battleAdapt = require "adapt.battleAdapt" local sessionData = require("data.session") local battleData = require("data.battle") local nodename = skynet.getenv("nodeName") local root = class("Battle") function root:ctor(matchInfo, battleParams, settleNodeInfo) self.matchNodeInfo = {} self.matchNodeInfo.nodeName = matchInfo.matchNode self.matchNodeInfo.agent = matchInfo.matchAgent self.roomId = matchInfo.roomId self.matchId = matchInfo.matchId self.battleId = matchInfo.battleId self.isMatchSettle = matchInfo.isMatchSettle -- 结算经过业务服 self.settleNodeInfo = settleNodeInfo -- 结算节点 self.battleParams = battleParams local w = battleParams.w local h = battleParams.h local debugJsonObj = battleParams.debugJsonObj self.core = battleCore.new(self, matchInfo.battleReal, matchInfo.battleType, w, h, debugJsonObj) self.record = {} self.isActive = true end -- 获取战斗标示 function root:get_core_id() return string.format("%s:%s:%s", self.matchNodeInfo.nodeName, self.matchId, self.battleId) end function root:enableRecord() return true end function root:addRecord(protoName, msg) if self:enableRecord() then table.insert(self.record, {proto = protoName, data = msg}) end end local protos = { "on_battle_qipan_info", "on_battle_operate_info", "on_battle_start", "on_battle_finish", "on_battle_attack", "on_battle_attack_finish", "on_battle_create_info" } function root:notifyPlayer(uid, protoName, msg) if uid == nil or is_robot(uid) or is_empty(protoName) then return end local uidList = self.core:get_real_uid_list() if uidList[1] == uid and table.include(protos, protoName) then self:addRecord(protoName, msg) end util_user:user_proto_notify(uid, protoName, msg) end -- game节点结算 function root:game_player_settle(uid, msg) -- 机器人 if uid == nil or is_robot(uid) then return end -- 玩家不在线 local nodeInfo = util_user:user_get_cluster_info(uid, "game") if not nodeMgr.is_node_info_valid(nodeInfo) then nodeMgr.send("game1_1", ".settleSrv", "offline_settle", uid, msg) return end util_user:user_send_game_agent(uid, "battle.settleBattle", msg) end function root:notifyClientLog(uid, logStr) if uid == nil or is_robot(uid) or is_empty(logStr) then return end battleLog:logClient(logStr) -- TODO: Debug 测试代码,上线前修改过来. util_user:user_notify_client_log(uid, logStr) end function root:recordOpenLog(...) local logUtil = require "utils.serverLogUtil" logUtil.logOpen(...) end function root:logEvent(...) util_user:log_event(...) end function root:getBattleNode() return nodename end function root:getBattleId() return self.battleId end function root:getBattleParams() return self.battleParams end local GAME_SALT_MD5 = "0bdb9a5863c8c9063a42f38a9d5166fe" -- 游戏服加盐 md5 local function sendRecord(battleNode, battleStartTime, battleId, version, record) local server = machine.get("record_server") if is_nil(server) then return end local url = "/record/add?sign=" local head = {["Content-Type"] = "application/json"} local body = cjson_encode( { node = tostring(battleNode), startTime = tonumber(battleStartTime), id = tonumber(battleId), version = tostring(version), record = cjson_encode(record) } ) url = url .. md5.sumhexa(body .. GAME_SALT_MD5) local ok, errCode, response = pcall(httpc.request, "POST", server, url, nil, head, body) if not ok then battleLog:logError( string.format( "添加录像失败 battleNode=%s battleStartTime=%s battleId=%s version=%s", battleNode, battleStartTime, battleId, version ) ) end if errCode ~= 200 then battleLog:logError( string.format( "添加录像失败 battleNode=%s battleStartTime=%s battleId=%s version=%s response=%s", battleNode, battleStartTime, battleId, version, tostring(response and cjson_decode(response)) ) ) end end -- 开始战斗 function root:startBattle(playerList, viewerList) local battleInfo = { matchId = self.matchId, battleId = self.battleId, nodeName = nodename, agent = skynet.self() } for _, v in ipairs(playerList) do if not is_robot(v.uid) then sessionData:user_update_cluster_info(v.uid, "battle", battleInfo) end end self.core:startBattle(playerList, viewerList) end -- 结算 function root:settleBattle(result) -- 测试战斗类型 if battleAdapt:isAiTestBattle(self.core.battleType) then log.warning( "settleBattle battleId[%s] settleNodeInfo[%s]", tostring(self.battleId), tostring(self.settleNodeInfo) ) if nodeMgr.is_node_info_valid(self.settleNodeInfo) then nodeMgr.send_with_node_info(self.settleNodeInfo, "settle", result) else nodeMgr.send("test", ".aiSrv", "settle", result) end return end -- 组队 -- 业务服结算 if self.isMatchSettle then nodeMgr.send_with_node_info(self.matchNodeInfo, "match_settle", self.roomId, result) return end for _, v in ipairs(self.core:getAllPlayer()) do self:game_player_settle(v.uid, result) end end -- 消耗战斗 function root:dismissBattle(reason) self.isActive = false battleLog:logWarning(string.format("开始销毁对战服务并退出 battleId=%s reason=%s", self.battleId, reason)) nodeMgr.send_with_node_info(self.matchNodeInfo, "destory_battle", self.roomId) local uidList = self.core:get_real_uid_list() for _, v in ipairs(uidList) do -- 清除玩家战斗节点信息 battleData:user_clear_battle_info(v) self:notifyPlayer(v, "on_battle_finish", {code = battleCode.OK}) end if self:enableRecord() then sendRecord(self:getBattleNode(), self.core.battleStartTime, self:getBattleId(), 1.0, self.record) end skynet.call(".BattleMgr", "lua", "battleLeave", self.battleId, skynet.self()) end function root:loginBattle(uid) battleLog:logInfo(string.format("玩家%d登入对战", uid)) local playerData = self.core:getPlayer(uid) if not playerData then -- 围观进入 self.core:viewerLoginBattle(uid) return end self.core:loginBattle(playerData) -- self:playFinish(uid, self.core:getCurRound()) end function root:logoutBattle(uid) battleLog:logInfo(string.format("玩家%d登出对战", uid)) local playerData = self.core:getPlayer(uid) if not playerData then return end self.core:logoutBattle(playerData) -- self.core:dismissBattle("force") end -- 玩家是否在战斗中 function root:is_user_in_battle(uid) local playerData = self.core:getPlayer(uid) if playerData then return true end return false end function root:operate(uid, ids, exSkillGridId) if not ids or #ids < battleDefine.MIN_LINK_BLOCK then return {code = battleCode.BATTLE_COUNT_LESS} end local playerData = self.core:getPlayer(uid) if not playerData then return {code = battleCode.BATTLE_PLAYER_NOT_EXIST} end if self.core:getNextLinkUid() ~= uid then return {code = battleCode.BATTLE_ROUND_ERR} end if self.core:isPlayerOperated(playerData) then return {code = battleCode.BATTLE_OPERATED} end if not self.core:operate(playerData, ids, exSkillGridId) then if IS_TEST then self.core:sendTestGrids(playerData) end return {code = battleCode.BATTLE_CANNOT_LINK} end return {code = battleCode.OK} end function root:playFinish(uid, round) local playerData = self.core:getPlayer(uid) if not playerData then return {code = battleCode.BATTLE_PLAYER_NOT_EXIST} end if self.core:getCurRound() ~= round then return {code = battleCode.BATTLE_ROUND_EXPIRED} end self.core:playFinish(playerData, uid, round) return {code = battleCode.OK} end -- 玩家托管 function root:auto_link(uid, isAuto) local playerData = self.core:getPlayer(uid) if not playerData then return {code = battleCode.BATTLE_PLAYER_NOT_EXIST} end self.core:updateAutoLink(playerData, isAuto) return {code = code.OK} end function root:info(uid) local playerData = self.core:getPlayer(uid) if not playerData then return {code = battleCode.BATTLE_PLAYER_NOT_EXIST} end self.core:info(playerData) return {code = battleCode.OK} end function root:debug(uid, debugType, debugArgs) local playerData = self.core:getPlayer(uid) if not playerData then return {code = battleCode.BATTLE_PLAYER_NOT_EXIST} end local errorMsg if IS_TEST then errorMsg = self.core:debug(playerData, debugType, debugArgs) end return {code = battleCode.OK, errorMsg = errorMsg} end function root:chat(uid, id, text) local playerData = self.core:getPlayer(uid) if not playerData then return {code = battleCode.BATTLE_PLAYER_NOT_EXIST} end self.core:chat(playerData, id, text) return {code = battleCode.OK} end function root:getOverview(uid) local playerData = self.core:getPlayer(uid) if not playerData then return {code = battleCode.BATTLE_PLAYER_NOT_EXIST} end local msg = self.core:getOverview(playerData) msg.code = battleCode.OK return msg end function root:addViewers(uid) self.core:addViewers(uid) end function root:deleteViewers(uid) self.core:deleteViewers(uid) end -- 测试对战服务是否还在 function root:ping(uid) local playerData = self.core:getPlayer(uid) return playerData and true or false end function root:fastSettle(uid) log.info("battle fastSettle uid = %s", tostring(uid)) self.core:settleBattle(2, nil, uid) end -- 服务端是否启用AI function root:isServerBattleAiOpen() return true end return root