CommonRankDB.lua 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. --------------------------------
  2. -- 文件名 : CommonRankDB.lua
  3. -- 文件说明 : 通用排行榜DB数据
  4. -- 创建时间 : 2024/12/09
  5. -- 创建人 : FC
  6. --------------------------------
  7. local Msg = require("core.Msg")
  8. local Timer = require("core.Timer")
  9. local DB = require("common.DB")
  10. local CommonDB = require("common.CommonDB")
  11. local CommonDefine = require("common.CommonDefine")
  12. local Log = require("common.Log")
  13. local LuaMongo = _G.lua_mongo
  14. local Util = require("common.Util")
  15. local Grid = require("bag.Grid")
  16. local OpenAct = require("present.OpenAct")
  17. local RoleDBLogic = require("role.RoleDBLogic")
  18. local YunYingLogic = require("yunying.YunYingLogic")
  19. local MailManager = require("mail.MailManager")
  20. local MailExcel = require("excel.mail")
  21. local OpenActExcel = require("excel.openAct")
  22. local WeekLoopActCof = require("excel.WeekLoopAct")
  23. local WeekLoopActDef = require("WeekendLoopActivity.WeekendLoopActDefine")
  24. --[[
  25. 开服活动排行DB操作,封装了一些公共处理方法
  26. db字段只是缓存排名好的数据(只是内存数据)
  27. Coomondb = {
  28. [rankType] = { -- 排名类型
  29. rankType = xxx, -- 排名类型
  30. uuid2rank = { -- 根据UUID获取名次
  31. [uuid] = rank, -- 玩家uuid = 排行名次
  32. ...
  33. },
  34. sendUuid2rank = { -- 根据UUID获取发送名次
  35. [uuid] = rank, -- 玩家uuid = 真实发送的排行名次
  36. ...
  37. },
  38. rank2data = { -- 根据名次获取DATA
  39. [rank] = { -- 排行名次 = 玩家排名数据
  40. uuid = xxx, -- 玩家uuid
  41. rankType = xxx, -- 排名类型
  42. value = xxx, -- 排名值
  43. time = xxx, -- 排名值更新时间
  44. _id = xxx, -- db记录中的uuid
  45. },
  46. ...
  47. },
  48. sendRank2data = { -- 根据名次获取发送DATA
  49. [rank] = { -- 排行名次 = 真实发送玩家排名数据
  50. uuid = xxx, -- 玩家uuid
  51. rankType = xxx, -- 排名类型
  52. value = xxx, -- 排名值
  53. time = xxx, -- 排名值更新时间
  54. _id = xxx, -- db记录中的uuid
  55. },
  56. ...
  57. }
  58. },
  59. ...
  60. }
  61. DB:
  62. db_common_rank = { -- 开服排行类活动
  63. [uuid] = {
  64. uuid = xxx, -- 玩家uuid
  65. rankType= xxx, -- 排名类型
  66. value = xxx, -- 排行值
  67. time = xxx, -- 排行值更新时间
  68. }
  69. }
  70. local:
  71. CommonDB_GetConfig() -- 得到指定排名类型的活动配置
  72. getMinRankValue() -- 得到排行榜中最低上榜条件数
  73. getMaxRank() -- 得到活动最多排名名次
  74. getRankNeedValue() -- 得到排行榜中名次对应需要达到的条件数
  75. getRankInfo() -- 得到指定排行榜指定名次的配置信息
  76. getRewardInfoByRank() -- 获取奖励信息
  77. getBoard() -- 获取指定排名类型DB数据
  78. getRank() -- 获取指定排名类型、指定用户的排名
  79. getSendRank() -- 获取指定排名类型、指定用户的发送排名
  80. cmpRank() -- 排名算法
  81. updateRank() -- 更新排名
  82. updateData() -- 更新数据
  83. loadBoard() -- 加载排行榜
  84. resertBoard() -- 重置排行数据
  85. initBoard() -- 初始排行榜
  86. getDBData() -- 根据类型+uuid从db中取data
  87. updateDBData() -- 更新DB数据
  88. billboardSet() -- 设置排名数据
  89. getMailID() -- 获取发送奖励的邮件ID
  90. getRewardInfoByInfo() -- 得到指定排行榜指定配置信息的奖励信息
  91. rewardSend() -- 奖励发送
  92. wrapOpenServerRankRewardList -- 包装档位奖励详情数据
  93. public:
  94. initAfterStart() -- 启动就初始化
  95. getMaxSendRank() -- 得到最大发送排行名次数据
  96. wrapOpenServerRankList() -- 包装档位名次数据
  97. wrapOwnerData() -- 包装自己名次数据
  98. rewardQuery() -- 发送奖励详情
  99. onValueAdd() -- 排行值增加回调
  100. onValueSet() -- 排行值设置回调
  101. onRewardSend() -- 奖励发送回调
  102. --]]
  103. WeekAct_RankName = "WeekAct_ChargeRank"
  104. MAX_SEND_RANK = 10 -- 最大发送排名数
  105. MAX_SEND_WEEKACTRANK = 21 -- 周活动排行榜发送排名数
  106. Coomondb = Coomondb or {} -- [rankType] = board
  107. CoomonQueryForData = {rankType = 1, uuid = 1} -- 通过排名类型和玩家uuid查找DB数据
  108. CoomonQueryByUuid = {_id = 1} -- 通过DB的uuid更新DB数据
  109. CoomonQueryByRankType = {rankType = 1} -- 通过排名类型查找DB数据
  110. local function CommonDB_GetConfig(rankType)
  111. if CommonDefine.COMMONRANK_TYPE_WEEKRANK == rankType then
  112. return WeekLoopActCof.Rank
  113. end
  114. return nil
  115. end
  116. -- 得到排行榜中最低上榜条件数
  117. local MIN_RANK_VALUES
  118. local function getMinRankValue(rankType)
  119. MIN_RANK_VALUES = MIN_RANK_VALUES or {}
  120. if MIN_RANK_VALUES[rankType] then return MIN_RANK_VALUES[rankType] end
  121. local tWeekRankConfig = CommonDB_GetConfig(rankType)
  122. if not tWeekRankConfig then return end
  123. -- 这里后续有排行榜类型,保持命名一致
  124. local minRankValue
  125. for _,info in ipairs(tWeekRankConfig) do
  126. if not minRankValue or minRankValue > info.nMoney then
  127. minRankValue = info.nMoney
  128. end
  129. end
  130. MIN_RANK_VALUES[rankType] = minRankValue
  131. return MIN_RANK_VALUES[rankType]
  132. end
  133. --local MAX_RANKS
  134. local function getMaxRank(rankType)
  135. return 200
  136. end
  137. -- 得到排行榜中名次对应需要达到的条件数
  138. local RANK_NEED_VALUES
  139. local function getRankNeedValue(rankType, rank)
  140. RANK_NEED_VALUES = RANK_NEED_VALUES or {}
  141. local minRankValue = getMinRankValue(rankType)
  142. if RANK_NEED_VALUES[rankType] then
  143. local nValue = nil
  144. for _, tData in ipairs(RANK_NEED_VALUES[rankType]) do
  145. if tData.nMinRank <= rank and tData.nMaxRank >= rank then
  146. nValue = tData.nValue
  147. break
  148. end
  149. end
  150. return nValue or minRankValue
  151. end
  152. local tWeekRankConfig = CommonDB_GetConfig(rankType)
  153. if not tWeekRankConfig then return end
  154. RANK_NEED_VALUES[rankType] = {}
  155. local nValue = nil
  156. for _, info in pairs(tWeekRankConfig) do
  157. local nMinRank = info.ranks[1]
  158. local nMaxRank = info.ranks[2]
  159. table.insert(RANK_NEED_VALUES[rankType], {nMinRank = nMinRank, nMaxRank = nMaxRank, nValue = info.nMoney})
  160. if nMinRank <= rank and nMaxRank >= rank then
  161. nValue = info.nMoney
  162. end
  163. end
  164. return nValue or minRankValue
  165. end
  166. -- 得到指定排行榜指定名次的配置信息
  167. local function getRankInfo(rankType, rank)
  168. local tWeekRankConfig = CommonDB_GetConfig(rankType)
  169. if not tWeekRankConfig then return end
  170. local rankInfo
  171. for _,info in pairs(tWeekRankConfig) do
  172. if rank >= info.ranks[1] and rank <= info.ranks[2] then
  173. rankInfo = info
  174. break
  175. end
  176. end
  177. return rankInfo
  178. end
  179. -- 获取奖励信息
  180. local function getRewardInfoByRank(rankType, rank)
  181. local tWeekRankConfig = CommonDB_GetConfig(rankType)
  182. if not tWeekRankConfig then return end
  183. local rewardInfo
  184. for _,info in pairs(tWeekRankConfig) do
  185. if rank >= info.ranks[1] and rank <= info.ranks[2] then
  186. rewardInfo = info.prize
  187. break
  188. end
  189. end
  190. return rewardInfo
  191. end
  192. -- 获取指定排名类型DB数据
  193. local function getBoard(rankType)
  194. return Coomondb[rankType]
  195. end
  196. -- -- 获取指定排名类型、指定用户的排名
  197. local function getRank(rankType, uuid)
  198. local board = getBoard(rankType)
  199. if not board then return end
  200. return board.uuid2rank[uuid]
  201. end
  202. -- 获取指定排名类型、指定用户的发送排名
  203. local function getSendRank(rankType, uuid)
  204. local board = getBoard(rankType)
  205. if not board then return end
  206. return board.sendUuid2rank[uuid]
  207. end
  208. -- 排名算法
  209. local function cmpRank(rankType, data1, data2)
  210. if data1.value ~= data2.value then
  211. return data1.value > data2.value
  212. end
  213. return data1.time < data2.time
  214. end
  215. -- 更新排名
  216. local function updateRank(board)
  217. if not board then return end
  218. -- 清空普通排名和发送排名玩家数据
  219. for uuid in pairs(board.uuid2rank) do
  220. board.uuid2rank[uuid] = nil
  221. board.sendUuid2rank[uuid] = nil
  222. end
  223. -- 设置普通排名
  224. for rank, data in ipairs(board.rank2data) do
  225. board.uuid2rank[data.uuid] = rank
  226. end
  227. -- 清空发送排名
  228. for rank in ipairs(board.sendRank2data) do
  229. board.sendRank2data[rank] = nil
  230. end
  231. local minRankValue = getMinRankValue(board.rankType) -- 排名最小需要的排名值
  232. local aleadyRankCnt = 0 -- 已经排好的玩家数
  233. local maxRank = getMaxRank(board.rankType) -- 最多排名玩家数量
  234. for rank = 1, maxRank do
  235. local rankNeedValue = getRankNeedValue(board.rankType, rank) -- 取当前排名需要的排名值
  236. local rank2data = board.rank2data[aleadyRankCnt + 1] -- 当前排的玩家
  237. if rank2data then -- 还有玩家需要排
  238. if rank2data.value >= rankNeedValue then -- 达到排名值,可以排名
  239. board.sendUuid2rank[rank2data.uuid] = rank -- 设置玩家发送排名
  240. board.sendRank2data[rank] = rank2data -- 设置发送排名数据
  241. aleadyRankCnt = aleadyRankCnt + 1 -- 排名玩家数量+1
  242. elseif rankNeedValue <= minRankValue then -- 未达到排名值 且 当前排名值 小于等于 最小需要的排名值了,则后面的玩家都不需要排了
  243. break
  244. else -- 未到达最低排名值,当前名次未有玩家达到
  245. board.sendRank2data[rank] = -1
  246. end
  247. else -- 没玩家排了直接停止
  248. break
  249. end
  250. end
  251. end
  252. -- 更新数据
  253. local function updateData(rankType, data)
  254. local board = getBoard(rankType)
  255. if not board then return end
  256. local uuid = data.uuid
  257. local oldRank = getRank(rankType, uuid) or (#board.rank2data + 1)
  258. board.rank2data[oldRank] = data
  259. -- 向后比较(data.value 减少时),往排名低方向->
  260. for i = oldRank + 1, #board.rank2data do
  261. local data1 = board.rank2data[i - 1]
  262. local data2 = board.rank2data[i]
  263. if cmpRank(rankType, data1, data2) then
  264. break
  265. end
  266. board.rank2data[i - 1] = data2
  267. board.rank2data[i] = data1
  268. end
  269. -- 向前比较(data.value 增加时),往排名高方向<-
  270. for i = oldRank - 1, 1, -1 do
  271. local data1 = board.rank2data[i]
  272. local data2 = board.rank2data[i + 1]
  273. if cmpRank(rankType, data1, data2) then
  274. break
  275. end
  276. board.rank2data[i] = data2
  277. board.rank2data[i + 1] = data1
  278. end
  279. local maxRank = getMaxRank(rankType)
  280. board.rank2data[maxRank + 1] = nil
  281. return true
  282. end
  283. -- 加载排行榜
  284. local function loadBoard()
  285. local cnt = 0
  286. LuaMongo.find(DB.db_common_rank, nil)
  287. while true do
  288. local data = {}
  289. if not LuaMongo.next(data) then
  290. break
  291. end
  292. cnt = cnt + 1
  293. if cnt % 1000 == 0 then
  294. _G.collectgarbage("step", 100000)
  295. end
  296. updateData(data.rankType, data)
  297. end
  298. for _, board in pairs(Coomondb) do
  299. updateRank(board)
  300. end
  301. end
  302. -- 重置排行数据
  303. local function resertBoard(board)
  304. board.uuid2rank = {} -- 根据UUID获取名次
  305. board.sendUuid2rank = {} -- 根据UUID获取发送名次
  306. board.rank2data = {} -- 根据名次获取DATA
  307. board.sendRank2data = {} -- 根据名次获取发送DATA
  308. end
  309. -- 初始排行榜
  310. local function initBoard(rankType)
  311. local board = {}
  312. resertBoard(board)
  313. board.rankType = rankType
  314. Coomondb[rankType] = board
  315. end
  316. -- 根据类型+uuid从db中取data
  317. local function getDBData(rankType, uuid)
  318. CoomonQueryForData.rankType = rankType
  319. CoomonQueryForData.uuid = uuid
  320. local data = {}
  321. LuaMongo.find(DB.db_common_rank, CoomonQueryForData)
  322. return LuaMongo.next(data) and data
  323. end
  324. -- 更新DB数据
  325. local function updateDBData(data)
  326. local oldData = getDBData(data.rankType, data.uuid)
  327. if oldData then
  328. CoomonQueryByUuid._id = oldData._id
  329. LuaMongo.update(DB.db_common_rank, CoomonQueryByUuid, data)
  330. else
  331. LuaMongo.insert(DB.db_common_rank, data)
  332. end
  333. end
  334. -- 设置排名数据
  335. local function billboardSet(data)
  336. local board = getBoard(data.rankType)
  337. if not board then return end
  338. updateData(data.rankType, data)
  339. updateRank(board)
  340. updateDBData(data)
  341. end
  342. -- 获取发送奖励的邮件ID
  343. local function getMailID(rankType, rankInfo)
  344. if CommonDefine.COMMONRANK_TYPE_WEEKRANK == rankType then
  345. return WeekLoopActDef.WEEKACT_RANK_MAILID
  346. end
  347. return WeekLoopActDef.WEEKACT_RANK_MAILID
  348. end
  349. -- 得到指定排行榜指定配置信息的奖励信息
  350. local function getRewardInfoByInfo(rankType, rankInfo)
  351. if CommonDefine.COMMONRANK_TYPE_WEEKRANK == rankType then
  352. return rankInfo.prize
  353. end
  354. return rankInfo.prize
  355. end
  356. -- 奖励发送
  357. MAIL_SEND_CACHE = MAIL_SEND_CACHE or nil
  358. local function rewardSend(rankType)
  359. local board = getBoard(rankType)
  360. if not board then return end
  361. MAIL_SEND_CACHE = MAIL_SEND_CACHE or {}
  362. MAIL_SEND_CACHE[rankType] = {}
  363. local mailID = getMailID()
  364. for rank, rankData in ipairs(board.sendRank2data) do
  365. if rankData and rankData ~= -1 then
  366. local rankInfo = getRankInfo(rankType, rank)
  367. if rankInfo then
  368. MAIL_SEND_CACHE[rankType][rank] = rankData.uuid
  369. --mailID = getMailID(rankType, rankInfo)
  370. --[[
  371. local mailID = getMailID(rankType, rankInfo)
  372. local rewardInfo = getRewardInfoByInfo(rankType, rankInfo)
  373. local mailConfig = MailExcel.mail[mailID]
  374. local title = mailConfig.title
  375. local senderName = mailConfig.senderName
  376. local content = mailConfig.content
  377. MailManager.add(MailManager.SYSTEM, rankData.uuid,
  378. title, Util.format(content, rank), rewardInfo, senderName) --]]
  379. end
  380. end
  381. end
  382. Timer.addLater(10, CommonDB_SendPrize, mailID, rankType)
  383. -- 把内存中的数据重置,并移除DB中数据
  384. resertBoard(board)
  385. CoomonQueryByRankType.rankType = rankType
  386. LuaMongo.remove(DB.db_common_rank, CoomonQueryByRankType)
  387. end
  388. -- 包装档位奖励详情数据
  389. local function wrapOpenServerRankRewardList(rankType, net, info)
  390. net.minRank = info.ranks[1]
  391. net.maxRank = info.ranks[2]
  392. local rewardInfo = info.prize
  393. local len = 0
  394. for index,itemInfo in ipairs(rewardInfo) do
  395. len = len + 1
  396. Grid.makeItem(net.items[index], itemInfo[1], itemInfo[2])
  397. end
  398. net.items[0] = len
  399. end
  400. -- 启动就初始化
  401. function initAfterStart()
  402. if _G.is_middle == true then return end
  403. for nType = CommonDefine.COMMONRANK_TYPE_MIN, CommonDefine.COMMONRANK_TYPE_MAX do
  404. initBoard(nType)
  405. print("[initAfterStart] 初始化排行榜 nType = "..nType)
  406. end
  407. loadBoard()
  408. end
  409. -- 得到最大发送排行名次数据
  410. function getMaxSendRank(rankType)
  411. if CommonDefine.COMMONRANK_TYPE_WEEKRANK == rankType then
  412. return MAX_SEND_WEEKACTRANK
  413. end
  414. return MAX_SEND_RANK
  415. end
  416. -- 包装档位名次数据
  417. function wrapOpenServerRankList(rankType, net, rank)
  418. local board = getBoard(rankType)
  419. local sendRankData = board.sendRank2data[rank]
  420. net.rank = rank
  421. net.rankNeedValue = getRankNeedValue(rankType, rank)
  422. if sendRankData and sendRankData ~= -1 then
  423. local userDB = RoleDBLogic.getDb(sendRankData.uuid)
  424. net.uid = sendRankData.uuid
  425. net.name = userDB.name
  426. net.head = userDB.head
  427. net.rankValue = sendRankData.value
  428. net.headFrame = userDB.headFrame
  429. else
  430. net.uid = "-1"
  431. net.name = ""
  432. net.head = -1
  433. net.rankValue = 0
  434. net.headFrame = -1
  435. end
  436. local rewardInfo = getRewardInfoByRank(rankType, rank)
  437. local len = 0
  438. if rewardInfo then
  439. for index,itemInfo in ipairs(rewardInfo) do
  440. len = len + 1
  441. Grid.makeItem(net.items[index], itemInfo[1], itemInfo[2])
  442. end
  443. end
  444. net.items[0] = len
  445. end
  446. -- 包装自己名次数据
  447. function wrapOwnerData(rankType, net, uuid)
  448. local maxRank = getMaxRank(rankType)
  449. local sendRank = getSendRank(rankType, uuid)
  450. local board = getBoard(rankType)
  451. local rankData
  452. if sendRank then
  453. rankData = board.sendRank2data[sendRank]
  454. else
  455. local rank = getRank(rankType, uuid)
  456. rankData = rank and board.rank2data[rank]
  457. end
  458. net.rank = sendRank or -1
  459. net.rankValue = rankData and rankData.value or 0
  460. local len = 0
  461. if sendRank then
  462. local rewardInfo = getRewardInfoByRank(rankType, sendRank)
  463. for index,itemInfo in ipairs(rewardInfo) do
  464. len = len + 1
  465. Grid.makeItem(net.items[index], itemInfo[1], itemInfo[2])
  466. end
  467. end
  468. net.items[0] = len
  469. end
  470. -- 发送奖励详情
  471. function rewardQuery(human, rankType)
  472. local tWeekRankConfig = CommonDB_GetConfig(rankType)
  473. local msgRet = Msg.gc.GC_OPEN_SERVER_RANK_REWARD_QUERY
  474. msgRet.type = rankType
  475. local len = 0
  476. for _,info in ipairs(tWeekRankConfig) do
  477. len = len + 1
  478. wrapOpenServerRankRewardList(rankType, msgRet.list[len], info)
  479. end
  480. msgRet.list[0] = len
  481. Msg.send(msgRet, human.fd)
  482. end
  483. -- 排行值增加回调
  484. function onValueAdd(human, rankType, value)
  485. local dbData = getDBData(rankType, human.db._id) or {}
  486. local tValue = (dbData.value or 0) + value
  487. onValueSet(human, rankType, tValue)
  488. end
  489. -- 排行值设置回调
  490. function onValueSet(human, rankType, tValue)
  491. local dbData = getDBData(rankType, human.db._id) or {}
  492. dbData.value = tValue
  493. dbData.time = os.time()
  494. dbData.rankType = rankType
  495. dbData.uuid = human.db._id
  496. billboardSet(dbData)
  497. end
  498. -- 奖励发送回调
  499. function onRewardSend(nRankType)
  500. local openDay = CommonDB.getServerOpenDay()
  501. if not openDay then return end
  502. rewardSend(nRankType)
  503. end
  504. -- 定时器 邮件分开发,预防崩溃
  505. function CommonDB_SendPrize(mailID, rankType)
  506. if mailID and MAIL_SEND_CACHE and MAIL_SEND_CACHE[rankType] then
  507. local mailConfig = MailExcel.mail[mailID]
  508. local title = mailConfig.title
  509. local senderName = mailConfig.senderName
  510. local content = mailConfig.content
  511. local mailSends = MAIL_SEND_CACHE[rankType]
  512. for rank,uuid in pairs(mailSends) do
  513. local rankInfo = getRankInfo(rankType, rank)
  514. if rankInfo then
  515. local rewardInfo = getRewardInfoByInfo(rankType, rankInfo)
  516. if rewardInfo then
  517. MailManager.add(MailManager.SYSTEM, uuid,
  518. title, Util.format(content, rank), rewardInfo, senderName)
  519. end
  520. end
  521. end
  522. MAIL_SEND_CACHE[rankType] = nil
  523. end
  524. --[[
  525. -- 发完奖励后,把内存中的数据重置,并移除DB中数据
  526. local board = getBoard(rankType)
  527. if board then
  528. resertBoard(board)
  529. CoomonQueryByRankType.rankType = rankType
  530. LuaMongo.remove(DB.db_common_rank, CoomonQueryByRankType)
  531. end--]]
  532. end