Commit 68a6dc62ec61db12b5bfa60653991c6082b9a7a6
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) | ... | ... |