From fff7319fd0fb06d03364c5be64edc5bc22e1fe3f Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期四, 28 八月 2025 18:04:18 +0800
Subject: [PATCH] 129 【战斗】战斗系统-服务端(NPC支持成长属性;NPC支持关联武将;)
---
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py | 185 +++++++++++++++++++++++++++++++--------------
1 files changed, 126 insertions(+), 59 deletions(-)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py
index 99738ed..99dc267 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/DB/DBDataMgr.py
@@ -15,126 +15,180 @@
#"""Version = 2025-05-09 12:20"""
#-------------------------------------------------------------------------------
+import CommFunc
+import DBStruct
+import ChConfig
import GameWorld
import PyGameData
-import DBEventTrig
+import PyMongoMain
import DBPlayerViewCache
+import DBEventTrig
import DBBillboard
+import DBFuncTeam
+import DBGameRec
import DBFamily
import DBMail
-import binascii
import time
-import zlib
import os
BakRoot = "C:\ServerRealTimeBackup"
-BakFileType = ".bak"
+BakFileType = ".rtb"
+BackupCopyMax = 5 # 保留历史备档文件数
+BackupInterval = 30 # 备档频率,分钟,暂定每30分钟
-#临时变量,之后优化
-g_loadErr = False
-Map2ServerID = {
- 10010:87,
- 10090:89,
- }
-
def OnServerStart():
+ ##启动服务器数据处理
GameWorld.DebugLog("地图服务器启动")
- LoadServerDataBackup()
+ if not LoadGameWorldDataFromBackup():
+ LoadGameWorldDataFromDB()
return
def OnServerClose():
+ ##关服服务器数据处理
+ SaveGameWorldDataToDB()
return
def OnMinute(curTime):
- #curMinute = curTime.minute
- ServerDataBackup()
+ if PyGameData.g_serverClosing:
+ return
DBFamily.OnMinute()
DBBillboard.OnMinute()
+
+ #备档、入库放最后,等数据都处理完后再保存,每天 [[时,分], ...],尽量岔开整点、5分
+ if [curTime.hour, curTime.minute] in [[3, 6]]:
+ BackupGameWorldData(True)
+ else:
+ BackupGameWorldData(False)
return
#------------------------------------------- 备档 ---------------------------------------------------
def GetBakFileSortList(bakPath):
- ## 按备档时间倒序排序返回 [[bakTime, filePath], ...]
+ ## 按备档时间倒序排序返回 [[bakTime, 数据版本号, filePath], ...]
bakFileList = []
for parent, _, filenames in os.walk(bakPath):
for filename in filenames:
if not filename.endswith(BakFileType):
continue
fullPath = os.path.join(parent, filename)
- bakTime = GameWorld.ToIntDef(filename[:filename.index(".")].split("_")[1])
- bakFileList.append([bakTime, fullPath])
+ bakInfo = filename[:filename.index(".")].split("_")
+ if len(bakInfo) != 3:
+ continue
+ dataVersionNO = GameWorld.ToIntDef(bakInfo[1]) # 数据版本号
+ bakTime = GameWorld.ToIntDef(bakInfo[2]) # yyyyMMddhhmmss
+ bakFileList.append([bakTime, dataVersionNO, fullPath])
bakFileList.sort(reverse=True)
return bakFileList
-def LoadServerDataBackup():
- ## 服务器公共数据备档加载
- global g_loadErr
- mapID = GameWorld.GetMap().GetMapID()
- if mapID not in Map2ServerID:
- return
- serverName = "S%s" % Map2ServerID[mapID]
+def LoadGameWorldDataFromBackup():
+ ## 备档加载服务器公共数据
+ # @return: 是否存在备档成功加载
+ serverID = GameWorld.GetGameWorld().GetServerID()
+ serverName = "S%s" % serverID
BakDir = os.path.join(BakRoot, serverName)
GameWorld.Log("加载备档: %s" % BakDir)
bakFileList = GetBakFileSortList(BakDir)
if not bakFileList:
GameWorld.Log("不存在备档!")
return
- bakFilePath = bakFileList[0][1] # 取第一个为最近的一次备档
+ finalBakInfo = bakFileList[0] # 排序后的第一个为最新备档数据
+ bakVersionNO = finalBakInfo[1]
+ bakFilePath = finalBakInfo[2]
+ if bakVersionNO != DBStruct.GAMEWORLD_DATA_VERSION_NO:
+ GameWorld.ErrLog("备档数据版本号校验失败,请使用正确版本服务器启动重新导入数据! bakVersionNO=%s, GAMEWORLD_DATA_VERSION_NO=%s"
+ % (bakVersionNO, DBStruct.GAMEWORLD_DATA_VERSION_NO))
+ raise
+
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:
- g_loadErr = True
- raise
+ saveData = CommFunc.Decompress(compressed_data)
+ if not saveData:
+ raise
- LoadPyGameData(bakData, 0)
- return
+ LoadPyGameData(saveData, 0)
+ SaveGameWorldDataToDB(saveData) # 如果是从备档读取的则直接入库
+ return True
-def ServerDataBackup():
+def BackupGameWorldData(saveToDB=False):
## 服务器公共数据定时备档,暂时直接存盘
- if g_loadErr:
- GameWorld.ErrLog("加载备档已异常,暂时不在存储备档")
+ # @param saveToDB: 是否附带入库,为确保备档数据存在时一定优于db库数据,故常规入库时必须附带先备档一次
+ if PyGameData.g_serverClosing:
return
- mapID = GameWorld.GetMap().GetMapID()
- if mapID not in Map2ServerID:
+ if not PyGameData.g_loadDataOK:
+ GameWorld.Log("加载数据未完成,不存储备档")
return
- serverName = "S%s" % Map2ServerID[mapID]
+ curTime = int(time.time())
+ if saveToDB:
+ if curTime - PyGameData.g_lastRTBTime < BackupInterval * 60:
+ GameWorld.Log("备档冷却中!")
+ return
+
+ 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):
os.makedirs(BakDir)
- curTime = int(time.time())
- bakFilePath = os.path.join(BakDir, "%s_%s%s" % (serverName, curTime, BakFileType))
- bakData = GetSavePyData()
- GameWorld.Log("Bak:%s, len=%s, %s" % (serverName, len(bakData), bakFilePath))
+ dataVersionNO = DBStruct.GAMEWORLD_DATA_VERSION_NO
+ bakTiemStr = GameWorld.ChangeTimeNumToStr(curTime, ChConfig.TYPE_Time_Format_YmdHMS)
+ bakFilePath = os.path.join(BakDir, "%s_%s_%s%s" % (serverName, dataVersionNO, bakTiemStr, BakFileType))
+ saveData = GetSavePyData()
+ GameWorld.Log("Bak:%s, len=%s, %s" % (serverName, len(saveData), bakFilePath))
+ compressed_data = CommFunc.Compress(saveData) # 备档数据才进行压缩
+ 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()
except:
return
+ PyGameData.g_lastRTBTime = curTime
bakFileList = GetBakFileSortList(BakDir)
# 删除多余备档
- for _, filePath in bakFileList[BackupCopyMax:]:
+ for bakInfo in bakFileList[BackupCopyMax:]:
+ filePath = bakInfo[-1]
os.remove(filePath)
GameWorld.Log("删除多余备档文件: %s" % filePath)
+ if saveToDB:
+ SaveGameWorldDataToDB(saveData)
+ return
+
+def ClearBackupFile():
+ ## 清空备档文件
+ serverID = GameWorld.GetGameWorld().GetServerID()
+ serverName = "S%s" % serverID
+ BakDir = os.path.join(BakRoot, serverName)
+ GameWorld.Log("清空备档: %s" % BakDir)
+ CommFunc.DelFolder(BakDir, True)
return
#--------------------------------------------------------------------------------------------------
+
+def LoadGameWorldDataFromDB():
+ ## 直接从db读取公共数据
+ GameWorld.Log("没有备档数据,直接从db加载数据!")
+ serverData = PyMongoMain.GetUserCtrlDB().readGameWorldData()
+ LoadPyGameData(serverData, 0)
+ return
+
+def SaveGameWorldDataToDB(saveData=""):
+ ## 公共数据入库
+ if not saveData:
+ saveData = GetSavePyData()
+ PyMongoMain.GetUserCtrlDB().saveGameWorldData(saveData)
+ return
def GetSavePyData():
@@ -144,12 +198,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()
@@ -159,33 +208,42 @@
#加载数据后,一些功能转化为功能业务数据
#...
+
+ #放最后
+ PyGameData.g_loadDataOK = True
return pos
class PyGameDataManager(object):
def __init__(self):
self.EventTrigMgr = DBEventTrig.EventTrigMgr()
self.PlayerViewCacheMgr = DBPlayerViewCache.PlayerViewCacheMgr()
- self.FamilyMgr = DBFamily.FamilyMgr()
- self.MailMgr = DBMail.MailMgr()
self.BillboardMgr = DBBillboard.BillboardMgr()
+ self.MailMgr = DBMail.MailMgr()
+ self.FamilyMgr = DBFamily.FamilyMgr()
+ self.GameRecMgr = DBGameRec.GameRecMgr()
+ self.FuncTeamMgr = DBFuncTeam.FuncTeamMgr()
return
def GetSaveData(self):
buff = ""
buff += self.EventTrigMgr.GetSaveData()
buff += self.PlayerViewCacheMgr.GetSaveData()
- buff += self.FamilyMgr.GetSaveData()
- buff += self.MailMgr.GetSaveData()
buff += self.BillboardMgr.GetSaveData()
+ buff += self.MailMgr.GetSaveData()
+ buff += self.FamilyMgr.GetSaveData()
+ buff += self.GameRecMgr.GetSaveData()
+ buff += self.FuncTeamMgr.GetSaveData()
return buff
def LoadGameData(self, gameBuffer, pos):
dataslen = len(gameBuffer)
pos = self.EventTrigMgr.LoadPyGameData(gameBuffer, pos, dataslen)
pos = self.PlayerViewCacheMgr.LoadPyGameData(gameBuffer, pos, dataslen)
- pos = self.FamilyMgr.LoadPyGameData(gameBuffer, pos, dataslen)
- pos = self.MailMgr.LoadPyGameData(gameBuffer, pos, dataslen)
pos = self.BillboardMgr.LoadPyGameData(gameBuffer, pos, dataslen)
+ pos = self.MailMgr.LoadPyGameData(gameBuffer, pos, dataslen)
+ pos = self.FamilyMgr.LoadPyGameData(gameBuffer, pos, dataslen)
+ pos = self.GameRecMgr.LoadPyGameData(gameBuffer, pos, dataslen)
+ pos = self.FuncTeamMgr.LoadPyGameData(gameBuffer, pos, dataslen)
return pos
def GetDBDataMgr():
@@ -225,3 +283,12 @@
dbDataMgr = GetDBDataMgr()
return dbDataMgr.BillboardMgr
+def GetGameRecMgr():
+ ## 通用记录数据管理器
+ dbDataMgr = GetDBDataMgr()
+ return dbDataMgr.GameRecMgr
+
+def GetFuncTeamMgr():
+ ## 功能队伍数据管理器
+ dbDataMgr = GetDBDataMgr()
+ return dbDataMgr.FuncTeamMgr
--
Gitblit v1.8.0