16 卡牌服务端(优化备档存取逻辑,GetServerID改为取接口;调整单服StartDB渠口、启动加载数据流程,支持服层级每秒、每分Process)
9个文件已修改
287 ■■■■ 已修改文件
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/CommFunc.py 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script.ini
@@ -13,7 +13,7 @@
FuncName = InitPython
[StartDB]
ScriptName = ChConfig.py
ScriptName = GameWorldLogic\GameWorldEvent.py
Writer = Alee
Releaser = Alee
RegType = 1
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -32,15 +32,6 @@
    #初始化python
    return
#调用该函数时,C++已经设置好区服,如果改变区服需重启
#在该文件调用此函数为了减少import带来的影响
def StartDB(tick):
    #初始化数据库, 恢复备档(按区服记录), 加载静态表
    from PyMongoDB import PyMongoMain
    PyMongoMain.StartDB()
    return
#---------------------------------------------------------------------
##获得MapServer脚本路径
# @param 无参数
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/CommFunc.py
@@ -28,6 +28,8 @@
import subprocess
import binascii
import GameWorld
import traceback
import zlib
#---------------------------------------------------------------------
#全局变量
@@ -363,6 +365,55 @@
    hStr="0x"+str(red+green+blue)
    return hStr
def Compress(data, use_hex=False):
    """压缩数据
    @param use_hex: 可选十六进制转换(非必要不建议)导致压缩效率降低(体积可能翻倍),且增加转换出错风险。
    @return: None or compresseData
    """
    try:
        if use_hex:
            data = binascii.b2a_hex(data)
        compresseData = zlib.compress(data, 9)
        return compresseData
    except:
        GameWorld.ErrLog('压缩数据  - > %s' % str(traceback.format_exc()))
        return
def Decompress(compressed_data, expect_hex=False):
    """解压数据,处理格式和完整性检查
    @param use_hex: 可选十六进制转换,与压缩参数一致
    @return: None or data
    """
    # 检查最小长度(zlib 头部至少 2 字节)
    if len(compressed_data) < 2:
        GameWorld.ErrLog("解压失败 -> 压缩数据长度异常.")
        return
    try:
        # 尝试标准 zlib 解压
        data = zlib.decompress(compressed_data)
    except zlib.error:
        GameWorld.ErrLog("解压失败(尝试调整参数).")
        try:
            # 尝试 GZIP 格式
            data = zlib.decompress(compressed_data, wbits=31)
        except zlib.error:
            # 尝试原始 DEFLATE
            data = zlib.decompress(compressed_data, wbits=-15)
    if expect_hex:
        try:
            if len(data) % 2 != 0:
                GameWorld.ErrLog("解压失败 -> 十六进制字符串长度非偶数.")
                return
            return binascii.a2b_hex(data)
        except TypeError:
            GameWorld.ErrLog("解压失败 -> 无效的十六进制数据.")
            return
    return data
#提示除零错误的EVAL
## 
#  @param 参数
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py
@@ -15,6 +15,7 @@
#"""Version = 2025-05-09 12:20"""
#-------------------------------------------------------------------------------
import CommFunc
import GameWorld
import PyGameData
import DBEventTrig
@@ -23,20 +24,14 @@
import DBFamily
import DBMail
import binascii
import time
import zlib
import os
BakRoot = "C:\ServerRealTimeBackup"
BakFileType = ".bak"
BackupCopyMax = 3
#临时变量,之后优化
g_loadErr = False
Map2ServerID = {
                10010:87,
                10090:89,
                }
    
def OnServerStart():
    GameWorld.DebugLog("地图服务器启动")
@@ -70,10 +65,8 @@
def LoadServerDataBackup():
    ## 服务器公共数据备档加载
    global g_loadErr
    mapID = GameWorld.GetMap().GetMapID()
    if mapID not in Map2ServerID:
        return
    serverName = "S%s" % Map2ServerID[mapID]
    serverID = GameWorld.GetGameWorld().GetServerID()
    serverName = "S%s" % serverID
    BakDir = os.path.join(BakRoot, serverName)
    GameWorld.Log("加载备档: %s" % BakDir)
    bakFileList = GetBakFileSortList(BakDir)
@@ -84,13 +77,11 @@
    GameWorld.Log("读取备档: %s" % bakFilePath)
    
    f = open(bakFilePath, 'rb')
    compressed_data = f.read().strip()
    compressed_data = f.read()
    f.close()
    
    try:
        decompressed_data = zlib.decompress(compressed_data)
        bakData = binascii.a2b_hex(decompressed_data)
    except:
    bakData = CommFunc.Decompress(compressed_data)
    if not bakData:
        g_loadErr = True
        raise 
    
@@ -100,14 +91,11 @@
def ServerDataBackup():
    ## 服务器公共数据定时备档,暂时直接存盘
    if g_loadErr:
        GameWorld.ErrLog("加载备档已异常,暂时不在存储备档")
        GameWorld.ErrLog("加载备档已异常,暂时不再存储备档,防止已经错误加载的数据覆盖")
        return
    mapID = GameWorld.GetMap().GetMapID()
    if mapID not in Map2ServerID:
        return
    serverName = "S%s" % Map2ServerID[mapID]
    serverID = GameWorld.GetGameWorld().GetServerID()
    serverName = "S%s" % serverID
    BakDir = os.path.join(BakRoot, serverName)
    BackupCopyMax = 3
    GameWorld.Log("服务器备档: %s" % serverName)
    
    if not os.path.exists(BakDir):
@@ -117,9 +105,13 @@
    bakFilePath = os.path.join(BakDir, "%s_%s%s" % (serverName, curTime, BakFileType))
    bakData = GetSavePyData()
    GameWorld.Log("Bak:%s, len=%s, %s" % (serverName, len(bakData), bakFilePath))
    compressed_data = CommFunc.Compress(bakData)
    if not compressed_data:
        GameWorld.SendGameError("ServerDataBackupError")
        return
    GameWorld.Log("compress len=%s" % len(compressed_data))
    try:
        compressed_data = zlib.compress(bakData, 9)    #最大压缩
        GameWorld.Log("compress len=%s" % len(compressed_data))
        fp = open(bakFilePath, "wb")
        fp.write(compressed_data)
        fp.close()
@@ -144,12 +136,7 @@
    pyGameDataMgr = GetDBDataMgr()
    result = pyGameDataMgr.GetSaveData()
    GameWorld.Log("GetSavePyData!! id = %s-%s"%(id(pyGameDataMgr), len(result)))
    result = binascii.b2a_hex(result)
    #GameWorld.DebugLog("GetSavePyData!! result = %s-%s"%(result, len(result)))
    # 字节码在C++转化会发生错误must be string without null bytes, not str,但是可以正常保存,错误会在下次调用便宜接口才会触发
    # 暂时改成字符串返回,暂无解决方案
    return result
#    return str(len(result)) + "|" + result
def LoadPyGameData(gameBuffer, pos):
    pyGameDataMgr = GetDBDataMgr()
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py
@@ -1320,10 +1320,6 @@
    ## 服务器组ID,必须唯一,代表这台物理服务器
    return ToIntDef(ReadChConfig.GetPyMongoConfig("platform", "GroupID"), 0)
def GetServerID():
    ## 当前服务器ID
    return 87
def GetMainServerID(serverID):
    ## 获取服务器ID所属主服ID
    ServerIDMainServerDict = IpyGameDataPY.GetConfigEx("ServerIDMainServerDict")
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldEvent.py
@@ -17,8 +17,10 @@
import DBDataMgr
import GameWorld
import IpyGameDataPY
import PlayerEventCounter
import ShareDefine
import PlayerTeam
import PyGameData
import datetime
@@ -57,15 +59,23 @@
    
    return Get_Server_Hour(), Get_Server_Day(), Get_Server_Week(), Get_Server_Month(), Get_Server_Year()
#调用该函数时,C++已经设置好区服,如果改变区服需重启
def StartDB(tick):
    #初始化数据库, 恢复备档(按区服记录), 加载静态表
    from PyMongoDB import PyMongoMain
    PyMongoMain.StartDB()
    InitGameWorld(tick)
    return
def InitGameWorld(tick):
    ## GameWorld初始化
    if PyGameData.g_initGameTime:
        return
    PyGameData.g_initGameTime = int(time.time())
    serverID = GameWorld.GetServerID()
    serverID = GameWorld.GetGameWorld().GetServerID()
    GameWorld.Log("服务器启动初始化InitGameWorld: serverID=%s" % serverID)
    DBDataMgr.OnServerStart() # 优先加载公共数据
    LoadDBPlayer()
    PyGameData.g_initGameTime = int(time.time()) # 放到加载数据之后
    
    #初始话开服时间、星期几
    initOpenServerTime = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_InitOpenServerTime)
@@ -90,7 +100,7 @@
    else:
        serverGroupID = GameWorld.GetServerGroupID()
        GameWorld.Log("服务器启动成功: ServerGroupID=%s,serverID=%s" % (serverGroupID, serverID))
    GameWorld.GetGameWorld().SetGameWorldDict(ShareDefine.Def_WorldKey_GameWorldInitOK, 1)
    PyGameData.g_serverInitOK = True
    return
def AllMapServerInitOK(tick):
@@ -107,7 +117,7 @@
    @param openServerTime: 开服时间戳
    @return: 1-成功;-1-设置的时间异常;-2-已经设置过且开服了,不能重复设置
    '''
    serverID = GameWorld.GetServerID()
    serverID = GameWorld.GetGameWorld().GetServerID()
    curTime = int(time.time())
    if openServerTime < curTime:
        GameWorld.ErrLog("当前时间已经超过设置的开服时间,不能设置! serverID=%s" % serverID)
@@ -145,7 +155,7 @@
def OnNewServerOpen(tick):
    '''新服开启需要处理的逻辑'''
    
    serverID = GameWorld.GetServerID()
    serverID = GameWorld.GetGameWorld().GetServerID()
    GameWorld.Log("执行正式开服重置逻辑... serverID=%s" % serverID)
    
    setOpenServerTime = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_SetOpenServerTime)
@@ -215,11 +225,27 @@
def OnHighProcess(tick):
    ## 每秒分钟执行一次
    if not PyGameData.g_initGameTime:
        return
    if tick - PyGameData.g_highProcessTick < 1000:
        return
    PyGameData.g_highProcessTick = tick
    OnMinute(tick)
    # 其他逻辑
    return
def OnMinute(tick):
    ## 每整分钟执行一次
    curTime = GameWorld.GetCurrentTime()
    curMinute = curTime.minute
    if curMinute == PyGameData.g_minuteProcess:
        return
    PyGameData.g_minuteProcess = curMinute
    #检查服务器正式开服
    DoCheckNewServerOpen(tick)
    DBDataMgr.OnMinute(curTime)
@@ -229,6 +255,9 @@
    #GameWorldActionControl.Dispose_OperationActionState()
    #GameWorldActionControl.Dispose_DailyActionState()
    #GameWorldActionControl.Dispose_FBStateTime()
    PlayerTeam.OnCheckTeamPlayerDisconnectTimeout(tick)
    __CheckIpyDataRecycle(curTime)
    return
    
def DoLogic_GameWorldEvenByTime(tick):
@@ -307,3 +336,29 @@
    PlayerEventCounter.DoLogic_OnYear(tick)
    return
def __CheckIpyDataRecycle(timeNow):
    ## 检查IpyData数据回收
    playerCount = GameWorld.GetPlayerManager().OnlineCount()
    if playerCount:
        PyGameData.g_ipyDataRecycleCheckTime = 0
        #GameWorld.DebugLog("地图还有玩家在线! playerCount=%s" % playerCount)
        return
    curTime = GameWorld.ChangeDatetimeToNum(timeNow)
    if not PyGameData.g_ipyDataRecycleCheckTime:
        PyGameData.g_ipyDataRecycleCheckTime = curTime
        #GameWorld.DebugLog("地图没有玩家在线")
        return
    if PyGameData.g_ipyDataRecycleCheckTime == 1:
        # 已经回收了
        #GameWorld.DebugLog("本次已经回收过了")
        return
    if curTime - PyGameData.g_ipyDataRecycleCheckTime < 24 * 3600:
        #GameWorld.DebugLog("还未到达回收时间, passSeconds=%s" % (curTime - PyGameData.g_ipyDataRecycleCheckTime))
        return
    PyGameData.g_ipyDataRecycleCheckTime = 1
    IpyGameDataPY.IPYData.Recycle()
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py
@@ -47,10 +47,8 @@
import EventReport
import ItemCommon
import PyGameData
import PlayerTeam
import GameMap
import NPCRealmRefresh
import IpyGameDataPY
import GameWorldEvent
#---------------------------------------------------------------------
## 副本开启
@@ -527,6 +525,8 @@
    if not gameWorld.GetInitOK() :
        return
    
    GameWorldEvent.OnHighProcess(tick)
    __ProcessOpen(gameWorld, tick)
    
    __ProcessTimeKickPlayer(gameWorld, tick) # 处理副本生存周期强关副本
@@ -548,12 +548,6 @@
    #通知RouteServer 消息
    __ProcessRouteServer(gameWorld, tick)
    
    #每分钟触发
    curTime = GameWorld.GetCurrentTime()
    __OnMapMinute(curTime, tick)
    __RefreshOnMinute(curTime, tick)
    #五分钟触发
    __RefreshOnFiveMinute(tick)
    #定时检测关闭超时文件
    EventReport.OnTimeCloseScribeTxt()
    
@@ -592,7 +586,6 @@
#  @return None
#  @remarks 函数详细说明 每条分线都会触发该函数
def InitGameWorld(tick):
    GameWorldEvent.InitGameWorld(tick)
    gameWorld = GameWorld.GetGameWorld()
    ItemCommon.InitPyItem()
    EventShell.DoReloadRefresh()
@@ -741,96 +734,3 @@
    return
#---------------------------------------------------------------------
## 五分钟刷新
# @param tick
# @return None
def __RefreshOnFiveMinute(tick):
    gameWorld = GameWorld.GetGameWorld()
    lastTick = gameWorld.GetTickByType(ChConfig.TYPE_Map_Tick_ProcessFiveMinute)
    tickInterval = ChConfig.TYPE_Map_Tick_Time[ChConfig.TYPE_Map_Tick_ProcessFiveMinute]
    if tick - lastTick < tickInterval:
        return
    gameWorld.SetTickByType(ChConfig.TYPE_Map_Tick_ProcessFiveMinute, tick)
#    playerManager = GameWorld.GetMapCopyPlayerManager()
#    for index in xrange(playerManager.GetPlayerCount()):
#        curPlayer = playerManager.GetPlayerByIndex(index)
#        if not curPlayer:
#            continue
    return
## 按分钟刷新
# @param tick
# @return None
def __RefreshOnMinute(curTime, tick):
    gameWorld = GameWorld.GetGameWorld()
    lastTick = gameWorld.GetTickByType(ChConfig.TYPE_Map_Tick_ProcessMinute)
    tickInterval = ChConfig.TYPE_Map_Tick_Time[ChConfig.TYPE_Map_Tick_ProcessMinute]
    if tick - lastTick < tickInterval:
        return
    gameWorld.SetTickByType(ChConfig.TYPE_Map_Tick_ProcessMinute, tick)
    playerManager = GameWorld.GetMapCopyPlayerManager()
    for index in xrange(playerManager.GetPlayerCount()):
        curPlayer = playerManager.GetPlayerByIndex(index)
        if not curPlayer:
            continue
        __ProcessHalfHour(curPlayer, curTime, tick)
    return
def __OnMapMinute(curTime, tick):
    ## 地图层级每分钟处理, 每分钟最多只会处理一次, 无视虚拟分线
    if not PyGameData.g_initGameTime:
        return
    curMinute = curTime.minute
    if curMinute == PyGameData.g_mapLastProcess_Minute:
        return
    PyGameData.g_mapLastProcess_Minute = curMinute
    GameWorldEvent.OnMinute(tick)
    PlayerTeam.OnCheckTeamPlayerDisconnectTimeout(tick)
    __CheckIpyDataRecycle(curTime)
    return
def __CheckIpyDataRecycle(timeNow):
    ## 检查IpyData数据回收
    playerCount = GameWorld.GetPlayerManager().OnlineCount()
    if playerCount:
        PyGameData.g_ipyDataRecycleCheckTime = 0
        #GameWorld.DebugLog("地图还有玩家在线! playerCount=%s" % playerCount)
        return
    curTime = GameWorld.ChangeDatetimeToNum(timeNow)
    if not PyGameData.g_ipyDataRecycleCheckTime:
        PyGameData.g_ipyDataRecycleCheckTime = curTime
        #GameWorld.DebugLog("地图没有玩家在线")
        return
    if PyGameData.g_ipyDataRecycleCheckTime == 1:
        # 已经回收了
        #GameWorld.DebugLog("本次已经回收过了")
        return
    if curTime - PyGameData.g_ipyDataRecycleCheckTime < 24 * 3600:
        #GameWorld.DebugLog("还未到达回收时间, passSeconds=%s" % (curTime - PyGameData.g_ipyDataRecycleCheckTime))
        return
    PyGameData.g_ipyDataRecycleCheckTime = 1
    IpyGameDataPY.IPYData.Recycle()
    return
## 整半小时触发 <00和30分钟时触发>
# @param curPlayer
# @param curTime 当前时间对象
# @param tick
# @return None
def __ProcessHalfHour(curPlayer, curTime, tick):
    if curTime.minute not in [0, 30]:
        return
    EventShell.EventResponse_OnHalfHour(curPlayer)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -15,7 +15,10 @@
#"""Version = 2017-09-05 21:30"""
#-------------------------------------------------------------------------------
g_initGameTime = 0 # 初始化游戏时间戳
g_initGameTime = 0 # 开始初始化服务器时间戳
g_serverInitOK = False # 服务器是否启动成功
g_highProcessTick = 0 # 每秒触发一次,上次Tick
g_minuteProcess = -1 # 每分钟触发一次,上次处理的分钟
g_pyGameDataManager = None
@@ -26,7 +29,6 @@
g_playerReqEnterFBEx = {} # 请求进入地图额外信息 {playerID:[...], ...}
g_commMapLinePlayerCountDict = {} # 常规地图分线人数 {mapID:{lineID:人数, ...}}
g_needRefreshMapServerState = True # 常规地图分线人数是否有变更需要通知
g_mapLastProcess_Minute = -1 # 地图上次处理的分钟
g_ipyDataRecycleCheckTime = 0 # 地图IpyData数据回收检查time
InitPyItem = False # 是否加载过物品表所需要的Py数据, 每张地图只在启动时执行一次
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -41,7 +41,6 @@
Def_SetOpenServerTime = 'SetOpenServerTime' # GM工具预定的开服时间
# ------------------------- WorldKey ------------------------- 
Def_WorldKey_GameWorldInitOK = 'GameWorldInitOK'             #GameWold是否初始化完成OK
#---奇迹, 职业枚举定义---
(