Commit 68a6dc62ec61db12b5bfa60653991c6082b9a7a6

Authored by zhouhaihai
1 parent cf584618

匹配规则调整

Showing 2 changed files with 261 additions and 141 deletions   Show diff stats
src/actions/PvpAction.lua
... ... @@ -171,7 +171,7 @@ function _M.infoRpc(agent, data)
171 171  
172 172 local pvpMC = role:getProperty("pvpMC")
173 173 if not next(pvpMC) then --没有分配过对手
174   - role:refreshPvpMatchC(score)
  174 + role:refreshPvpMatchC(score, -1)
175 175 pvpMC = role:getProperty("pvpMC")
176 176 end
177 177 if not next(pvpMC) then return end
... ... @@ -191,7 +191,7 @@ function _M.infoRpc(agent, data)
191 191  
192 192 local pvpMH = role:getProperty("pvpMH")
193 193 if not next(pvpMH) then --没有分配过对手
194   - role:refreshPvpMatchH(score)
  194 + role:refreshPvpMatchH(score, -1)
195 195 pvpMH = role:getProperty("pvpMH")
196 196 end
197 197 if not next(pvpMH) then return end
... ...
src/models/RolePvp.lua
... ... @@ -6,7 +6,12 @@ RolePvp.bind = function (Role)
6 6 local PVP_RANK_TIME_SORT_STD = 1924876800 -- 2030-12-31 00:00:00
7 7 local PVP_RANK_TIME_SORT_PLACE = 1000000 -- 时间戳占据 6位数
8 8 local PVP_RANK_TIME_SORT_PRECISION = 360 -- 时间精度 每6分钟忽略差异
9   -local PVP_RANK_BASE_SCORE = globalCsv.pvp_base_score -- 机器人积分
  9 +local PVP_RANK_BASE_SCORE = globalCsv.pvp_base_score -- 初始积分
  10 +
  11 +-- 匹配规则改为以排名来匹配
  12 +local PVP_GET_ROBOT_SCORE = 2400 -- 2400分以下低档位匹配机器人
  13 +local PRE_RANGE_COUNT = 20 -- 每个档位人数
  14 +local NEED_MATCH = 3 --匹配到多少人
10 15  
11 16  
12 17 function Role:unpackPvpScore(score)
... ... @@ -78,7 +83,7 @@ function Role:changePvpScoreCommon(matchId, isWin)
78 83 end
79 84  
80 85 local result = self:changePvpScore(RANK_PVP_COMMON, changeScoreCallback, matchId)
81   - self:refreshPvpMatchC(result[1])
  86 + self:refreshPvpMatchC(result[1], result[5])
82 87 return table.unpack(result)
83 88 end
84 89  
... ... @@ -162,7 +167,7 @@ function Role:changePvpScoreHigh(matchId, isWin)
162 167 })
163 168 end
164 169  
165   - self:refreshPvpMatchH(result[1])
  170 + self:refreshPvpMatchH(result[1], result[5])
166 171 return table.unpack(result)
167 172 end
168 173  
... ... @@ -179,82 +184,33 @@ function Role:isInPvpRank(rankKey)
179 184 return false
180 185 end
181 186  
182   -
183   -function Role:refreshPvpMatch(score, rankKey)
184   -
  187 +-- 新的匹配规则
  188 +function Role:refreshPvpMatch(score, rank, rankKey)
185 189 local Fields = {
186 190 [RANK_PVP_COMMON] = "pvpMC",
187 191 [RANK_PVP_HIGHT] = "pvpMH",
188 192 }
189 193 local RobotCsvs = {
190 194 [RANK_PVP_COMMON] = "pvp_robotCsv",
191   - [RANK_PVP_HIGHT] = "pvp_robotCsv",
  195 + [RANK_PVP_HIGHT] = "pvp_robot_groupCsv",
192 196 }
  197 +
193 198 local mField = Fields[rankKey]
194 199 local robotCsv = RobotCsvs[rankKey]
195   - local dbKey = self:getPvpDBKey(rankKey)
196 200  
  201 + local dbKey = self:getPvpDBKey(rankKey)
197 202 local roleId = self:getProperty("id")
198   - score = score or self:unpackPvpScore(redisproxy:zscore(dbKey, roleId))
199   -
200   - local function getPlayers(levels)
  203 + if not score and not rank then
201 204 local redret = redisproxy:pipelining(function(red)
202   - for _, level in ipairs(levels) do
203   - local low, high = table.unpack(level)
204   - red:zadd(dbKey, low * PVP_RANK_TIME_SORT_PLACE, "std_temp1")
205   - red:zadd(dbKey, high * PVP_RANK_TIME_SORT_PLACE + PVP_RANK_TIME_SORT_PLACE - 1, "std_temp2")
206   - red:ZREVRANK(dbKey, "std_temp1")
207   - red:ZREVRANK(dbKey, "std_temp2")
208   - end
209   - red:zrem(dbKey, "std_temp1", "std_temp2")
  205 + red:zscore(dbKey, roleId)
  206 + red:zrevrank(dbKey, roleId)
210 207 end)
211   -
212   - local PreGetCount = 7
213   - local redret = redisproxy:pipelining(function(red)
214   - for idx, level in ipairs(levels) do
215   - local rank1 = tonumber(redret[(idx - 1) * 4 + 3])
216   - local rank2 = tonumber(redret[(idx - 1) * 4 + 4])
217   - if rank1 - rank2 > PreGetCount then
218   - rank2 = math.randomInt(rank2, rank1 - PreGetCount + 1)
219   - rank1 = rank2 + PreGetCount - 1
220   - end
221   - red:ZREVRANGE(dbKey, rank2, rank1)
222   - end
223   - end)
224   - return redret
225   - end
226   -
227   - local findIdx = #globalCsv.pvp_division
228   - for idx, limit in ipairs(globalCsv.pvp_division) do
229   - if score < limit then
230   - findIdx = idx - 1
231   - break
232   - end
233   - end
234   - local levels = {
235   - {}, {}, {}
236   - }
237   - if globalCsv.pvp_division[findIdx + 1] then
238   - levels[1] = {globalCsv.pvp_division[findIdx + 1], (globalCsv.pvp_division[findIdx + 2] or 100000000) - 1}
239   - end
240   - levels[2] = {globalCsv.pvp_division[findIdx], (globalCsv.pvp_division[findIdx + 1] or 100000000) - 1}
241   - if globalCsv.pvp_division[findIdx - 1] then
242   - levels[3] = {globalCsv.pvp_division[findIdx - 1], globalCsv.pvp_division[findIdx] - 1}
243   - end
244   - local redirect = {}
245   - for i = #levels , 1, -1 do
246   - if not next(levels[i]) then
247   - table.remove(levels, i)
248   - redirect[i] = -1
249   - for _, v in pairs(redirect) do
250   - redirect[_] = v - 1
251   - end
252   - else
253   - redirect[i] = i
254   - end
  208 + score = self:unpackPvpScore(redret[1])
  209 + rank = tonumber(redret[2] or -2) + 1
255 210 end
256   -
257   - local result = getPlayers(levels)
  211 + score = score or self:unpackPvpScore(redisproxy:zscore(dbKey, roleId))
  212 + rank = rank or tonumber(redisproxy:zrevrank(dbKey, roleId) or -2) + 1
  213 +
258 214 local match = self:getProperty(mField)
259 215 local hadPlayer = {[roleId] = 1}
260 216 local hadRobot = {}
... ... @@ -266,97 +222,261 @@ function Role:refreshPvpMatch(score, rankKey)
266 222 end
267 223 end
268 224  
269   - for _, temp in pairs(result) do
270   - for i = #temp, 1, -1 do
271   - local id = tonumber(temp[i])
272   - if hadPlayer[id] then
273   - table.remove(temp, i)
274   - else
275   - temp[i] = id
276   - hadPlayer[id] = 1
277   - end
  225 + local tempMatch = {}
  226 + local needRobot = 0
  227 + -- -1 没有上榜
  228 + if rank == -1 then
  229 + needRobot = NEED_MATCH
  230 + else
  231 + local need = PRE_RANGE_COUNT * NEED_MATCH
  232 + local low, heigh = math.floor(rank - need / 2 - 1), math.floor(rank + need / 2 - 1)
  233 + if low < 0 then
  234 + low = 0
278 235 end
279   - end
280   - -- 增加第几个
281   - local function getPlayer(idx)
282   - for i = idx, 3 do
283   - if redirect[i] ~= -1 then
284   - local curR = result[redirect[i]] or {}
285   - if next(curR) then
286   - local curIdx = math.randomInt(1, #curR)
287   - local objId = curR[curIdx]
288   - table.remove(curR, curIdx)
289   - return objId
290   - end
  236 + print(low, heigh)
  237 + local rangeIds = redisproxy:ZREVRANGE(dbKey, low, heigh)
  238 + local lastRangeIds = {}
  239 + for idx, one in ipairs(rangeIds) do
  240 + local cid = tonumber(one)
  241 + if not hadPlayer[cid] then
  242 + lastRangeIds[#lastRangeIds + 1] = cid
291 243 end
292 244 end
293   - end
294   -
295   - local tempMatch = {}
296   - local curCount = 0
297   - for i = 1, 3 do
298   - local objId = getPlayer(i)
299   - if objId then
300   - tempMatch[i] = {t = 1, id = objId}
301   - curCount = curCount + 1
  245 + if score < PVP_GET_ROBOT_SCORE then
  246 + needRobot = 1
302 247 end
303   - end
304   -
305   - -- 正常的玩家不够了 低一档继续
306   - if curCount < 3 then
307   - local level = nil
308   - if globalCsv.pvp_division[findIdx - 2] then
309   - level = {globalCsv.pvp_division[findIdx - 2], globalCsv.pvp_division[findIdx - 1] - 1}
  248 + local len = #lastRangeIds
  249 + if len < NEED_MATCH then
  250 + needRobot = NEED_MATCH - len
310 251 end
311   - if level then
312   - local result = getPlayers({level})[1] or {}
313   - for i = #result, 1, -1 do
314   - local id = tonumber(result[i])
315   - if hadPlayer[id] then
316   - table.remove(result, i)
317   - else
318   - result[i] = id
319   - hadPlayer[id] = 1
320   - end
  252 + local needPlayer = NEED_MATCH - needRobot
  253 + if needPlayer > 0 then
  254 + local pre = math.floor(len / needPlayer)
  255 + for i = 1, needPlayer do
  256 + local idx = math.randomInt((i - 1) * pre + 1, i * pre)
  257 + tempMatch[#tempMatch + 1] = {t = 1, id = lastRangeIds[idx]}
321 258 end
  259 + end
322 260  
323   - if next(result) then
324   - for i = curCount + 1, 3 do
325   - local curIdx = math.randomInt(1, #result)
326   - local objId = result[curIdx]
327   - table.remove(result, curIdx)
328   - tempMatch[i] = {t = 1, id = objId}
329   - curCount = curCount + 1
330   - if not next(result) then
331   - break
332   - end
333   - end
  261 + end
  262 + if needRobot > 0 then
  263 + local RobotPoolCount = 20
  264 + local max = #csvdb[robotCsv]
  265 + local min = 1
  266 + local mid
  267 + while min <= max do
  268 + mid = math.floor((min + max) / 2)
  269 + local tempPt = csvdb[robotCsv][mid].pt
  270 + if score == tempPt then
  271 + break
  272 + elseif score > tempPt then
  273 + min = mid + 1
  274 + elseif score < tempPt then
  275 + max = mid - 1
334 276 end
335 277 end
336   - end
337   -
338   - -- 增加机器人
339   - if curCount < 3 then
340   - for i = curCount + 1, 3 do
341   - while true do
342   - local id = math.randomInt(1, #csvdb[robotCsv])
343   - if not hadRobot[id] then
344   - hadRobot[id] = 1
345   - tempMatch[i] = {t = 2, id = id}
346   - break
347   - end
  278 + assert(mid, "pvp no robot " .. robotCsv)
  279 + local low = mid - RobotPoolCount / 2
  280 + local heigh = mid + RobotPoolCount / 2
  281 + if low < 1 then
  282 + heigh = heigh + (1 - low)
  283 + low = 1
  284 + end
  285 + if heigh > #csvdb[robotCsv] then
  286 + heigh = #csvdb[robotCsv]
  287 + end
  288 + local pools = {}
  289 + for i = low, heigh do
  290 + if not hadRobot[i] then
  291 + pools[#pools + 1] = i
348 292 end
349 293 end
  294 + local pre = math.floor(#pools / needRobot)
  295 + for i = 1, needRobot do
  296 + local idx = math.randomInt((i - 1) * pre + 1, i * pre)
  297 + tempMatch[#tempMatch + 1] = {t = 2, id = pools[idx]}
  298 + end
350 299 end
351 300 self:setProperty(mField, tempMatch)
352 301 end
353 302  
354   -function Role:refreshPvpMatchC(score)
355   - self:refreshPvpMatch(score, RANK_PVP_COMMON)
  303 +-- function Role:refreshPvpMatch(score, rank, rankKey)
  304 +
  305 +-- local Fields = {
  306 +-- [RANK_PVP_COMMON] = "pvpMC",
  307 +-- [RANK_PVP_HIGHT] = "pvpMH",
  308 +-- }
  309 +-- local RobotCsvs = {
  310 +-- [RANK_PVP_COMMON] = "pvp_robotCsv",
  311 +-- [RANK_PVP_HIGHT] = "pvp_robotCsv",
  312 +-- }
  313 +-- local mField = Fields[rankKey]
  314 +-- local robotCsv = RobotCsvs[rankKey]
  315 +-- local dbKey = self:getPvpDBKey(rankKey)
  316 +
  317 +-- local roleId = self:getProperty("id")
  318 +-- score = score or self:unpackPvpScore(redisproxy:zscore(dbKey, roleId))
  319 +
  320 +-- local function getPlayers(levels)
  321 +-- local redret = redisproxy:pipelining(function(red)
  322 +-- for _, level in ipairs(levels) do
  323 +-- local low, high = table.unpack(level)
  324 +-- red:zadd(dbKey, low * PVP_RANK_TIME_SORT_PLACE, "std_temp1")
  325 +-- red:zadd(dbKey, high * PVP_RANK_TIME_SORT_PLACE + PVP_RANK_TIME_SORT_PLACE - 1, "std_temp2")
  326 +-- red:ZREVRANK(dbKey, "std_temp1")
  327 +-- red:ZREVRANK(dbKey, "std_temp2")
  328 +-- end
  329 +-- red:zrem(dbKey, "std_temp1", "std_temp2")
  330 +-- end)
  331 +
  332 +-- local PreGetCount = 7
  333 +-- local redret = redisproxy:pipelining(function(red)
  334 +-- for idx, level in ipairs(levels) do
  335 +-- local rank1 = tonumber(redret[(idx - 1) * 4 + 3])
  336 +-- local rank2 = tonumber(redret[(idx - 1) * 4 + 4])
  337 +-- if rank1 - rank2 > PreGetCount then
  338 +-- rank2 = math.randomInt(rank2, rank1 - PreGetCount + 1)
  339 +-- rank1 = rank2 + PreGetCount - 1
  340 +-- end
  341 +-- red:ZREVRANGE(dbKey, rank2, rank1)
  342 +-- end
  343 +-- end)
  344 +-- return redret
  345 +-- end
  346 +
  347 +-- local findIdx = #globalCsv.pvp_division
  348 +-- for idx, limit in ipairs(globalCsv.pvp_division) do
  349 +-- if score < limit then
  350 +-- findIdx = idx - 1
  351 +-- break
  352 +-- end
  353 +-- end
  354 +-- local levels = {
  355 +-- {}, {}, {}
  356 +-- }
  357 +-- if globalCsv.pvp_division[findIdx + 1] then
  358 +-- levels[1] = {globalCsv.pvp_division[findIdx + 1], (globalCsv.pvp_division[findIdx + 2] or 100000000) - 1}
  359 +-- end
  360 +-- levels[2] = {globalCsv.pvp_division[findIdx], (globalCsv.pvp_division[findIdx + 1] or 100000000) - 1}
  361 +-- if globalCsv.pvp_division[findIdx - 1] then
  362 +-- levels[3] = {globalCsv.pvp_division[findIdx - 1], globalCsv.pvp_division[findIdx] - 1}
  363 +-- end
  364 +-- local redirect = {}
  365 +-- for i = #levels , 1, -1 do
  366 +-- if not next(levels[i]) then
  367 +-- table.remove(levels, i)
  368 +-- redirect[i] = -1
  369 +-- for _, v in pairs(redirect) do
  370 +-- redirect[_] = v - 1
  371 +-- end
  372 +-- else
  373 +-- redirect[i] = i
  374 +-- end
  375 +-- end
  376 +
  377 +-- local result = getPlayers(levels)
  378 +-- local match = self:getProperty(mField)
  379 +-- local hadPlayer = {[roleId] = 1}
  380 +-- local hadRobot = {}
  381 +-- for _, one in pairs(match) do
  382 +-- if one.t == 1 then
  383 +-- hadPlayer[one.id] = 1
  384 +-- elseif one.t == 2 then
  385 +-- hadRobot[one.id] = 1
  386 +-- end
  387 +-- end
  388 +
  389 +-- for _, temp in pairs(result) do
  390 +-- for i = #temp, 1, -1 do
  391 +-- local id = tonumber(temp[i])
  392 +-- if hadPlayer[id] then
  393 +-- table.remove(temp, i)
  394 +-- else
  395 +-- temp[i] = id
  396 +-- hadPlayer[id] = 1
  397 +-- end
  398 +-- end
  399 +-- end
  400 +-- -- 增加第几个
  401 +-- local function getPlayer(idx)
  402 +-- for i = idx, 3 do
  403 +-- if redirect[i] ~= -1 then
  404 +-- local curR = result[redirect[i]] or {}
  405 +-- if next(curR) then
  406 +-- local curIdx = math.randomInt(1, #curR)
  407 +-- local objId = curR[curIdx]
  408 +-- table.remove(curR, curIdx)
  409 +-- return objId
  410 +-- end
  411 +-- end
  412 +-- end
  413 +-- end
  414 +
  415 +-- local tempMatch = {}
  416 +-- local curCount = 0
  417 +-- for i = 1, 3 do
  418 +-- local objId = getPlayer(i)
  419 +-- if objId then
  420 +-- tempMatch[i] = {t = 1, id = objId}
  421 +-- curCount = curCount + 1
  422 +-- end
  423 +-- end
  424 +
  425 +-- -- 正常的玩家不够了 低一档继续
  426 +-- if curCount < 3 then
  427 +-- local level = nil
  428 +-- if globalCsv.pvp_division[findIdx - 2] then
  429 +-- level = {globalCsv.pvp_division[findIdx - 2], globalCsv.pvp_division[findIdx - 1] - 1}
  430 +-- end
  431 +-- if level then
  432 +-- local result = getPlayers({level})[1] or {}
  433 +-- for i = #result, 1, -1 do
  434 +-- local id = tonumber(result[i])
  435 +-- if hadPlayer[id] then
  436 +-- table.remove(result, i)
  437 +-- else
  438 +-- result[i] = id
  439 +-- hadPlayer[id] = 1
  440 +-- end
  441 +-- end
  442 +
  443 +-- if next(result) then
  444 +-- for i = curCount + 1, 3 do
  445 +-- local curIdx = math.randomInt(1, #result)
  446 +-- local objId = result[curIdx]
  447 +-- table.remove(result, curIdx)
  448 +-- tempMatch[i] = {t = 1, id = objId}
  449 +-- curCount = curCount + 1
  450 +-- if not next(result) then
  451 +-- break
  452 +-- end
  453 +-- end
  454 +-- end
  455 +-- end
  456 +-- end
  457 +
  458 +-- -- 增加机器人
  459 +-- if curCount < 3 then
  460 +-- for i = curCount + 1, 3 do
  461 +-- while true do
  462 +-- local id = math.randomInt(1, #csvdb[robotCsv])
  463 +-- if not hadRobot[id] then
  464 +-- hadRobot[id] = 1
  465 +-- tempMatch[i] = {t = 2, id = id}
  466 +-- break
  467 +-- end
  468 +-- end
  469 +-- end
  470 +-- end
  471 +-- self:setProperty(mField, tempMatch)
  472 +-- end
  473 +
  474 +function Role:refreshPvpMatchC(score, rank)
  475 + self:refreshPvpMatch(score, rank, RANK_PVP_COMMON)
356 476 end
357 477  
358   -function Role:refreshPvpMatchH(score)
359   - self:refreshPvpMatch(score, RANK_PVP_HIGHT)
  478 +function Role:refreshPvpMatchH(score, rank)
  479 + self:refreshPvpMatch(score, rank, RANK_PVP_HIGHT)
360 480 end
361 481  
362 482 function Role:getPvpDBKey(ptype)
... ...