HomeServer/Server/Common/Player/PlayerCenter.lua

638 lines
24 KiB
Lua
Raw Normal View History

2024-11-20 15:41:09 +08:00
local skynet = require "skynet"
local mysql = require "skynet.db.mysql"
local oo = require "Class"
local cmd = require "GameCmd"
local json =require "json"
local player = require "Player"
local log = require "Log"
local pb = require "pb"
local sqlUrl = require "SqlUrl"
local playerFields = require "PlayerFields"
local redisKeyUrl = require "RedisKeyUrl"
local dyeworkshop = require "DyeWorkShop"
local errorInfo = require "ErrorInfo"
local dataType = require "DataType"
local cluserServer = require "ClusterServer"
local serverId = tonumber(skynet.getenv "serverId")
local PlayerCenter = oo.class()
--[[
REDIS中
]]
PlayerCenter.Status_Login = 1 --用户已登陆
PlayerCenter.Status_Playing = 2 --用户游戏中
PlayerCenter.Status_Offline = 3 --用户掉线
function PlayerCenter:Init()
self.redisKeyPlaying = string.format( redisKeyUrl.GameServerPlayingInServerZSet , serverId ) --玩家正在当前游戏服的redis key
self.playerList = {}
self.listAuditUser = {} --审核玩家列表
self.listPreCloseSocket = {} --准备关闭SocketId
--table.insert( self.listAuditUser , "xxx")
end
--跨天
function PlayerCenter:OnNewDay()
for k, v in pairs(self.playerList) do
function Do()
--非存档玩家才能走这里
if self.Status_Playing == v.status then
v.player:ResetTodayData()
--判断是否是新的一周或一月
if skynet.server.common:IsNewWeek(v.player.basicInfo.lastLoginTime) then
v.player:ResetWeekData()
end
if skynet.server.common:IsNewMonth(v.player.basicInfo.lastLoginTime) then
v.player:ResetMonthData()
end
v.player.basicInfo.lastLoginTime = skynet.GetTime()
end
--主动推送当前活动信息
local data = {}
data.activityInfos = skynet.server.activity:GetAllActivityInfo( v.player )
skynet.server.gameServer:SendMsgToUser( v.player.userId , "CMD_S2C_UpdateShowUI" , data )
--检查一下是否有新的活动邮件需要发送
skynet.server.activity:ActivityExpiredSendMail(v.player)
return true
end
local ret,err = pcall(Do)
if not ret or not err then
local account = v.player.basicInfo.accountName
local userId = player.userId
log.info("内部错误信息 PlayerCenter:OnNewDay", account ,userId ,ret ,err )
return false
end
end
end
--每5秒调一次
function PlayerCenter:On5SecTimer()
if not cluserServer:IsGameServer(serverId) then
return
end
local nowTime = skynet.GetTime()
--被顶号的sokcet超过5秒就关闭一下
for k, v in pairs( self.listPreCloseSocket ) do
if nowTime - v.recordTime >= 5 then
self:CloseSocket( v.netType , v.socketId , v.agentId )
self.listPreCloseSocket[ k ] = nil
end
end
end
--关闭SocketId连接
function PlayerCenter:CloseSocket( netType , socketId , agentId )
function Do()
local s2cData,retLen = nil , nil
if dataType.NetType_Tcp == netType then
s2cData,retLen = skynet.call( "TcpSocket", "lua","KickUserOffline", socketId )
elseif agentId and dataType.NetType_WebSocket == netType then
s2cData,retLen = skynet.call( "WebSocketAgent", "lua","KickUserOffline", socketId , agentId )
end
if errorInfo.Suc == s2cData.code then
log.info(string.format("关闭 网络类型 %d 连接 socketId %d 成功" , netType , socketId ))
return true
else
log.info(string.format("关闭 网络类型 %d 连接 socketId %d 失败" , netType , socketId ))
return false
end
return true
end
local ret,err = pcall(Do)
if not ret or not err then
log.info("内部错误信息 PlayerCenter:CloseSocket", netType ,socketId , agentId , ret ,err )
return false
end
return true
end
--是否存在游戏玩家查找帐号
function PlayerCenter:IsExistPlayerForAccount( account )
account = tostring(account)
for k, v in pairs( self.playerList ) do
if account == v.account then
return true
end
end
return false
end
--是否存在游戏玩家
function PlayerCenter:IsExistPlayer( account )
for k, v in pairs( self.playerList ) do
if account == v.account then
return true
end
end
return false
end
--根据account判断玩家是否在线
function PlayerCenter:IsPlayingByAccount( account )
for k, v in pairs( self.playerList ) do
if account == v.account and v.status == self.Status_Playing then
--log.debug(string.format("玩家 %s 在线,data:%s" , account ,json:encode(v)))
return true
end
end
return false
end
--玩家是否在线
function PlayerCenter:IsPlaying( userId )
if self.playerList[ userId ] and self.Status_Playing == self.playerList[ userId ].status then
return true
end
return false
end
--是否掉线
function PlayerCenter:IsOffline( socketId )
if self.playerList[ socketId ] and self.Status_Offline == self.playerList[ socketId ].status then
return true
end
return false
end
--根据帐号获取SocketId
function PlayerCenter:GetSocketIdForAccount( account )
for k, v in pairs(self.playerList) do
if account == v.account then
return k
end
end
return -1
end
--根据userId获取SocketId
function PlayerCenter:GetSocketIdForUserID( userId )
if self.playerList[ userId ] then
return self.playerList[ userId ].netType , self.playerList[ userId ].socketId , self.playerList[ userId ].agentId
end
return -1,-1
end
--根据SocketId获取userId
function PlayerCenter:GetUserIDForSocketId( netType , socketId )
for k, v in pairs(self.playerList) do
if netType == v.netType and socketId == v.socketId then
return v.userId
end
end
return nil
end
--获取人数信息
function PlayerCenter:GetPlayerCount()
local countInfo = {}
countInfo.playing = 0
countInfo.offline = 0
for k, v in pairs(self.playerList) do
if self.Status_Playing == v.status then
countInfo.playing = countInfo.playing + 1
elseif self.Status_Offline == v.status then
countInfo.offline = countInfo.offline + 1
end
end
return countInfo
end
--进入平台
function PlayerCenter:UserEnter( c2sData , playerData )
local netType = c2sData.netType
local socketId = c2sData.socketId
local addr = c2sData.addr
local platform = c2sData.data.platform
local curHardwareCode = tostring(c2sData.data.hardwareCode)
local userId = tonumber(playerData.basicInfo.userID)
local account = playerData.basicInfo.accountName
playerData.basicInfo.userID = userId --老版本的还是字符串,这里强制改成数字型
playerData.basicInfo.isAudit = self:IsAudit( account ) --是否为审核帐号
local cfgSValue = skynet.server.gameConfig:GetPlayerAllCfg( playerData , "SValue")
local nowTime = skynet.GetTime()
if self.playerList[ userId ] then
--关闭其它Tcp连接
local oldHardwareCode = tostring( self.playerList[ userId ].player.basicInfo.hardwareCode )
local oldNetType = self.playerList[ userId ].netType
local oldSocketId = self.playerList[ userId ].socketId
local oldAgentId = self.playerList[ userId ].agentId
if oldHardwareCode ~= curHardwareCode and "" ~= oldHardwareCode and "" ~= curHardwareCode then
skynet.server.gameServer:SendMsgToUser( userId , "CMD_S2C_UserExit" , { exitType = 2 })
table.insert( self.listPreCloseSocket , { netType = oldNetType , socketId = oldSocketId , agentId = oldAgentId , recordTime = nowTime } )
log.info(string.format("玩家 %d 登陆设备信息不一致 开始顶号 原设备 %s 当前设备码 %s" ,userId , oldHardwareCode , curHardwareCode))
else
self:CloseSocket( oldNetType , oldSocketId , oldAgentId )
end
--self:CloseSocket( oldNetType , oldSocketId , oldAgentId )
log.info(string.format("玩家 %d socket %d 帐号 %s 重新进入游戏 关闭原 socket %d 当前设备码 %s" , userId , socketId , account , oldSocketId , curHardwareCode))
self.playerList[ userId ].player.basicInfo.hardwareCode = curHardwareCode
--计算在线时间
self.playerList[ userId ].player:CalcGameTime( nowTime )
--如果是同一天 则增加当天登录时间
if skynet.server.common:IsSameDay(self.playerList[ userId ].player.basicInfo.lastGameTime , nowTime) then
--这里提前保存下agentId,因为商城要发送消息给客户端,这时玩家新的客房端已经更新了agentId , 如果不更新的化,会找不到对应的玩家.
self.playerList[ userId ].netType = netType
self.playerList[ userId ].socketId = socketId
if dataType.NetType_WebSocket == netType then
self.playerList[ userId ].agentId = c2sData.agentId
end
--判断是否可以触发相关礼包
local packInfo = cfgSValue.triggerUpgradePack
if self.playerList[ userId ].player.gameData.todayGain.todayGameTime >= packInfo[1]*60*60
and nowTime - self.playerList[ userId ].player.gameData.upTime >= packInfo[1]*60*60
and self.playerList[ userId ].player.gameData.level < self.playerList[ userId ].player.maxLevelLimt
and self.playerList[ userId ].player.gameData.level > cfgSValue.storeUnlockLvl then
skynet.server.store:TriggerPack(self.playerList[ userId ].player , skynet.server.store.TriggerPack_UpGrade)
end
end
else
playerData.basicInfo.hardwareCode = curHardwareCode
local newPlayer = player.new( userId , playerData )
self.playerList[ userId ] = {}
self.playerList[ userId ].player = newPlayer
--将玩家的账号加入到当前服的在线列表中
skynet.server.redis:zadd( self.redisKeyPlaying , nowTime , account )
log.info(string.format("玩家 %d socket %d 帐号 %s 进入游戏 设备码 %s" , userId , socketId , account , "" == curHardwareCode and "暂无" or curHardwareCode))
end
self.playerList[ userId ].netType = netType
if dataType.NetType_WebSocket == netType then
self.playerList[ userId ].agentId = c2sData.agentId --websocket需要保存下代理的ID
end
self.playerList[ userId ].socketId = socketId
self.playerList[ userId ].platform = platform
self.playerList[ userId ].userId = userId
self.playerList[ userId ].account = account
self.playerList[ userId ].addr = addr
self.playerList[ userId ].status = self.Status_Playing
self.playerList[ userId ].offlineTime = 0
self.playerList[ userId ].pingTime = nowTime
self.playerList[ userId ].lastSaveTime = nowTime --上一次间隔保存
self.playerList[ userId ].onlineMailList = {} --在线发送的邮件列表
self.playerList[ userId ].saveMysqlCount = 0 --mysql保存次数
self.playerList[ userId ].player:Init( c2sData )
local player = self.playerList[ userId ].player
local partnerId = player.gameData.partner.id
skynet.server.personal:SetDetail( partnerId ,"isOnline", true , "gameServerId", serverId )
--检查是否有离线消息
skynet.server.personal:CheckOfflineMsg( player )
--检查是否有失败的充值信息
skynet.server.gameServer:CheckFailedPay( player )
--检查是否有失败的官方充值信息
skynet.server.gameServer:CheckOfficialFailedPay( player )
--检查是否有失败的 微信通知 信息
skynet.server.gameServer:CheckWXNotifyFailedPay( player )
end
--退出平台
function PlayerCenter:UserExit( userId )
local netType = self.playerList[ userId ].netType
local socketId = self.playerList[ userId ].socketId
local account = self.playerList[ userId ].account
local agentId = self.playerList[ userId ].agentId
if self:CloseSocket( netType , socketId , agentId ) then
log.info(string.format("玩家 %d socket %d 帐号 %s 退出游戏" , userId , socketId , account))
else
log.info(string.format("玩家 %d socket %d 帐号 %s 退出游戏 未成功关闭socket" , userId , socketId , account))
end
--将玩家的账号移除到当前服的在线列表中
skynet.server.redis:zrem( self.redisKeyPlaying , account )
skynet.server.playerRecord:Add( userId , dataType.RecordType_3 , 0 )
self.playerList[ userId ].player = nil
self.playerList[ userId ]= nil
return true
end
--Ping时间
function PlayerCenter:Ping( userId )
self.playerList[ userId ].pingTime = skynet.GetTime()
end
--掉线
function PlayerCenter:UserOffline( userId )
if not self.playerList[ userId ] then
return
end
self.playerList[ userId ].status = self.Status_Offline
self.playerList[ userId ].offlineTime = skynet.GetTime()
local player = self.playerList[ userId ].player
local partnerId = player.gameData.partner.id
skynet.server.personal:SetDetail( partnerId ,"isOnline", false , "gameServerId", 0 )
skynet.server.playerRecord:Add( userId , dataType.RecordType_2 , 0 )
log.info(string.format("玩家 %d 掉线" , userId ))
--触发离线订阅
skynet.server.subscribe:UpdateOfflineTime(player,1)
end
--获取玩家数据
function PlayerCenter:Get( userId )
if not self.playerList[ userId ] then
return nil
end
return self.playerList[ userId ]
end
--获取玩家数据
function PlayerCenter:GetPlayer( userId )
userId = tonumber( userId )
if not self.playerList[ userId ] then
return nil
end
return self.playerList[ userId ].player
end
--获取玩家数据
function PlayerCenter:GetPlayerForAccount( account )
for k, v in pairs( self.playerList ) do
if account == v.account then
return v.player
end
end
return nil
end
--获取玩家数据列表
function PlayerCenter:GetPlayerList()
return self.playerList
end
--获取当前玩家数量
function PlayerCenter:GetPlayerOnlineCount()
return #self.playerList
end
--获取玩家登陆数据
function PlayerCenter:GetLoginInfo( userId )
if not self.playerList[ userId ] then
return nil
end
local userData = {}
local player = self.playerList[ userId ].player
--每次登录更新下我的时间
local redisKey = redisKeyUrl.GameServerPartnerAllUserZSet
local myPartnerId = player.gameData.partner.id
skynet.server.redis:zadd( redisKey , skynet.GetTime() , myPartnerId )
--用户数据
userData.userId = tonumber(player.basicInfo.userID)
userData.account = player.basicInfo.accountName
userData.playerData = nil
userData.announce = ""
userData.serverTime = skynet.GetTime()
userData.msgVersion = 2
userData.nickName = player.gameData.nickName
userData.partnerId = myPartnerId
local curDetail = skynet.server.personal:GetDetail( myPartnerId )
if not curDetail then
player.gameData.partner.id = "XJtuaqxodoDf"
myPartnerId = player.gameData.partner.id
curDetail = skynet.server.personal:GetDetail( myPartnerId ) --内网测试ID 由于从线上拷贝的数据没有partnerid只能默认一个内网有的partnerid
if not curDetail then
player.gameData.partner.id = "AACJQUquNsJM"
myPartnerId = player.gameData.partner.id
curDetail = skynet.server.personal:GetDetail( myPartnerId ) --内网测试ID 由于从线上拷贝的数据没有partnerid只能默认一个内网有的partnerid
end
if not curDetail then
player.gameData.partner.id = "cMqfgHeQCxbN"
myPartnerId = player.gameData.partner.id
curDetail = skynet.server.personal:GetDetail( myPartnerId ) --内网测试ID 由于从线上拷贝的数据没有partnerid只能默认一个内网有的partnerid
end
--内网3
if not curDetail then
player.gameData.partner.id = "TsnQYmRAxfcy"
myPartnerId = player.gameData.partner.id
curDetail = skynet.server.personal:GetDetail( myPartnerId ) --内网测试ID 由于从线上拷贝的数据没有partnerid只能默认一个内网有的partnerid
end
end
--兼容redis数据
player:InitNoRedisData( player , curDetail )
local myGroupId = curDetail.groupId
local groupData = skynet.server.group:GetGroupInfo( myGroupId , "contributeReward", "joinType")
local money = {}
table.insert( money , { type = pb.enum("EnumGoodsType","Coin") , count = player.gameData.coin })
table.insert( money , { type = pb.enum("EnumGoodsType","Clovers") , count = player.gameData.clovers })
table.insert( money , { type = pb.enum("EnumGoodsType","VoluteCoin") , count = player.gameData.volute })
table.insert( money , { type = pb.enum("EnumGoodsType","ContributeCoin") , count = player.gameData.contributeCoin })
userData.money = money
userData.level = player.gameData.level
userData.exp = player.gameData.exp
--当前房子ID和方案ID
local houseId = player.gameData.curHouseID
userData.curHouseID = houseId
userData.curSchemeID = player.gameData.house[ houseId ].curSchemeId
--获取方案信息
userData.schemeInfo = {}
for k, v in pairs( player.gameData.house[ houseId ].scheme ) do
table.insert( userData.schemeInfo , { id = v.id , name = v.name , status = v.status })
end
--当前房子和当前方案下的家具信息
userData.furnitureInfo = skynet.server.house:GetCurSchemeFurniture( player , houseId , userData.curSchemeID )
local tmpDecorateInfo = skynet.server.house:GetCurSchemeDecorate( player , houseId , userData.curSchemeID )
userData.decorateInfo = {}
--装修时摆放了类型10的户外装饰后面又取消了在LUA表中没有10这个索引所以后面的值没传过来这里按这种方式重新赋值
if tmpDecorateInfo then
for k, v in pairs( tmpDecorateInfo ) do
table.insert( userData.decorateInfo , v )
end
end
--当前已经解锁的区域ID
userData.areaId = {}
for areaId, v in pairs( player.gameData.house[ houseId ].unlockAreaList ) do
if true == v then
table.insert( userData.areaId , areaId )
end
end
--提示信息
userData.tipsInfo = skynet.server.msgTips:GetAllTips( player , curDetail , groupData )
userData.finishGuide = player.gameData.finishGuide --完成的引导记录
--将未解锁的宠物发给玩家
userData.lockPetId = {}
for k, v in pairs( player.gameData.pet ) do
if dataType.PetStatus_Lock == v.status then
table.insert( userData.lockPetId , v.skinId )
end
end
--获取拥有的房子数量
userData.houseCount = skynet.server.house:GetHouseCount( player )
userData.isVip = {}
if userData.passCheck then
table.insert(userData.isVip ,userData.passCheck.isVip )
else
table.insert(userData.isVip , false)
end
userData.goodsStat = {}
local goodsType = dataType.GoodsType_Furniture
table.insert( userData.goodsStat , { goodsType = goodsType , goodsCount = skynet.server.bag:GetGoodsStat( player , goodsType )})
userData.allGameTime = player.basicInfo.allGameTime
--头像 若头像id=0则带上自定义头像信息
if player.gameData.personal.headId == 0 then
if player.gameData.personal.diyHeadInfo == nil or next(player.gameData.personal.diyHeadInfo) == nil then
player.gameData.personal.headId = 1
else
userData.DIYHeadInfo = player.gameData.personal.diyHeadInfo
end
end
userData.currentHeadId = player.gameData.personal.headId
userData.currentHpFrameId = player.gameData.personal.headFrameId
if curDetail and "" == curDetail.groupId then
userData.isJoinGroup = false
player:SetSwitch( dataType.SwitchType_JoinGroup , false )
else
userData.isJoinGroup = true
player:SetSwitch( dataType.SwitchType_JoinGroup , true )
end
-- 到达18级后给给鱼竿鱼饵数据赋值
if player.gameData.shop[dataType.ShopType_Fish] then
for k,v in pairs(player.gameData.shop[dataType.ShopType_Fish].fishingRodInfos) do
if v.status == 2 then
userData.fishRod = v.id -- 当前装备的鱼竿
end
end
userData.fishLures = player.gameData.shop[dataType.ShopType_Fish].fishingLure --当前拥有的鱼饵
end
--宠物状态
userData.petStatus = {}
for k, v in pairs( player.gameData.pet ) do
table.insert( userData.petStatus , { petType = k , petStatus = v.status })
end
--可显示活动的相关数据
userData.activityInfos = skynet.server.activity:GetAllActivityInfo( player )
userData.configType = player.basicInfo.configType
userData.switches = player.gameData.switches --所有开关信息
userData.adInfos = skynet.server.ad:GetAllAD( player ) --所有广告信息
--需要进行拍屏的礼包
userData.popupStoreInfos = {}
if player.gameData.storePack.popupPackInfo then
for k , v in pairs(player.gameData.storePack.popupPackInfo) do
if v.status == 1 then
--单独处理下月卡的拍屏
if v.id == 61 then
table.insert(userData.popupStoreInfos , {storeId = v.id , buyTimes = 0 , failureTime = 0 , redDot = false})
else
local packInfo = player.gameData.storePack.storePackInfo[ v.id ]
--限购礼包购买完后也不进行拍屏
if packInfo and packInfo.failureTime ~= nil and packInfo.failureTime ~= "" and packInfo.buyTimes < packInfo.packLimit[2] and skynet.GetTime() < packInfo.failureTime then
table.insert(userData.popupStoreInfos , {storeId = v.id , buyTimes = packInfo.buyTimes , failureTime = packInfo.failureTime , redDot = false})
elseif packInfo and not packInfo.failureTime and packInfo.buyTimes < packInfo.packLimit[2] then
--礼包对应的失效时间
local endTime = skynet.server.common:GetTime(skynet.server.gameConfig:GetPlayerCurCfg( player , "StorePack" , v.id).endTime)
if skynet.GetTime() < endTime then
table.insert(userData.popupStoreInfos , {storeId = v.id , buyTimes = packInfo.buyTimes , failureTime = endTime , redDot = false})
end
end
end
end
end
end
--需要进行礼包发奖表现补发的礼包id
userData.storePackIds = {}
if player.tmpData.sendStorePackIds then
userData.storePackIds = player.tmpData.sendStorePackIds
end
--微信订阅信息
userData.subscribeInfo=skynet.server.subscribe:GetPlayerSubscribeInfo(player,1)
--是否有官网离线充值信息
if next(player.tmpData.officialPayDatas) then
userData.officialPayInfos=player.tmpData.officialPayDatas
--清除数据
player.tmpData.officialPayDatas = {}
end
if userData.level>=3 then
userData.isDialogShow = skynet.server.birthday:CheckUnlockNpcDialog( player )
end
return userData
end
--是否为相同服务器
function PlayerCenter:IsSameServer( otherPartnerId )
local playerInfo = skynet.server.personal:GetDetail( otherPartnerId )
if playerInfo and playerInfo.isOnline and playerInfo.gameServerId then
if serverId == playerInfo.gameServerId then
return true
else
return false
end
else
return nil
end
end
--是否为审核玩家
function PlayerCenter:IsAudit( account )
for k, v in pairs( self.listAuditUser ) do
if account == v then
return true
end
end
return false
end
skynet.server.playerCenter = PlayerCenter
return PlayerCenter