组队和公会系统的功能实现

组队和公会系统的功能实现

Scroll Down

组队数据结构

服务器队伍类,组队数据仅在内存中使用,如果做成支付宝种树,叠猫猫那类持久组队,可以新建张数据表

function TeamMgr:Init()
	self.teamlist = {}
	self.singlePersion = {}
end

玩家队伍数据

local Team = oo.class()
local _TEAM_MEM_NUM = 5 --一个队伍最多有5个成员,包括仙君和玩家--

function Team:ctor(teamid,player,targetid)
	self.teamid = teamid
	self.leader = player
	self.targetid = targetid
	self.cfgid = math.floor(targetid / 1000)
	self.index =  targetid % 1000
	self.isAuto = 1--是否进行自动匹配	 
	if self.targetid == 0 then
		self.isAuto = 0--是否进行自动匹配
	end
	self.memlist = {player}
	self.xianjunlist = {}
	self.levelRange = {0,1000}
	--self.xianjunStar = 0
end

组队功能

组队事件

注册onJoinTeam入队和onLeaveTeam离队方法

function TeamPerson:ctor(player,targetid)
	self.player = player
	self.targetid = targetid
	self.cfgid = math.floor(targetid / 1000)
end

function TeamPerson:init()	
	self.config = server.configCenter.TeamTargetConfig[self.cfgid]
	if not self.config then 
		return false
	end	
	self.m_joinTeamE = self.player:SubEvent(server.enEvent.PlayerEvnt.EVENTID_ENTITY_JION_TEAM,self.onJoinTeam,self)
	self.m_leaveTeamE = self.player:SubEvent(server.enEvent.PlayerEvnt.EVENTID_ENTITY_LEAVE_TEAM,self.onLeaveTeam,self)
	return true
end
--示例
function TeamPerson:onLeaveTeam(args)
	if args.entityID ~= self.player.entityID then
		return
	end
	--删除定时器
	if self.del_timer  then 
		lua_app.del_timer(self.del_timer)
		self.del_timer =  nil
	end 
end

创建队伍

function TeamMgr:createTeam(player,targetid)
	if player.prop.teamid ~= 0 then --已经有队伍不能再次创建
		return false
	end
	local teamid =  _Cur_TeamID + 1
	local team =  Team.new(teamid,player,targetid)
	if team and team:init(true) then
		_Cur_TeamID = teamid
		self.teamlist[teamid] = team
	else
		return false
	end
	--触发入队事件
	local args = {}
	args.entityID = player.entityID  --创建队伍
	args.teamid = teamid
	args.EventID = server.enEvent.PlayerEvnt.EVENTID_ENTITY_JION_TEAM
	player:FireEvent(args.EventID,args)
	local function  _matchTeam()
		if self.matchTime then
			lua_app.del_timer(self.matchTime)
		end
		if next(self.singlePersion) then
			self:doMatch() 
		end
		self.matchTime =  lua_app.add_timer(5000, _matchTeam)
	end
	if not self.matchTime then
		self.matchTime =  lua_app.add_timer(5000, _matchTeam)
	end
	--存在目标的的可以进行发送超链接
	if targetid and targetid > 0 then
		local info = team:getTargetInfo()		
		local players = {}
		for _, actor in pairs(server.playerCenter:GetOnlinePlayers()) do
			if actor.prop.level >= team.levelRange[1] and 
			actor.prop.level <= team.levelRange[2] then
				table.insert(players,actor)
			end
		end
	server.chatCenter:SendLink2SomePalyers(1320,player,players,info.activeName,info.rangeName,
		{server.ChatLinkType.team,teamid,player.entityID,"申请组队"})
	end 
	return true
end

申请加入队伍

与客户端通信协议

--[[
#请求加入队伍
cs_team_jointeam 17002 {
	request { 
	teamid	0 : integer
	}
}

]]
function server.cs_team_jointeam(socketid, msg)
    local player = server.playerCenter:GetPlayerBySocket(socketid)
    server.teamMgr:joinTeam(msg.teamid,player.entityID)
end

服务器验证队伍信息

function TeamMgr:joinTeam(teamid,entityID)
	local player  = server.gameEntityCenter:GetEntityByID(entityID)
	if not player then
		return false
	end
	local team = self.teamlist[teamid]
	if not team then
		--链接已经失效
		server.chatCenter:sendTipMsg(1321,player.dbid)
		return false
	end
	if player.prop.teamid ~= 0 then
		server.sendErr(player, "你已经有队伍了")
		return false
	end
	--判断是否满组队伍的要求
	if not team:canJoinTeam(player) then
		server.chatCenter:sendTipMsg(1322,player.dbid,tostring(team.levelRange[1]))
		return false
	end
	if team:GetMemberCount() >= _MaxCount then
		server.chatCenter:sendTipMsg(1321,player.dbid)
		return false
	end
	return team:joinTeam(player)
end

玩家队伍类处理

function Team:joinTeam(player)
	if player.prop.teamid ~= 0 then
		return false
	end
	if self:GetMemberCount() >= 3 then
		return false
	end
	--加入者在战斗中
	if player.prop.status == server.enDef.entityStatus.fighting then
		return false
	end
	--队长在战斗中
	if self.leader.prop.status == server.enDef.entityStatus.fighting then
		return false
	end
	local targetEntity =  self.memlist[#self.memlist]
	if not server.mapMgr:Fly(player.entityID,targetEntity.prop.mapID,targetEntity.prop.sceneID,targetEntity.prop.x,targetEntity.prop.y,true) then
		return false
	end
	table.insert(self.memlist,player)
	player.prop.teamid = self.teamid
	self:resetXianJun()
	self:Broadcast("sc_team_info",{data = self:packMsg()})
	local args = {}
	args.entityID = player.entityID  --加入队伍的实体id
	args.teamid = self.teamid
	args.EventID = server.enEvent.PlayerEvnt.EVENTID_ENTITY_JION_TEAM
	for _,mem in pairs(self.memlist) do
		mem:FireEvent(args.EventID,args)
	end
	return true
end

邀请加入队伍

function TeamMgr:inviteJoinTeam(player,beinviteid)
	local team = self:getTeam(player.prop.teamid)
	if not team then
		server.sendErr(self.player, "你还没有队伍,无法邀请别人")
		return false
	end
	local beinviter = server.playerCenter:GetPlayerByDBID(beinviteid)
	--local beinviter = server.gameEntityCenter:GetEntityByID(beinviteid)	
	if not beinviter or beinviter.prop.teamid ~= 0 then
		server.sendErr(self.player, "被邀请的人不存在,或者被邀请者已经有队伍了")
		return false
	end 
	if not team:canJoinTeam(beinviter) then 
		server.chatCenter:sendTipMsg(1323,player.dbid,tostring(team.levelRange[1]))
		return false
	end 
	--通知被邀请
	local msg  =  {}
	msg.inviteid =  player.dbid
	msg.inviteTeamid = player.prop.teamid
	msg.targetid = team.targetid
	msg.inviteName = player.prop.name
	beinviter:sendReq("sc_team_invite",msg)
	return true
end

响应邀请

teamid 0 : integer #响应的队伍id
inviteid 1 : integer #邀请者的dbid
isConfirm 2 : integer #同意 1, 拒绝0

function TeamMgr:responeInvite(teamid,inviteid,beInviteEnityid,isconfirm)
	--local inviter = server.gameEntityCenter:GetEntityByID(inviteid)	
	local inviter = server.playerCenter:GetPlayerByDBID(inviteid)
	if not  inviter or inviter.prop.teamid ~= teamid then
		return false
	end
	local team = self.teamlist[teamid]
	if not team then
		return false
	end
	local beinviter = server.gameEntityCenter:GetEntityByID(beInviteEnityid)	
	if not beinviter  or beinviter.prop.teamid ~= 0 then
		return false
	end
	if not team:canJoinTeam(beinviter) then 
		lua_app.log_info("忙活了半天,还是不能加入队伍, 被邀请者等级不符合条件,或者队长在战斗中")
		return false
	end
	if isconfirm == 1 then
		team:joinTeam(beinviter)
		return  true
	end
	--对邀请者发送 被邀请者拒绝入队的提示
	server.sendErr(inviter,beinviter.prop.name.."拒绝加入队伍")
	return true
end

踢出队伍

function TeamMgr:kickMem(player,entityID)
	local kickPlayer = server.gameEntityCenter:GetEntityByID(entityID)
	if not  kickPlayer then
		return false
	end
	local teamid = player.prop.teamid
	if teamid ~= kickPlayer.prop.teamid then
		return false
	end
	local team = self.teamlist[teamid]
	if not team then
		return false
	end
	if not team:isLeader(player.entityID) then
		server.sendErr(self.player, "你不是队长,没有踢人的权限")
		return false
	end
	local ret =  team:kickTeam(player,kickPlayer)
	if ret then 
		local teamPsersion  =  self.singlePersion[entityID]
		if teamPsersion  then
			teamPsersion:sendMyInfo()
		end
	end
	return ret
end

玩家组队类踢出

function Team:kickTeam(leader,beKicker)
	if leader.dbid ~=  self.leader.dbid then
		return false
	end
	if beKicker.prop.teamid ~=  self.teamid then
		return false
	end
	if leader.entityID ~= self.leader.entityID then
		return false
	end
	local args = {}
	args.entityID = beKicker.entityID  --离开队伍的的实体id
	args.EventID = server.enEvent.PlayerEvnt.EVENTID_ENTITY_LEAVE_TEAM
	args.teamid = self.teamid
	for _,mem in pairs(self.memlist) do
		mem:FireEvent(args.EventID,args)
	end
	for i = 1,#self.memlist do 
		if self.memlist[i].entityID == beKicker.entityID then
			table.remove(self.memlist,i)
			break
		end
	end
	beKicker.prop.teamid = 0
	--直接向客服端发送离开队伍
	local leavemsg = {}
	beKicker:sendReq("sc_team_leave",leavemsg)
	--重新甚至队伍的仙君信息
	self:resetXianJun()
	self:Broadcast("sc_team_info",{data = self:packMsg()})
end

离开队伍

function TeamMgr:leaveTeam(player)
	local teamid = player.prop.teamid
	local team = self.teamlist[teamid]
	if not team then
		player.prop.teamid = 0
		server.sendErr(self.player, "你没有队伍,无需离队")
		return false
	end
	local ret =  team:leaveTeam(player)
	if ret then 
		--主动离队要删除自己的自动匹配
		self:deletePerson(player.entityID)
	end 
	return ret
end

玩家组队类离开队伍

function Team:leaveTeam(player)
	if player.prop.teamid ~= self.teamid then
		return false
	end
	local args = {}
	args.entityID = player.entityID  --离开队伍的实体id
	args.EventID = server.enEvent.PlayerEvnt.EVENTID_ENTITY_LEAVE_TEAM
	args.teamid = self.teamid
	args.preStatus = server.enDef.teamStatues.mem
	if self:isLeader(player.entityID) then
		args.preStatus = server.enDef.teamStatues.leader
	end
	for _,mem in pairs(self.memlist) do
		mem:FireEvent(args.EventID,args)
	end
	--确定可以离队了,先清掉队伍id吧
	player.prop.teamid =  0
	player.prop.leaderSign = 0
	--直接向客服端发送离开队伍
	local leavemsg = {}
	player:sendReq("sc_team_leave",leavemsg)
	--战斗中允许直接离队,先这样吧
	if self.leader.entityID == player.entityID then
		--离队的是队长
		local mem = {}
		for i = 2 ,#self.memlist do 
			table.insert(mem,self.memlist[i])
		end
		self.memlist =  mem
		if #self.memlist > 0 then
			self.leader = self.memlist[1]
			self.leader.prop.leaderSign = 1
			local largs = {}
			largs.newLeader = self.leader.entityID  --新的队长
			largs.oldLeader = player.entityID --老的队长 ,此处队长可能已经不再队伍里面了
			largs.EventID = server.enEvent.PlayerEvnt.EVENTID_ENTITY_BE_TEAM_LEADER
			largs.teamid = self.teamid
			for _,mem in pairs(self.memlist) do
				mem:FireEvent(largs.EventID,largs)
			end
		else 
			--队伍解散了
			server.teamMgr:deleteTeam(self.teamid)
			player.prop.teamid =  0
			return true
		end
	else
		for i =  2 ,#self.memlist do 
			if self.memlist[i].entityID == player.entityID then
				table.remove(self.memlist,i)
				break
			end
		end
	end
	self:resetXianJun()
	self:Broadcast("sc_team_info",{data = self:packMsg()})
end

获取组队目标下的队伍列表

function TeamMgr:getAndSendTeamList(player,targetid)
	if not targetid then
		return false
	end 
	local msg =  {}
	local cfgid = math.floor(targetid / 1000)
	--获取目标相同的所有,可以匹配的队伍
	for teamid,team in pairs(self.teamlist) do 
		if team.cfgid == cfgid and team:GetMemberCount() < 3 then
			local teammsg =  team:packTeamShowMsg()
			table.insert(msg,teammsg)
		end
	end
	if #msg > 0 then
		player:sendReq("sc_team_list",{targetid =  targetid,teamlist = msg})
		table.print(msg)
		return true
	end
end

更改组队设置

targetid 0 : integer #如果是队长该id为cfgid*1000 +index ,如果是队员改id直接是 cfgid
isAuto 1 : integer #设置自动匹配或者取消自动匹配

function TeamMgr:setAutoMatch(player,targetid,isAuto)
	local teamid = player.prop.teamid
	if teamid == 0 then
		if not isAuto then
			self:deletePerson(player.entityID)
			return true
		end
		local teamPsersion  =  self.singlePersion[player.entityID]
		if teamPsersion  and teamPsersion.release then
			teamPsersion:release()
			self.singlePersion[player.entityID] = nil
		end
		local persion =  TeamPerson.new(player,targetid)
		if not persion or not persion:init() then
			return false
		end
		self.singlePersion[player.entityID] = persion
		return true
	end
	--如果有队伍
	local team = self.teamlist[teamid]
	if not team then
		player.prop.teamid = 0 
		return false
	end
	if not team:isLeader(player.entityID) then
		return false
	end
    return team:setTarget(targetid,isAuto)
end

玩家组队类设置

function Team:setTarget(targetid,isAuto)
	if #self.memlist >= 3 then
		return false
	end
	if self.isAuto == isAuto and self.targetid == targetid then
		--没有任何变化,不用继续去处理了
		return true
	end
	self.isAuto  = isAuto
	if self.targetid == targetid then
		local msg = {targetid = self.targetid ,isAuto = self.isAuto}
		self:Broadcast("sc_team_target", msg)
		return true
	end
	self.targetid = targetid 
	local cfgid = math.floor(targetid / 1000)
	local index =  targetid % 1000	
	if self.targetid > 0 then
		self.config = server.configCenter.TeamTargetConfig[cfgid]
		if not self.config then
			return false
		end
		--等级段
		local range = self.config.levelrange[index]
		if not range then 
			return false
		end
		if range[0] == -1 then
			if index <=  1 then
				return false
			end
			local prerange =  self.config.levelrange[index -1]
			local minlvl =  self.player.prop.level - 5 
			minlvl =  math.max(minlvl,prerange[0] + 5)
			self.levelRange[1] =  minlvl
			self.levelRange[2] =  range[2]
		else 
			self.levelRange[1] = range[1]
			self.levelRange[2] =  range[2]
		end
		local info = self:getTargetInfo()
		local players = {}
		for _, player in pairs(server.playerCenter:GetOnlinePlayers()) do
			if player.prop.level >= self.levelRange[1] and 
				player.prop.level <= self.levelRange[2] then
				table.insert(players,player)
			end 
		end
		--发送超链接
		server.chatCenter:SendLink2SomePalyers(1320,self.leader,players,info.activeName,info.rangeName,				{server.ChatLinkType.team,self.teamid,self.leader.entityID,"申请组队"})
	else 
		self.levelRange = {0,1000}
		self.isAuto = 0
		self.config = nil
	end
	self.targetid = targetid 
	self.cfgid = cfgid
	self.index =  index	
	local msg = {targetid = self.targetid ,isAuto = self.isAuto}
	--广播目标改变信息	
	self:Broadcast("sc_team_target",msg)
	return true
end

公会基本结构

公会和组队类似不多讲了,只是数据保存在公会表中

公会数据

玩家实体信息保存公会id和活动数据

		{ "guildid" 	 		,"bigint(20)"		,0		,"公会ID" },
		{ "guildcontribute" 	,"bigint(20)"		,0		,"公会贡献" },
		{ "guild_data"					,"mediumblob"		,{
			skillinfo = {skills = {}},
			fuli	  =  {},
			pray	  =  {},
		}		,"玩家公会数据" },

公会表保存公会信息

guild = {
	columns = {
		{ "dbid"			,"bigint(20)"		,0		,"公会id" },
		{ "name"			,"varchar(128)"		,""		,"公会名称" },
		{ "serverid" 		,"int(11)"			,0		,"公会创建所在服务器" },
		{ "changename_count","int(11)"			,0		,"剩余改名次数" },
		{ "players"			,"mediumblob"		,{}		,"公会成员表" },
		{ "level"			,"int(11)"			,0		,"帮派等级" },
		{ "notice"			,"varchar(256)"		,""		,"帮派签名" },
		{ "fund"			,"int(11)"			,0		,"帮派资金" },
		{ "fuliawardtips"	,"mediumblob"		,{}		,"福利抽奖传闻列表" },
		{ "partnerswapbit"  ,"mediumblob"       ,{}     ,"仙君碎片交换区"},
		{ "partnerswaphis"  ,"mediumblob"       ,{}     ,"仙君交换历史数据"},
	},
	prikey = { "dbid" },
	comment = "公会表",
	initdbid = "platonly",
},

公会管理类

初始加载信息,对应guild表

function Guild:Init(cache)
	self.cache = cache
	self:RefrushData()	
end

function Guild:RefrushData()
	self.dbid = self.cache.dbid
	self.players = {}
	self.admin = {}
	for _, v in ipairs(self.cache.players) do
		self.players[v.playerid] = v
		if v.office ~= _Office.Mem then
			if v.office == _Office.Leader then
				self.leader = self.players[v.playerid]
			end
			self.admin[v.playerid] = v
		end
	end
	self.summary = {
			id = self.dbid,
			level = self.cache.level,
			playercount = #self.cache.players,
			name = self.cache.name,
			leaderinfo = self.leader,
			notice = self.cache.notice
		}
end

创建公会

function Guild:Create(data)
	data.serverid = server.serverID
	self.cache = server.mysqlBlob:CreateDmg(tbname,data,true)
	self:RefrushData()
	self.sceneid = server.mapMgr:createMap(GuildConfig.MapID, self.cache.dbid)
	self.guildmapid = GuildConfig.MapID
	self.guildRobberCtrl = GuildRobberCtrl.new()
	self.guildRobberCtrl:Create(self.dbid, self.sceneid)
end

玩家公会类

对应数据guild_data,主管管理活动信息

local GuildCtrl = oo.class()

function GuildCtrl:ctor(player)
	self.player = player
	self.guildSkill = GuildSkill.new(player,self)
	self.guildFuLi =  GuildFuLi.new(player,self)
	self.guildPray =  GuildPray.new(player,self)
end

function GuildCtrl:onCreate()
	self:onLoad()
end

function GuildCtrl:onLoad()
	self.cache = self.player.cache.guild_data
	self:Init(self.cache)
end

公会活动示例

--帮派祈愿
local GuildPray = oo.class()

local MAX_TASKID = 3

function GuildPray:ctor(player, guildctrl)
	self.player = player
	self.guildctrl = guildctrl
end

function GuildPray:Init(datas)
	self.cache = datas.pray or {}
	self.cache.offerGoods = self.cache.offerGoods or {}
	self.cache.circleCount = self.cache.circleCount  or 0
	self.cache.iscomplete = self.cache.iscomplete or 0
	self.cache.updatetime = self.cache.updatetime or 0
end

function GuildPray:onJoinGuild(guild)
	local playerinfo = guild:GetPlayerInfo(self.player.dbid)
	if not playerinfo then
		return
	end
	self:Refresh()
	self:SendClientMsg()
end

公会和组队功能应该也很比较有参考意义