local ipairs = ipairs local table = table local math = math local redisproxy = redisproxy local MsgPack = MsgPack local httpc = require("http.httpc") local remoteUrl = skynet.getenv("codeurl") local _M = {} local _pvpBattleInfoCacheC = {} --查询列表 缓存pvp战斗相关数据缓存 local _pvpStartBattleCache = nil -- local _pvpRecordInfoCache = {} -- 记录缓存 local _pvpRecordBattleInfoCache = {} -- 记录战斗数据缓存 local _revengeRecord = {} -- 复仇对单人1分钟间隔 local RevengeWaitTime = 60 function _M.formatCommonRpc(agent , data) local role = agent.role local roleId = role:getProperty("id") local msg = MsgPack.unpack(data) local pvpTC = role:getProperty("pvpTC") for slot, heroId in pairs(msg.heros or {}) do if not role.heros[heroId] then return end end if not msg.heros or not next(msg.heros) then return end local supports = {} for slot, support in pairs(msg.supports) do if slot ~= 1 and slot ~= 2 then return end local level = role.dinerData:getProperty("dishTree"):getv(support, 0) if level <= 0 then return end supports[slot] = support end table.clear(pvpTC) pvpTC.heros = {} for slot, heroId in pairs(msg.heros) do pvpTC.heros[slot] = heroId end pvpTC.leader = msg.leader pvpTC.supports = supports role:savePvpCTeam(pvpTC) SendPacket(actionCodes.Pvp_formatCommonRpc, '') return true end local function getMatchInfo(role, pvpList, battleCache) table.clear(battleCache) local redret = redisproxy:pipelining(function(red) for _, info in ipairs(pvpList) do if info.t == 1 then red:zscore(RANK_PVP_COMMON, info.id) end end end) local matches = {} local curIdx = 1 for idx, info in ipairs(pvpList) do local curInfo = {idx = idx} if info.t == 1 then --玩家 curInfo.roleId = info.id curInfo.score = role:unpackPvpScore(redret[curIdx] or 0) curIdx = curIdx + 1 -- name, level, headId, battleV, heros local online, roleInfo = rpcRole(curInfo.roleId, "pvpCInfo") for k , v in pairs(roleInfo) do if k == "battleInfo" then battleCache[curInfo.roleId] = v else curInfo[k] = v end end elseif info.t == 2 then -- robot curInfo.robot = info.id end table.insert(matches, curInfo) end return matches end -- 获取pvp信息 function _M.infoRpc(agent, data) local role = agent.role local roleId = role:getProperty("id") local msg = MsgPack.unpack(data) local ptype = msg.ptype or 1 local response = {} if ptype == 1 then -- 普通pvp local redret = redisproxy:pipelining(function(red) red:zscore(RANK_PVP_COMMON, roleId) red:zrevrank(RANK_PVP_COMMON, roleId) end) local score = role:unpackPvpScore(redret[1]) local rank = tonumber(redret[2] or -2) + 1 --排名 1 - ... -1 未上榜 没打过pvp local pvpMC = role:getProperty("pvpMC") if not next(pvpMC) then --没有分配过对手 role:refreshPvpMatchC(score) pvpMC = role:getProperty("pvpMC") end if not next(pvpMC) then return end response.rank = rank response.score = score response.matches = getMatchInfo(role, pvpMC, _pvpBattleInfoCacheC) elseif ptype == 2 then -- 高级pvp return else return end SendPacket(actionCodes.Pvp_infoRpc, MsgPack.pack(response)) return true end function _M.refreshMatchCRpc(agent, data) local role = agent.role local msg = MsgPack.unpack(data) role:refreshPvpMatchC() local pvpMC = role:getProperty("pvpMC") local matches = getMatchInfo(role, pvpMC, _pvpBattleInfoCacheC) SendPacket(actionCodes.Pvp_refreshMatchCRpc, MsgPack.pack({matches = matches})) return true end function _M.buyCountRpc(agent, data) local role = agent.role local msg = MsgPack.unpack(data) local count = msg.count if math.illegalNum(count, 1, math.huge) then return 1 end local cost = {[ItemId.Diamond] = globalCsv.pvp_buy_cost * count} if not role:checkItemEnough(cost) then return 2 end role:costItems(cost) role:award({[ItemId.PvpKey] = count}) SendPacket(actionCodes.Pvp_buyCountRpc, '') return true end function _M.startBattleRpc(agent, data) local role = agent.role local msg = MsgPack.unpack(data) local idx = msg.idx local revenge = msg.revenge local pvpTC = role:getProperty("pvpTC") if not pvpTC.heros or not next(pvpTC.heros) then return 1 end local matchInfo, result, key, wait local now = skynet.timex() if revenge then --复仇 local temp = _pvpRecordInfoCache[idx] if not temp then return 2 end if not _revengeRecord[temp.id] or now >= _revengeRecord[temp.id] then if temp.t == 1 then matchInfo = _pvpRecordBattleInfoCache[temp.id] elseif temp.t == 2 then matchInfo = {robot = temp.id} end else result = 1 wait = _revengeRecord[temp.id] - now end else --打正常 local pvpMC = role:getProperty("pvpMC") if not pvpMC[idx] then return 3 end if pvpMC[idx].t == 1 then matchInfo = _pvpBattleInfoCacheC[pvpMC[idx].id] elseif pvpMC[idx].t == 2 then matchInfo = {robot = pvpMC[idx].id} end end if not result and not matchInfo then return 4 end if not result then -- 次数扣一波 local pvpFree = role.dailyData:getProperty("pvpFree") if pvpFree >= globalCsv.pvp_battle_free_count then local cost = {[ItemId.PvpKey] = 1} if not role:checkItemEnough(cost) then return 5 end role:costItems(cost) else role.dailyData:updateProperty({field = "pvpFree", delta = 1}) end key = tostring(math.random()) _pvpStartBattleCache = {idx = idx, key = key, revenge = revenge} role:checkTaskEnter("PvpBattle") end SendPacket(actionCodes.Pvp_startBattleRpc, MsgPack.pack({matchInfo = matchInfo, key = key, result = result, wait = wait})) return true end function _M.endBattleRpc(agent, data) local role = agent.role local roleId = role:getProperty("id") local msg = MsgPack.unpack(data) if not msg.key or not _pvpStartBattleCache or msg.key ~= _pvpStartBattleCache.key then return 1 end if not msg.idx or msg.idx ~= _pvpStartBattleCache.idx then return 2 end local isWin = msg.starNum and msg.starNum > 0 local now = skynet.timex() local revenge = _pvpStartBattleCache.revenge local match if revenge then match = _pvpRecordInfoCache[msg.idx] _revengeRecord[match.id] = now + RevengeWaitTime -- 1分钟内不能再打 else local pvpMC = role:getProperty("pvpMC") match = pvpMC[msg.idx] end if not match then return end local temp = string.randWeight(csvdb["player_expCsv"][role:getProperty("level")].pvpBonus, true) local reward = role:award({[temp[1]] = temp[2]}) local myScore, matchScore, oldmyScore, oldMatchScore, myRank, oldMyRank = role:changePvpScoreCommon(match.t == 1 and match.id or -1, isWin) _pvpBattleInfoCacheC = {} --重新发阵容了 没毛病 _pvpRecordInfoCache = {} -- 记录刷新了 _pvpRecordBattleInfoCache = {} -- 取新纪录的时候搞 _pvpStartBattleCache = nil -- 请求上传录像 local params = { ["roleid"] = roleId, ["key"] = "zhaolugame20191016", ["time"] = now, } local status, body = httpc.get(remoteUrl, "/applyvideo?" .. httpGetFormatData(params), {}, {}) local video = nil if tonumber(status) == 200 then local result = json.decode(body) video = result.name else skynet.error("applyvideo", "error", status, body, content) end -- 加入战斗记录 redisproxy:pipelining(function(red) local dbKey = string.format(RECORD_PVP_COMMON, roleId) red:lpush(dbKey, MsgPack.pack({ id = match.id, t = match.t, win = isWin, time = now, video = video, sdelta = myScore - oldmyScore, })) red:ltrim(dbKey, 0, 9) -- 对方加入战斗记录 if match.t == 1 then dbKey = string.format(RECORD_PVP_COMMON, match.id) red:lpush(dbKey, MsgPack.pack({ id = roleId, t = 1, win = not isWin, time = now, video = video, sdelta = matchScore - oldMatchScore, })) red:ltrim(dbKey, 0, 9) end end) if isWin then role:checkTaskEnter("PvpWin", {score = myScore}) end SendPacket(actionCodes.Pvp_endBattleRpc, MsgPack.pack({ reward = reward, myScore = myScore, matchScore = matchScore, oldmyScore = oldmyScore, oldMatchScore = oldMatchScore, myRank = myRank, oldMyRank = oldMyRank, video = video, })) return true end function _M.rankListRpc(agent, data) local role = agent.role local roleId = role:getProperty("id") local msg = MsgPack.unpack(data) local ptype = msg.ptype or 1 local response = {} if ptype == 1 then -- 普通pvp local redret = redisproxy:pipelining(function(red) red:zscore(RANK_PVP_COMMON, roleId) red:zrevrank(RANK_PVP_COMMON, roleId) red:zrevrange(RANK_PVP_COMMON, 0, 99, "WITHSCORES") end) local score = role:unpackPvpScore(redret[1]) local rank = tonumber(redret[2] or -2) + 1 --排名 1 - ... -1 未上榜 没打过pvp local rankList = {} for i = 1, #redret[3], 2 do local roleId = tonumber(redret[3][i]) local score = role:unpackPvpScore(redret[3][i + 1]) local online, curInfo = rpcRole(roleId, "friendSInfo") curInfo.score = score curInfo.roleId = roleId table.insert(rankList, curInfo) end response.score = score response.rank = rank response.rankList = rankList elseif ptype == 2 then -- 高级pvp return else return end SendPacket(actionCodes.Pvp_rankListRpc, MsgPack.pack(response)) return true end function _M.recordListRpc(agent, data) local role = agent.role local roleId = role:getProperty("id") local msg = MsgPack.unpack(data) local ptype = msg.ptype or 1 local recordList = {} local now = skynet.timex() if ptype == 1 then -- 普通pvp local rlist = redisproxy:lrange(string.format(RECORD_PVP_COMMON, roleId), 0 , 9) local tempList = {} for _, temp in ipairs(rlist) do local one = MsgPack.unpack(temp) if now - one.time <= globalCsv.pvp_record_keep_time then -- 大于一天的弃之 table.insert(tempList, one) end end _pvpRecordInfoCache = tempList recordList = getMatchInfo(role, tempList, _pvpRecordBattleInfoCache) for idx, info in ipairs(recordList) do local temp = tempList[idx] info.win = temp.win info.time = temp.time info.video = temp.video info.sdelta = temp.sdelta end elseif ptype == 2 then -- 高级pvp return else return end SendPacket(actionCodes.Pvp_recordListRpc, MsgPack.pack({list = recordList})) return true end return _M