From 4cf742321f0433f557d5ff99d0f48874a9c1d759 Mon Sep 17 00:00:00 2001 From: zhouhaihai Date: Wed, 27 Nov 2019 19:55:16 +0800 Subject: [PATCH] pvp --- src/GlobalVar.lua | 2 +- src/ProtocolCode.lua | 12 ++++++++++++ src/RedisKeys.lua | 1 + src/actions/PvpAction.lua | 294 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- src/actions/RoleAction.lua | 50 ++++++++++++++++++++++++++++++++++++++++---------- src/config | 2 +- src/models/Daily.lua | 2 ++ src/models/Role.lua | 4 +--- src/models/RoleCross.lua | 20 ++++++-------------- src/models/RolePlugin.lua | 13 +++++++++++-- src/models/RolePvp.lua | 18 ++++++++++++++---- 11 files changed, 373 insertions(+), 45 deletions(-) diff --git a/src/GlobalVar.lua b/src/GlobalVar.lua index 3c078aa..1f84cef 100644 --- a/src/GlobalVar.lua +++ b/src/GlobalVar.lua @@ -79,7 +79,7 @@ ItemId = { LoveUp = 14, --好感度提升道具 DinerSpTask = 20, -- 餐厅任务采购券 LoveBreak = 21, --好感度突破道具 - PvpKey = 22, -- 开箱钥匙 + PvpKey = 22, -- pvp钥匙 LunchFragment = 23, HeroFC = {700, 701, 702, 703}, -- 通用角色碎片 AdvKey = 80, -- 冒险钥匙 diff --git a/src/ProtocolCode.lua b/src/ProtocolCode.lua index fea8560..51fc6d9 100644 --- a/src/ProtocolCode.lua +++ b/src/ProtocolCode.lua @@ -34,6 +34,7 @@ actionCodes = { Role_achiveRpc = 119, Role_chatRpc = 120, Role_chat = 121, + Role_chatGet = 122, Adv_startAdvRpc = 151, Adv_startHangRpc = 152, @@ -126,6 +127,17 @@ actionCodes = { Friend_pointRpc = 459, Friend_updateProperty = 460, Friend_randomRpc = 461, + + + Pvp_formatCommonRpc = 500, + Pvp_infoRpc = 501, + Pvp_refreshMatchCRpc = 502, + Pvp_buyCountRpc = 503, + Pvp_startBattleRpc = 504, + Pvp_endBattleRpc = 505, + Pvp_rankListRpc = 506, + Pvp_recordListRpc = 507, + } rpcResponseBegin = 10000 diff --git a/src/RedisKeys.lua b/src/RedisKeys.lua index b5f15cd..e63b23e 100644 --- a/src/RedisKeys.lua +++ b/src/RedisKeys.lua @@ -18,6 +18,7 @@ RANK_DINER = {"rank:diner1", "rank:diner2"} -- 餐厅排行榜 两个每天互 RANK_DINER_INFO = "rank:diner:info" RANK_PVP_COMMON = "rank:pvpc" +RECORD_PVP_COMMON = "record:pvpc:%d" RANK_PVP_HIGHT = "rank:pvph" -- -- role -- R_FARM_KEY = "role:%d:farm" diff --git a/src/actions/PvpAction.lua b/src/actions/PvpAction.lua index bd5ecec..2281960 100644 --- a/src/actions/PvpAction.lua +++ b/src/actions/PvpAction.lua @@ -3,10 +3,16 @@ 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 = {} -- 记录战斗数据缓存 function _M.formatCommonRpc(agent , data) local role = agent.role @@ -34,46 +40,314 @@ function _M.formatCommonRpc(agent , data) return true end -function _M.formatHighRpc(agent , data) + +local function getMatchInfo(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 = tonumber(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 pvpTH = role.pvpData:getProperty("pvpTH") + 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 = tonumber(redret[1] or 0) + 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.score = score + response.rank = rank + response.matches = getMatchInfo(pvpMC, _pvpBattleInfoCacheC) - role.pvpData:updateProperty({field = "pvpTH", value = pvpTH}) - SendPacket(actionCodes.Pvp_formatHighRpc, '') + elseif ptype == 2 then -- 高级pvp + return + else + return + end + SendPacket(actionCodes.Pvp_infoRpc, MsgPack.pack(response)) return true end -function _M.refreshMatchRpc(agent, data) +function _M.refreshMatchCRpc(agent, data) local role = agent.role local msg = MsgPack.unpack(data) - local pvpData = role.pvpData - pvpData:refreshMatchC() + role:refreshPvpMatchC() + + local pvpMC = role:getProperty("pvpMC") + local matches = getMatchInfo(pvpMC, _pvpBattleInfoCacheC) - SendPacket(actionCodes.Pvp_refreshMatchRpc, '') + 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 matchInfo + + if revenge then --复仇 + if not _pvpRecordInfoCache[idx] then return end + if _pvpRecordInfoCache[idx].t == 1 then + matchInfo = _pvpRecordBattleInfoCache[_pvpRecordInfoCache[idx].id] + elseif _pvpRecordInfoCache[idx].t == 2 then + matchInfo = {robot = _pvpRecordInfoCache[idx].id} + end + else --打正常 + local pvpMC = role:getProperty("pvpMC") + if not pvpMC[idx] then return 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 matchInfo then return end + + -- 次数扣一波 + 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 end + role:costItems(cost) + else + role.dailyData:updateProperty({field = "pvpFree", delta = 1}) + end + + local key = tostring(math.random()) + _pvpStartBattleCache = {idx = idx, key = key, revenge = revenge} + + SendPacket(actionCodes.Pvp_startBattleRpc, MsgPack.pack({matchInfo = matchInfo, key = key})) + return true end function _M.endBattleRpc(agent, data) + local role = agent.role + local roleId = role:getProperty("id") + local msg = MsgPack.unpack(data) -end + if not msg.key or not _pvpStartBattleCache or msg.key ~= _pvpStartBattleCache.key then + return 1 + end + if not msg.idx or not msg.idx ~= _pvpStartBattleCache.idx then + return 2 + end -function _M.matchListRpc(agent, data) + local isWin = msg.starNum and msg.starNum > 0 + + local revenge = _pvpStartBattleCache.revenge + local match + if revenge then + match = _pvpRecordInfoCache[msg.idx] + 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 now = skynet.timex() + 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:trim(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:trim(dbKey, 0, 9) + end + 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 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 = tonumber(redret[1] or 0) + local rank = tonumber(redret[2] or -2) + 1 --排名 1 - ... -1 未上榜 没打过pvp + + local rankList = {} + for i = 1, #redret[3], 2 do + local roleId = tonumber(redret[i]) + local score = tonumber(redret[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 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 <= 24 * 3600 then -- 大于一天的弃之 + table.insert(tempList, one) + end + end + _pvpRecordInfoCache = tempList + + recordList = getMatchInfo(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 \ No newline at end of file diff --git a/src/actions/RoleAction.lua b/src/actions/RoleAction.lua index 0af9643..ea2a949 100644 --- a/src/actions/RoleAction.lua +++ b/src/actions/RoleAction.lua @@ -222,7 +222,11 @@ function _M.loginRpc( agent, data ) msgs = {} end worldChatResponse.worldChats = msgs - worldChatResponse.p2pChats = redisproxy:lrange(CHAT_OFFLINE:format(roleId), 0, -1) + local redret = redisproxy:pipelining(function(red) + red:lrange(CHAT_OFFLINE:format(roleId), 0, -1) + red:del(CHAT_OFFLINE:format(roleId)) + end) + worldChatResponse.p2pChats = redret[1] worldChatResponse.chatWave = curWave + 1 curWave = curWave + 1 @@ -236,6 +240,13 @@ function _M.loginRpc( agent, data ) agent.role = role start_agent_timer() + + + -- 玩家登陆做的一些操作 + role:saveHangTeam() + role:savePvpCTeam() + + -- role:log("login", { ip = agent.ip, diamond = role:getProperty("diamond"), reDiamond = role:getProperty("reDiamond")}) return true @@ -644,23 +655,36 @@ function _M.chatRpc(agent, data) [2] = function () local objectId = msg.roleId response.objId = objectId - if 0 == redisproxy:exists(string.format("role:%d", objectId)) then - result = 1 + local redret = redisproxy:pipelining(function(red) + red:exists(string.format("role:%d", objectId)) + red:sismember(FRIEND_BLACK_KEY:format(roleId), objectId) + red:sismember(FRIEND_BLACK_KEY:format(objectId), roleId) + end) + if redret[1] ~= 1 then + result = 1 + return + end + -- 你把对方拉黑拉黑 + if redret[2] == 1 then + result = 2 return end + -- 对方把你拉黑 + local isBlock = redret[3] == 1 - -- 若在线,实时发送聊天信息 - local agent = datacenter.get("agent", objectId) local bin = MsgPack.pack(response) - if agent then - SendPacket(actionCode, bin, agent.fd) - else + if not isBlock then redisproxy:pipelining(function(red) red:rpush(CHAT_OFFLINE:format(objectId), bin) - red:ltrim(CHAT_OFFLINE:format(objectId), 0, 200) + red:ltrim(CHAT_OFFLINE:format(objectId), -200, -1) end) + -- 若在线,实时发送聊天信息 + local agent = datacenter.get("agent", objectId) + if agent then + SendPacket(actionCodes.Role_chat, bin, agent.fd) + end end - SendPacket(actionCode, bin, fromFd) + SendPacket(actionCodes.Role_chat, bin) end, } if not check[cmd] then return end @@ -672,5 +696,11 @@ function _M.chatRpc(agent, data) return true end +function _M.chatGet(agent, data) + local role = agent.role + local roleId = role:getProperty("id") + redisproxy:del(CHAT_OFFLINE:format(roleId)) + return true +end return _M \ No newline at end of file diff --git a/src/config b/src/config index 93a06b2..e3566c0 100644 --- a/src/config +++ b/src/config @@ -7,7 +7,7 @@ bootstrap = "snlua bootstrap" -- The service for bootstrap logd = 0 -- 是否开启日志 servId = 1 baseId = 0 -codeurl = "127.0.0.1:8686" +codeurl = "120.26.43.151:9090" lua_path = root .."skynet/lualib/?.lua;"..root.."src/?.lua;"..root.."tools/?.lua" luaservice = root.."skynet/service/?.lua;"..root.."src/?.lua" diff --git a/src/models/Daily.lua b/src/models/Daily.lua index 9fbc4e2..37f7156 100644 --- a/src/models/Daily.lua +++ b/src/models/Daily.lua @@ -18,6 +18,7 @@ Daily.schema = { bonusC = {"table", {}}, -- 奖励副本 次数 {[type] = {c = 0, b = 0}} giveFP = {"table", {}}, -- 给谁送过心心 getFP = {"table", {}}, -- 领过谁的心心 + pvpFree = {"number", 0}, -- pvp使用免费次数 } function Daily:updateProperty(params) @@ -65,6 +66,7 @@ function Daily:data() bonusC = self:getProperty("bonusC"), giveFP = self:getProperty("giveFP"), getFP = self:getProperty("getFP"), + pvpFree = self:getProperty("pvpFree"), } end diff --git a/src/models/Role.lua b/src/models/Role.lua index 19d066e..7c42822 100644 --- a/src/models/Role.lua +++ b/src/models/Role.lua @@ -142,9 +142,7 @@ function Role:updateProperty(params) end function Role:updateProperties(params, notNotify) - for field, value in pairs(params) do - self:setProperty(field, value) - end + self:setProperties(params) if not notNotify then SendPacket(actionCodes.Role_updateProperties, MsgPack.pack(params)) end diff --git a/src/models/RoleCross.lua b/src/models/RoleCross.lua index d62c7d6..d3c1ed9 100644 --- a/src/models/RoleCross.lua +++ b/src/models/RoleCross.lua @@ -29,20 +29,15 @@ RoleCross.bind = function (Role) return self:getProperty("pvpTBVC") ~= 0 and self:getProperty("pvpTBC") or self:getProperty("hangTB") end - -- pvp 战斗数据 - function Role:pvpCBattleInfo() - return self:getProperty("pvpTBC") - end - - -- pvp 简略数据 - function Role:pvpCSInfo() + -- pvp 数据 + function Role:pvpCInfo() local info = { name = self:getProperty("name"), level = self:getProperty("level"), headId = self:getProperty("headId"), - ltime = self:getProperty("ltime"), battleV = self:getProperty("pvpTBVC"), heros = self:getProperty("pvpTSC"), + battleInfo = self:getProperty("pvpTBC") } return info end @@ -149,18 +144,15 @@ function CMD.friendBattleInfo(roleId) return next(info.pvpTBC) and info.pvpTBC or info.hangTB end -function CMD.pvpCBattleInfo(roleId) - return CMD.getProperty(roleId, "pvpTBC") -end - -function CMD.pvpCSInfo(roleId) - local info = CMD.getProperties(roleId, {"name", "level", "headId", "pvpTBVC", "pvpTSC"}) +function CMD.pvpCInfo(roleId) + local info = CMD.getProperties(roleId, {"name", "level", "headId", "pvpTBVC", "pvpTSC", "pvpTBC"}) return { name = info.name, level = info.level, headId = info.headId, battleV = info.pvpTBVC, heros = info.pvpTSC, + battleInfo = info.pvpTBC } end diff --git a/src/models/RolePlugin.lua b/src/models/RolePlugin.lua index 7996cb3..5d2fdb4 100644 --- a/src/models/RolePlugin.lua +++ b/src/models/RolePlugin.lua @@ -843,8 +843,13 @@ function RolePlugin.bind(Role) return battleV end + -- 不传参数 只修改保存的阵容信息 function Role:saveHangTeam(team) - self:updateProperty({field = "hangTeam", value = team}) + if not team then + team = self:getProperty("pvpTSC") + else + self:updateProperty({field = "hangTeam", value = team}) + end self:setProperties({ hangTS = self:getTeamHerosInfo(team.heros), hangTB = self:getTeamBattleInfo(team), @@ -853,7 +858,11 @@ function RolePlugin.bind(Role) end function Role:savePvpCTeam(team) - self:updateProperty({field = "pvpTSC", value = team}) + if not team then + team = self:getProperty("pvpTSC") + else + self:updateProperty({field = "pvpTSC", value = team}) + end self:setProperties({ pvpTSC = self:getTeamHerosInfo(team.heros), pvpTBC = self:getTeamBattleInfo(team), diff --git a/src/models/RolePvp.lua b/src/models/RolePvp.lua index c68f550..fd2d3d6 100644 --- a/src/models/RolePvp.lua +++ b/src/models/RolePvp.lua @@ -24,15 +24,18 @@ function Role:changePvpScoreCommon(matchId, isWin) local isPlayer = matchId ~= -1 local redret = redisproxy:pipelining(function(red) red:zscore(RANK_PVP_COMMON, roleId) + red:zrevrank(RANK_PVP_COMMON, roleId) if isPlayer then red:zscore(RANK_PVP_COMMON, matchId) end end) local myScore = unpackScore(redret[1]) + local oldMyRank = tonumber(redret[2] or -2) + 1 local matchScore = PVP_RANK_ROBOT_SCORE if isPlayer then - matchScore = unpackScore(redret[2]) + matchScore = unpackScore(redret[3]) end + local oldmyScore, oldMatchScore = myScore, matchScore if isWin then local scoreChange = math.ceil(60 / (1 + 10 ^ ((myScore - matchScore) / 400))) @@ -53,14 +56,21 @@ function Role:changePvpScoreCommon(matchId, isWin) if isPlayer then red:zadd(RANK_PVP_COMMON, packScore(matchScore, now), matchId) end + red:zrevrank(RANK_PVP_COMMON, roleId) end) - self:refreshMatchC(myScore) - return myScore + local myRank + if isPlayer then + myRank = tonumber(redret[3] or -2) + 1 + else + myRank = tonumber(redret[2] or -2) + 1 + end + self:refreshPvpMatchC(myScore) + return myScore, matchScore, oldmyScore, oldMatchScore, myRank, oldMyRank end function Role:refreshPvpMatchC(score) local roleId = self:getProperty("id") - local score = score or redisproxy:zscore(RANK_PVP_COMMON, roleId) + local score = score or redisproxy:zscore(RANK_PVP_COMMON, roleId) or 0 local function getPlayers(levels) local redret = redisproxy:pipelining(function(red) -- libgit2 0.21.2