local RolePvp = {} RolePvp.bind = function (Role) local PVP_RANK_TIME_SORT_STD = 1924876800 -- 2030-12-31 00:00:00 local PVP_RANK_TIME_SORT_PLACE = 1000000 -- 时间戳占据 6位数 local PVP_RANK_TIME_SORT_PRECISION = 360 -- 时间精度 每6分钟忽略差异 local PVP_RANK_ROBOT_SCORE = globalCsv.pvp_base_score -- 机器人积分 function Role:unpackPvpScore(score) if not score then return globalCsv.pvp_base_score end score = tonumber(score) return math.floor(score / PVP_RANK_TIME_SORT_PLACE) end function Role:packPvpScore(score, now) now = now or skynet.timex() return math.floor(score * PVP_RANK_TIME_SORT_PLACE + (PVP_RANK_TIME_SORT_STD - now) / PVP_RANK_TIME_SORT_PRECISION) end function Role:changePvpScoreCommon(matchId, isWin) local roleId = self:getProperty("id") 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 = self:unpackPvpScore(redret[1]) local oldMyRank = tonumber(redret[2] or -2) + 1 local matchScore = PVP_RANK_ROBOT_SCORE if isPlayer then matchScore = self:unpackPvpScore(redret[3]) end local oldmyScore, oldMatchScore = myScore, matchScore if isWin then local scoreChange = math.ceil(60 / (1 + 10 ^ ((myScore - matchScore) / 400))) myScore = myScore + scoreChange matchScore = matchScore - scoreChange else local scoreChange = math.ceil(60 / (1 + 10 ^ ((matchScore - myScore) / 400))) myScore = myScore - scoreChange matchScore = matchScore + scoreChange end myScore = math.max(myScore, 0) matchScore = math.max(matchScore, 0) local now = skynet.timex() redret = redisproxy:pipelining(function(red) red:zadd(RANK_PVP_COMMON, self:packPvpScore(myScore, now), roleId) if isPlayer then red:zadd(RANK_PVP_COMMON, self:packPvpScore(matchScore, now), matchId) end red:zrevrank(RANK_PVP_COMMON, roleId) end) 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") score = score or self:unpackPvpScore(redisproxy:zscore(RANK_PVP_COMMON, roleId)) local function getPlayers(levels) local redret = redisproxy:pipelining(function(red) for _, level in ipairs(levels) do local low, high = table.unpack(level) red:zadd(RANK_PVP_COMMON, low * PVP_RANK_TIME_SORT_PLACE, "std_temp1") red:zadd(RANK_PVP_COMMON, high * PVP_RANK_TIME_SORT_PLACE + PVP_RANK_TIME_SORT_PLACE - 1, "std_temp2") red:ZREVRANK(RANK_PVP_COMMON, "std_temp1") red:ZREVRANK(RANK_PVP_COMMON, "std_temp2") end red:zrem(RANK_PVP_COMMON, "std_temp1", "std_temp2") end) local PreGetCount = 7 local redret = redisproxy:pipelining(function(red) for idx, level in ipairs(levels) do local rank1 = tonumber(redret[(idx - 1) * 4 + 3]) local rank2 = tonumber(redret[(idx - 1) * 4 + 4]) if rank1 - rank2 > PreGetCount then rank2 = math.randomInt(rank2, rank1 - PreGetCount + 1) rank1 = rank2 + PreGetCount - 1 end red:ZREVRANGE(RANK_PVP_COMMON, rank2, rank1) end end) return redret end local findIdx = #globalCsv.pvp_division for idx, limit in ipairs(globalCsv.pvp_division) do if score < limit then findIdx = idx - 1 break end end local levels = { {}, {}, {} } if globalCsv.pvp_division[findIdx + 1] then levels[1] = {globalCsv.pvp_division[findIdx + 1], (globalCsv.pvp_division[findIdx + 2] or 100000000) - 1} end levels[2] = {globalCsv.pvp_division[findIdx], (globalCsv.pvp_division[findIdx + 1] or 100000000) - 1} if globalCsv.pvp_division[findIdx - 1] then levels[3] = {globalCsv.pvp_division[findIdx - 1], globalCsv.pvp_division[findIdx] - 1} end local redirect = {} for i = #levels , 1, -1 do if not next(levels[i]) then table.remove(levels, i) redirect[i] = -1 for _, v in pairs(redirect) do redirect[_] = v - 1 end else redirect[i] = i end end local result = getPlayers(levels) local matchC = self:getProperty("pvpMC") local hadPlayer = {[roleId] = 1} local hadRobot = {} for _, one in pairs(matchC) do if one.t == 1 then hadPlayer[one.id] = 1 elseif one.t == 2 then hadRobot[one.id] = 1 end end for _, temp in pairs(result) do for i = #temp, 1, -1 do local id = tonumber(temp[i]) if hadPlayer[id] then table.remove(temp, i) else temp[i] = id hadPlayer[id] = 1 end end end -- 增加第几个 local function getPlayer(idx) for i = idx, 3 do if redirect[i] ~= -1 then local curR = result[redirect[i]] or {} if next(curR) then local curIdx = math.randomInt(1, #curR) local objId = curR[curIdx] table.remove(curR, curIdx) return objId end end end end local tempMatchC = {} local curCount = 0 for i = 1, 3 do local objId = getPlayer(i) if objId then tempMatchC[i] = {t = 1, id = objId} curCount = curCount + 1 end end -- 正常的玩家不够了 低一档继续 if curCount < 3 then local level = nil if globalCsv.pvp_division[findIdx - 2] then level = {globalCsv.pvp_division[findIdx - 2], globalCsv.pvp_division[findIdx - 1] - 1} end if level then local result = getPlayers({level})[1] or {} for i = #result, 1, -1 do local id = tonumber(result[i]) if hadPlayer[id] then table.remove(result, i) else result[i] = id hadPlayer[id] = 1 end end if next(result) then for i = curCount + 1, 3 do local curIdx = math.randomInt(1, #result) local objId = result[curIdx] table.remove(result, curIdx) tempMatchC[i] = {t = 1, id = objId} curCount = curCount + 1 if not next(result) then break end end end end end -- 增加机器人 if curCount < 3 then for i = curCount + 1, 3 do while true do local id = math.randomInt(1, #csvdb["pvp_robotCsv"]) if not hadRobot[id] then hadRobot[id] = 1 tempMatchC[i] = {t = 2, id = id} break end end end end self:setProperty("pvpMC", tempMatchC) end end return RolePvp