hxp
12 小时以前 dc0b92c1e2fe9f3d24c183b325dad54d088735c1
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