local skynet = require "skynet" local oo = require "Class" local log = require "Log" local pb = require "pb" local redisKeyUrl = require "RedisKeyUrl" local sqlUrl = require "SqlUrl" local mailManage = require "MailManage" local dataType = require "DataType" local errorInfo = require "ErrorInfo" local json = require "json" local Mail = oo.class() Mail.MailOpType_1 = 1 --获取邮件列表 Mail.MailOpType_2 = 2 --查阅/领取奖品 Mail.MailOpStatus_Suc = 1 --操作状态成功 Mail.MailOpStatus_NoMailID = 2 --不存在该邮件ID Mail.MailOpStatus_AlreadyGet = 3 --已经领取了 Mail.MailType_AllServer = 1 --全服邮件 Mail.MailType_User = 2 --用户邮件 Mail.MaxSendCount = 100 --一次发送最大数量 function Mail:Init() self.mailList = {} end --每5秒调一次 function Mail:On5SecTimer() self:BatchAddMail() end --从后台刷新邮件列表 function Mail:RefreshMailList() --向后端请求 local param = {} local web = skynet.server.gameConfig.WebConfig.host .. ":" .. skynet.server.gameConfig.WebConfig.port local url = skynet.server.common.getMailUrl local status, body = skynet.server.httpClient:PostJson(web, url, json:encode(param), "http") if 200 == status then local newbody = json:decode(body) if 200 == newbody.code then --判断旧的邮件是否还能继续使用 if next(self.mailList)~=nil then for k ,v in pairs(self.mailList) do local isCanGet = false for k1, v1 in pairs(newbody.data) do if k==v1.mailModel.mailId then isCanGet = true break end end v.isCanGet = isCanGet end end --添加新的邮件 for k, v in pairs(newbody.data) do local mailId = v.mailModel.mailId if not self.mailList[mailId] then self.mailList[mailId] = {} local curMail = self.mailList[mailId] curMail.mailInfo = v.mailModel curMail.award = v.giftArticlesModels curMail.isCanGet = true curMail.isSendAllOnlineUser = false --是否发送所有在线玩家 if "全服" == curMail.mailInfo.mailCondition then curMail.mailType = self.MailType_AllServer elseif "ID" == curMail.mailInfo.mailCondition then curMail.mailType = self.MailType_User local t1 = skynet.GetTime() local count = 0 local playerList = skynet.server.playerCenter:GetPlayerList() --给指定在线玩家发送新邮件 local uidList = skynet.server.common:Split( curMail.mailInfo.uidlist, ",") for k, v in pairs(uidList) do for userId, value in pairs(playerList) do if value.player.account == v and skynet.server.playerCenter.Status_Playing == value.status then self:AddMail(value.player, mailId , curMail.mailInfo , curMail.award , true ) count = count + 1 end end end log.info(string.format("邮箱 部分玩家发送邮件 发送数量 %d 时间花费 %d ", count, skynet.GetTime() - t1)) end end end elseif 702 == newbody.code then --s2cData.code = errorInfo.ErrorCode.AlreadyGet if next(self.mailList)~=nil then for k ,v in pairs(self.mailList) do v.isCanGet = false end end end else log.info("邮箱刷新 获取数据失败 status ", status) end end --邮件历史 function Mail:History(player, c2sData, s2cData) c2sData.data = assert(pb.decode("C2SMailHistory", c2sData.data)) local data = {} data.mailInfo = {} for k, v in pairs(player.gameData.mail.mailList) do for k1, v1 in pairs(player.gameData.mail.historyMail) do if v1 == v.mailId then table.insert(data.mailInfo, v) end end end s2cData.cmd = pb.enum("MsgType", "CMD_S2C_MailHistory") s2cData.data = assert(pb.encode("S2CMailHistory", data)) end --邮件领取奖励 function Mail:Award(player, c2sData, s2cData) c2sData.data = assert(pb.decode("C2SMailAward", c2sData.data)) local mailId = c2sData.data.mailId local data = {} data.mailInfo = {} if not mailId then s2cData.code = errorInfo.ErrorCode.ErrRequestParams else local isExist = false local nowTime = skynet.GetTime() for k, v in pairs(player.gameData.mail.mailList) do if mailId == v.mailId and dataType.MailStatus_NoGet == v.status and nowTime= v.failureTime then --已经领取了,无法再次领取 isExist = true s2cData.code = errorInfo.ErrorCode.AlreadyGet data.mailInfo = v break end end if not isExist then s2cData.code = errorInfo.ErrorCode.NoExistMailID end end s2cData.cmd = pb.enum("MsgType", "CMD_S2C_MailAward") s2cData.data = assert(pb.encode("S2CMailAward", data)) end --邮件读取 function Mail:Read(player, c2sData, s2cData) c2sData.data = assert(pb.decode("C2SReadMail", c2sData.data)) local mailId = c2sData.data.mailId local data = {} data.mailInfo = {} if not mailId then s2cData.code = errorInfo.ErrorCode.ErrRequestParams else for k, v in pairs(player.gameData.mail.mailList) do if mailId == v.mailId then -- 修改邮件的读取状态 v.status = dataType.MailStatus_AlreadyGet skynet.server.msgTips:Reduce(player , 23) data.mailInfo = v end end end s2cData.cmd = pb.enum("MsgType", "CMD_S2C_ReadMail") s2cData.data = assert(pb.encode("S2CReadMail", data)) log.info(string.format("玩家 %d 读取邮件 ID", player.userId, mailId)) end --删除已读邮件 function Mail:DeleteRead(player, c2sData, s2cData) c2sData.data = assert(pb.decode("C2SReadMail", c2sData.data)) local data = {} data.mailInfo = {} if player.gameData.mail.mailList then -- 当玩家有邮件才进行以下逻辑 for k, v in pairs(player.gameData.mail.mailList) do -- 领取或者读取过的邮件就删除 否则返回给客户端1 if dataType.MailStatus_AlreadyGet == v.status then player.gameData.mail.mailList[k] = nil else table.insert(data.mailInfo, v) end end end s2cData.cmd = pb.enum("MsgType", "CMD_S2C_DeleteReadMail") s2cData.data = assert(pb.encode("S2CDeleteReadMail", data)) log.info(string.format("删除 玩家 %d 读取过的邮件", player.userId)) end --一键领取邮件奖励 function Mail:AllAward(player, c2sData, s2cData) c2sData.data = assert(pb.decode("C2SMailAllAward", c2sData.data)) local data = {} data.mailInfo = {} local nowTime = skynet.GetTime() for k, v in pairs(player.gameData.mail.mailList) do if dataType.MailStatus_NoGet == v.status and pb.enum("PBMailInfo.MailType", "Award") == v.mailType and nowTime=v.failureTime then --邮件已经过期,无法进行领取 删除对应邮件 player.gameData.mail.mailList[k] = nil s2cData.code = errorInfo.ErrorCode.AlreadyGet end end s2cData.cmd = pb.enum("MsgType", "CMD_S2C_MailAllAward") s2cData.data = assert(pb.encode("S2CMailAllAward", data)) end --发放邮件奖励 function Mail:Bonus(player, mailId, award) for k, v in pairs(award) do if v.type >= dataType.GoodsType_Furniture and v.type <= dataType.GoodsType_PetClothes then skynet.server.bag:AddGoods(player, v.type, v.id, v.count) end --货币直接发放相应数量就行 if v.type <10 then if dataType.GoodsType_Coin == v.type then player:MoneyChange(pb.enum("EnumGoodsType", "Coin"), v.count) elseif dataType.GoodsType_Clovers == v.type then player:MoneyChange(pb.enum("EnumGoodsType", "Clovers"), v.count) elseif dataType.GoodsType_Volute == v.type then player:MoneyChange(pb.enum("EnumGoodsType", "VoluteCoin"), v.count) end end if not v.id then log.info(string.format("玩家 %d 邮件 ID %s 领取奖励 类型 %d 数量 %d", player.userId, mailId, v.type, v.count)) else log.info(string.format("玩家 %d 邮件 ID %s 领取奖励 类型 %d ID %d 数量 %d", player.userId, mailId, v.type, v.id, v.count)) end end end --发送新邮件给在线玩家 function Mail:SendMailToOnlineUser( mailId ) local mailInfo = self.mailList[mailId].mailInfo local award = self.mailList[mailId].award if not mailInfo or not award then return end local t1 = skynet.GetTime() local playerList = skynet.server.playerCenter:GetPlayerList() local count = 0 if "全服" == mailInfo.mailCondition then --给在线玩家发送新邮件 for userId, value in pairs(playerList) do if skynet.server.playerCenter.Status_Playing == value.status then --self:AddMail(value.player, mailId, mailInfo, award) count = count + 1 end end log.info(string.format("邮箱 全玩家发送邮件 发送数量 %d 时间花费 %d ", count, skynet.GetTime() - t1)) elseif "ID" == mailInfo.mailCondition then --给指定在线玩家发送新邮件 local uidList = skynet.server.common:Split(mailInfo.uidlist, ",") for k, v in pairs(uidList) do for userId, value in pairs(playerList) do if value.player.account == v and skynet.server.playerCenter.Status_Playing == value.status then --self:AddMail(value.player, mailId, mailInfo, award) count = count + 1 end end end log.info(string.format("邮箱 部分玩家发送邮件 发送数量 %d 时间花费 %d ", count, skynet.GetTime() - t1)) end end --批量发送邮件 function Mail:BatchAddMail() local t1 = skynet.GetTime() local playerList = skynet.server.playerCenter:GetPlayerList() local sendCount = 0 --此次发送邮件数量 local isSendMail = true --是否继续发送邮件 for mailId, v1 in pairs( self.mailList ) do local count = 0 if self.MailType_AllServer == v1.mailType and v1.isCanGet and not v1.isSendAllOnlineUser then --全服邮件 能发送 并且未发送完 for userId, value in pairs(playerList) do if skynet.server.playerCenter.Status_Playing == value.status and not value.onlineMailList[ mailId ] then --在线玩家并且未接收该邮件 self:AddMail( value.player , mailId , v1.mailInfo , v1.award , true ) value.onlineMailList[ mailId ] = true count = count + 1 sendCount = sendCount + 1 if sendCount >= self.MaxSendCount then isSendMail = false break end end end if 0 == count then v1.isSendAllOnlineUser = true log.info(string.format("邮箱 全服邮件 %s 在线已发送结束 ", mailId )) else log.info(string.format("邮箱 全服邮件 %s 发送 发送数量 %d 时间花费 %d ", mailId , count, skynet.GetTime() - t1)) end end if not isSendMail then break end end end --添加邮件 function Mail:AddMail(player , mailId , mailInfo , award , isWebSend) --玩家已经存在该邮件了,不再发送 if self:IsExist(player, mailId) then return true end local nowTime = os.time() --过了或者未到有效时间,不再发送 if isWebSend then if nowTime>skynet.server.common:GetTime(mailInfo.playerFailureTime) or nowTime < skynet.server.common:GetTime(mailInfo.playerEffectiveTime) then return true end end --[[ --玩家的APP版本是否符合 if self.basicInfo.appVersion < mailInfo.appVersion then return end --玩家的渠道是否符合 if self.basicInfo.channel ~= mailInfo.channel and "all" ~= mailInfo.channel then return end --玩家的系统不符也不发 if self.basicInfo.platform ~= mailInfo.system and "all" ~= mailInfo.system then return end ]] local mail = player.gameData.mail local mailType = nil if "信息" == mailInfo.mailType then mailType = pb.enum("PBMailInfo.MailType", "Message") elseif "奖励" == mailInfo.mailType then mailType = pb.enum("PBMailInfo.MailType", "Award") end local curIndex = mail.curIndex mail.mailList[curIndex] = {} mail.mailList[curIndex].mailId = mailId mail.mailList[curIndex].status = dataType.MailStatus_NoGet mail.mailList[curIndex].mailType = mailType mail.mailList[curIndex].mailSubType = 1 mail.mailList[curIndex].title = mailInfo.mailTitle mail.mailList[curIndex].content = mailInfo.mailText mail.mailList[curIndex].award = {} --奖励 if award then if not isWebSend then --不是来自后台的邮件 for k, v in pairs(award) do if v.type == 0 then table.insert(mail.mailList[curIndex].award, { type = v.id, count = v.count }) else table.insert(mail.mailList[curIndex].award, { type = v.type, id = v.id, count = v.count }) end end else --来自后台的邮件 for k, v in pairs(award) do local goodsType = skynet.server.common:AwardTypeStrToInt(v.articlesType) if goodsType == dataType.GoodsType_Init then table.insert(mail.mailList[curIndex].award, { type = v.articlesId, count = v.articlesNumber }) else table.insert(mail.mailList[curIndex].award, { type = goodsType, id = v.articlesId, count = v.articlesNumber }) end end end end mail.mailList[curIndex].receiveTime = skynet.GetTime() mail.mailList[curIndex].failureTime = skynet.server.common:GetAfterSomeHour(mailInfo.mailEffectiveTime * 24) --邮件的失效时间就是玩家获取到邮件之后的多少天 --插入玩家领取过的邮件ID table.insert(mail.historyMail, mailId) --增加邮件红点 skynet.server.msgTips:Add(player , 23) --玩家最多30条最近的邮件记录 mail.curIndex = mail.curIndex + 1 if mail.curIndex >= 30 then mail.curIndex = 1 end --skynet.server.gameServer:SendMsgToUser(self.userId, "CMD_S2C_Mail", data) log.info(string.format("玩家 %d 邮箱 新增邮件 ID %s ", player.userId, mailId)) end --检查玩家是否有新邮件 function Mail:CheckNewMail(player) for mailId, value in pairs(self.mailList) do if not self:IsExist(player, mailId) and value.isCanGet then if "全服" == value.mailInfo.mailCondition then self:AddMail(player, mailId, value.mailInfo , value.award , true ) elseif "ID" == value.mailInfo.mailCondition then local uidList = skynet.server.common:Split(value.mailInfo.uidlist, ",") for k, v in pairs(uidList) do --如果存在本人邮件就发送 if player.account == v then self:AddMail(player, mailId , value.mailInfo , value.award , true ) break end end end end end end --是否存在邮件 function Mail:IsExist(player, mailId) for k, v in pairs(player.gameData.mail.historyMail) do if mailId == v then return true end end return false end skynet.server.mail = Mail return Mail