local Msg = require("core.Msg") local Timer = require("core.Timer") local DB = require("common.DB") local CommonDB = require("common.CommonDB") 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") --[[ 开服活动排行DB操作,封装了一些公共处理方法 db字段只是缓存排名好的数据(只是内存数据) db = { [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_openServer_billboard = { -- 开服排行类活动 [uuid] = { uuid = xxx, -- 玩家uuid rankType= xxx, -- 排名类型 value = xxx, -- 排行值 time = xxx, -- 排行值更新时间 } } local: getOpenActConfig() -- 得到指定排名类型的活动配置 getMinRankValue() -- 得到排行榜中最低上榜条件数 getMaxRank() -- 得到活动最多排名名次 getRankNeedValue() -- 得到排行榜中名次对应需要达到的条件数 getRankInfo() -- 得到指定排行榜指定名次的配置信息 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() -- 奖励发送回调 --]] RANK_TYPE_DAY_TOPUP = 1 -- 开服充值每日排名类型 RANK_TYPE_TOTAL_TOPUP = 2 -- 开服充值累计排名类型 RANK_TYPE_DAY_DRAW_CARD = 3 -- 开服招募每日排名类型 RANK_TYPE_TOTAL_DRAW_CARD = 4 -- 开服招募累计排名类型 RANK_TYPE_TOTAL_TOWER = 5 -- 开服爬塔累计排名类型 MAX_SEND_RANK = 10 -- 最大发送排名数 db = db or {} -- [rankType] = board QueryForData = {rankType = 1, uuid = 1} -- 通过排名类型和玩家uuid查找DB数据 QueryByUuid = {_id = 1} -- 通过DB的uuid更新DB数据 QueryByRankType = {rankType = 1} -- 通过排名类型查找DB数据 local function getOpenActConfig(rankType) if rankType == RANK_TYPE_DAY_TOPUP or rankType == RANK_TYPE_TOTAL_TOPUP then return OpenActExcel.topupRank end if rankType == RANK_TYPE_DAY_DRAW_CARD or rankType == RANK_TYPE_TOTAL_DRAW_CARD then return OpenActExcel.drawCardRank end if rankType == RANK_TYPE_TOTAL_TOWER then return OpenActExcel.towerRank end 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 openActConfig = getOpenActConfig(rankType) if not openActConfig then return end local minRankValue for _,info in ipairs(openActConfig) do if rankType == RANK_TYPE_DAY_TOPUP or rankType == RANK_TYPE_DAY_DRAW_CARD then if not minRankValue or minRankValue > info.dayNeedValue then minRankValue = info.dayNeedValue end elseif rankType == RANK_TYPE_TOTAL_TOPUP or rankType == RANK_TYPE_TOTAL_DRAW_CARD or rankType == RANK_TYPE_TOTAL_TOWER then if not minRankValue or minRankValue > info.totalNeedValue then minRankValue = info.totalNeedValue end end end MIN_RANK_VALUES[rankType] = minRankValue return MIN_RANK_VALUES[rankType] end --local MAX_RANKS local function getMaxRank(rankType) return 200 --[[ MAX_RANKS = MAX_RANKS or {} if MAX_RANKS[rankType] then return MAX_RANKS[rankType] end local openActConfig = getOpenActConfig(rankType) if not openActConfig then return end local maxRank for _,info in ipairs(openActConfig) do if not maxRank or maxRank <= info.ranks[2] then maxRank = info.ranks[2] end end MAX_RANKS[rankType] = maxRank return maxRank --]] 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 return RANK_NEED_VALUES[rankType][rank] or minRankValue end local openActConfig = getOpenActConfig(rankType) if not openActConfig then return end RANK_NEED_VALUES[rankType] = {} for _,info in ipairs(openActConfig) do if rankType == RANK_TYPE_DAY_TOPUP or rankType == RANK_TYPE_DAY_DRAW_CARD then if minRankValue < info.dayNeedValue then for i = info.ranks[1],info.ranks[2] do RANK_NEED_VALUES[rankType][i] = info.dayNeedValue end else break end elseif rankType == RANK_TYPE_TOTAL_TOPUP or rankType == RANK_TYPE_TOTAL_DRAW_CARD or rankType == RANK_TYPE_TOTAL_TOWER then if minRankValue < info.totalNeedValue then for i = info.ranks[1],info.ranks[2] do RANK_NEED_VALUES[rankType][i] = info.totalNeedValue end else break end end end return RANK_NEED_VALUES[rankType][rank] or minRankValue end local function getRankInfo(rankType, rank) local openActConfig = getOpenActConfig(rankType) if not openActConfig then return end local rankInfo for _,info in ipairs(openActConfig) 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 openActConfig = getOpenActConfig(rankType) if not openActConfig then return end local rewardInfo for _,info in ipairs(openActConfig) do if rankType == RANK_TYPE_DAY_TOPUP or rankType == RANK_TYPE_DAY_DRAW_CARD then if rank >= info.ranks[1] and rank <= info.ranks[2] then rewardInfo = info.dayRewards break end elseif rankType == RANK_TYPE_TOTAL_TOPUP or rankType == RANK_TYPE_TOTAL_DRAW_CARD or rankType == RANK_TYPE_TOTAL_TOWER then if rank >= info.ranks[1] and rank <= info.ranks[2] then rewardInfo = info.totalRewards break end end end return rewardInfo end local function getBoard(rankType) return db[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_openServer_billboard, 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(db) 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 db[rankType] = board end local function getDBData(rankType, uuid) QueryForData.rankType = rankType QueryForData.uuid = uuid local data = {} LuaMongo.find(DB.db_openServer_billboard, QueryForData) return LuaMongo.next(data) and data end local function updateDBData(data) local oldData = getDBData(data.rankType, data.uuid) if oldData then QueryByUuid._id = oldData._id LuaMongo.update(DB.db_openServer_billboard, QueryByUuid, data) else LuaMongo.insert(DB.db_openServer_billboard, 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 local function getMailID(rankType, rankInfo) if rankType == RANK_TYPE_DAY_TOPUP or rankType == RANK_TYPE_DAY_DRAW_CARD then return rankInfo.dayMailID elseif rankType == RANK_TYPE_TOTAL_TOPUP or rankType == RANK_TYPE_TOTAL_DRAW_CARD or rankType == RANK_TYPE_TOTAL_TOWER then return rankInfo.totalMailID end end local function getRewardInfoByInfo(rankType, rankInfo) if rankType == RANK_TYPE_DAY_TOPUP or rankType == RANK_TYPE_DAY_DRAW_CARD then return rankInfo.dayRewards elseif rankType == RANK_TYPE_TOTAL_TOPUP or rankType == RANK_TYPE_TOTAL_DRAW_CARD or rankType == RANK_TYPE_TOTAL_TOWER then return rankInfo.totalRewards end 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 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, boardReward, mailID, rankType) -- 把内存中的数据重置,并移除DB中数据 resertBoard(board) QueryByRankType.rankType = rankType LuaMongo.remove(DB.db_openServer_billboard, QueryByRankType) end local function wrapOpenServerRankRewardList(rankType, net, info) net.minRank = info.ranks[1] net.maxRank = info.ranks[2] local rewardInfo if rankType == RANK_TYPE_DAY_TOPUP or rankType == RANK_TYPE_DAY_DRAW_CARD then net.rankNeedValue = info.dayNeedValue rewardInfo = info.dayRewards elseif rankType == RANK_TYPE_TOTAL_TOPUP or rankType == RANK_TYPE_TOTAL_DRAW_CARD or rankType == RANK_TYPE_TOTAL_TOWER then net.rankNeedValue = info.totalNeedValue rewardInfo = info.totalRewards end 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 initBoard(RANK_TYPE_DAY_TOPUP) initBoard(RANK_TYPE_TOTAL_TOPUP) initBoard(RANK_TYPE_DAY_DRAW_CARD) initBoard(RANK_TYPE_TOTAL_DRAW_CARD) initBoard(RANK_TYPE_TOTAL_TOWER) loadBoard() end function getMaxSendRank(rankType) 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 openActConfig = getOpenActConfig(rankType) local msgRet = Msg.gc.GC_OPEN_SERVER_RANK_REWARD_QUERY msgRet.type = rankType local len = 0 for _,info in ipairs(openActConfig) 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(funcID) local funcConfig = YunYingLogic.getFuncConfig(funcID) if not funcConfig then return end local config = OpenActExcel.openAct[funcConfig.param] if not config then return end local openDay = CommonDB.getServerOpenDay() if not openDay then return end if openDay > (config.eDay + 1) then return end if funcConfig.param == OpenAct.OPEN_ACT_TOPUP_RANK then rewardSend(RANK_TYPE_DAY_TOPUP) if openDay == (config.eDay + 1) then rewardSend(RANK_TYPE_TOTAL_TOPUP) end elseif funcConfig.param == OpenAct.OPEN_ACT_DRAW_CARD_RANK then rewardSend(RANK_TYPE_DAY_DRAW_CARD) if openDay == (config.eDay + 1) then rewardSend(RANK_TYPE_TOTAL_DRAW_CARD) end elseif funcConfig.param == OpenAct.OPEN_ACT_TOWER_RANK then if openDay == (config.eDay + 1) then rewardSend(RANK_TYPE_TOTAL_TOWER) end end end -- 定时器 邮件分开发,预防崩溃 function boardReward(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) QueryByRankType.rankType = rankType LuaMongo.remove(DB.db_openServer_billboard, QueryByRankType) end--]] end --[[ function gmSendReward() print("OpenServerRankDB gmSendReward start") local rankType = RANK_TYPE_DAY_TOPUP local board = getBoard(rankType) if not board then return end MAIL_SEND_CACHE = MAIL_SEND_CACHE or {} MAIL_SEND_CACHE[rankType] = {} local mailID 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) end end end Timer.addLater(10, boardReward, mailID, rankType) -- 日志 Log.write(Log.LOGID_DEBUG, "OpenServerRank", rankType) print("OpenServerRankDB gmSendReward end") end--]]