-------------------------------- -- 文件名 : CommonRankDB.lua -- 文件说明 : 通用排行榜DB数据 -- 创建时间 : 2024/12/09 -- 创建人 : FC -------------------------------- local Msg = require("core.Msg") local Timer = require("core.Timer") local DB = require("common.DB") local CommonDB = require("common.CommonDB") local CommonDefine = require("common.CommonDefine") local Log = require("common.Log") local LuaMongo = _G.lua_mongo local Util = require("common.Util") local Grid = require("bag.Grid") local OpenAct = require("present.OpenAct") local RoleDBLogic = require("role.RoleDBLogic") local YunYingLogic = require("yunying.YunYingLogic") local MailManager = require("mail.MailManager") local MailExcel = require("excel.mail") local OpenActExcel = require("excel.openAct") local WeekLoopActCof = require("excel.WeekLoopAct") local WeekLoopActDef = require("WeekendLoopActivity.WeekendLoopActDefine") --[[ 开服活动排行DB操作,封装了一些公共处理方法 db字段只是缓存排名好的数据(只是内存数据) Coomondb = { [rankType] = { -- 排名类型 rankType = xxx, -- 排名类型 uuid2rank = { -- 根据UUID获取名次 [uuid] = rank, -- 玩家uuid = 排行名次 ... }, sendUuid2rank = { -- 根据UUID获取发送名次 [uuid] = rank, -- 玩家uuid = 真实发送的排行名次 ... }, rank2data = { -- 根据名次获取DATA [rank] = { -- 排行名次 = 玩家排名数据 uuid = xxx, -- 玩家uuid rankType = xxx, -- 排名类型 value = xxx, -- 排名值 time = xxx, -- 排名值更新时间 _id = xxx, -- db记录中的uuid }, ... }, sendRank2data = { -- 根据名次获取发送DATA [rank] = { -- 排行名次 = 真实发送玩家排名数据 uuid = xxx, -- 玩家uuid rankType = xxx, -- 排名类型 value = xxx, -- 排名值 time = xxx, -- 排名值更新时间 _id = xxx, -- db记录中的uuid }, ... } }, ... } DB: db_common_rank = { -- 开服排行类活动 [uuid] = { uuid = xxx, -- 玩家uuid rankType= xxx, -- 排名类型 value = xxx, -- 排行值 time = xxx, -- 排行值更新时间 } } local: CommonDB_GetConfig() -- 得到指定排名类型的活动配置 getMinRankValue() -- 得到排行榜中最低上榜条件数 getMaxRank() -- 得到活动最多排名名次 getRankNeedValue() -- 得到排行榜中名次对应需要达到的条件数 getRankInfo() -- 得到指定排行榜指定名次的配置信息 getRewardInfoByRank() -- 获取奖励信息 getBoard() -- 获取指定排名类型DB数据 getRank() -- 获取指定排名类型、指定用户的排名 getSendRank() -- 获取指定排名类型、指定用户的发送排名 cmpRank() -- 排名算法 updateRank() -- 更新排名 updateData() -- 更新数据 loadBoard() -- 加载排行榜 resertBoard() -- 重置排行数据 initBoard() -- 初始排行榜 getDBData() -- 根据类型+uuid从db中取data updateDBData() -- 更新DB数据 billboardSet() -- 设置排名数据 getMailID() -- 获取发送奖励的邮件ID getRewardInfoByInfo() -- 得到指定排行榜指定配置信息的奖励信息 rewardSend() -- 奖励发送 wrapOpenServerRankRewardList -- 包装档位奖励详情数据 public: initAfterStart() -- 启动就初始化 getMaxSendRank() -- 得到最大发送排行名次数据 wrapOpenServerRankList() -- 包装档位名次数据 wrapOwnerData() -- 包装自己名次数据 rewardQuery() -- 发送奖励详情 onValueAdd() -- 排行值增加回调 onValueSet() -- 排行值设置回调 onRewardSend() -- 奖励发送回调 --]] WeekAct_RankName = "WeekAct_ChargeRank" MAX_SEND_RANK = 10 -- 最大发送排名数 MAX_SEND_WEEKACTRANK = 21 -- 周活动排行榜发送排名数 Coomondb = Coomondb or {} -- [rankType] = board CoomonQueryForData = {rankType = 1, uuid = 1} -- 通过排名类型和玩家uuid查找DB数据 CoomonQueryByUuid = {_id = 1} -- 通过DB的uuid更新DB数据 CoomonQueryByRankType = {rankType = 1} -- 通过排名类型查找DB数据 local function CommonDB_GetConfig(rankType) if CommonDefine.COMMONRANK_TYPE_WEEKRANK == rankType then return WeekLoopActCof.Rank end return nil end -- 得到排行榜中最低上榜条件数 local MIN_RANK_VALUES local function getMinRankValue(rankType) MIN_RANK_VALUES = MIN_RANK_VALUES or {} if MIN_RANK_VALUES[rankType] then return MIN_RANK_VALUES[rankType] end local tWeekRankConfig = CommonDB_GetConfig(rankType) if not tWeekRankConfig then return end -- 这里后续有排行榜类型,保持命名一致 local minRankValue for _,info in ipairs(tWeekRankConfig) do if not minRankValue or minRankValue > info.nMoney then minRankValue = info.nMoney end end MIN_RANK_VALUES[rankType] = minRankValue return MIN_RANK_VALUES[rankType] end --local MAX_RANKS local function getMaxRank(rankType) return 200 end -- 得到排行榜中名次对应需要达到的条件数 local RANK_NEED_VALUES local function getRankNeedValue(rankType, rank) RANK_NEED_VALUES = RANK_NEED_VALUES or {} local minRankValue = getMinRankValue(rankType) if RANK_NEED_VALUES[rankType] then local nValue = nil for _, tData in ipairs(RANK_NEED_VALUES[rankType]) do if tData.nMinRank <= rank and tData.nMaxRank >= rank then nValue = tData.nValue break end end return nValue or minRankValue end local tWeekRankConfig = CommonDB_GetConfig(rankType) if not tWeekRankConfig then return end RANK_NEED_VALUES[rankType] = {} local nValue = nil for _, info in pairs(tWeekRankConfig) do local nMinRank = info.ranks[1] local nMaxRank = info.ranks[2] table.insert(RANK_NEED_VALUES[rankType], {nMinRank = nMinRank, nMaxRank = nMaxRank, nValue = info.nMoney}) if nMinRank <= rank and nMaxRank >= rank then nValue = info.nMoney end end return nValue or minRankValue end -- 得到指定排行榜指定名次的配置信息 local function getRankInfo(rankType, rank) local tWeekRankConfig = CommonDB_GetConfig(rankType) if not tWeekRankConfig then return end local rankInfo for _,info in pairs(tWeekRankConfig) do if rank >= info.ranks[1] and rank <= info.ranks[2] then rankInfo = info break end end return rankInfo end -- 获取奖励信息 local function getRewardInfoByRank(rankType, rank) local tWeekRankConfig = CommonDB_GetConfig(rankType) if not tWeekRankConfig then return end local rewardInfo for _,info in pairs(tWeekRankConfig) do if rank >= info.ranks[1] and rank <= info.ranks[2] then rewardInfo = info.prize break end end return rewardInfo end -- 获取指定排名类型DB数据 local function getBoard(rankType) return Coomondb[rankType] end -- -- 获取指定排名类型、指定用户的排名 local function getRank(rankType, uuid) local board = getBoard(rankType) if not board then return end return board.uuid2rank[uuid] end -- 获取指定排名类型、指定用户的发送排名 local function getSendRank(rankType, uuid) local board = getBoard(rankType) if not board then return end return board.sendUuid2rank[uuid] end -- 排名算法 local function cmpRank(rankType, data1, data2) if data1.value ~= data2.value then return data1.value > data2.value end return data1.time < data2.time end -- 更新排名 local function updateRank(board) if not board then return end -- 清空普通排名和发送排名玩家数据 for uuid in pairs(board.uuid2rank) do board.uuid2rank[uuid] = nil board.sendUuid2rank[uuid] = nil end -- 设置普通排名 for rank, data in ipairs(board.rank2data) do board.uuid2rank[data.uuid] = rank end -- 清空发送排名 for rank in ipairs(board.sendRank2data) do board.sendRank2data[rank] = nil end local minRankValue = getMinRankValue(board.rankType) -- 排名最小需要的排名值 local aleadyRankCnt = 0 -- 已经排好的玩家数 local maxRank = getMaxRank(board.rankType) -- 最多排名玩家数量 for rank = 1, maxRank do local rankNeedValue = getRankNeedValue(board.rankType, rank) -- 取当前排名需要的排名值 local rank2data = board.rank2data[aleadyRankCnt + 1] -- 当前排的玩家 if rank2data then -- 还有玩家需要排 if rank2data.value >= rankNeedValue then -- 达到排名值,可以排名 board.sendUuid2rank[rank2data.uuid] = rank -- 设置玩家发送排名 board.sendRank2data[rank] = rank2data -- 设置发送排名数据 aleadyRankCnt = aleadyRankCnt + 1 -- 排名玩家数量+1 elseif rankNeedValue <= minRankValue then -- 未达到排名值 且 当前排名值 小于等于 最小需要的排名值了,则后面的玩家都不需要排了 break else -- 未到达最低排名值,当前名次未有玩家达到 board.sendRank2data[rank] = -1 end else -- 没玩家排了直接停止 break end end end -- 更新数据 local function updateData(rankType, data) local board = getBoard(rankType) if not board then return end local uuid = data.uuid local oldRank = getRank(rankType, uuid) or (#board.rank2data + 1) board.rank2data[oldRank] = data -- 向后比较(data.value 减少时),往排名低方向-> for i = oldRank + 1, #board.rank2data do local data1 = board.rank2data[i - 1] local data2 = board.rank2data[i] if cmpRank(rankType, data1, data2) then break end board.rank2data[i - 1] = data2 board.rank2data[i] = data1 end -- 向前比较(data.value 增加时),往排名高方向<- for i = oldRank - 1, 1, -1 do local data1 = board.rank2data[i] local data2 = board.rank2data[i + 1] if cmpRank(rankType, data1, data2) then break end board.rank2data[i] = data2 board.rank2data[i + 1] = data1 end local maxRank = getMaxRank(rankType) board.rank2data[maxRank + 1] = nil return true end -- 加载排行榜 local function loadBoard() local cnt = 0 LuaMongo.find(DB.db_common_rank, nil) while true do local data = {} if not LuaMongo.next(data) then break end cnt = cnt + 1 if cnt % 1000 == 0 then _G.collectgarbage("step", 100000) end updateData(data.rankType, data) end for _, board in pairs(Coomondb) do updateRank(board) end end -- 重置排行数据 local function resertBoard(board) board.uuid2rank = {} -- 根据UUID获取名次 board.sendUuid2rank = {} -- 根据UUID获取发送名次 board.rank2data = {} -- 根据名次获取DATA board.sendRank2data = {} -- 根据名次获取发送DATA end -- 初始排行榜 local function initBoard(rankType) local board = {} resertBoard(board) board.rankType = rankType Coomondb[rankType] = board end -- 根据类型+uuid从db中取data local function getDBData(rankType, uuid) CoomonQueryForData.rankType = rankType CoomonQueryForData.uuid = uuid local data = {} LuaMongo.find(DB.db_common_rank, CoomonQueryForData) return LuaMongo.next(data) and data end -- 更新DB数据 local function updateDBData(data) local oldData = getDBData(data.rankType, data.uuid) if oldData then CoomonQueryByUuid._id = oldData._id LuaMongo.update(DB.db_common_rank, CoomonQueryByUuid, data) else LuaMongo.insert(DB.db_common_rank, data) end end -- 设置排名数据 local function billboardSet(data) local board = getBoard(data.rankType) if not board then return end updateData(data.rankType, data) updateRank(board) updateDBData(data) end -- 获取发送奖励的邮件ID local function getMailID(rankType, rankInfo) if CommonDefine.COMMONRANK_TYPE_WEEKRANK == rankType then return WeekLoopActDef.WEEKACT_RANK_MAILID end return WeekLoopActDef.WEEKACT_RANK_MAILID end -- 得到指定排行榜指定配置信息的奖励信息 local function getRewardInfoByInfo(rankType, rankInfo) if CommonDefine.COMMONRANK_TYPE_WEEKRANK == rankType then return rankInfo.prize end return rankInfo.prize end -- 奖励发送 MAIL_SEND_CACHE = MAIL_SEND_CACHE or nil local function rewardSend(rankType) local board = getBoard(rankType) if not board then return end MAIL_SEND_CACHE = MAIL_SEND_CACHE or {} MAIL_SEND_CACHE[rankType] = {} local mailID = getMailID() for rank, rankData in ipairs(board.sendRank2data) do if rankData and rankData ~= -1 then local rankInfo = getRankInfo(rankType, rank) if rankInfo then MAIL_SEND_CACHE[rankType][rank] = rankData.uuid --mailID = getMailID(rankType, rankInfo) --[[ local mailID = getMailID(rankType, rankInfo) local rewardInfo = getRewardInfoByInfo(rankType, rankInfo) local mailConfig = MailExcel.mail[mailID] local title = mailConfig.title local senderName = mailConfig.senderName local content = mailConfig.content MailManager.add(MailManager.SYSTEM, rankData.uuid, title, Util.format(content, rank), rewardInfo, senderName) --]] end end end Timer.addLater(10, CommonDB_SendPrize, mailID, rankType) -- 把内存中的数据重置,并移除DB中数据 resertBoard(board) CoomonQueryByRankType.rankType = rankType LuaMongo.remove(DB.db_common_rank, CoomonQueryByRankType) end -- 包装档位奖励详情数据 local function wrapOpenServerRankRewardList(rankType, net, info) net.minRank = info.ranks[1] net.maxRank = info.ranks[2] local rewardInfo = info.prize local len = 0 for index,itemInfo in ipairs(rewardInfo) do len = len + 1 Grid.makeItem(net.items[index], itemInfo[1], itemInfo[2]) end net.items[0] = len end -- 启动就初始化 function initAfterStart() if _G.is_middle == true then return end for nType = CommonDefine.COMMONRANK_TYPE_MIN, CommonDefine.COMMONRANK_TYPE_MAX do initBoard(nType) print("[initAfterStart] 初始化排行榜 nType = "..nType) end loadBoard() end -- 得到最大发送排行名次数据 function getMaxSendRank(rankType) if CommonDefine.COMMONRANK_TYPE_WEEKRANK == rankType then return MAX_SEND_WEEKACTRANK end return MAX_SEND_RANK end -- 包装档位名次数据 function wrapOpenServerRankList(rankType, net, rank) local board = getBoard(rankType) local sendRankData = board.sendRank2data[rank] net.rank = rank net.rankNeedValue = getRankNeedValue(rankType, rank) if sendRankData and sendRankData ~= -1 then local userDB = RoleDBLogic.getDb(sendRankData.uuid) net.uid = sendRankData.uuid net.name = userDB.name net.head = userDB.head net.rankValue = sendRankData.value net.headFrame = userDB.headFrame else net.uid = "-1" net.name = "" net.head = -1 net.rankValue = 0 net.headFrame = -1 end local rewardInfo = getRewardInfoByRank(rankType, rank) local len = 0 if rewardInfo then for index,itemInfo in ipairs(rewardInfo) do len = len + 1 Grid.makeItem(net.items[index], itemInfo[1], itemInfo[2]) end end net.items[0] = len end -- 包装自己名次数据 function wrapOwnerData(rankType, net, uuid) local maxRank = getMaxRank(rankType) local sendRank = getSendRank(rankType, uuid) local board = getBoard(rankType) local rankData if sendRank then rankData = board.sendRank2data[sendRank] else local rank = getRank(rankType, uuid) rankData = rank and board.rank2data[rank] end net.rank = sendRank or -1 net.rankValue = rankData and rankData.value or 0 local len = 0 if sendRank then local rewardInfo = getRewardInfoByRank(rankType, sendRank) for index,itemInfo in ipairs(rewardInfo) do len = len + 1 Grid.makeItem(net.items[index], itemInfo[1], itemInfo[2]) end end net.items[0] = len end -- 发送奖励详情 function rewardQuery(human, rankType) local tWeekRankConfig = CommonDB_GetConfig(rankType) local msgRet = Msg.gc.GC_OPEN_SERVER_RANK_REWARD_QUERY msgRet.type = rankType local len = 0 for _,info in ipairs(tWeekRankConfig) do len = len + 1 wrapOpenServerRankRewardList(rankType, msgRet.list[len], info) end msgRet.list[0] = len Msg.send(msgRet, human.fd) end -- 排行值增加回调 function onValueAdd(human, rankType, value) local dbData = getDBData(rankType, human.db._id) or {} local tValue = (dbData.value or 0) + value onValueSet(human, rankType, tValue) end -- 排行值设置回调 function onValueSet(human, rankType, tValue) local dbData = getDBData(rankType, human.db._id) or {} dbData.value = tValue dbData.time = os.time() dbData.rankType = rankType dbData.uuid = human.db._id billboardSet(dbData) end -- 奖励发送回调 function onRewardSend(nRankType) local openDay = CommonDB.getServerOpenDay() if not openDay then return end rewardSend(nRankType) end -- 定时器 邮件分开发,预防崩溃 function CommonDB_SendPrize(mailID, rankType) if mailID and MAIL_SEND_CACHE and MAIL_SEND_CACHE[rankType] then local mailConfig = MailExcel.mail[mailID] local title = mailConfig.title local senderName = mailConfig.senderName local content = mailConfig.content local mailSends = MAIL_SEND_CACHE[rankType] for rank,uuid in pairs(mailSends) do local rankInfo = getRankInfo(rankType, rank) if rankInfo then local rewardInfo = getRewardInfoByInfo(rankType, rankInfo) if rewardInfo then MailManager.add(MailManager.SYSTEM, uuid, title, Util.format(content, rank), rewardInfo, senderName) end end end MAIL_SEND_CACHE[rankType] = nil end --[[ -- 发完奖励后,把内存中的数据重置,并移除DB中数据 local board = getBoard(rankType) if board then resertBoard(board) CoomonQueryByRankType.rankType = rankType LuaMongo.remove(DB.db_common_rank, CoomonQueryByRankType) end--]] end