ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
@@ -56,6 +56,7 @@
import PyGameData
import urllib
import md5
import uuid
#---------------------------------------------------------------------
#设置允许的最大迭代数目, 默认1000
#在NPCAI中, 可能超过1000, 所以要设定为2000
@@ -94,23 +95,23 @@
# @return 返回值无意义
# @remarks 重新加载脚本
def ReloadScript(scriptPath, importDir):
    gameWorld = GetGameWorld()
    tick = gameWorld.GetTick()
    #未到刷新间隔
    if tick - gameWorld.GetTickByType(ChConfig.TYPE_Map_Tick_ReloadScript) < \
                ChConfig.TYPE_Map_Tick_Time[ChConfig.TYPE_Map_Tick_ReloadScript]:
        return
    gameWorld.SetTickByType(ChConfig.TYPE_Map_Tick_ReloadScript, tick)
    if __GetPsycoIsOpen():
        #Psyco开启
        PsycoReload(tick)
        return
#    gameWorld = GetGameWorld()
#    tick = gameWorld.GetTick()
#
#    #未到刷新间隔
#    if tick - gameWorld.GetTickByType(ChConfig.TYPE_Map_Tick_ReloadScript) < \
#                ChConfig.TYPE_Map_Tick_Time[ChConfig.TYPE_Map_Tick_ReloadScript]:
#        return
#
#    gameWorld.SetTickByType(ChConfig.TYPE_Map_Tick_ReloadScript, tick)
#
#    if __GetPsycoIsOpen():
#        #Psyco开启
#        PsycoReload(tick)
#        return
    #Psyco关闭
    __ReloadScript()
    #__ReloadScript() 不再调用,c++会触发多个Reload,py默认只在 ReloadEvent 调用一次
    return
#---------------------------------------------------------------------
@@ -120,16 +121,24 @@
# @remarks 
def __ReloadScript():
    #重新加载已经预存的脚本
    Log("=============================== ReloadScript Begin ===============================")
    for name, reloadPath in sys.modules.items():
        try:
            pathStr = str(reloadPath)
            if "\\Lib\\" in pathStr or "\\DLLs\\" in pathStr:
                #DebugLog("Py库脚本不重读,会引起类继承出现问题导致报错! %s, %s" % (name, reloadPath))
                continue
            if name in ["PyGameData"]:
                DebugLog("%s 模块不重读!" % name)
                continue
            reload(reloadPath)
        except Exception:
            continue
    Log("Reload Begin : time = %s"%GetCurrentDataTimeStr())
    import DataRecordPack
    DataRecordPack.DR_Reload("script")
    Log("=============================== ReloadScript End ===============================")
    ReadChConfig.OnReloadConfig()
    return
#---------------------------------------------------------------------
@@ -506,7 +515,9 @@
# @return 返回值. 是否通过检查
# @remarks 概率相关, 这个事件是否能够出现
def CanHappen(rate, maxRate=ShareDefine.Def_MaxRateValue):
    if random.randint(0, maxRate -1) < rate:
    if rate <= 0:
        return 0
    if rate >= maxRate or random.randint(0, maxRate -1) < rate:
        return 1
    
    return 0
@@ -608,10 +619,8 @@
        return False
    #if not curPlayer.GetInitOK():
    #    return False
    #if IsTJGPlayer(curPlayer):
    #if IsMirrorPlayer(curPlayer):
    #    return False
    if IsMirrorPlayer(curPlayer):
        return False
    return True
#---------------------------------------------------------------------
@@ -865,6 +874,8 @@
# @remarks 获得服务器系统时间
def GetCurrentTime():
    return datetime.datetime.today()
def GetServerTime():
    return datetime.datetime.today()
#    ctime = GetGameWorld().GetGameServerEventTime()
#    
#    if not ctime:
@@ -896,6 +907,22 @@
        return
    
    return
## 获得指定的时间格式
#  @param timeStr 时间列表
#  @param timeFormat 指定的转换格式
#  @return 时间datetime格式
#  @remarks 获得指定的时间格式
def GetDateTimeByFormatStr(timeStr, timeFormat):
    timeStr = timeStr.strip().split(".")[0]
    try:
        return  datetime.datetime.strptime(timeStr, timeFormat)
    except BaseException , e :
        Log("%s : %s"%(e, timeStr))
        return
    return
#---------------------------------------------------------------------
##获得与现实时间差距的小时数
# @param dateTimeStr 比较时间字符 如"2010-05-26 11:21:25"
@@ -970,6 +997,16 @@
    dateTimeB = ChangeTimeNumToDatetime(timeB)
    dateTimeB = datetime.datetime(dateTimeB.year, dateTimeB.month, dateTimeB.day, 0, 0, 0)
    return (dateTimeA - dateTimeB).days
def GetEndTimeByZeroTime(startTime, addDays):
    ## 获取结束时间,根据0点结束计算
    # @param startTime: 起始时间戳
    # @param addDays: 增加的天数,如果是1天实际为当天,即1代表当天
    startDate = ChangeTimeNumToDatetime(startTime)
    startZeroDate = datetime.datetime(startDate.year, startDate.month, startDate.day, 23, 59, 59)
    startZeroTime = int(time.mktime(startZeroDate.timetuple()))
    endTime = startTime + (startZeroTime - startTime) + max(addDays - 1, 0) * 24 * 3600
    return endTime
#---------------------------------------------------------------------
##获取与当前时间相差天数的datetime格式数据
@@ -1159,9 +1196,6 @@
    if npcObj == IPY_GameWorld.gnotSummon:
        return GetNPCManager().FindSummonNPCByID(curTagNPC.GetID())
    
    elif npcObj == IPY_GameWorld.gnotTruck:
        return GetNPCManager().FindTruckByID(curTagNPC.GetID())
    elif npcObj == IPY_GameWorld.gnotPet:
        return GetNPCManager().FindPetByID(curTagNPC.GetID())
    
@@ -1279,6 +1313,22 @@
    LogUI.Msg('%s\t%s\tPyDebug:%s'%(par, playerID, msg))
    return
def DebugLogEx(logFormat, *args):
    ## DEBUG调试输出信息,只传入日志格式跟参数,非debug下不进行日志内容格式化
    # @param logFormat: 日志内容格式,也可以直接传入完整的日志内容
    # @param args: 日志参数,最后一个参数可以多传一个参数作为playerID用
    if not __GameWorld.GetDebugLevel():
        return
    par = 0
    playerID = 0
    try:
        msg = logFormat % args
    except:
        msg = logFormat % args[:-1]
        playerID = args[-1]
    LogUI.Msg('%s\t%s\tPyDebug:%s'%(par, playerID, msg))
    return True
#---------------------------------------------------------------------
##获得当前服务器跨服ID
# @param 无
@@ -1313,44 +1363,82 @@
def GetServerVersion():
    return GetGameWorld().GetServerVersion()
def GetServerGroupID():
    ## 服务器组ID,必须唯一,代表这台物理服务器
    return ToIntDef(ReadChConfig.GetPyMongoConfig("platform", "GroupID"), 0)
def IsCrossServer():
    ## 是否跨服服务器,跨服中心跟常规跨服都算跨服
    return GetServerType() in [ShareDefine.serverType_Cross, ShareDefine.serverType_CrossCenter]
def IsCrossCenter():
    ## 是否跨服中心服务器
    return GetServerType() == ShareDefine.serverType_CrossCenter
def CheckCrossCenterUniquenessErr():
    ## 检查跨服中心唯一性
    # @return: 是否异常
    if not IsCrossCenter():
        return
    serverCnt = 0
    serverDict = ReadChConfig.GetServerConfigDict()
    for serverInfo in serverDict.values():
        serverType = serverInfo[ShareDefine.serverCfgIndex_ServerType]
        if serverType == ShareDefine.serverType_CrossCenter:
            serverCnt += 1
            if serverCnt > 1:
                SendGameErrorEx("CrossCenterUniquenessErr", "跨服中心只允许配置一台", isRaiseErr=True)
                return
    return
def IsMainServer():
    ## 是否游戏服
    return GetServerType() == ShareDefine.serverType_Main
def IsBattleServer():
    ## 是否战斗服务器
    return GetServerType() == ShareDefine.serverType_Battle
def GetServerType():
    ## 本服服务器类型
    ServerType = IpyGameDataPY.GetConfigEx("ServerType")
    if ServerType == None:
        ServerType = 0
        serverDict = ReadChConfig.GetServerConfigDict()
        serverID = GetGameWorld().GetServerID()
        if serverID in serverDict:
            serverInfo = serverDict[serverID]
            ServerType = serverInfo[ShareDefine.serverCfgIndex_ServerType]
            DebugLog("加载本服服务器类型: serverID=%s,ServerType=%s,serverInfo=%s" % (serverID, ServerType, serverInfo))
        IpyGameDataPY.SetConfigEx("ServerType", ServerType)
    return ServerType
def GetServerGroupName():
    ## 服务器组名,取 ServersRoute 中的配置
    return ReadChConfig.GetServersRouteConfig("platform", "GroupName")
def GetMixServerDict():
    ## 获取合服信息
    # @return: {主服ID:[主服ID, 子服ID, ...], ...}
    return # 待处理,以后有合服需要再写
    #MixServerDict = IpyGameDataPY.GetConfigEx("MixServerDict")
    #if MixServerDict == None:
    #    MixServerDict = {}
    #    MainServerDict = {} # 所属主服ID {子服ID:主服ID, ...}
    #    groupName = GetServerGroupName()
    #    serverDict = ReadChConfig.GetServerConfigDict()
    #    for serverInfo in serverDict.values():
    #        groupName = serverInfo[ShareDefine.serverCfgIndex_GroupName]
    #        serverMapID = serverInfo[ShareDefine.serverCfgIndex_MapID]
    #        serverType = serverInfo[ShareDefine.serverCfgIndex_ServerType]
    #    IpyGameDataPY.SetConfigEx("MixServerDict", MixServerDict)
    #    IpyGameDataPY.SetConfigEx("MainServerDict", MainServerDict)
    #return MixServerDict
def GetMainServerID(serverID):
    ## 获取服务器ID所属主服ID
    ServerIDMainServerDict = IpyGameDataPY.GetConfigEx("ServerIDMainServerDict")
    if ServerIDMainServerDict == None:
        filePath = ChConfig.GetDBPath() + ("\\MixServerMap_%s.json" % GetPlatform())
        if not os.path.isfile(filePath):
            SendGameErrorEx("GetMainServerIDError", "file can not found. %s" % filePath)
        else:
            fileObj = open(filePath, 'rb')
            content = fileObj.read()
            fileObj.close()
            MixServerMapDict = eval(content)
            ServerIDMainServerDict = {}
            for mainServerIDStr, serverIDList in MixServerMapDict.items():
                mainServerID = int(mainServerIDStr)
                for sID in serverIDList:
                    ServerIDMainServerDict[sID] = mainServerID
            IpyGameDataPY.SetConfigEx("ServerIDMainServerDict", ServerIDMainServerDict)
            Log("加载 ServerIDMainServerDict=%s" % ServerIDMainServerDict)
    if not ServerIDMainServerDict:
        return serverID
    return ServerIDMainServerDict.get(serverID, serverID)
def GetPlatformServerNum(platform):
    # 获取服务器的平台编号
    platformNumDict = ReadChConfig.GetDBEvalChConfig("DBPlatformNum")
    #===========================================================================
    # if platform not in platformNumDict:
    #    ErrLog("DBPlatformNum没有配置该服务器平台所对应的编号!platfrom=%s" % platform)
    #    raise Exception("DBPlatformNum没有配置该服务器平台所对应的编号!platfrom=%s" % platform)
    #===========================================================================
    return platformNumDict.get(platform, 0)
    return serverID
    #GetMixServerDict()
    #MainServerDict = IpyGameDataPY.GetConfigEx("MainServerDict")
    #if not MainServerDict or serverID not in MainServerDict:
    #    return serverID
    #return MainServerDict[serverID]
##获得当前服务器平台
# @param 无
@@ -1358,19 +1446,11 @@
def GetPlatform():
    return ReadChConfig.GetPyMongoConfig("platform", "PlatformName")
#===============================================================================
# ##获得当前服务器ID
# # @param 无
# # @return
# def GetServerID():
#    return ToIntDef(GetServerSID()[1:], 0)
#===============================================================================
def GetAppID():
    ## 获取渠道ID
    return ReadChConfig.GetPyMongoConfig("platform", "AppID")
#===============================================================================
# def GetServerSID():
#    ##获得当前服务器ID, 带s的
#    return ReadChConfig.GetPyMongoConfig("platform", "ServerID")
#===============================================================================
def IsTestPlatform(platform): return platform in ["test", "yun"]
def GetCreateRoleDays(curPlayer):
    # 获取创角第几天
@@ -1384,8 +1464,8 @@
##获取玩家所属区服ID
# @param curPlayer
# @return
def GetPlayerServerID(curPlayer):
    accID = curPlayer.GetAccID()
def GetPlayerServerID(curPlayer): return GetAccIDServerID(curPlayer.GetAccID())
def GetAccIDServerID(accID):
    infoList = accID.split(Def_AccID_Split_Sign)
    return 0 if len(infoList) < 3 else ToIntDef(infoList[-1][1:])
@@ -1395,14 +1475,20 @@
    infoList = accID.split(Def_AccID_Split_Sign)
    return "" if len(infoList) < 3 else infoList[-1]
def GetPlayerMainServerID(accIDPlatform):
    # 玩家合服后所属主服ID
    # @param accIDPlatform: 玩家账号所属的平台
    mainServerID = ToIntDef(ReadChConfig.GetPyMongoConfig("platform", "%sMainServerID" % accIDPlatform), None)
    if mainServerID != None:
        return mainServerID
    return 0
def GetDBPlayerAccIDByID(playerID):
    ## 获取玩家表账号ID - 根据玩家ID, 可用于判断是否本服玩家
    return PyGameData.g_dbPlayerIDMap.get(playerID, "")
def CheckServerIDInList(serverID, serverIDList):
    if serverIDList == 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
#===============================================================================
# ƽ̨ID = appid
@@ -1422,7 +1508,10 @@
##获取玩家所属平台
def GetPlayerPlatform(curPlayer):
    return curPlayer.GetAccountData().GetOperator()
    appID = curPlayer.GetAccountData().GetOperator()
    if not appID:
        appID = GetAppIDByAccID(curPlayer.GetAccID())
    return appID
##获取平台账号
def GetPlatformAccID(gameAccID):
@@ -1430,6 +1519,10 @@
    paInfoList = infoList[:-2]
    platformAccID = Def_AccID_Split_Sign.join(paInfoList)
    return platformAccID
def GetAppIDByAccID(gameAccID):
    ## 根据账号获取appID
    infoList = gameAccID.split(Def_AccID_Split_Sign)
    return infoList[-2]
def GetSessionID(curPlayer):
    return md5.md5(curPlayer.GetAccID() + curPlayer.GetAccountData().GetLastLoginTime() +'mobile').hexdigest()
@@ -1474,6 +1567,8 @@
    
    ChannelCodeDict = ReadChConfig.GetEvalChConfig("ChannelCode")
    return ChannelCodeDict.get(codeNum, "")
def GetGUID(): return str(uuid.uuid1())
#---------------------------------------------------------------------
##大额度金钱记录
@@ -1724,6 +1819,8 @@
    randList = []
    weight = 0
    for info in weightList:
        if not info[0]:
            continue
        weight += info[0]
        randList.append([weight, info[1] if len(info) == 2 else info[1:]])
    if not randList:
@@ -1879,18 +1976,12 @@
#  @param inputText 输入的文字
#  @return: 是否符合编码格式
def EncodingToUnicode(inputText):
    encodingList = ReadChConfig.GetEvalChConfig("EncodingTex")
    if len(encodingList) != 2:
        ErrLog("EncodingTex.txt Error len != 2")
        return False
    if encodingList[0]:
    if IpyGameDataPY.GetFuncCfg("EncodingTex", 1):
        #不檢查
        return True
        
    try:
        unicode(inputText, encodingList[1])
        unicode(inputText, IpyGameDataPY.GetFuncCfg("EncodingTex", 2))
    except:
        return False
    
@@ -1898,23 +1989,10 @@
# 获得游戏设置的字符编码
def GetCharacterEncoding():
    encodingList = ReadChConfig.GetEvalChConfig("EncodingTex")
    if len(encodingList) != 2:
        ErrLog("EncodingTex.txt Error len != 2")
        return 'utf8'
    return encodingList[1]
def GetCharacterEncoding(): return IpyGameDataPY.GetFuncCfg("EncodingTex", 2)
# 服务器默认GBK,转配置编码如UTF8,一般用于与显示层交互,不判断是否base64
def GbkToCode(inputText):
    encodingList = ReadChConfig.GetEvalChConfig("EncodingTex")
    if len(encodingList) != 2:
        ErrLog("EncodingTex.txt Error len != 2")
        return inputText
    try:
        return inputText.decode(ShareDefine.Def_Game_Character_Encoding).encode(GetCharacterEncoding())
    except:
@@ -1922,26 +2000,13 @@
    
    return inputText
def IsCrossServer():
    ## 是否跨服服务器
    return ToIntDef(ReadChConfig.GetPyMongoConfig("Merge", "IsMergeServer"), 0)
def GetCrossZoneName():
    ## 跨服服务器分区名,标记一起跨服分区的名字,配置在跨服服务器,子服不用配置,由跨服服务器同步
    if IsCrossServer():
        return ReadChConfig.GetPyMongoConfig("Merge", "CrossZoneName")
    return PyGameData.g_crossZoneName
def GetCrossServerTimeStr():
    ## 跨服服务器时间
    if IsCrossServer():
        return GetCurrentDataTimeStr()
    lastCrossServerTime, lastServerTime, _ = PyGameData.g_crossServerTimeInfo
    if not lastCrossServerTime:
        return GetCurrentDataTimeStr()
    curTime = int(time.time())
    crossServerTime = lastCrossServerTime + (curTime - lastServerTime)
    return ChangeTimeNumToStr(crossServerTime)
def CodeToGbk(inputText):
    try:
        return inputText.decode(GetCharacterEncoding()).encode(ShareDefine.Def_Game_Character_Encoding)
    except:
        return inputText
    return inputText
## 时间格式转换成数值时间,可参考datetime.datetime.fromtimestamp(102645645)
#  @param timeNum
@@ -2109,6 +2174,32 @@
    numValue += pow(10, dataIndex)*(dataValue - lastTagLV)
    return numValue
def GetValue(dataValue, fromRight, bits):
    '''获取某个数值中,从右往左数第x位开始,截图n位得到的数据
    @param dataValue: 原始数值
    @param fromRight: 从右往左数第x位开始,从1开始
    @param bits: 截取n位
    @return: 数值value
    '''
    lPow = pow(10, fromRight)
    rPow = pow(10, fromRight - bits)
    curValue = dataValue % lPow / rPow
    return curValue
def SetValue(dataValue, fromRight, bits, updValue):
    '''修改某个数值,从右往左数第x位开始,截图n位得到的数据,替换为具体数值
    @param dataValue: 原始数值
    @param fromRight: 从右往左数第x位开始,从1开始
    @param bits: 截取n位
    @param updValue: 替换值
    @return: 修改后的value值
    '''
    lPow = pow(10, fromRight)
    rPow = pow(10, fromRight - bits)
    leftValue = dataValue / lPow * lPow
    rightValue = dataValue % rPow
    return leftValue + updValue * rPow + rightValue
def GetBitValue(dataValue, index):
    """ 得到某个字节值中某一位(Bit)的值
    @param dataValue: 待取值的字节值
@@ -2370,15 +2461,32 @@
def DebugAnswer(curPlayer, text):
    '''转码后再发DebugAnswer'''
    '''转码后再发DebugAnswer
    @param curPlayer: 跨服服务器时支持直接传入 crossPlayer
    '''
    #===========================================================================
    # if not GetGameWorld().GetDebugLevel():
    #    return
    #===========================================================================
    DebugLog(text)
    playerID = curPlayer.GetPlayerID()
    if IsCrossServer():
        crossPlayer = curPlayer
        mainServerID = crossPlayer.GetMainServerID()
        if not mainServerID:
            return
        import CrossMsg
        CrossMsg.SendToClientServer(ShareDefine.C2S_GMDebugAnswer, {"text":text}, [mainServerID], playerID)
        return
    DebugLog(text, playerID)
    text = text.decode(ShareDefine.Def_Game_Character_Encoding).encode(GetCharacterEncoding())
    curPlayer.DebugAnswer(text)
    return
def C2S_GMDebugAnswer(dataMsg, playerID):
    text = dataMsg["text"]
    curPlayer = GetPlayerManager().FindPlayerByID(playerID)
    if curPlayer:
        DebugAnswer(curPlayer, text)
    return
def RaiseException(errorMsg, playerID=0):
@@ -2390,12 +2498,11 @@
        SendGameError("MapServerRaiseException", errorMsg)
    return
def SendGameErrorEx(errType, msgInfo="", playerID=0):
def SendGameErrorEx(errType, msgInfo="", playerID=0, isRaiseErr=False):
    ErrLog("SendGameErrorEx: %s -> %s" % (errType, msgInfo), playerID)
    if GetGameWorld().GetDebugLevel():
    SendGameError(errType, msgInfo)
    if isRaiseErr or GetGameWorld().GetDebugLevel():
        raise Exception("%s -> %s" % (errType, msgInfo))
    else:
        SendGameError(errType, msgInfo)
    return
def SendGameError(errType, msgInfo=""):
@@ -2404,9 +2511,9 @@
    @param msgInfo: 错误信息,可选
    '''
    getUrl = ReadChConfig.GetPyMongoConfig("EventReport", "OpenStateUrl")
    groupID = ReadChConfig.GetPyMongoConfig("platform", "GroupID")
    groupName = GetServerGroupName()
    userDBName = ReadChConfig.GetPyMongoConfig("connect", "USER_DB_NAME")
    getUrl = getUrl + "?Type=%s&groupID=%s&userDBName=%s&mapID=%s"%(errType, groupID, userDBName, GetMap().GetMapID())
    getUrl = getUrl + "?Type=%s&groupID=%s&userDBName=%s&mapID=%s"%(errType, groupName, userDBName, GetMap().GetMapID())
    if msgInfo:
        getUrl = getUrl + "&MsgInfo=%s" % urllib.quote_plus(msgInfo)
    GetGameWorld().EventReport_EventReport("", "", "", "", 0, getUrl)