66 【公会】基础主体-服务端(优化公会互通后某个游戏服在没有公会没有玩家加入跨服公会时下次维护无法成功显示加入跨服分区;优化分区配置检查,异常时不应用配置且发送qq邮件;)
2个文件已修改
1个文件已添加
839 ■■■■■ 已修改文件
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/CheckServerID.py 797 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/GMToolLogicProcess/ProjSpecialProcess.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/CheckServerID.py
New file
@@ -0,0 +1,797 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package CheckServerID
#
# @todo:跨服相关活动配置服务器ID检查
# @author hxp
# @date 2026-02-11
# @version 1.0
#
# 详细描述: 跨服相关活动配置服务器ID检查
#
#-------------------------------------------------------------------------------
#"""Version = 2026-02-11 17:30"""
#-------------------------------------------------------------------------------
def CheckServerIDInList(serverID, serverIDList):
    """检查serverID是否在serverIDList中,serverIDList包含区间和单个ID"""
    if serverIDList is None:
        return False
    if not serverIDList:
        return True
    for serverIDInfo in serverIDList:
        if (isinstance(serverIDInfo, (list, tuple)) and len(serverIDInfo) == 2
                and serverIDInfo[0] <= serverID <= serverIDInfo[1]) \
            or (isinstance(serverIDInfo, int) and serverIDInfo == serverID):
            return True
    return False
def CheckCrossZoneCfg(curCrossZoneCfgDict, updCrossZoneCfgDict):
    '''检查待更新的分区配置是否符合规则,不符合的话保留原配置,不更新
    @param curCrossZoneCfgDict: 当前跨服分区配置  {crossServerID:{zoneID:[[serverIDA, toServerIDB], serverID, ...], ...}, ...}
    @param updCrossZoneCfgDict: 要更新的跨服分区配置  {crossServerID:{zoneID:[[serverIDA, toServerIDB], serverID, ...], ...}, ...}
    @return: (isOK, errMsg) isOK为True表示符合规则,errMsg为错误信息
    '''
    #if curCrossZoneCfgDict == updCrossZoneCfgDict:
    #    return False, "跨服公会互通分区配置不变不处理"
    # 1. 检查格式是否正确
    is_ok, err_msg = _validate_format(updCrossZoneCfgDict)
    if not is_ok:
        return False, err_msg
    # 2. 检查zoneID全局唯一
    is_ok, err_msg = _check_zone_id_unique(updCrossZoneCfgDict)
    if not is_ok:
        return False, err_msg
    # 3. 检查serverID全局唯一(不交叉)
    is_ok, err_msg = _check_server_id_unique(updCrossZoneCfgDict)
    if not is_ok:
        return False, err_msg
    # 4. 检查不能删除已存在的crossServerID
    is_ok, err_msg = _check_no_delete_cross_server_id(curCrossZoneCfgDict, updCrossZoneCfgDict)
    if not is_ok:
        return False, err_msg
    # 5. 检查已配置的serverID区间不能拆分
    is_ok, err_msg = _check_old_server_ranges_not_split(curCrossZoneCfgDict, updCrossZoneCfgDict)
    if not is_ok:
        return False, err_msg
    # 6. 检查不能跨crossServerID合并
    is_ok, err_msg = _check_no_cross_server_merge(curCrossZoneCfgDict, updCrossZoneCfgDict)
    if not is_ok:
        return False, err_msg
    # 7. 检查不能跨crossServerID有交叉
    is_ok, err_msg = _check_cross_server_overlap(updCrossZoneCfgDict)
    if not is_ok:
        return False, err_msg
    return True, ""
def _validate_format(cfgDict):
    """验证配置格式是否正确"""
    if not isinstance(cfgDict, dict):
        return False, "配置必须是字典类型"
    for crossServerID, zones in cfgDict.items():
        if not isinstance(zones, dict):
            return False, "crossServerID=%s的分区配置必须是字典类型" % crossServerID
        for zoneID, serverList in zones.items():
            if not isinstance(serverList, list):
                return False, "crossServerID=%s,zoneID=%s的服务器列表必须是列表类型" % (crossServerID, zoneID)
            for item in serverList:
                if isinstance(item, list):
                    # 区间格式 [start, end]
                    if len(item) != 2:
                        return False, "crossServerID=%s,zoneID=%s的区间格式错误,必须是[start, end]格式" % (crossServerID, zoneID)
                    if not isinstance(item[0], int) or not isinstance(item[1], int):
                        return False, "crossServerID=%s,zoneID=%s的区间值必须是整数" % (crossServerID, zoneID)
                    if item[0] > item[1]:
                        return False, "crossServerID=%s,zoneID=%s的区间起始值不能大于结束值" % (crossServerID, zoneID)
                elif not isinstance(item, int):
                    return False, "crossServerID=%s,zoneID=%s的服务器ID必须是整数" % (crossServerID, zoneID)
    return True, ""
def _check_zone_id_unique(cfgDict):
    """检查zoneID是否全局唯一"""
    zone_id_map = {}
    for crossServerID, zones in cfgDict.items():
        for zoneID in zones.keys():
            if zoneID in zone_id_map:
                err_msg = "zoneID必须全局唯一!zoneID=%s重复出现在crossServerID=%s和crossServerID=%s" % (
                    zoneID, zone_id_map[zoneID], crossServerID)
                return False, err_msg
            zone_id_map[zoneID] = crossServerID
    return True, ""
def _get_server_ranges(serverList):
    """从服务器列表中提取区间"""
    ranges = []
    for item in serverList:
        if isinstance(item, list):
            ranges.append((item[0], item[1]))
    return ranges
def _check_range_overlap(range1, range2):
    """检查两个区间是否有重叠"""
    a1, a2 = range1
    b1, b2 = range2
    return not (a2 < b1 or a1 > b2)
def _check_server_id_unique(cfgDict):
    """检查serverID是否全局唯一(不交叉)"""
    all_server_ranges = []
    all_server_ids = set()
    # 收集所有serverID和区间
    for crossServerID, zones in cfgDict.items():
        for zoneID, serverList in zones.items():
            # 提取区间
            ranges = _get_server_ranges(serverList)
            for r in ranges:
                all_server_ranges.append((crossServerID, zoneID, r))
            # 提取单独的服务器ID
            for item in serverList:
                if isinstance(item, int):
                    if item in all_server_ids:
                        # 找到这个serverID出现在哪里
                        for csid, zid, rng in all_server_ranges:
                            if rng[0] <= item <= rng[1]:
                                err_msg = "serverID必须全局唯一!serverID=%s在crossServerID=%s,zoneID=%s区间[%s,%s]内与crossServerID=%s,zoneID=%s重复" % (
                                    item, csid, zid, rng[0], rng[1], crossServerID, zoneID)
                                return False, err_msg
                        # 如果不在区间内,那就是单独的ID重复
                        err_msg = "serverID必须全局唯一!serverID=%s在crossServerID=%s,zoneID=%s中与其他地方重复" % (
                            item, crossServerID, zoneID)
                        return False, err_msg
                    all_server_ids.add(item)
    # 检查区间之间的交叉
    for i in range(len(all_server_ranges)):
        csid1, zid1, r1 = all_server_ranges[i]
        for j in range(i + 1, len(all_server_ranges)):
            csid2, zid2, r2 = all_server_ranges[j]
            if _check_range_overlap(r1, r2):
                err_msg = "serverID区间不能交叉!crossServerID=%s,zoneID=%s区间[%s,%s]与crossServerID=%s,zoneID=%s区间[%s,%s]有交叉" % (
                    csid1, zid1, r1[0], r1[1], csid2, zid2, r2[0], r2[1])
                return False, err_msg
    # 检查单独服务器ID是否在区间内
    for server_id in all_server_ids:
        for csid, zid, rng in all_server_ranges:
            if rng[0] <= server_id <= rng[1]:
                err_msg = "serverID必须全局唯一!serverID=%s在crossServerID=%s,zoneID=%s区间[%s,%s]" % (
                    server_id, csid, zid, rng[0], rng[1])
                return False, err_msg
    return True, ""
def _check_no_delete_cross_server_id(curCrossZoneCfgDict, updCrossZoneCfgDict):
    """检查不能删除已存在的crossServerID"""
    old_cross_servers = set(curCrossZoneCfgDict.keys())
    new_cross_servers = set(updCrossZoneCfgDict.keys())
    # 检查删除的crossServerID
    removed_cross_servers = old_cross_servers - new_cross_servers
    if removed_cross_servers:
        err_msg = "不能删除已存在的crossServerID!删除的crossServerID:%s" % ", ".join(str(s) for s in removed_cross_servers)
        return False, err_msg
    return True, ""
def _get_all_server_ids_from_zone(serverList):
    """从分区配置中获取所有服务器ID(展开区间)"""
    server_ids = set()
    for item in serverList:
        if isinstance(item, list):
            # 区间
            start, end = item
            for server_id in range(start, end + 1):
                server_ids.add(server_id)
        else:
            # 单独服务器ID
            server_ids.add(item)
    return server_ids
def _check_old_server_ranges_not_split(curCrossZoneCfgDict, updCrossZoneCfgDict):
    """检查已配置的serverID区间不能拆分"""
    # 构建旧配置中所有服务器ID到(crossServerID, zoneID)的映射
    old_server_to_location = {}
    for crossServerID, zones in curCrossZoneCfgDict.items():
        for zoneID, serverList in zones.items():
            server_ids = _get_all_server_ids_from_zone(serverList)
            for server_id in server_ids:
                old_server_to_location[server_id] = (crossServerID, zoneID)
    # 对于旧配置中的每个服务器ID,检查在新配置中是否还在同一个crossServerID下
    # 并且检查同一个旧zoneID的服务器ID是否还在同一个新zoneID中
    old_zone_to_new_zone = {}
    for crossServerID, zones in curCrossZoneCfgDict.items():
        for zoneID, serverList in zones.items():
            # 获取这个旧zoneID的所有服务器ID
            old_server_ids = _get_all_server_ids_from_zone(serverList)
            # 找到这些服务器ID在新配置中的位置
            new_locations = set()
            for server_id in old_server_ids:
                # 在新配置中查找这个服务器ID
                found = False
                for new_crossServerID, new_zones in updCrossZoneCfgDict.items():
                    for new_zoneID, new_serverList in new_zones.items():
                        if CheckServerIDInList(server_id, new_serverList):
                            new_locations.add((new_crossServerID, new_zoneID))
                            found = True
                            break
                    if found:
                        break
                if not found:
                    # 服务器ID消失了(不允许)
                    err_msg = "已配置的serverID不能删除!serverID=%s原本在crossServerID=%s,zoneID=%s" % (
                        server_id, crossServerID, zoneID)
                    return False, err_msg
            # 如果旧zoneID的服务器ID出现在多个新位置,说明被拆分了
            if len(new_locations) > 1:
                locations_str = ["crossServerID=%s,zoneID=%s" % (csid, zid) for csid, zid in new_locations]
                err_msg = "已配置的serverID区间不能拆分!原crossServerID=%s,zoneID=%s的服务器被拆分到:%s" % (
                    crossServerID, zoneID, "、".join(locations_str))
                return False, err_msg
            # 记录旧zoneID到新zoneID的映射(如果存在)
            if new_locations:
                old_zone_to_new_zone[(crossServerID, zoneID)] = list(new_locations)[0]
    return True, ""
def _check_no_cross_server_merge(curCrossZoneCfgDict, updCrossZoneCfgDict):
    """检查不能跨crossServerID合并"""
    # 构建旧配置中所有服务器ID到crossServerID的映射
    old_server_to_cross_server = {}
    for crossServerID, zones in curCrossZoneCfgDict.items():
        for zoneID, serverList in zones.items():
            server_ids = _get_all_server_ids_from_zone(serverList)
            for server_id in server_ids:
                old_server_to_cross_server[server_id] = crossServerID
    # 检查新配置中是否有服务器ID被分配到了不同的crossServerID
    for crossServerID, zones in updCrossZoneCfgDict.items():
        for zoneID, serverList in zones.items():
            server_ids = _get_all_server_ids_from_zone(serverList)
            for server_id in server_ids:
                if server_id in old_server_to_cross_server:
                    old_cross_server = old_server_to_cross_server[server_id]
                    if old_cross_server != crossServerID:
                        # 找到具体的服务器ID
                        err_msg = "不能跨crossServerID合并!serverID=%s原本在crossServerID=%s,现在被分配到crossServerID=%s,zoneID=%s" % (
                            server_id, old_cross_server, crossServerID, zoneID)
                        return False, err_msg
    return True, ""
def _check_cross_server_overlap(cfgDict):
    """检查不同crossServerID之间是否有交叉"""
    cross_server_items = list(cfgDict.items())
    for i in range(len(cross_server_items)):
        cross_server_id1, zones1 = cross_server_items[i]
        for j in range(i + 1, len(cross_server_items)):
            cross_server_id2, zones2 = cross_server_items[j]
            # 检查两个crossServerID之间的serverID是否交叉
            for zoneID1, serverList1 in zones1.items():
                server_ids1 = _get_all_server_ids_from_zone(serverList1)
                for zoneID2, serverList2 in zones2.items():
                    server_ids2 = _get_all_server_ids_from_zone(serverList2)
                    # 检查是否有交集
                    if server_ids1.intersection(server_ids2):
                        # 找到具体的交集
                        intersection = server_ids1.intersection(server_ids2)
                        sample_id = list(intersection)[0]
                        err_msg = "不同crossServerID之间serverID不能交叉!serverID=%s同时出现在crossServerID=%s,zoneID=%s和crossServerID=%s,zoneID=%s" % (
                            sample_id, cross_server_id1, zoneID1, cross_server_id2, zoneID2)
                        return False, err_msg
    return True, ""
# 测试用例
if __name__ == "__main__":
    # 原始配置
    curCrossZoneCfgDict = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    print "=" * 80
    print "开始测试所有不合法情况"
    print "=" * 80
    # 测试CheckServerIDInList函数
    print "\n1. 测试CheckServerIDInList函数:"
    test_list = [[1, 50], 1001, [101, 200]]
    print "  25在列表中:", CheckServerIDInList(25, test_list)  # True
    print "  1001在列表中:", CheckServerIDInList(1001, test_list)  # True
    print "  150在列表中:", CheckServerIDInList(150, test_list)  # True
    print "  75在列表中:", CheckServerIDInList(75, test_list)  # False
    # 测试用例1: 格式错误 - 非字典类型
    print "\n" + "=" * 80
    print "测试1: 格式错误 - 非字典类型"
    upd1 = "不是字典类型"
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd1)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例2: 格式错误 - 区间格式错误
    print "\n" + "=" * 80
    print "测试2: 格式错误 - 区间格式错误(不是[start,end]格式)"
    upd2 = {
        10000: {
            1: [[1, 50, 60], 1001],  # 区间有三个元素
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd2)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例3: 格式错误 - 区间起始值大于结束值
    print "\n" + "=" * 80
    print "测试3: 格式错误 - 区间起始值大于结束值"
    upd3 = {
        10000: {
            1: [[50, 1], 1001],  # 50>1
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd3)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例4: 格式错误 - 服务器ID不是整数
    print "\n" + "=" * 80
    print "测试4: 格式错误 - 服务器ID不是整数"
    upd4 = {
        10000: {
            1: [[1, 50], "1001"],  # 1001是字符串
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd4)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例5: zoneID全局重复
    print "\n" + "=" * 80
    print "测试5: zoneID全局重复"
    upd5 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            1: [[201, 300], 1004],  # zoneID=1重复
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd5)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例6: serverID重复 - 单独的服务器ID重复
    print "\n" + "=" * 80
    print "测试6: serverID重复 - 单独的服务器ID重复"
    upd6 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1001],  # 1001重复
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd6)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例7: serverID重复 - 区间包含单独的服务器ID
    print "\n" + "=" * 80
    print "测试7: serverID重复 - 区间包含单独的服务器ID"
    upd7 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[100, 200], 1003]  # 区间包含100,而100在[51,100]区间内
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd7)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例8: serverID重复 - 区间交叉
    print "\n" + "=" * 80
    print "测试8: serverID重复 - 区间交叉"
    upd8 = {
        10000: {
            1: [[1, 60], 1001],  # [1,60]与[51,100]交叉
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd8)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例9: serverID重复 - 区间完全重叠
    print "\n" + "=" * 80
    print "测试9: serverID重复 - 区间完全重叠"
    upd9 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[1, 50], 1002],  # 完全相同的区间
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd9)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例10: serverID重复 - 区间包含另一个区间
    print "\n" + "=" * 80
    print "测试10: serverID重复 - 区间包含另一个区间"
    upd10 = {
        10000: {
            1: [[1, 100], 1001],  # [1,100]包含[51,100]
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd10)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例11: 删除已存在的crossServerID
    print "\n" + "=" * 80
    print "测试11: 删除已存在的crossServerID"
    upd11 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        }
        # 删除了10001
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd11)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例12: 已配置的serverID区间被拆分
    print "\n" + "=" * 80
    print "测试12: 已配置的serverID区间被拆分"
    upd12 = {
        10000: {
            1: [[1, 25], 1001],  # 拆分原[1,50]区间
            2: [[26, 100], 1002],  # 包含[26,50]和[51,100]
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd12)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例13: 已配置的serverID区间被拆分到不同crossServerID
    print "\n" + "=" * 80
    print "测试13: 已配置的serverID区间被拆分到不同crossServerID"
    upd13 = {
        10000: {
            1: [[1, 25], 1001],  # 拆分原[1,50]区间
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[26, 50], 1004],  # 原[1,50]的另一部分
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd13)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例14: 已配置的serverID被删除
    print "\n" + "=" * 80
    print "测试14: 已配置的serverID被删除"
    upd14 = {
        10000: {
            1: [[1, 49], 1001],  # 删除了serverID=50
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd14)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例15: 跨crossServerID合并
    print "\n" + "=" * 80
    print "测试15: 跨crossServerID合并"
    upd15 = {
        10000: {
            1: [[1, 50], 1001, 1004],  # 1004原本在10001中
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300]],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd15)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例16: 跨crossServerID合并区间
    print "\n" + "=" * 80
    print "测试16: 跨crossServerID合并区间"
    upd16 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[101, 200], 1003],
            6: [[201, 250]]  # 部分原10001的区间
        },
        10001: {
            4: [[251, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd16)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例17: 跨crossServerID交叉
    print "\n" + "=" * 80
    print "测试17: 跨crossServerID交叉"
    upd17 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[150, 250], 1004],  # [150,250]与[101,200]交叉
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd17)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例18: 跨crossServerID交叉(新区间)
    print "\n" + "=" * 80
    print "测试18: 跨crossServerID交叉(新区间)"
    upd18 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[101, 200], 1003],
            6: [[290, 310]]  # 与[201,300]交叉
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd18)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例19: serverID重复 - 单独ID在区间内(跨crossServerID)
    print "\n" + "=" * 80
    print "测试19: serverID重复 - 单独ID在区间内(跨crossServerID)"
    upd19 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]],
            6: [150]  # 150在10000的[101,200]区间内
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd19)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例20: 已配置的serverID被移动到不同的crossServerID
    print "\n" + "=" * 80
    print "测试20: 已配置的serverID被移动到不同的crossServerID"
    upd20 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300]],
            5: [[9000, 9999]]
        },
        10002: {
            6: [[1, 10]]  # 将原10000的[1,10]移动到新的crossServerID
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd20)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例21: 已配置的serverID被拆分到不同的zoneID
    print "\n" + "=" * 80
    print "测试21: 已配置的serverID被拆分到不同的zoneID"
    upd21 = {
        10000: {
            1: [[1, 30], 1001],
            2: [[31, 100], 1002],  # [31,50]原本在zoneID=1
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd21)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回False
    # 测试用例22: 合法的配置 - 同crossServerID下合并
    print "\n" + "=" * 80
    print "测试22: 合法的配置 - 同crossServerID下合并"
    upd22 = {
        10000: {
            1: [[1, 100], 1001, 1002],  # 合并1和2区
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd22)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回True
    # 测试用例23: 合法的配置 - 扩容新区间
    print "\n" + "=" * 80
    print "测试23: 合法的配置 - 扩容"
    upd23 = {
        10000: {
            1: [[1, 50], [500, 600], 1001, 2001],  # 增加新区间
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], [601, 700], 1004, 2004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd23)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回True
    # 测试用例24: 合法的配置 - 增加新的crossServerID
    print "\n" + "=" * 80
    print "测试24: 合法的配置 - 增加新的crossServerID"
    upd24 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        },
        10002: {  # 新增的crossServerID
            6: [[10000, 20000]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd24)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回True
    # 测试用例25: 合法的配置 - 增加新的zoneID
    print "\n" + "=" * 80
    print "测试25: 合法的配置 - 增加新的zoneID"
    upd25 = {
        10000: {
            1: [[1, 50], 1001],
            2: [[51, 100], 1002],
            3: [[101, 200], 1003],
            7: [[301, 400]]  # 新增zoneID
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd25)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回True
    # 测试用例26: 合法的配置 - 删除zoneID(同crossServerID下)
    print "\n" + "=" * 80
    print "测试26: 合法的配置 - 删除zoneID(同crossServerID下)"
    upd26 = {
        10000: {
            1: [[1, 100], 1001, 1002],  # 合并1和2区,删除了zoneID=2
            3: [[101, 200], 1003]
        },
        10001: {
            4: [[201, 300], 1004],
            5: [[9000, 9999]]
        }
    }
    is_ok, err_msg = CheckCrossZoneCfg(curCrossZoneCfgDict, upd26)
    print "  结果:", is_ok, "错误信息:", err_msg  # 应该返回True
    print "\n" + "=" * 80
    print "所有测试用例执行完毕"
    print "=" * 80
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/StructData/DBFamily.py
@@ -20,6 +20,7 @@
import CommFunc
import GameWorld
import ShareDefine
import CheckServerID
import PlayerViewCache
import ChPyNetSendPack
import NetPackCommon
@@ -800,7 +801,7 @@
        ## 更新分区配置,重置分区,重新分配
        ## @return: 本跨服是否成功更新分区,验证不通过的话不会重置,保留原分区
        GameWorld.Log("跨服公会互通配置更新! updCrossZoneCfgDict=%s" % updCrossZoneCfgDict)
        if not CheckCrossZoneCfg(self.__crossZoneCfgDict, updCrossZoneCfgDict):
        if not CheckFamilyCrossZoneCfg(self.__crossZoneCfgDict, updCrossZoneCfgDict):
            return
        
        crossServerID = GameWorld.GetGameWorld().GetServerID()
@@ -1052,15 +1053,17 @@
    GameWorld.Log("跨服公会分区配置加载: appID=%s,%s" % (appID, crossZoneCfgDict))
    return crossZoneCfgDict
def CheckCrossZoneCfg(curCrossZoneCfgDict, updCrossZoneCfgDict):
    # 检查待更新的分区配置是否符合规则,不符合的话保留原配置,不更新,待扩展
def CheckFamilyCrossZoneCfg(curCrossZoneCfgDict, updCrossZoneCfgDict):
    # 检查待更新的分区配置是否符合规则,不符合的话保留原配置,不更新
    
    if curCrossZoneCfgDict == updCrossZoneCfgDict:
        GameWorld.Log("跨服公会互通分区配置不变不处理")
        return
    
    # 验证配置,是否有交叉、拆分,并邮件通知运维,待扩展,功能完整性优先
    #GameWorld.SendGameErrorEx("FamilyCrossZoneCfgError", "noZoneServerIDList=%s" % noZoneServerIDList)
    isOK, errInfo = CheckServerID.CheckCrossZoneCfg(curCrossZoneCfgDict, updCrossZoneCfgDict)
    if not isOK:
        GameWorld.SendGameErrorEx("FamilyCrossZoneCfgError", errInfo)
        return
    
    return True
@@ -1186,23 +1189,26 @@
    ## 本服公会首次跨服互通同步数据中
    return DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_FamilyTransDataTime) > 0
def CheckMainServerNoFamilyToCross(connServerID=0):
    '''已经互通的情况下,需要再额外检查本服是否有公会
    没有公会时需要主动告知跨服检查是否成功加入互通分区,否则本服将无法正常进行公会互通
def CheckMainServerNoFamilyToCross(connServerID):
    '''已经互通的情况下,需要再额外检查本服是否有在目标服务器互通分区里
    有一种情况:游戏加入互通后,该服的所有公会被删除(可能玩家主动删除、可能系统认为需要删除的公会)
    导致该游戏服在跨服服务器没有公会了,且该服没有任何玩家加入任何公会,此时该服务器就无法正常被划入某个分区
    所以已互通的游戏服受到跨服同步的分区信息时,需要检查是否已在分区里,没有的话需要主动汇报请求加入
    '''
    if not IsFamilyCross():
        return
    familyMgr = DBDataMgr.GetFamilyMgr()
    familyIDList = familyMgr.GetFamilyIDList()
    if familyIDList:
    if not connServerID:
        return
    familyMgr = DBDataMgr.GetFamilyMgr()
    #familyIDList = familyMgr.GetFamilyIDList()
    #if familyIDList:
    #    return
    
    serverID = GameWorld.GetGameWorld().GetServerID()
    GameWorld.Log("本服无公会需直接同步跨服请求检查加入互通分区! serverID=%s" % (serverID))
    
    curZoneServerIDList = familyMgr.GetCurZoneServerIDList()
    if serverID in curZoneServerIDList:
        GameWorld.Log("已经在互通分区里了不处理! serverID=%s in %s" % (serverID, curZoneServerIDList))
        GameWorld.Log("已经在该跨服互通分区里了不处理! serverID=%s in %s" % (serverID, curZoneServerIDList))
        return
    
    crossServerID = 0
@@ -1221,16 +1227,10 @@
        GameWorld.Log("本服公会未分配互通分区! serverID=%s" % (serverID))
        return
    
    if connServerID:
        if connServerID != crossServerID:
            GameWorld.Log("本服公会互通非目标跨服ID不处理! serverID=%s,crossServerID=%s != %s" % (serverID, crossServerID, connServerID))
            return
    else:
        ssServer = CrossMgr.GetSSServerMgr().GetSSServer(crossServerID)
        connState = ssServer.GetConnState()
        if connState != ShareDefine.ssConn_Normal:
            GameWorld.Log("本服公会互通目标跨服ID非连接状态! serverID=%s,crossServerID=%s,connState=%s" % (serverID, crossServerID, connState))
            return
    GameWorld.Log("本服已互通但没有在该跨服互通分区里,直接请求加入! serverID=%s,crossServerID=%s,toZoneID=%s" % (serverID, crossServerID, toZoneID))
        
    CrossMsg.SendToCrossServer(ShareDefine.S2C_FamilyData, {"checkInZone":1, "toZoneID":toZoneID}, [crossServerID])
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyMongoDB/GMToolLogicProcess/ProjSpecialProcess.py
@@ -102,6 +102,8 @@
    mylog.info('GM Tool Cmd->%s,orderId->%s'%(cmd, orderId))
    funcName = ''
    try:
        GameWorld.GetGameWorld().SetCurGameWorldIndex(0) # 需要设置,不然获取不到 GetMap 等虚拟分线相关接口
        # 获得gm命令信息
        gmCmdDict = eval(cmd)          
        funcName = gmCmdDict.get(GMCommon.Def_GMKey_Type, '')