From a6fe9b060edf315f6abde7443e48db5dea439f47 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 28 五月 2025 09:59:08 +0800
Subject: [PATCH] 16 卡牌服务端(功能队伍数据基础;不含功能逻辑;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFuncTeam.py | 1104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 1,067 insertions(+), 37 deletions(-)

diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFuncTeam.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFuncTeam.py
index e1bc7c2..5ef3994 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFuncTeam.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFuncTeam.py
@@ -6,51 +6,1081 @@
 #
 # @todo:功能队伍表
 # @author hxp
-# @date 2024-08-02
+# @date 2025-05-28
 # @version 1.0
 #
-# 详细描述: 功能队伍表
+# 详细描述: 功能队伍表,支持跨服
 #
 #-------------------------------------------------------------------------------
-#"""Version = 2024-08-02 16:30"""
+#"""Version = 2025-05-28 10:00"""
 #-------------------------------------------------------------------------------
 
-import PyGameData
+import GameWorld
+import ShareDefine
+import IpyGameDataPY
+#import CrossBattlefield
+import CrossRealmPlayer
+import PlayerViewCache
+import ChPyNetSendPack
+#import CrossRealmMsg
+import PlayerControl
+import NetPackCommon
+import DBDataMgr
+import DirtyList
+import ChConfig
 
-def OnFuncTeamMemIDRefresh(msgList):
-    ## 功能队伍成员ID刷新
-    teamIDList, delTeamIDList, teamMemIDInfoDict = msgList
+# 队伍操作
+Def_FuncTeamOPList = (
+Def_FuncTeamOP_JoinApply, # 申请加入 1
+Def_FuncTeamOP_JoinCancel, # 申请取消 2
+Def_FuncTeamOP_JoinAgree, # 同意入队 3
+Def_FuncTeamOP_JoinRefuse, # 拒绝入队 4
+Def_FuncTeamOP_Exit, # 退出队伍 5
+Def_FuncTeamOP_Kick, # 踢出队伍 6
+Def_FuncTeamOP_Transfer, # 转让队长 7
+Def_FuncTeamOP_Dissolve, # 解散队伍 8
+) = range(1, 1 + 8)
+
+def IsOPLimitInAct(curPlayer, funcMapID):
+    ## 活动期间是否限制队伍操作
+    ipyData = IpyGameDataPY.GetIpyGameData("FuncTeamSet", funcMapID)
+    if not ipyData:
+        return
+    if not ipyData.GetOPLimitInAct():
+        return
+    isInAct = False
+    if funcMapID == ChConfig.Def_FBMapID_CrossBattlefield:
+        isInAct = CrossBattlefield.GetCrossBattlefieldState()
+    if isInAct:
+        GameWorld.ErrLog("活动期间无法操作队伍! funcMapID=%s" % funcMapID, curPlayer.GetPlayerID())
+    return isInAct
+
+def GetFuncTeamZoneID(funcMapID):
+    zoneID = 0
+    if funcMapID == ChConfig.Def_FBMapID_CrossBattlefield:
+        zoneID = CrossBattlefield.GetCrossBattlefieldZoneID(GameWorld.GetServerGroupID())
+    return zoneID
+
+#// B9 20 创建功能队伍 #tagCMCreateFuncTeam
+#
+#struct    tagCMCreateFuncTeam
+#{
+#    tagHead        Head;
+#    DWORD        FuncMapID;    // 功能地图ID或自定义的活动功能ID
+#    DWORD        FuncMapEx;    // 功能地图扩展,如不同的层级
+#    BYTE        NameLen;
+#    char        TeamName[NameLen];    // 队伍名称,可为空
+#    WORD        MinLV;        //最低等级限制
+#    DWORD        MinFightPower;    //最低战力限制,求余亿
+#    DWORD        MinFightPowerEx;    //最低战力限制,整除亿
+#    BYTE        ServerOnly;    //是否仅本服玩家可加入,0-否,1-是
+#    BYTE        NeedCheck;     //是否需要审核
+#};
+def OnCreateFuncTeam(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    funcMapID = clientData.FuncMapID
+    funcMapEx = clientData.FuncMapEx
+    teamName = clientData.TeamName
+    minLV = clientData.MinLV
+    minFightPower = clientData.MinFightPower
+    minFightPowerEx = clientData.MinFightPowerEx
+    serverOnly = clientData.ServerOnly
+    needCheck = clientData.NeedCheck
     
-    # 没有指定时,全部刷新
-    if not teamIDList:
-        PyGameData.g_funcTeamPlayerDict = {}
-        
-    for key, refreshDict in teamMemIDInfoDict.items():
-        if key not in PyGameData.g_funcTeamPlayerDict:
-            PyGameData.g_funcTeamPlayerDict[key] = {}
-        infoDict = PyGameData.g_funcTeamPlayerDict[key]
-        infoDict.update(refreshDict)
-        
-    for teamInfoDict in PyGameData.g_funcTeamPlayerDict.values():
-        for delTeamID in delTeamIDList[::-1]:
-            if delTeamID not in teamInfoDict:
-                continue
-            teamInfoDict.pop(delTeamID, None)
-            delTeamIDList.remove(delTeamID)
-            
+    if IsOPLimitInAct(curPlayer, funcMapID):
+        return
+    
+    zoneID = GetFuncTeamZoneID(funcMapID)
+    if not zoneID:
+        return
+    
+    teamInfo = {"funcMapID":funcMapID, "funcMapEx":funcMapEx, "teamName":teamName, "minLV":minLV, 
+               "minFightPower":minFightPower, "minFightPowerEx":minFightPowerEx, 
+               "serverOnly":serverOnly, "needCheck":needCheck}
+    dataMsg = {"zoneID":zoneID, "playerID":playerID, "teamInfo":teamInfo, "cacheBase":PlayerViewCache.GetSyncCrossCacheBase(curPlayer)}
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_CreateFuncTeam, dataMsg)
     return
 
-def GetPlayerTeamID(playerID, funcMapID):
-    for key, infoDict in PyGameData.g_funcTeamPlayerDict.items():
-        if funcMapID != key[1]:
-            continue
-        for teamID, memIDList in infoDict.items():
-            if playerID in memIDList:
-                return teamID
-    return 0
+#// B9 21 修改功能队伍 #tagCMChangeFuncTeam
+#
+#struct    tagCMChangeFuncTeam
+#{
+#    tagHead        Head;
+#    DWORD        TeamID;
+#    DWORD        FuncMapID;    // 功能地图ID或自定义的活动功能ID
+#    WORD        MinLV;        //最低等级限制
+#    DWORD        MinFightPower;    //最低战力限制,求余亿
+#    DWORD        MinFightPowerEx;    //最低战力限制,整除亿
+#    BYTE        ServerOnly;    //是否仅本服玩家可加入,0-否,1-是
+#    BYTE        NeedCheck;     //是否需要审核
+#};
+def OnChangeFuncTeam(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    teamID = clientData.TeamID
+    funcMapID = clientData.FuncMapID
+    minLV = clientData.MinLV
+    minFightPower = clientData.MinFightPower
+    minFightPowerEx = clientData.MinFightPowerEx
+    serverOnly = clientData.ServerOnly
+    needCheck = clientData.NeedCheck
+    
+    if IsOPLimitInAct(curPlayer, funcMapID):
+        return
+    
+    zoneID = GetFuncTeamZoneID(funcMapID)
+    if not zoneID:
+        return
+    
+    teamInfo = {"teamID":teamID, "funcMapID":funcMapID, "minLV":minLV, 
+               "minFightPower":minFightPower, "minFightPowerEx":minFightPowerEx, 
+               "serverOnly":serverOnly, "needCheck":needCheck}
+    dataMsg = {"zoneID":zoneID, "playerID":playerID, "teamInfo":teamInfo, "cacheBase":PlayerViewCache.GetSyncCrossCacheBase(curPlayer)}
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_ChangeFuncTeam, dataMsg)
+    return
 
-def GetMemberIDList(teamID):
-    for infoDict in PyGameData.g_funcTeamPlayerDict.values():
-        if teamID in infoDict:
-            return infoDict[teamID]
-    return []
+#// B9 22 功能队伍成员操作 #tagCMFuncTeamMemOP
+#
+#struct    tagCMFuncTeamMemOP
+#{
+#    tagHead        Head;
+#    DWORD        TeamID;
+#    DWORD        FuncMapID;    // 功能地图ID或自定义的活动功能ID
+#    BYTE        OPType;        // 1-申请加入;2-申请取消;3-同意入队;4-拒绝入队;5-退出队伍;6-踢出队伍;7-转让队长;8-解散队伍;
+#    DWORD        OPData;        // 可选
+#};
+def OnFuncTeamMemOP(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    teamID = clientData.TeamID
+    funcMapID = clientData.FuncMapID
+    opType = clientData.OPType
+    opData = clientData.OPData
+    
+    if opType not in Def_FuncTeamOPList:
+        return
+    
+    if IsOPLimitInAct(curPlayer, funcMapID):
+        return
+    
+    zoneID = GetFuncTeamZoneID(funcMapID)
+    if not zoneID:
+        return
+    
+    dataMsg = {"zoneID":zoneID, "playerID":playerID, "teamID":teamID, "funcMapID":funcMapID, 
+               "opType":opType, "opData":opData}
+    dataMsg["cacheBase"] = PlayerViewCache.GetSyncCrossCacheBase(curPlayer)
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_FuncTeamMemOP, dataMsg)
+    return
+
+#// B9 23 查找功能队伍列表 #tagCMQueryFuncTeam
+#
+#struct    tagCMQueryFuncTeam
+#{
+#    tagHead        Head;
+#    DWORD        FuncMapID;    // 功能地图ID或自定义的活动功能ID
+#    DWORD        FuncMapEx;    // 功能地图扩展,如不同的层级,0代表所有
+#    DWORD        StartIndex;    // 查看的起始索引, 默认0
+#    BYTE        QueryCnt;    // 查看条数,默认20,最大不超过100
+#    BYTE        HaveSpace;    // 是否只查看有空位置的队伍
+#    BYTE        IDLimitType;    // ID限制类型:1-同仙盟队长;2-同ServerGroupID队长;3-同ServerID队长
+#    BYTE        SearchLen;
+#    char        SearchMsg[SearchLen];    // 指定搜索时有用,可搜索指定队伍ID或模糊搜索队伍名称,搜索时返回最多QueryCnt个数的队伍
+#};
+def OnQueryFuncTeam(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    funcMapID = clientData.FuncMapID
+    funcMapEx = clientData.FuncMapEx
+    startIndex = clientData.StartIndex
+    queryCnt = clientData.QueryCnt
+    haveSpace = clientData.HaveSpace
+    idLimitType = clientData.IDLimitType
+    searchMsg = clientData.SearchMsg
+    
+    zoneID = GetFuncTeamZoneID(funcMapID)
+    if not zoneID:
+        return
+    
+    dataMsg = {"zoneID":zoneID, "playerID":playerID, "funcMapID":funcMapID, "funcMapEx":funcMapEx, 
+               "startIndex":startIndex, "queryCnt":queryCnt, "haveSpace":haveSpace, "idLimitType":idLimitType, 
+               "searchMsg":searchMsg}
+    dataMsg["cacheBase"] = PlayerViewCache.GetSyncCrossCacheBase(curPlayer)
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_QueryFuncTeam, dataMsg)
+    return
+
+#// B9 24 查找玩家功能队伍 #tagCMQueryPlayerFuncTeam
+#
+#struct    tagCMQueryPlayerFuncTeam
+#{
+#    tagHead        Head;
+#    DWORD        FuncMapID;    // 功能地图ID或自定义的活动功能ID
+#};
+def OnQueryPlayerFuncTeam(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    playerID = curPlayer.GetPlayerID()
+    funcMapID = clientData.FuncMapID
+    
+    zoneID = GetFuncTeamZoneID(funcMapID)
+    if not zoneID:
+        return
+    
+    dataMsg = {"zoneID":zoneID, "playerID":playerID, "funcMapID":funcMapID}
+    dataMsg["cacheBase"] = PlayerViewCache.GetSyncCrossCacheBase(curPlayer)
+    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_QueryFuncTeam, dataMsg)
+    return
+
+def CrossServerMsg_FuncTeamInfo(msgData):
+    ## 子服收到跨服信息 - 队伍刷新信息
+    infoType = msgData["infoType"]
+    playerID = msgData["playerID"]
+    funcMapID = msgData["funcMapID"]
+    teamInfo = msgData["teamInfo"]
+    teamID = msgData.get("teamID", 0)
+    syncPlayerIDList = msgData.get("syncPlayerIDList", [])
+    notifyMark = msgData.get("notifyMark", "")
+    
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+    if curPlayer:
+        if notifyMark:
+            PlayerControl.NotifyCode(curPlayer, notifyMark)
+            
+    if infoType == "QueryPlayerFuncTeam":
+        if curPlayer:
+            if teamInfo:
+                Sync_FuncTeamRefresh(teamInfo, [playerID])
+            else:
+                clientPack = ChPyNetSendPack.tagGCQueryPlayerFuncTeamRet()
+                clientPack.FuncMapID = funcMapID
+                clientPack.TeamID = 0
+                NetPackCommon.SendFakePack(curPlayer, clientPack)
+        return
+    
+    if not teamInfo:
+        # 操作后没有队伍信息了,解散
+        if infoType == "FuncTeamMemOP":
+            Sync_FuncTeamDissolve(teamID, syncPlayerIDList)
+        return
+    
+    Sync_FuncTeamRefresh(teamInfo, syncPlayerIDList)
+    return
+
+def CrossServerMsg_FuncTeamDel(msgData):
+    ## 子服收到跨服信息 - 队伍删除
+    #"zoneID":zoneID, "funcMapID":funcMapID, "delTeamDict":delTeamDict
+    #zoneID = msgData["zoneID"]
+    #funcMapID = msgData["funcMapID"]
+    delTeamDict = msgData["delTeamDict"]
+    for teamID, syncPlayerIDList in delTeamDict.items():
+        Sync_FuncTeamDissolve(teamID, syncPlayerIDList)
+    return
+
+def CrossServerMsg_FuncTeamList(msgData):
+    ## 子服收到跨服信息 - 队伍列表
+    queryInfo = msgData["queryInfo"]
+    loopIndex = msgData["loopIndex"]
+    teamInfoList = msgData["teamInfoList"]
+    
+    playerID = queryInfo["playerID"]
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+    if not curPlayer:
+        return
+    
+    clientPack = ChPyNetSendPack.tagGCFuncTeamList()
+    clientPack.FuncMapID = queryInfo["funcMapID"]
+    clientPack.FuncMapEx = queryInfo["funcMapEx"]
+    clientPack.StartIndex = queryInfo["startIndex"]
+    clientPack.QueryCnt = queryInfo["queryCnt"]
+    clientPack.HaveSpace = queryInfo["haveSpace"]
+    clientPack.IDLimitType = queryInfo["idLimitType"]
+    clientPack.SearchMsg = queryInfo["searchMsg"]
+    clientPack.SearchLen = len(clientPack.SearchMsg)
+    clientPack.LoopIndex = loopIndex
+    
+    for teamInfo in teamInfoList:
+        team = ChPyNetSendPack.tagGCFuncTeam()
+        team.TeamID = teamInfo["TeamID"]
+        team.CreateTime = teamInfo["CreateTime"]
+        team.FuncMapEx = teamInfo["FuncMapEx"]
+        team.TeamName = teamInfo["TeamName"]
+        team.NameLen = len(team.TeamName)
+        team.CaptainID = teamInfo["CaptainID"]
+        team.MinLV = teamInfo["MinLV"]
+        team.MinFightPower = teamInfo["MinFightPower"] % ChConfig.Def_PerPointValue
+        team.MinFightPowerEx = teamInfo["MinFightPower"] / ChConfig.Def_PerPointValue
+        team.ServerOnly = teamInfo["ServerOnly"]
+        team.NeedCheck = teamInfo["NeedCheck"]
+        team.Value1 = teamInfo["Value1"]
+        team.Value2 = teamInfo["Value2"]
+        
+        memberList = []
+        for memberInfo in teamInfo["MemberList"]:
+            mem = ChPyNetSendPack.tagGCFuncTeamMem()
+            mem.ServerID = memberInfo.get("ServerID", 0)
+            mem.PlayerID = memberInfo["PlayerID"]
+            mem.Name = memberInfo.get("Name", "")
+            mem.NameLen = len(mem.Name)
+            mem.LV = memberInfo.get("LV", 0)
+            mem.Job = memberInfo.get("Job", 0)
+            mem.RealmLV = memberInfo.get("RealmLV", 0)
+            mem.Face = memberInfo.get("Face", 0)
+            mem.FacePic = memberInfo.get("FacePic", 0)
+            mem.FightPower = memberInfo.get("FightPower", 0) % ChConfig.Def_PerPointValue
+            mem.FightPowerEx = memberInfo.get("FightPower", 0) / ChConfig.Def_PerPointValue
+            mem.Value1 = memberInfo["Value1"]
+            mem.Value2 = memberInfo["Value2"]
+            memberList.append(mem)
+            
+        team.MemberList = memberList
+        team.MemberCount = len(team.MemberList)
+        team.ApplyIDList = teamInfo["ApplyIDList"]
+        team.ApplyCount = len(team.ApplyIDList)
+        
+        clientPack.TeamList.append(team)
+    clientPack.TeamCount = len(clientPack.TeamList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
+def Sync_FuncTeamRefresh(teamInfo, syncPlayerIDList):
+    ## 功能队伍刷新
+    if not teamInfo or not syncPlayerIDList:
+        return
+    
+    syncPlayerList = []
+    playerManager = GameWorld.GetPlayerManager()
+    for playerID in syncPlayerIDList:
+        player = playerManager.FindPlayerByID(playerID)
+        if player == None or not player.GetInitOK():
+            continue
+        syncPlayerList.append(player)
+        
+    if not syncPlayerList:
+        return
+    
+    clientPack = ChPyNetSendPack.tagGCFuncTeamRefresh()
+    clientPack.TeamID = teamInfo["TeamID"]
+    clientPack.CreateTime = teamInfo["CreateTime"]
+    clientPack.FuncMapID = teamInfo["FuncMapID"]
+    clientPack.FuncMapEx = teamInfo["FuncMapEx"]
+    clientPack.TeamName = teamInfo["TeamName"]
+    clientPack.NameLen = len(clientPack.TeamName)
+    clientPack.CaptainID = teamInfo["CaptainID"]
+    clientPack.MinLV = teamInfo["MinLV"]
+    clientPack.MinFightPower = teamInfo["MinFightPower"] % ChConfig.Def_PerPointValue
+    clientPack.MinFightPowerEx = teamInfo["MinFightPower"] / ChConfig.Def_PerPointValue
+    clientPack.ServerOnly = teamInfo["ServerOnly"]
+    clientPack.NeedCheck = teamInfo["NeedCheck"]
+    clientPack.Value1 = teamInfo["Value1"]
+    clientPack.Value2 = teamInfo["Value2"]
+    
+    memberInfoList = teamInfo["MemberList"]
+    applyInfoList = teamInfo["ApplyList"]
+    
+    memberList = []
+    for memberInfo in memberInfoList:
+        mem = ChPyNetSendPack.tagGCFuncTeamRefreshMem()
+        mem.ServerID = memberInfo.get("ServerID", 0)
+        mem.PlayerID = memberInfo["PlayerID"]
+        mem.Name = memberInfo.get("Name", "")
+        mem.NameLen = len(mem.Name)
+        mem.LV = memberInfo.get("LV", 0)
+        mem.Job = memberInfo.get("Job", 0)
+        mem.RealmLV = memberInfo.get("RealmLV", 0)
+        mem.Face = memberInfo.get("Face", 0)
+        mem.FacePic = memberInfo.get("FacePic", 0)
+        mem.FightPower = memberInfo.get("FightPower", 0) % ChConfig.Def_PerPointValue
+        mem.FightPowerEx = memberInfo.get("FightPower", 0) / ChConfig.Def_PerPointValue
+        mem.OfflineValue = memberInfo.get("OfflineValue", 0)
+        mem.Value1 = memberInfo["Value1"]
+        mem.Value2 = memberInfo["Value2"]
+        memberList.append(mem)
+        
+    applyList, applyIDList = [], []
+    for applyInfo in applyInfoList:
+        applyP = ChPyNetSendPack.tagGCFuncTeamRefreshApply()
+        applyP.ServerID = applyInfo["ServerID"]
+        applyP.PlayerID = applyInfo["PlayerID"]
+        applyP.Name = applyInfo["Name"]
+        applyP.NameLen = len(applyP.Name)
+        applyP.LV = applyInfo["LV"]
+        applyP.Job = applyInfo["Job"]
+        applyP.RealmLV = applyInfo["RealmLV"]
+        applyP.Face = applyInfo.get("Face", 0)
+        applyP.FacePic = applyInfo.get("FacePic", 0)
+        applyP.FightPower = applyInfo["FightPower"] % ChConfig.Def_PerPointValue
+        applyP.FightPowerEx = applyInfo["FightPower"] / ChConfig.Def_PerPointValue
+        applyList.append(applyP)
+        applyIDList.append(applyInfo["PlayerID"])
+        
+    clientPack.MemberList = memberList
+    clientPack.MemberCount = len(clientPack.MemberList)
+    clientPack.ApplyIDList = applyIDList
+    clientPack.ApplyInfoList = applyList
+    clientPack.ApplyCount = len(clientPack.ApplyInfoList)
+    
+    for player in syncPlayerList:
+        NetPackCommon.SendFakePack(player, clientPack)
+    return
+
+def Sync_FuncTeamDissolve(teamID, syncPlayerIDList):
+    ## 功能队伍解散
+    if not teamID or not syncPlayerIDList:
+        return
+    
+    syncPlayerList = []
+    playerManager = GameWorld.GetPlayerManager()
+    for playerID in syncPlayerIDList:
+        player = playerManager.FindPlayerByID(playerID)
+        if player == None or not player.GetInitOK():
+            continue
+        syncPlayerList.append(player)
+        
+    if not syncPlayerList:
+        return
+    
+    clientPack = ChPyNetSendPack.tagGCFuncTeamDissolve()
+    clientPack.TeamID = teamID
+    for player in syncPlayerList:
+        NetPackCommon.SendFakePack(player, clientPack)
+    return
+
+##--------------------------------------------------------------------------------------------------
+
+def GetFuncTeamMapIDZoneInfo(funcMapID, serverGroupID):
+    ## 获取功能队伍分区信息
+    
+    funcZoneID = 0
+    serverGroupList = []
+    
+    if funcMapID == ChConfig.Def_FBMapID_CrossBattlefield:
+        zoneIpyData = CrossBattlefield.GetCrossBattlefieldZoneIpyData(serverGroupID)
+        if not zoneIpyData:
+            return
+        funcZoneID = zoneIpyData.GetZoneID()
+        serverGroupList = zoneIpyData.GetServerGroupIDList() # 只通知该分区服务器
+        
+    return funcZoneID, serverGroupList
+
+def ClientServerMsg_CreateFuncTeam(serverGroupID, msgData):
+    ## 收到子服 - 功能队伍创建
+    
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"]
+    teamInfo = msgData["teamInfo"]
+    cacheBase = msgData["cacheBase"]
+    
+    funcMapID = teamInfo["funcMapID"]
+    
+    zoneInfo = GetFuncTeamMapIDZoneInfo(funcMapID, serverGroupID)
+    if not zoneInfo:
+        return
+    funcZoneID, _ = zoneInfo
+    
+    if zoneID != funcZoneID:
+        GameWorld.ErrLog("功能队伍分区不一致,无法创建! funcMapID=%s,zoneID=%s != %s" % (funcMapID, zoneID, funcZoneID), playerID)
+        return
+    
+    canCreate, notifyMark = CheckCanCreateFuncTeam(playerID, teamInfo, zoneID)
+    
+    # 某些功能创建前检查
+    if funcMapID == ChConfig.Def_FBMapID_CrossBattlefield:
+        pass
+    
+    newTeam = None
+    teamID = 0
+    newTeamInfo = {}
+    if canCreate:
+        PlayerViewCache.UpdCrossCacheBase(playerID, cacheBase)
+        funcTeamMgr = DBDataMgr.GetFuncTeamMgr()
+        newTeam = funcTeamMgr.CreateFuncTeam(playerID, teamInfo, zoneID)
+        
+    if newTeam:
+        teamID = newTeam.GetTeamID()
+        newTeamInfo = newTeam.GetSyncDict(True)
+        
+        # 某些功能创建后处理
+        if funcMapID == ChConfig.Def_FBMapID_CrossBattlefield:
+            pass
+        
+    else:
+        if not notifyMark:
+            notifyMark = "CreatTeamFail"
+            
+    serverGroupList = [serverGroupID] # 创建仅通知指定服即可
+    syncPlayerIDList = [playerID]
+    sendMsg = {"infoType":"CreateFuncTeam", "zoneID":zoneID, "playerID":playerID, "funcMapID":funcMapID, 
+               "teamInfo":newTeamInfo, "teamID":teamID, "syncPlayerIDList":syncPlayerIDList, "notifyMark":notifyMark}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FuncTeamInfo, sendMsg, serverGroupList)
+    return
+
+def CheckCanCreateFuncTeam(playerID, teamInfo, zoneID=0, checkInTeam=True):
+    ## 检查可否创建功能队伍 - 本服跨服通用
+    # @param checkInTeam: 是否检查已经在队伍中,如果功能只允许单个队伍,则需要检查,反之可设置为不检查
+    # @return: 是否可创建, 不可创建提示信息
+    
+    funcMapID = teamInfo["funcMapID"]
+    ipyData = IpyGameDataPY.GetIpyGameData("FuncTeamSet", funcMapID)
+    if not ipyData:
+        return False, ""
+    
+    needName = ipyData.GetNeedName()
+    if needName:
+        teamName = teamInfo["teamName"]
+        if not teamName or len(teamName) > 33:
+            # 队伍名不合法
+            return False, "TeamNameLenError"
+        
+        if DirtyList.IsWordForbidden(teamName):
+            return False, "TeamNameUnallow"
+        
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    teamList = funcTeamMgr.GetFuncTeamList(zoneID, funcMapID)
+    for funcTeam in teamList:
+        if needName:
+            if teamName == funcTeam.GetTeamName():
+                # 队伍名已存在
+                return False, "TeamNameExist"
+        
+        if checkInTeam:
+            if funcTeam.GetMemberByID(playerID):
+                # 已经在队伍中
+                return False, "AlreadyHaveTeam"
+            
+    return True, ""
+
+def ClientServerMsg_ChangeFuncTeam(serverGroupID, msgData):
+    ## 收到子服 - 功能队伍修改
+    
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"]
+    teamInfo = msgData["teamInfo"]
+    cacheBase = msgData.get("cacheBase", {})
+    
+    teamID = teamInfo["teamID"]
+    funcMapID = teamInfo["funcMapID"]
+    
+    zoneInfo = GetFuncTeamMapIDZoneInfo(funcMapID, serverGroupID)
+    if not zoneInfo:
+        return
+    funcZoneID, serverGroupList = zoneInfo
+    
+    if zoneID != funcZoneID:
+        GameWorld.ErrLog("功能队伍分区不一致,无法修改! funcMapID=%s,zoneID=%s != %s" % (funcMapID, zoneID, funcZoneID), playerID)
+        return
+    
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        GameWorld.ErrLog("功能队伍不存在! funcMapID=%s,teamID=%s" % (funcMapID, teamID), playerID)
+        return
+    
+    if playerID != funcTeam.GetCaptainID():
+        GameWorld.DebugLog("非功能队伍队长,无法修改! funcMapID=%s,teamID=%s,CaptainID=%s" % (funcMapID, teamID, funcTeam.GetCaptainID()), playerID)
+        return
+    
+    if cacheBase:
+        PlayerViewCache.UpdCrossCacheBase(playerID, cacheBase)
+        
+    funcTeam.SetMinFightPower(teamInfo["minFightPower"] + teamInfo["minFightPowerEx"] * ChConfig.Def_PerPointValue)
+    funcTeam.SetMinLV(teamInfo["minLV"])
+    funcTeam.SetServerOnly(teamInfo["serverOnly"])
+    funcTeam.SetNeedCheck(teamInfo["needCheck"])
+    
+    if not funcTeam.GetNeedCheck():
+        pass
+    
+    teamID = funcTeam.GetTeamID()
+    teamInfo = funcTeam.GetSyncDict(True)
+    syncPlayerIDList = funcTeam.GetSyncPlayerIDList()
+    sendMsg = {"infoType":"ChangeFuncTeam", "zoneID":zoneID, "playerID":playerID, "funcMapID":funcMapID, 
+               "teamInfo":teamInfo, "teamID":teamID, "syncPlayerIDList":syncPlayerIDList}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FuncTeamInfo, sendMsg, serverGroupList)
+    return
+
+def ClientServerMsg_FuncTeamMemOP(serverGroupID, msgData):
+    ## 收到子服 - 功能队伍操作
+    
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"] # 操作的玩家ID
+    teamID = msgData["teamID"]
+    funcMapID = msgData["funcMapID"]
+    opType = msgData["opType"]
+    opData = msgData["opData"]
+    cacheBase = msgData.get("cacheBase", {})
+    
+    zoneInfo = GetFuncTeamMapIDZoneInfo(funcMapID, serverGroupID)
+    if not zoneInfo:
+        return
+    funcZoneID, serverGroupList = zoneInfo
+    
+    if zoneID != funcZoneID:
+        GameWorld.ErrLog("功能队伍分区不一致,无法操作! funcMapID=%s,zoneID=%s != %s" % (funcMapID, zoneID, funcZoneID), playerID)
+        return
+    
+    if cacheBase:
+        PlayerViewCache.UpdCrossCacheBase(playerID, cacheBase)
+        
+    isOK = False
+    syncDict = {}
+    teamInfo = {}
+    
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        GameWorld.ErrLog("功能队伍不存在! funcMapID=%s,teamID=%s,opType=%s" % (funcMapID, teamID, opType), playerID)
+        syncDict["notifyMark"] = "TeamNotExist"
+        syncPlayerIDList = [playerID]
+    else:
+        # 仅队长可操作
+        if opType in [Def_FuncTeamOP_JoinAgree, Def_FuncTeamOP_JoinRefuse, Def_FuncTeamOP_Kick, 
+                      Def_FuncTeamOP_Transfer, Def_FuncTeamOP_Dissolve]:
+            if playerID != funcTeam.GetCaptainID():
+                GameWorld.ErrLog("仅队长可操作! funcMapID=%s,teamID=%s,opType=%s,CaptainID=%s" 
+                                 % (funcMapID, teamID, opType, funcTeam.GetCaptainID()), playerID)
+                return
+            
+        syncPlayerIDList = funcTeam.GetSyncPlayerIDList()
+        
+        # 申请加入
+        if opType == Def_FuncTeamOP_JoinApply:
+            isOK = __DoFuncTeamOP_JoinApply(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict)
+            if playerID not in syncPlayerIDList:
+                syncPlayerIDList.append(playerID)
+                
+        # 申请取消
+        elif opType == Def_FuncTeamOP_JoinCancel:
+            isOK = __DoFuncTeamOP_JoinCancel(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict)
+            if playerID not in syncPlayerIDList:
+                syncPlayerIDList.append(playerID)
+                
+        # 同意入队
+        elif opType == Def_FuncTeamOP_JoinAgree:
+            isOK = __DoFuncTeamOP_JoinAgree(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict)
+            
+        # 拒绝入队
+        elif opType == Def_FuncTeamOP_JoinRefuse:
+            isOK = __DoFuncTeamOP_JoinRefuse(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict)
+            
+        # 退出队伍
+        elif opType == Def_FuncTeamOP_Exit:
+            isOK = __DoFuncTeamOP_Exit(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict)
+            
+        # 踢出队伍
+        elif opType == Def_FuncTeamOP_Kick:
+            isOK = __DoFuncTeamOP_Kick(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict)
+            
+        # 转让队长
+        elif opType == Def_FuncTeamOP_Transfer:
+            isOK = __DoFuncTeamOP_Transfer(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict)
+                
+        # 解散队伍
+        elif opType == Def_FuncTeamOP_Dissolve:
+            isOK = __DoFuncTeamOP_Dissolve(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict)
+            
+    if not isOK and not syncDict:
+        # 没有执行成功 且 没有需要回复的信息,则不需要回发子服
+        return
+    
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if funcTeam:
+        teamInfo = funcTeam.GetSyncDict(True)
+        
+    sendMsg = {"infoType":"FuncTeamMemOP", "zoneID":zoneID, "playerID":playerID, "funcMapID":funcMapID, 
+               "teamInfo":teamInfo, "teamID":teamID, "syncPlayerIDList":syncPlayerIDList, "opType":opType}
+    sendMsg.update(syncDict)
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FuncTeamInfo, sendMsg, serverGroupList)
+    return
+
+def DelTeam(teamID):
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        GameWorld.ErrLog("删除功能队伍时不存在! teamID=%s" % teamID)
+        return
+    zoneID = funcTeam.GetZoneID()
+    funcMapID = funcTeam.GetFuncMapID()
+    syncPlayerIDList = funcTeam.GetSyncPlayerIDList()
+    
+    funcTeamMgr.DelTeam(teamID)
+    
+    if not funcTeamMgr.IsLockBatch():
+        sendMsg = {"zoneID":zoneID, "funcMapID":funcMapID, "delTeamDict":{teamID:syncPlayerIDList}}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FuncTeamDel, sendMsg)
+        
+    return syncPlayerIDList
+
+def DelTeamByFunc(delFuncMapID):
+    GameWorld.Log("清空功能队伍! delFuncMapID=%s" % delFuncMapID)
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeamMgr.LockBatch()
+    delTeamIDList = []
+    for key, teamList in funcTeamMgr.funcTeamListDict.items():
+        zoneID, funcMapID = key
+        if funcMapID != delFuncMapID:
+            continue
+        delTeamDict = {}
+        for funcTeam in teamList[::-1]:
+            teamID = funcTeam.GetTeamID()
+            syncPlayerIDList = DelTeam(teamID)
+            if syncPlayerIDList:
+                delTeamDict[teamID] = syncPlayerIDList
+            delTeamIDList.append(teamID)
+             
+        # 按分区处理后一次性同步子服
+        zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByZoneID(funcMapID, zoneID)
+        serverGroupIDList = zoneIpyData.GetServerGroupIDList() if zoneIpyData else []
+        sendMsg = {"zoneID":zoneID, "funcMapID":funcMapID, "delTeamDict":delTeamDict}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FuncTeamDel, sendMsg, serverGroupIDList)
+    funcTeamMgr.UnLockBatch()
+    
+    delCount = len(delTeamIDList)
+    funcTeamMgr.SyncMapFuncTeamMemIDInfo(delTeamIDList)
+    return delCount
+
+def DelTealAll():
+    delCount = 0
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    for index in range(ipyDataMgr.GetFuncTeamSetCount()):
+        ipyData = ipyDataMgr.GetFuncTeamSetByIndex(index)
+        delCount += DelTeamByFunc(ipyData.GetFuncMapID())
+    return delCount
+
+def SendFuncTeamToClientServer(teamID):
+    ## 同步队伍明细到子服
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        return
+    funcMapID = funcTeam.GetFuncMapID()
+    teamInfo = funcTeam.GetSyncDict(True)
+    syncPlayerIDList = funcTeam.GetSyncPlayerIDList()
+    
+    sendMsg = {"infoType":"", "playerID":0, "funcMapID":funcMapID, 
+               "teamInfo":teamInfo, "teamID":teamID, "syncPlayerIDList":syncPlayerIDList}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FuncTeamInfo, sendMsg)
+    return
+
+def __DoFuncTeamOP_JoinApply(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict):
+    ## 申请加入
+    
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    playerTeamID = funcTeamMgr.GetPlayerTeamID(playerID, funcMapID)
+    if playerTeamID:
+        GameWorld.Log("已经有功能队伍了,不能再申请! funcMapID=%s,playerTeamID=%s" % (funcMapID, playerTeamID), playerID)
+        return
+    
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        return
+    
+    if funcTeam.GetMemberByID(playerID):
+        GameWorld.Log("已在功能队伍中! funcMapID=%s,teamID=%s" % (funcMapID, teamID), playerID)
+        return
+    
+    if playerID in funcTeam.GetApplyIDList():
+        GameWorld.Log("已在功能队伍申请列表中! funcMapID=%s,teamID=%s" % (funcMapID, teamID), playerID)
+        return
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("FuncTeamSet", funcMapID)
+    if not ipyData:
+        return
+    
+    memberMax = ipyData.GetMemberMax()
+    applyMax = ipyData.GetApplyMax()
+    reqApplyMax = ipyData.GetReqApplyMax()
+    
+    if len(funcTeam.GetMemberList()) >= memberMax:
+        GameWorld.DebugLog("功能队伍成员已满! funcMapID=%s,teamID=%s,memberMax=%s" % (funcMapID, teamID, memberMax), playerID)
+        syncDict["notifyMark"] = "TeamMemFull"
+        return
+    
+    if applyMax and len(funcTeam.GetApplyIDList()) >= applyMax:
+        GameWorld.DebugLog("功能队伍申请队列已满! funcMapID=%s,teamID=%s,applyMax=%s" % (funcMapID, teamID, applyMax), playerID)
+        syncDict["notifyMark"] = "TeamApplyFull"
+        return
+    
+    minLV = funcTeam.GetMinLV()
+    if minLV and minLV > cacheBase.get("LV", 0):
+        GameWorld.DebugLog("功能队伍最低等级限制,无法申请! funcMapID=%s,teamID=%s,minLV=%s" % (funcMapID, teamID, minLV), playerID)
+        syncDict["notifyMark"] = "TeamLVLimit"
+        return
+    
+    minFightPower = funcTeam.GetMinFightPower()
+    if minFightPower and minFightPower > cacheBase.get("FightPower", 0):
+        GameWorld.DebugLog("功能队伍最低战力限制,无法申请! funcMapID=%s,teamID=%s,minFightPower=%s" % (funcMapID, teamID, minFightPower), playerID)
+        syncDict["notifyMark"] = "TeamFightPowerLimit"
+        return
+    
+    minServerOnly = funcTeam.GetServerOnly()
+    if minServerOnly:
+        # 待扩展,看是取ServerID,还是 ServerGroupID,需注意GroupID合服后可能不一致的问题
+        pass
+    
+    if reqApplyMax:
+        applyTeamIDList = []
+        teamList = funcTeamMgr.GetFuncTeamList(zoneID, funcMapID)
+        for fTeam in teamList:
+            if playerID in fTeam.GetApplyIDList():
+                applyTeamIDList.append(fTeam.GetTeamID())
+        if len(applyTeamIDList) >= reqApplyMax:
+            GameWorld.DebugLog("玩家申请加入队伍数已满,无法申请! funcMapID=%s,applyTeamCount=%s, %s" 
+                               % (funcMapID, len(applyTeamIDList), applyTeamIDList), playerID)
+            syncDict["notifyMark"] = "TeamReqJoinApplyFull"
+            return
+        
+    if funcTeam.GetNeedCheck():
+        syncDict["notifyMark"] = "TeamReqJoinApplyOK"
+        funcTeam.AddApplyID(playerID)
+    else:
+        funcTeam.AddTeamMember(playerID)
+        
+    return True
+
+def __DoFuncTeamOP_JoinCancel(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict):
+    ## 申请取消
+    
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        return
+    
+    funcTeam.DelApplyID(playerID)
+    
+    return True
+
+def __DoFuncTeamOP_JoinAgree(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict):
+    ## 同意入队
+    # @param opData: 目标玩家ID,为0时一键同意
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("FuncTeamSet", funcMapID)
+    if not ipyData:
+        return
+    
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        return
+    
+    applyIDList = funcTeam.GetApplyIDList()
+    if not applyIDList:
+        return
+        
+    memberMax = ipyData.GetMemberMax()
+    joinPlayerIDList = []
+    tagPlayerID = opData
+    if tagPlayerID:
+        if tagPlayerID not in applyIDList:
+            GameWorld.Log("目标玩家不在功能队伍申请列表中! funcMapID=%s,teamID=%s,tagPlayerID=%s not in applyIDList=%s" 
+                          % (funcMapID, teamID, tagPlayerID, applyIDList), playerID)
+            return
+        
+        tagPlayerTeamID = funcTeamMgr.GetPlayerTeamID(tagPlayerID, funcMapID)
+        if tagPlayerTeamID:
+            GameWorld.DebugLog("目标玩家已加入其他功能队伍! funcMapID=%s,tagPlayerID=%s,tagPlayerTeamID=%s" 
+                               % (funcMapID, tagPlayerID, tagPlayerTeamID), playerID)
+            syncDict["notifyMark"] = "PlayerInOtherTeam"
+        else:
+            joinPlayerIDList = [tagPlayerID]
+    else:
+        joinPlayerIDList = [] + applyIDList # 一键同意按申请顺序,如需按战力再做优化
+        
+    for joinPlayerID in joinPlayerIDList:
+        if len(funcTeam.GetMemberList()) >= memberMax:
+            GameWorld.DebugLog("功能队伍成员已满! funcMapID=%s,teamID=%s,memberMax=%s" % (funcMapID, teamID, memberMax), playerID)
+            break
+        tagPlayerTeamID = funcTeamMgr.GetPlayerTeamID(joinPlayerID, funcMapID)
+        if tagPlayerTeamID:
+            GameWorld.DebugLog("目标玩家已加入其他功能队伍! funcMapID=%s,joinPlayerID=%s,tagPlayerTeamID=%s" 
+                               % (funcMapID, joinPlayerID, tagPlayerTeamID), playerID)
+            continue
+        funcTeam.AddTeamMember(joinPlayerID)
+        
+    return True
+
+def __DoFuncTeamOP_JoinRefuse(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict):
+    ## 拒绝入队
+    # @param opData: 目标玩家ID,为0时一键拒绝
+    
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        return
+    
+    tagPlayerID = opData
+    if tagPlayerID:
+        funcTeam.DelApplyID(tagPlayerID)
+    else:
+        funcTeam.DelApplyIDAll() # 一键拒绝
+        
+    return True
+
+def __DoFuncTeamOP_Exit(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict):
+    ## 退出队伍
+    
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        return
+    
+    # 队长退出,直接解散
+    if playerID == funcTeam.GetCaptainID():
+        return __DoFuncTeamOP_Dissolve(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict)
+    
+    funcTeam.DelTeamMember(playerID)
+    
+    return True
+
+def __DoFuncTeamOP_Kick(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict):
+    ## 踢出队伍
+    
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        return
+    
+    tagPlayerID = opData
+    if not tagPlayerID:
+        GameWorld.DebugLog("需指定踢出队伍目标队员! opData=%s" % opData, playerID)
+        return
+    
+    if tagPlayerID == funcTeam.GetCaptainID():
+        GameWorld.DebugLog("不能踢队长! opData=%s" % opData, playerID)
+        return
+    
+    funcTeam.DelTeamMember(tagPlayerID)
+    
+    return True
+
+def __DoFuncTeamOP_Transfer(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict):
+    ## 转让队长
+    
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+    if not funcTeam:
+        return
+    
+    memberIDList = funcTeam.GetMemberIDList()
+    tagPlayerID = opData
+    if tagPlayerID not in memberIDList:
+        GameWorld.Log("目标玩家不是队员,无法转让队长! funcMapID=%s,teamID=%s,tagPlayerID=%s not in %s" 
+                      % (funcMapID, teamID, tagPlayerID, memberIDList), playerID)
+        return
+    
+    funcTeam.SetCaptainID(tagPlayerID)
+    
+    return True
+
+def __DoFuncTeamOP_Dissolve(zoneID, funcMapID, teamID, playerID, opType, opData, cacheBase, syncDict):
+    ## 解散队伍
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    funcTeamMgr.DelTeam(teamID)
+    return True
+
+def ClientServerMsg_QueryFuncTeam(serverGroupID, msgData):
+    ## 收到子服 - 查找队伍列表
+    
+    zoneID = msgData["zoneID"]
+    playerID = msgData["playerID"]
+    funcMapID = msgData["funcMapID"]
+    cacheBase = msgData.get("cacheBase", {})
+    
+    zoneInfo = GetFuncTeamMapIDZoneInfo(funcMapID, serverGroupID)
+    if not zoneInfo:
+        return
+    funcZoneID, _ = zoneInfo
+    
+    if zoneID != funcZoneID:
+        GameWorld.ErrLog("功能队伍分区不一致,无法查询! funcMapID=%s,zoneID=%s != %s" % (funcMapID, zoneID, funcZoneID), playerID)
+        return
+    
+    if cacheBase:
+        PlayerViewCache.UpdCrossCacheBase(playerID, cacheBase)
+        
+    # 非列表查询,返回玩家相关队伍
+    if "startIndex" not in msgData:
+        syncPlayerIDList = [playerID]
+        serverGroupList = [serverGroupID]
+        
+        funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+        # 申请的队伍
+        funcTeamList = funcTeamMgr.GetFuncTeamList(zoneID, funcMapID)
+        for funcTeam in funcTeamList:
+            if playerID not in funcTeam.GetApplyIDList():
+                continue
+            teamID = funcTeam.GetTeamID()
+            teamInfo = funcTeam.GetSyncDict(True)
+            sendMsg = {"infoType":"QueryPlayerFuncTeam", "zoneID":zoneID, "playerID":playerID, "funcMapID":funcMapID, 
+                       "teamInfo":teamInfo, "teamID":teamID, "syncPlayerIDList":syncPlayerIDList}
+            CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FuncTeamInfo, sendMsg, serverGroupList)
+            
+        # 玩家所属队伍
+        teamID = funcTeamMgr.GetPlayerTeamID(playerID, funcMapID)
+        funcTeam = funcTeamMgr.GetFuncTeam(teamID)
+        teamInfo = funcTeam.GetSyncDict(True) if funcTeam else {}
+        sendMsg = {"infoType":"QueryPlayerFuncTeam", "zoneID":zoneID, "playerID":playerID, "funcMapID":funcMapID, 
+                   "teamInfo":teamInfo, "teamID":teamID, "syncPlayerIDList":syncPlayerIDList}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FuncTeamInfo, sendMsg, serverGroupList)
+        return
+    
+    # 列表查询
+    funcMapEx = msgData["funcMapEx"]
+    startIndex = msgData["startIndex"]
+    queryCnt = msgData["queryCnt"]
+    haveSpace = msgData["haveSpace"]
+    idLimitType = msgData["idLimitType"]
+    searchMsg = msgData["searchMsg"]
+    if queryCnt <= 0:
+        queryCnt = 20
+    queryCnt = min(100, queryCnt) # 默认20,最大100
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("FuncTeamSet", funcMapID)
+    if not ipyData:
+        return
+    memberMax = ipyData.GetMemberMax()
+    
+    idLimitTypeDict = {1:"FamilyID", 2:"ServerGroupID", 3:"AccID"}
+    loopIndex = startIndex
+    teamInfoList = []
+    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
+    teamList = funcTeamMgr.GetFuncTeamList(zoneID, funcMapID)
+    for index in xrange(startIndex, len(teamList)):
+        loopIndex = index + 1
+        funcTeam = teamList[index]
+        if searchMsg:
+            # 精确匹配队伍名、队伍ID的插入在最前面
+            if searchMsg == funcTeam.GetTeamName() or searchMsg == str(funcTeam.GetTeamID()):
+                teamInfoList.insert(0, funcTeam.GetSyncDict(False))
+            elif searchMsg in funcTeam.GetTeamName():
+                teamInfoList.append(funcTeam.GetSyncDict(False))
+            else:
+                continue
+        else:
+            if funcMapEx != 0 and funcMapEx != funcTeam.GetFuncMapEx():
+                continue
+            if haveSpace and len(funcTeam.GetMemberList()) >= memberMax:
+                #GameWorld.DebugLog("已满员,不加入列表查看 teamID=%s" % funcTeam.GetTeamID())
+                continue
+            if idLimitType in idLimitTypeDict:
+                limitAttrName = idLimitTypeDict[idLimitType]
+                curIDValue = cacheBase.get(limitAttrName, 0)
+                captainID = funcTeam.GetCaptainID()
+                cacheDict = PlayerViewCache.GetCachePropDataDict(PlayerViewCache.FindViewCache(captainID))
+                teamIDValue = cacheDict.get(limitAttrName, 0)
+                if limitAttrName == "AccID":
+                    curIDValue = GameWorld.GetAccIDServerID(str(curIDValue))
+                    teamIDValue = GameWorld.GetAccIDServerID(str(teamIDValue))
+                    
+                if not curIDValue or curIDValue != teamIDValue:
+                    #GameWorld.DebugLog("没有或不同ID限制,不加入列表查看! idLimitType=%s,curIDValue=%s != %s, teamID=%s, captainID=%s" 
+                    #                   % (idLimitType, curIDValue, teamIDValue, funcTeam.GetTeamID(), captainID))
+                    continue
+            teamInfoList.append(funcTeam.GetSyncDict(False))
+            
+        if len(teamInfoList) >= queryCnt:
+            break
+        
+    serverGroupList = [serverGroupID] # 仅通知查询服即可
+    sendMsg = {"teamInfoList":teamInfoList, "loopIndex":loopIndex, "queryInfo":msgData}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FuncTeamList, sendMsg, serverGroupList)
+    return

--
Gitblit v1.8.0