From 68a6dc62ec61db12b5bfa60653991c6082b9a7a6 Mon Sep 17 00:00:00 2001 From: zhouhaihai Date: Wed, 9 Dec 2020 15:37:34 +0800 Subject: [PATCH] 匹配规则调整 --- src/actions/PvpAction.lua | 4 ++-- src/models/RolePvp.lua | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------------------------- 2 files changed, 261 insertions(+), 141 deletions(-) diff --git a/src/actions/PvpAction.lua b/src/actions/PvpAction.lua index 4e34bc4..8c8183d 100644 --- a/src/actions/PvpAction.lua +++ b/src/actions/PvpAction.lua @@ -171,7 +171,7 @@ function _M.infoRpc(agent, data) local pvpMC = role:getProperty("pvpMC") if not next(pvpMC) then --没有分配过对手 - role:refreshPvpMatchC(score) + role:refreshPvpMatchC(score, -1) pvpMC = role:getProperty("pvpMC") end if not next(pvpMC) then return end @@ -191,7 +191,7 @@ function _M.infoRpc(agent, data) local pvpMH = role:getProperty("pvpMH") if not next(pvpMH) then --没有分配过对手 - role:refreshPvpMatchH(score) + role:refreshPvpMatchH(score, -1) pvpMH = role:getProperty("pvpMH") end if not next(pvpMH) then return end diff --git a/src/models/RolePvp.lua b/src/models/RolePvp.lua index 4bfe882..3afbd69 100644 --- a/src/models/RolePvp.lua +++ b/src/models/RolePvp.lua @@ -6,7 +6,12 @@ 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_BASE_SCORE = globalCsv.pvp_base_score -- 机器人积分 +local PVP_RANK_BASE_SCORE = globalCsv.pvp_base_score -- 初始积分 + +-- 匹配规则改为以排名来匹配 +local PVP_GET_ROBOT_SCORE = 2400 -- 2400分以下低档位匹配机器人 +local PRE_RANGE_COUNT = 20 -- 每个档位人数 +local NEED_MATCH = 3 --匹配到多少人 function Role:unpackPvpScore(score) @@ -78,7 +83,7 @@ function Role:changePvpScoreCommon(matchId, isWin) end local result = self:changePvpScore(RANK_PVP_COMMON, changeScoreCallback, matchId) - self:refreshPvpMatchC(result[1]) + self:refreshPvpMatchC(result[1], result[5]) return table.unpack(result) end @@ -162,7 +167,7 @@ function Role:changePvpScoreHigh(matchId, isWin) }) end - self:refreshPvpMatchH(result[1]) + self:refreshPvpMatchH(result[1], result[5]) return table.unpack(result) end @@ -179,82 +184,33 @@ function Role:isInPvpRank(rankKey) return false end - -function Role:refreshPvpMatch(score, rankKey) - +-- 新的匹配规则 +function Role:refreshPvpMatch(score, rank, rankKey) local Fields = { [RANK_PVP_COMMON] = "pvpMC", [RANK_PVP_HIGHT] = "pvpMH", } local RobotCsvs = { [RANK_PVP_COMMON] = "pvp_robotCsv", - [RANK_PVP_HIGHT] = "pvp_robotCsv", + [RANK_PVP_HIGHT] = "pvp_robot_groupCsv", } + local mField = Fields[rankKey] local robotCsv = RobotCsvs[rankKey] - local dbKey = self:getPvpDBKey(rankKey) + local dbKey = self:getPvpDBKey(rankKey) local roleId = self:getProperty("id") - score = score or self:unpackPvpScore(redisproxy:zscore(dbKey, roleId)) - - local function getPlayers(levels) + if not score and not rank then local redret = redisproxy:pipelining(function(red) - for _, level in ipairs(levels) do - local low, high = table.unpack(level) - red:zadd(dbKey, low * PVP_RANK_TIME_SORT_PLACE, "std_temp1") - red:zadd(dbKey, high * PVP_RANK_TIME_SORT_PLACE + PVP_RANK_TIME_SORT_PLACE - 1, "std_temp2") - red:ZREVRANK(dbKey, "std_temp1") - red:ZREVRANK(dbKey, "std_temp2") - end - red:zrem(dbKey, "std_temp1", "std_temp2") + red:zscore(dbKey, roleId) + red:zrevrank(dbKey, roleId) 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(dbKey, 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 + score = self:unpackPvpScore(redret[1]) + rank = tonumber(redret[2] or -2) + 1 end - - local result = getPlayers(levels) + score = score or self:unpackPvpScore(redisproxy:zscore(dbKey, roleId)) + rank = rank or tonumber(redisproxy:zrevrank(dbKey, roleId) or -2) + 1 + local match = self:getProperty(mField) local hadPlayer = {[roleId] = 1} local hadRobot = {} @@ -266,97 +222,261 @@ function Role:refreshPvpMatch(score, rankKey) 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 + local tempMatch = {} + local needRobot = 0 + -- -1 没有上榜 + if rank == -1 then + needRobot = NEED_MATCH + else + local need = PRE_RANGE_COUNT * NEED_MATCH + local low, heigh = math.floor(rank - need / 2 - 1), math.floor(rank + need / 2 - 1) + if low < 0 then + low = 0 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 + print(low, heigh) + local rangeIds = redisproxy:ZREVRANGE(dbKey, low, heigh) + local lastRangeIds = {} + for idx, one in ipairs(rangeIds) do + local cid = tonumber(one) + if not hadPlayer[cid] then + lastRangeIds[#lastRangeIds + 1] = cid end end - end - - local tempMatch = {} - local curCount = 0 - for i = 1, 3 do - local objId = getPlayer(i) - if objId then - tempMatch[i] = {t = 1, id = objId} - curCount = curCount + 1 + if score < PVP_GET_ROBOT_SCORE then + needRobot = 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} + local len = #lastRangeIds + if len < NEED_MATCH then + needRobot = NEED_MATCH - len 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 + local needPlayer = NEED_MATCH - needRobot + if needPlayer > 0 then + local pre = math.floor(len / needPlayer) + for i = 1, needPlayer do + local idx = math.randomInt((i - 1) * pre + 1, i * pre) + tempMatch[#tempMatch + 1] = {t = 1, id = lastRangeIds[idx]} 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) - tempMatch[i] = {t = 1, id = objId} - curCount = curCount + 1 - if not next(result) then - break - end - end + end + if needRobot > 0 then + local RobotPoolCount = 20 + local max = #csvdb[robotCsv] + local min = 1 + local mid + while min <= max do + mid = math.floor((min + max) / 2) + local tempPt = csvdb[robotCsv][mid].pt + if score == tempPt then + break + elseif score > tempPt then + min = mid + 1 + elseif score < tempPt then + max = mid - 1 end end - end - - -- 增加机器人 - if curCount < 3 then - for i = curCount + 1, 3 do - while true do - local id = math.randomInt(1, #csvdb[robotCsv]) - if not hadRobot[id] then - hadRobot[id] = 1 - tempMatch[i] = {t = 2, id = id} - break - end + assert(mid, "pvp no robot " .. robotCsv) + local low = mid - RobotPoolCount / 2 + local heigh = mid + RobotPoolCount / 2 + if low < 1 then + heigh = heigh + (1 - low) + low = 1 + end + if heigh > #csvdb[robotCsv] then + heigh = #csvdb[robotCsv] + end + local pools = {} + for i = low, heigh do + if not hadRobot[i] then + pools[#pools + 1] = i end end + local pre = math.floor(#pools / needRobot) + for i = 1, needRobot do + local idx = math.randomInt((i - 1) * pre + 1, i * pre) + tempMatch[#tempMatch + 1] = {t = 2, id = pools[idx]} + end end self:setProperty(mField, tempMatch) end -function Role:refreshPvpMatchC(score) - self:refreshPvpMatch(score, RANK_PVP_COMMON) +-- function Role:refreshPvpMatch(score, rank, rankKey) + +-- local Fields = { +-- [RANK_PVP_COMMON] = "pvpMC", +-- [RANK_PVP_HIGHT] = "pvpMH", +-- } +-- local RobotCsvs = { +-- [RANK_PVP_COMMON] = "pvp_robotCsv", +-- [RANK_PVP_HIGHT] = "pvp_robotCsv", +-- } +-- local mField = Fields[rankKey] +-- local robotCsv = RobotCsvs[rankKey] +-- local dbKey = self:getPvpDBKey(rankKey) + +-- local roleId = self:getProperty("id") +-- score = score or self:unpackPvpScore(redisproxy:zscore(dbKey, 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(dbKey, low * PVP_RANK_TIME_SORT_PLACE, "std_temp1") +-- red:zadd(dbKey, high * PVP_RANK_TIME_SORT_PLACE + PVP_RANK_TIME_SORT_PLACE - 1, "std_temp2") +-- red:ZREVRANK(dbKey, "std_temp1") +-- red:ZREVRANK(dbKey, "std_temp2") +-- end +-- red:zrem(dbKey, "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(dbKey, 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 match = self:getProperty(mField) +-- local hadPlayer = {[roleId] = 1} +-- local hadRobot = {} +-- for _, one in pairs(match) 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 tempMatch = {} +-- local curCount = 0 +-- for i = 1, 3 do +-- local objId = getPlayer(i) +-- if objId then +-- tempMatch[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) +-- tempMatch[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[robotCsv]) +-- if not hadRobot[id] then +-- hadRobot[id] = 1 +-- tempMatch[i] = {t = 2, id = id} +-- break +-- end +-- end +-- end +-- end +-- self:setProperty(mField, tempMatch) +-- end + +function Role:refreshPvpMatchC(score, rank) + self:refreshPvpMatch(score, rank, RANK_PVP_COMMON) end -function Role:refreshPvpMatchH(score) - self:refreshPvpMatch(score, RANK_PVP_HIGHT) +function Role:refreshPvpMatchH(score, rank) + self:refreshPvpMatch(score, rank, RANK_PVP_HIGHT) end function Role:getPvpDBKey(ptype) -- libgit2 0.21.2