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.playerList = {} end --跨天 function PlayerCenter:OnNewDay() for k, v in pairs(self.playerList) do --非存档玩家才能走这里 if self.Status_Playing == v.status then v.player:ResetTodayData() end end end --每5秒调一次 function PlayerCenter:On5SecTimer() if not cluserServer:IsGameServer(serverId) then return end end --关闭SocketId连接 function PlayerCenter:CloseSocket( socketId ) local s2cData,retLen = skynet.call( "TcpSocket", "lua","KickUserOffline", socketId ) if errorInfo.Suc == s2cData.code then log.info(string.format("关闭socketId %d 成功" , socketId )) return true else log.info(string.format("关闭socketId %d 失败" , socketId )) return false end 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( platform , account ) for k, v in pairs( self.playerList ) do if platform == v.platform and account == v.account then 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 ].socketId end return -1 end --根据SocketId获取userId function PlayerCenter:GetUserIDForSocketId( socketId ) for k, v in pairs(self.playerList) do if 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:InitPlayer( player , c2sData) local addr = c2sData.addr local platform = c2sData.data.platform local curHardwareCode = tostring(c2sData.data.hardwareCode) --检查房间是否有新的配置 skynet.server.passCheck:CheckNew( player ) skynet.server.house:CheckNew( player ) skynet.server.msgTips:CheckNew( player ) skynet.server.friend:CheckNewMsg( player ) skynet.server.extraRevenue:CalcOffline( player ) skynet.server.mail:CheckNewMail( player) skynet.server.announcement:CheckNewAnnouncement( player) skynet.server.flowerpot:RefreshFlowerpot( player ) skynet.server.map:InitData( player ) skynet.server.dyeworkshop:InitData(player) skynet.server.store:InitData(player) skynet.server.store:SendIconPackToUser(player) --是否完成第一步新手引导 local isExistFirstStep = false for k, v in pairs( player.gameData.finishGuide ) do if 1 == v then isExistFirstStep = true break end end if player.basicInfo.isNewPlayer then --新玩家 player.basicInfo.isNewPlayer = false for i = dataType.FirstOpType_Start, dataType.FirstOpType_End, 1 do if not player.gameData.firstOp[ i ] then player.gameData.firstOp[ i ] = false end end --解锁 player:CheckUnlockSystem() --赠送家具到房间 self:InitPlayerData( player ) --新人签到数据初始化 skynet.server.playerLand:InitData(player) --设置界面关注有礼 skynet.server.msgTips:Add( player , 20 ) skynet.server.msgTips:Add( player , 21 ) skynet.server.msgTips:Add( player , 22 ) elseif not player.basicInfo.isNewPlayer and not isExistFirstStep then --未完成成第一步新手引导,就把家具摆放回去 self:InitPlayerData( player) end --初始化商店 player:InitShop() skynet.server.audit:InitData( player , platform , curHardwareCode ) skynet.server.playerRecord:Add( player.userId , dataType.RecordType_1 , addr , curHardwareCode , c2sData.data.version) --增加登录历史 self:AddLoginHistory( player ) end --进入平台 function PlayerCenter:UserEnter( c2sData , playerData ) 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 --老版本的还是字符串,这里强制改成数字型 if self.playerList[ userId ] then --关闭其它Tcp连接 local oldHardwareCode = tostring( self.playerList[ userId ].player.basicInfo.hardwareCode ) local oldSocketId = self.playerList[ userId ].socketId if oldHardwareCode ~= curHardwareCode and "" ~= oldHardwareCode and "" ~= curHardwareCode then skynet.server.gameServer:SendMsgToUser( userId , "CMD_S2C_UserExit" , { exitType = 2 }) log.info(string.format("玩家 %d 登陆设备信息不一致 开始顶号 原设备 %s 当前设备码 %s" ,userId , oldHardwareCode , curHardwareCode)) end self:CloseSocket( oldSocketId ) log.info(string.format("玩家 %d socket %d 帐号 %s 重新进入游戏 关闭原 socket %d 当前设备码 %s" , userId , socketId , account , oldSocketId , curHardwareCode)) self.playerList[ userId ].player.basicInfo.hardwareCode = curHardwareCode --计算在线时间 local gameTime = os.time() - self.playerList[ userId ].player.tmpData.intoTime self.playerList[ userId ].player.basicInfo.allGameTime = self.playerList[ userId ].player.basicInfo.allGameTime + gameTime else playerData.basicInfo.hardwareCode = curHardwareCode local newPlayer = player.new( userId , playerData ) self.playerList[ userId ] = {} self.playerList[ userId ].player = newPlayer log.info(string.format("玩家 %d socket %d 帐号 %s 进入游戏 设备码 %s" , userId , socketId , account , "" == curHardwareCode and "暂无" or curHardwareCode)) 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 = 0 self.playerList[ userId ].isIntervalSave = false --是否间隔保存 self.playerList[ userId ].lastIntervalSaveTime = skynet.GetTime() --上一次间隔保存 self.playerList[ userId ].onlineMailList = {} --在线发送的邮件列表 self.playerList[ userId ].onlineAnnounceList = {} --在线发送的公告列表 self.playerList[ userId ].player:Init( c2sData ) self.playerList[ userId ].player.tmpData.intoTime = os.time() if nil == self.playerList[ userId ].lastExtraRevenueTime or 0 == self.playerList[ userId ].lastExtraRevenueTime then self.playerList[ userId ].lastExtraRevenueTime = skynet.GetTime() --上一次计算额外奖励时间 end --初始化玩家 self:InitPlayer( self.playerList[ userId ].player , c2sData ) end --退出平台 function PlayerCenter:UserExit( userId ) local socketId = self.playerList[ userId ].socketId local account = self.playerList[ userId ].account if self:CloseSocket( socketId ) 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 self.playerList[ userId ].player = nil self.playerList[ userId ]= nil skynet.server.playerRecord:Add( userId , dataType.RecordType_3 ) 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() skynet.server.playerRecord:Add( userId , dataType.RecordType_2 ) log.info(string.format("玩家 %d 掉线" , userId )) end --获取玩家数据 function PlayerCenter:Get( userId ) if not self.playerList[ userId ] then return nil end return self.playerList[ userId ] end --获取玩家数据 function PlayerCenter:GetPlayer( 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:GetOnlineCount() return #self.playerList end --更新间隔保存 function PlayerCenter:UpdateIntervalSave( userId ) if not self.playerList[ userId ].isIntervalSave then self.playerList[ userId ].isIntervalSave = true --是否间隔保存 self.playerList[ userId ].lastIntervalSaveTime = skynet.GetTime() --上一次间隔保存 end end --增加登陆历史 function PlayerCenter:AddLoginHistory( player ) local data = player.basicInfo.loginHistory data.curIndex = data.curIndex + 1 --最多保存30条 if data.curIndex > 30 then data.curIndex = 1 end data.history[ data.curIndex ] = { serverId = serverId , time = skynet.server.common:GetStrTime(skynet.GetTime())} end --获取玩家登陆数据 function PlayerCenter:GetLoginInfo( playerData ) local userId = tonumber(playerData.basicInfo.userID) if not self.playerList[ userId ] then return nil end local userData = {} local playerData = self.playerList[ userId ].player --用户数据 userData.userId = tonumber(playerData.basicInfo.userID) userData.account = playerData.basicInfo.accountName userData.playerData = nil userData.announce = "" userData.serverTime = skynet.GetTime() userData.msgVersion = 2 userData.nickName = playerData.gameData.nickName local money = {} table.insert( money , { type = pb.enum("EnumGoodsType","Coin") , count = playerData.gameData.coin }) table.insert( money , { type = pb.enum("EnumGoodsType","Clovers") , count = playerData.gameData.clovers }) table.insert( money , { type = pb.enum("EnumGoodsType","VoluteCoin") , count = playerData.gameData.volute }) userData.money = money userData.level = playerData.gameData.level userData.exp = playerData.gameData.exp --当前房子ID和方案ID local houseId = playerData.gameData.curHouseID userData.curHouseID = houseId userData.curSchemeID = playerData.gameData.house[ houseId ].curSchemeId --获取方案信息 userData.schemeInfo = {} for k, v in pairs( playerData.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( playerData , houseId , userData.curSchemeID ) userData.decorateInfo = skynet.server.house:GetCurSchemeDecorate( playerData , houseId , userData.curSchemeID ) --当前已经解锁的区域ID userData.areaId = {} for areaId, v in pairs( playerData.gameData.house[ houseId ].unlockAreaList ) do if true == v then table.insert( userData.areaId , areaId ) end end --提示信息 userData.tipsInfo = skynet.server.msgTips:GetAllTips( playerData ) userData.finishGuide = playerData.gameData.finishGuide --完成的引导记录 --将未解锁的宠物发给玩家 userData.lockPetId = {} for k, v in pairs( playerData.gameData.pet ) do if dataType.PetStatus_Lock == v.status then table.insert( userData.lockPetId , v.skinId ) end end --获取拥有的房子数量 userData.houseCount = skynet.server.house:GetHouseCount( playerData ) 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( playerData , goodsType )}) userData.allGameTime = playerData.basicInfo.allGameTime --是否给玩家显示新人签到 userData.canShowPlayerLand = playerData.gameData.playerLand.isShow return userData end --赠送默认家具到房间 function PlayerCenter:InitPlayerData( player , goodsType ) local goodsType = dataType.GoodsType_Furniture local cfgSValue = skynet.server.gameConfig.SValue player.gameData.coin = cfgSValue.initCoin --player.gameData.clovers = cfgSValue.initVoluteCoin --player.gameData.coin = 10000 --player.gameData.clovers = 10000 player.gameData.volute = cfgSValue.initVoluteCoin player.gameData.level = 1 player.gameData.exp = 0 player.gameData.bag = {} player.gameData.bagCount = {} player.gameData.used.logisticsInfo = {} --存在装修商店数据就处理一下 local shopType = dataType.ShopType_Decorate if player.gameData.shop[ shopType ] then player.gameData.shop[ shopType ].door = {} player.gameData.shop[ shopType ].nextRefreshTime = 0 player.gameData.shop[ shopType ].firstRefresh = true skynet.server.decorateShop:RefreshShop( player , shopType ) end --赠送一个免费的物流 table.insert( player.gameData.used.logisticsInfo , { goodsId = 53 , npcNameId = 2 , copyId = 2 , goodsStatus = skynet.server.used.GoodsStatus_AlreadyReach , reachTime = 0 , deliverTime = 0 } ) --赠送家具到背包 skynet.server.bag:AddGoods( player , goodsType , 1 , 1) skynet.server.bag:AddGoods( player , goodsType , 10 , 1) --赠送家具到背包 需要摆放到房间的 skynet.server.bag:AddGoods( player , goodsType , 197 , 1) skynet.server.bag:AddGoods( player , goodsType , 200 , 1) skynet.server.bag:AddGoods( player , goodsType , 511 , 1) skynet.server.bag:AddGoods( player , goodsType , 510 , 1) skynet.server.bag:AddGoods( player , goodsType , 202 , 1) skynet.server.bag:AddGoods( player , goodsType , 199 , 1) skynet.server.bag:AddGoods( player , goodsType , 199 , 1) --赠送默认衣服 local cfgDefalutClothes = skynet.server.gameConfig.SValue.DefalutClothes for k, v in pairs( cfgDefalutClothes ) do skynet.server.bag:AddGoods( player , dataType.GoodsType_Clothes , v , 1) end --赠送房间 local houseId = 4 player.gameData.curHouseID = houseId skynet.server.house:Add( player , houseId, {}) --获取当前房间当前方案 local schemeInfo = skynet.server.house:GetCurScheme( player ) schemeInfo.furniture = {} schemeInfo.decorate = skynet.server.house:InitDecorate( player , houseId ) --在室内摆放家具 skynet.server.house:AddFurniture( player , { type = goodsType , id = 197 , nowPos ={ x= -4.348 , y= 4.89} , rotateType = 0 } , 1 ) skynet.server.house:AddFurniture( player , { type = goodsType , id = 200 , nowPos ={ x= -7.698 , y= 7.29} , rotateType = 0 } , 1 ) skynet.server.house:AddFurniture( player , { type = goodsType , id = 511 , nowPos ={ x= -10.378 , y= 7.29} , rotateType = 1 } , 1 ) skynet.server.house:AddFurniture( player , { type = goodsType , id = 510 , nowPos ={ x= -4.013 , y= 8.690001} , rotateType = 0 } , 1 ) skynet.server.house:AddFurniture( player , { type = goodsType , id = 202 , nowPos ={ x= 0.006999969 , y= 8.29} , rotateType = 1 } , 1 ) skynet.server.house:AddFurniture( player , { type = goodsType , id = 199 , nowPos ={ x= -9.222 , y= 13.58} , rotateType = 0 } , 1 ) skynet.server.house:AddFurniture( player , { type = goodsType , id = 199 , nowPos ={ x= 1.49 , y= 11.407} , rotateType = 0 } , 1 ) --个人和宠物的装扮 skynet.server.personal:InitData( player ) skynet.server.levelTask:CheckNew( player ) player.gameData.design.basicFreeTime = skynet.GetTime() player.gameData.design.advancedFreeTime = skynet.GetTime() end skynet.server.playerCenter = PlayerCenter return PlayerCenter