local skynet = require "skynet" local oo = require "Class" local pb = require "pb" local log = require "Log" local json =require "json" local errorInfo = require "ErrorInfo" local dataType = require "DataType" local redisKeyUrl = require "RedisKeyUrl" local curServerId = tonumber(skynet.getenv "serverId") local Group = oo.class() Group.MaxQueryCount = 4 --最大查询数量 Group.MaxMapCount = 12 --最大地图数量 Group.RankStatus_Acc = 1 --累加状态 Group.RankStatus_Calc = 2 --结算状态 Group.PutType_House = 1 --放房间 Group.PutType_Bag = 2 --放背包 Group.PutType_Move = 3 --移动 Group.PutType_Operate = 4 --原地操作 Group.ArchType_House = 1 --房子 Group.ArchType_Garden = 2 --花园景观 Group.MaxMsgRecordToClient = 50 --发送给客户端最大的消息记录数量 Group.IdentityType_Leader = 1 --园长 Group.IdentityType_ViceLeader = 2 --副园长 Group.IdentityType_Member = 3 --成员 Group.ArchType_Park = 1 --公园 Group.ArchType_Market = 2 --集市 Group.ArchType_Library = 3 --图书馆 Group.ArchType_Dessert = 4 --甜品店 Group.ArchType_Road = 5 --路面 Group.ContributeType_Wood = 1 --木材 Group.ContributeType_Cement = 2 --水泥 Group.ContributeType_Rebar = 3 --钢筋 Group.GroupOpType_Create = 1 --创建 Group.GroupOpType_Update = 2 --更新 Group.GroupOpType_Dissolve = 3 --解散 Group.onlineGroupList = {} --初始建筑 Group.InitArchs = { { id = 62 , nowPos = { x = 0, y = 0 } , rotateType = 0 , isPutInFurniture = false , clickType = 1 }, { id = 56 , nowPos = { x = -5.705, y = -3.18999958 } , rotateType = 0 , isPutInFurniture = false , clickType = 1 }, { id = 57 , nowPos = { x = -3.36000013, y = -1.38999963 } , rotateType = 0 , isPutInFurniture = false , clickType = 1 } } --初始化地块 function Group:InitScenePlot( player , groupId , plotId , partnerId ) local myPartnerId = player.gameData.partner.id local redisKey = string.format( redisKeyUrl.GameServerGroupPrivatePlot, groupId ) local plotInfo = { plotId = plotId , partnerId = partnerId , archs = skynet.server.common:DeepCopy( self.InitArchs ) } --如果已经初始化了庭院,就用初始化后的庭院数据,只有自己才会同步 ,有可能是群主审核通过,player是群主的,后面考虑优化 local curHouse = player.gameData.house[ 11 ] if myPartnerId == partnerId and curHouse and #curHouse.groupGarden.archs > 0 then plotInfo.archs = curHouse.groupGarden.archs end skynet.server.redis:lset( redisKey , plotId - 1 , json:encode( plotInfo )) end --重置土地 function Group:ResetScenePlot( groupId , plotId ) local redisKey = string.format( redisKeyUrl.GameServerGroupPrivatePlot, groupId ) local plotInfo = {} plotInfo.plotId = plotId plotInfo.partnerId = "" plotInfo.archs = {} skynet.server.redis:lset( redisKey , plotId - 1 , json:encode(plotInfo)) end --是否存在家园 function Group:IsExistGroup( groupId ) local redisKey = string.format( redisKeyUrl.GameServerGroupInfoHash , groupId ) if not skynet.server.redis:exists( redisKey) then return false end return true end --是否为园长 function Group:IsLeader( myPartnerId ) local curDetail = skynet.server.personal:GetDetail( myPartnerId ) if self.IdentityType_Leader == curDetail.groupIdentityType then return true else return false end end --是否为管理员 function Group:IsManage( myPartnerId ) local curDetail = skynet.server.personal:GetDetail( myPartnerId ) if self.IdentityType_Leader == curDetail.groupIdentityType or self.IdentityType_ViceLeader == curDetail.groupIdentityType then return true else return false end end --获取家园ID function Group:GetGroupID( player ) local myPartnerId = player.gameData.partner.id local curDetail = skynet.server.personal:GetDetail( myPartnerId ) if not curDetail then return "" end return curDetail.groupId or "" end --获取家园 function Group:GetGroup( groupId ) local redisKey = string.format( redisKeyUrl.GameServerGroupInfoHash , groupId ) if not skynet.server.redis:exists( redisKey) then return nil end local basicInfo = skynet.server.redis:hgetall(redisKey) basicInfo = redisKeyUrl:CovertTable(basicInfo) return basicInfo end --获取当前家园所有信息 function Group:GetGroupAllInfo( player ) local curPartner = player.gameData.partner local partnerId = curPartner.id local curDetail = skynet.server.personal:GetDetail( partnerId ) local groupId = curDetail.groupId local groupInfo = {} local curGroupInfo = self:GetGroup( groupId ) if curGroupInfo then groupInfo = {} groupInfo.id = curGroupInfo.id groupInfo.name = curGroupInfo.name groupInfo.level = curGroupInfo.communityLevel groupInfo.exp = curGroupInfo.communityExp groupInfo.declaration = curGroupInfo.declaration groupInfo.badgeId = curGroupInfo.badgeId groupInfo.myTotalScore = curDetail.groupContributeScore groupInfo.signInType = curDetail.groupSignInType groupInfo.joinType = curGroupInfo.joinType groupInfo.minJoinLevel = curGroupInfo.minJoinLevel groupInfo.member = self:GetMember( groupId , partnerId ) end return groupInfo end --设置家园信息 function Group:SetGroupInfo( groupId , ... ) local redisKey = string.format( redisKeyUrl.GameServerGroupInfoHash , groupId ) skynet.server.redis:hmset( redisKey , ... ) end --获取家园信息 function Group:GetGroupInfo( groupId , ... ) local redisKey = string.format( redisKeyUrl.GameServerGroupInfoHash , groupId ) return skynet.server.redis:hmget( redisKey , ... ) end --累加家园信息数量 function Group:AccGroupInfo( groupId , param , count ) local redisKey = string.format( redisKeyUrl.GameServerGroupInfoHash , groupId ) skynet.server.redis:hincrby( redisKey , param , count ) end function Group:GetMember( groupId , myPartnerId ) local member = {} --获取所有的分数排行 local redisKey = string.format( redisKeyUrl.GameServerGroupContributionScoreZSet, groupId ) local memeberScore = skynet.server.redis:zrange( redisKey , 0 , -1 , "withscores") memeberScore = redisKeyUrl:CovertTable(memeberScore) --获取我的好友列表 local redisKey = string.format( redisKeyUrl.GameServerPartnerMyFriendZSet , myPartnerId ) local friendList = skynet.server.redis:zrange( redisKey , 0 , -1 ) --是否为好友 local function IsFriend( otherPartnerId ) for k, v in pairs( friendList ) do if otherPartnerId == v then return true end end return false end for partnerId, v in pairs( memeberScore ) do --获取个人信息 local detail = skynet.server.personal:GetDetail( partnerId ) local medals = {} table.insert( medals , detail.medals1) table.insert( medals , detail.medals2) table.insert( medals , detail.medals3) --衣服数据 local clothesData = {} table.insert( clothesData , detail.clothesData1 or 2 ) table.insert( clothesData , detail.clothesData2 or 3 ) table.insert( clothesData , detail.clothesData3 or 10 ) table.insert( clothesData , detail.clothesData4 or 14 ) table.insert( clothesData , detail.clothesData5 or 17 ) table.insert( clothesData , detail.clothesData6 or 16 ) table.insert( clothesData , detail.clothesData7 or 0 ) table.insert( clothesData , detail.clothesData8 or 0 ) table.insert( clothesData , detail.clothesData9 or 0 ) table.insert( clothesData , detail.clothesData10 or 0 ) --肤色 local colorData = {} table.insert( colorData , detail.colorData1 or 1 ) table.insert( colorData , detail.colorData2 or 6 ) table.insert( colorData , detail.colorData3 or 26 ) --自定义头像处理 if detail.birthdayShow==false then detail.birthdayDate="" end if detail.headId ==0 and detail.DIYHeadInfo ~=nil then table.insert( member , { partnerId = detail.partnerId , nickName = detail.nickName , level = detail.level , headId = detail.headId , headFrameId = detail.headFrameId , identityType = detail.groupIdentityType , contributionScore = v , joinTime = detail.groupJoinTime , isFriend = IsFriend( partnerId ) , title1 = detail.title1, title2 = detail.title2, medals = medals , clothesData = clothesData , colorData = colorData, DIYHeadInfo = detail.DIYHeadInfo, birthdayDate=detail.birthdayDate }) else table.insert( member , { partnerId = detail.partnerId , nickName = detail.nickName , level = detail.level , headId = detail.headId , headFrameId = detail.headFrameId , identityType = detail.groupIdentityType , contributionScore = v , joinTime = detail.groupJoinTime , isFriend = IsFriend( partnerId ) , title1 = detail.title1, title2 = detail.title2, medals = medals , clothesData = clothesData , colorData = colorData, birthdayDate=detail.birthdayDate }) end end return member end --计算排行榜状态和时间 function Group:CalcRankStatusAndTime() local curDay = skynet.server.common:GetDayInWeek() local curTime = skynet.server.common:GetTableTime() if 7 == curDay and curTime.hour >= 20 then --周天晚上8点进行结算 local nexRankStatusTime = skynet.server.common:GetAfterSomeDayTime(1) return self.RankStatus_Calc,nexRankStatusTime else local nexRankStatusTime = skynet.server.common:GetAfterSomeDayTime( 7 - curDay , 20 ) return self.RankStatus_Acc,nexRankStatusTime end end --计算福利结算时间 function Group:CalcContributeRewardTime() local curDay = skynet.server.common:GetDayInWeek() local curTime = skynet.server.common:GetTableTime() if 7 == curDay and curTime.hour >= 12 then --周天中午12点进行结算 return skynet.server.common:GetAfterSomeDayTime( 7 , 12 ) else return skynet.server.common:GetAfterSomeDayTime( 7 - curDay , 12 ) end end --是否有效地块 function Group:IsVaildMapId( mapId ) if mapId < 1 or mapId > self.MaxMapCount then return false else return true end end --家园合法参数检测 function Group:IsVaildParam( key , value ) if nil == key or nil == value then return false end if "groupId" == key and 10 == #value then return true elseif "partnerId" == key and 12 == #value then return true elseif "groupName" == key and #value >= 1 and #value <= 30 then return true elseif "declaration" == key and #value <= 150 then return true elseif "badgeId" == key then --and tonumber(value) > 0 and tonumber(value) < 10 then return true elseif "joinType" == key and tonumber(value) >= self.JoinType_Freedom and tonumber(value) <= self.JoinType_Audit then return true elseif "minJoinLevel" == key and tonumber(value) > 0 and tonumber(value) < 100 then return true elseif "identityType" == key and tonumber(value) >= self.IdentityType_Leader and tonumber(value) <= self.IdentityType_Member then return true elseif "plotId" == key and tonumber(value) > 0 and tonumber(value) <= self.MaxMapCount then return true elseif "msgText" == key and #value >= 1 and #value < 90 then return true elseif "archType" == key and value >= self.ArchType_Park and value <= self.ArchType_Road then return true elseif "contributeType" == key and value >= self.ContributeType_Wood and value <= self.ContributeType_Rebar then return true end log.warning("错误参数 ",key,value) return false end --获取消息ID function Group:GetLastMsgID( groupId ) local redisKey = string.format( redisKeyUrl.GameServerGroupMsgID , groupId ) local msgId = skynet.server.redis:incr( redisKey ) return msgId,redisKey end --将群信息同步到其它游戏服 function Group:SyncOnlineGroupInfo( groupId , groupOpType , isSync ) if self.GroupOpType_Create == groupOpType then --同步本地 local curInfo = self:GetGroup( groupId ) if curInfo then table.insert( self.onlineGroupList , curInfo) end elseif self.GroupOpType_Update == groupOpType then for k, v in pairs( self.onlineGroupList ) do if groupId == v.id then local curInfo = self:GetGroup( groupId ) if curInfo then self.onlineGroupList[ k ] = curInfo end break end end elseif self.GroupOpType_Dissolve == groupOpType then --同步本地 for k, v in pairs( self.onlineGroupList ) do if groupId == v.id then self.onlineGroupList[ k ] = nil break end end end if isSync then --同步其它服 local c2sData = {} c2sData.groupOpType = groupOpType c2sData.groupId = groupId local minGameId = skynet.server.clusterServer.gameServerMinID local maxGameId = skynet.server.clusterServer.gameServerMaxID local serverCmd = skynet.server.gameServer.GameToGame_SyncOnlineGroup for k, v in pairs( skynet.server.gameServer.clusterInfo ) do if curServerId ~= v.serverId and v.serverId >= minGameId and v.serverId <= maxGameId and skynet.server.clusterServer.Status_Running == v.status then skynet.server.gameServer:SendMsgToServer( v.serverId , serverCmd, c2sData ) end end end end --是否为房屋ID function Group:IsHouseID( player , houseId ) local cfgCurGarden = skynet.server.gameConfig:GetPlayerCurCfg( player, "Garden" , houseId ) if cfgCurGarden and 4 == cfgCurGarden.gardenType then return true end return false end --排行榜排序 function Group:SortRank( rankList ) local sortRank = {} for k, v in pairs( rankList ) do table.insert( sortRank , { partnerId = k , score = v }) end table.sort( sortRank , function (a , b) return a.score > b.score end) return sortRank end --同步家园庭院数据 function Group:SyncGarden( player , groupId , plotId, allArchs ) if self:IsVaildParam( "groupId" , groupId ) then local redisKey = string.format( redisKeyUrl.GameServerGroupPrivatePlot, groupId ) local plotInfo = skynet.server.redis:lindex( redisKey , plotId - 1 ) --获取家园信息 plotInfo = json:decode(plotInfo) plotInfo.archs = allArchs skynet.server.redis:lset( redisKey , plotId - 1 , json:encode(plotInfo)) end end --记录单个向往一日家园任务数据 function Group:SaveDreamLifeTask( player , taskId , finishTime ) local groupId = self:GetGroupID( player ) local redisKey = string.format( redisKeyUrl.GameServerGroupDreamLifeTaskList , groupId) --确保有家园 再保存任务数据 if self:GetGroup( groupId ) then local taskInfo = {} taskInfo.taskId = taskId taskInfo.partnerId = player.gameData.partner.id taskInfo.finishTime = finishTime taskInfo.isCheck = 0 --该状态记录是否被检查过 0 否 1 是 skynet.server.redis:lpush( redisKey , json:encode(taskInfo) ) local redisKey1 = string.format( redisKeyUrl.GameServerGroupInfoHash , groupId ) skynet.server.redis:hmset(redisKey1 , "dailyTaskTime" , skynet.GetTime() ) --dailyTaskTime 日常任务记录时间 ,后面可能有周任务记录时间 end end --检查家园中是否有完成的向往一日家园任务 function Group:CheckDreamLifeTask( player ) local groupId = self:GetGroupID( player ) local redisKey = string.format( redisKeyUrl.GameServerGroupDreamLifeTaskList , groupId) --确保有家园和对应任务数据 if self:GetGroup( groupId ) and skynet.server.redis:exists(redisKey) then local allTaskInfo = skynet.server.redis:lrange(redisKey , 0 , -1) for k , v in pairs(allTaskInfo) do local taskInfo = json:decode( v ) --检查任务是否已经完成 if skynet.GetTime() >= taskInfo.finishTime and taskInfo.isCheck == 0 then --修改对应任务数据 self:UpdateDreamLifeTask(player , dataType.GroupTaskType_DreamLife , taskInfo.taskId) taskInfo.isCheck = 1 skynet.server.redis:lset(redisKey , k-1 , json:encode(taskInfo)) end end end end --获取玩家对应任务是否完成 function Group:GetDreamLifeTaskState(player , taskId) local partnerId = player.gameData.partner.id local groupId = self:GetGroupID( player ) local redisKey = string.format( redisKeyUrl.GameServerGroupDreamLifeTaskList , groupId) --确保有家园和对应任务数据 if self:GetGroup( groupId ) and skynet.server.redis:exists(redisKey) then local allTaskInfo = skynet.server.redis:lrange(redisKey , 0 , -1) for k , v in pairs(allTaskInfo) do local taskInfo = json:decode( v ) if taskInfo.partnerId == partnerId and taskInfo.taskId == taskId then if taskInfo.isCheck == 1 then return true else return false end end end end return false end --更新任务 function Group:UpdateDreamLifeTask( player , taskType , taskId ) local groupId = self:GetGroupID( player ) local redisKey = string.format( redisKeyUrl.GameServerGroupInfoHash , groupId ) --拼接对应的key 例如 DreamLifeTask_5 local stringKey = taskType .. "_" .. taskId skynet.server.redis:hincrby( redisKey , stringKey , 1) end --获取任务次数 function Group:GetTaskCount( player , taskType , taskId ) local t = skynet.GetTime() local groupId = self:GetGroupID( player ) local curGroup = self:GetGroup( groupId ) if not curGroup then log.warning("家园 获取任务次数 未找到家园信息 ", player.gameData.partner.id ,groupId ) return 0 end local redisKey = string.format( redisKeyUrl.GameServerGroupInfoHash , groupId ) local stringKey = taskType .. "_" .. taskId local dailyTaskTime = curGroup.dailyTaskTime if dailyTaskTime and not skynet.server.common:IsSameDay( t , dailyTaskTime ) then --新的一天,初始化日常任务的数据 skynet.server.redis:hmset(redisKey , "dailyTaskTime" , t ) if taskType == dataType.GroupTaskType_DreamLife then local cfgDreamLifeTask = skynet.server.gameConfig:GetPlayerAllCfg(player , taskType) for k , v in pairs(cfgDreamLifeTask) do if v.taskType == 2 then local key = taskType .. "_" .. v.id skynet.server.redis:hmset(redisKey , key , 0 ) end end end --移除前一天的任务数据 local redisKey1 = string.format( redisKeyUrl.GameServerGroupDreamLifeTaskList , groupId) skynet.server.redis:del(redisKey1) curGroup[stringKey] = 0 end return curGroup[stringKey] or 0 end --清理所有的提示信息 function Group:ResetAllMsgTips( partnerId ) skynet.server.partner:SendMsgTips( partnerId , 38 , false ) skynet.server.partner:SendMsgTips( partnerId , 39 , false ) skynet.server.partner:SendMsgTips( partnerId , 60 , false ) skynet.server.partner:SendMsgTips( partnerId , 65 , false ) skynet.server.partner:SendMsgTips( partnerId , 66 , false ) end skynet.server.group = Group return Group