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 #---奇迹, 职业枚举定义--- (