| | |
| | | # 如切磋一下,玩家可以在任意场景对任意本服或跨服玩家发起切磋,与其镜像进行一场友谊PK,纯娱乐
|
| | | # 这种为被动式,即目标玩家可能不存在打包数据表中,需要取拉取
|
| | | #
|
| | | # 由于打包数据较大,影响开关服及备档的速度,还会导致内存不足,故改为db直接管理打包数据获取及入库
|
| | | # GameServer仅保留单次启动后有同步/获取的玩家数据,一般比db少,只保留打包数据信息,玩家基本信息改为从ViewCahce中获取
|
| | | #-------------------------------------------------------------------------------
|
| | | #"""Version = 2024-10-17 15:00"""
|
| | | #-------------------------------------------------------------------------------
|
| | |
|
| | | import CommFunc
|
| | | import GameWorld
|
| | | import PyDataManager
|
| | | import PlayerViewCache
|
| | |
| | | import PyGameData
|
| | | import ChConfig
|
| | |
|
| | | import time
|
| | | import base64
|
| | |
|
| | | Def_CahceCountMax = 100 # 最大缓存个数,注:GameServer缓不缓存这个数据都无所谓(改为在db缓存),保留原取数据逻辑不变,暂时缓存个x条,方便本服的直接取
|
| | | TempDBPlayer = PyGameDataStruct.tagDBPlayer()
|
| | |
|
| | | def GetDBPlayerByPackData(packData):
|
| | | ## 根据 curPlayer.GetPackData() 打包返回的数据获取DBPlayer数据
|
| | | TempDBPlayer.clear()
|
| | | if packData:
|
| | | TempDBPlayer.readData(base64.b64decode(packData))
|
| | | return TempDBPlayer
|
| | | |
| | | class DBPlayerPackDataManager():
|
| | | ## 玩家打包数据管理
|
| | | ## 玩家打包数据管理 - 这里仅管理本次启动后的热数据缓存,不入库
|
| | |
|
| | | def __init__(self):
|
| | | self.Clear()
|
| | | return
|
| | |
|
| | | def Clear(self):
|
| | | self.playerPackDataDict = {} # {playerID:tagDBPlayerPackData, ...}
|
| | | self.__packDataDcit = {} # {playerID:packData, ...}
|
| | | self.__packDataPlayerIDList = [] # [playerID, ...] # 限制缓存数,先进先出
|
| | | return
|
| | | |
| | | def IsPlayerIn(self, playerID):
|
| | | return playerID in self.__packDataDcit
|
| | |
|
| | | def GetPlayerPackObj(self, playerID, isAddNew=False):
|
| | | packDataObj = None
|
| | | if playerID in self.playerPackDataDict:
|
| | | packDataObj = self.playerPackDataDict[playerID]
|
| | | elif isAddNew:
|
| | | packDataObj = PyGameDataStruct.tagDBPlayerPackData()
|
| | | packDataObj.PlayerID = playerID
|
| | | self.playerPackDataDict[playerID] = packDataObj
|
| | | return packDataObj
|
| | | def GetCount(self): return len(self.__packDataDcit)
|
| | | |
| | | def GetPlayerPackdata(self, playerID):
|
| | | if playerID not in self.__packDataDcit:
|
| | | return ""
|
| | | # 恢复数据热度
|
| | | if playerID in self.__packDataPlayerIDList:
|
| | | self.__packDataPlayerIDList.remove(playerID)
|
| | | self.__packDataPlayerIDList.append(playerID)
|
| | | GameWorld.DebugLog("获取打包数据缓存数更新: %s,%s" % (len(self.__packDataPlayerIDList), self.__packDataPlayerIDList))
|
| | | return self.__packDataDcit[playerID]
|
| | |
|
| | | def UpdPlayerPackData(self, playerID, packData):
|
| | | if not packData:
|
| | | return
|
| | | packObj = self.GetPlayerPackObj(playerID, True)
|
| | | packObj.UpdTime = int(time.time())
|
| | | packObj.PackData = packData
|
| | | packObj.PackDataSize = len(packObj.PackData)
|
| | | self.__packDataDcit[playerID] = packData
|
| | | if playerID in self.__packDataPlayerIDList:
|
| | | # 添加热度,重复更新的不影响热度
|
| | | self.__packDataPlayerIDList.append(playerID)
|
| | | if len(self.__packDataPlayerIDList) > Def_CahceCountMax:
|
| | | delPlayerID = self.__packDataPlayerIDList.pop(0)
|
| | | if delPlayerID in self.__packDataDcit:
|
| | | del self.__packDataDcit[delPlayerID]
|
| | | GameWorld.DebugLog("删除打包数据缓存: delPlayerID=%s" % delPlayerID)
|
| | | GameWorld.DebugLog("添加打包数据缓存数更新: %s,%s" % (len(self.__packDataPlayerIDList), self.__packDataPlayerIDList))
|
| | | return
|
| | | |
| | | # 保存数据 存数据库和realtimebackup
|
| | | def GetSaveData(self):
|
| | | savaData = ""
|
| | | cntData = ""
|
| | | cnt = 0
|
| | | |
| | | for dbData in self.playerPackDataDict.values():
|
| | | cnt += 1
|
| | | savaData += dbData.getBuffer()
|
| | | |
| | | GameWorld.Log("Save DBPlayerPackData count :%s len=%s" % (cnt, len(savaData)))
|
| | | return CommFunc.WriteDWORD(cntData, cnt) + savaData
|
| | | |
| | | # 从数据库载入数据
|
| | | def LoadPyGameData(self, datas, pos, dataslen):
|
| | | cnt, pos = CommFunc.ReadDWORD(datas, pos)
|
| | | GameWorld.Log("Load DBPlayerPackData count :%s" % cnt)
|
| | | |
| | | self.Clear()
|
| | | |
| | | for _ in xrange(cnt):
|
| | | dbData = PyGameDataStruct.tagDBPlayerPackData()
|
| | | pos += dbData.readData(datas, pos, dataslen)
|
| | | |
| | | self.playerPackDataDict[dbData.PlayerID] = dbData
|
| | | |
| | | return pos
|
| | |
|
| | | def IsSaveDB(packDataObj):
|
| | | ## 是否入库
|
| | | if not packDataObj:
|
| | | return False
|
| | | |
| | | # 功能固定需要的
|
| | | # ...
|
| | | |
| | | maxDays = 7 # 默认7天
|
| | | MaxTime = maxDays * 3600 * 24
|
| | | curTime = int(time.time())
|
| | | passTime = curTime - packDataObj.UpdTime
|
| | | if passTime < MaxTime:
|
| | | return True
|
| | | |
| | | return False
|
| | |
|
| | | def DelOutofTimePackData():
|
| | | ## 删除过期
|
| | | |
| | | packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
|
| | | playerPackDataDict = packDataMgr.playerPackDataDict
|
| | | for playerID, packDataObj in playerPackDataDict.items():
|
| | | if IsSaveDB(packDataObj):
|
| | | continue
|
| | | playerPackDataDict.pop(playerID)
|
| | | |
| | | return
|
| | |
|
| | | def IsPackDataPlayer(playerID):
|
| | | return playerID in PyDataManager.GetDBPlayerPackDataManager().playerPackDataDict
|
| | | return PyDataManager.GetDBPlayerPackDataManager().IsPlayerIn(playerID)
|
| | |
|
| | | def OnPlayerLogin(curPlayer):
|
| | | ## 本服登录逻辑
|
| | | playerID = curPlayer.GetPlayerID()
|
| | | packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
|
| | | if playerID in packDataMgr.playerPackDataDict:
|
| | | isCross, isNeed = 0, 1
|
| | | QueryPlayerResult_PlayerMirror(curPlayer, "PackDataSyncState", [isCross, isNeed])
|
| | | return
|
| | |
|
| | | def OnPlayerLogin_CrossLogic(serverGroupID, serverID, playerID):
|
| | | ## 跨服登录逻辑
|
| | | packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
|
| | | if playerID in packDataMgr.playerPackDataDict:
|
| | | dataMsg = {"playerID":playerID}
|
| | | CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PlayerPackDataState, dataMsg, [serverGroupID])
|
| | | if packDataMgr.IsPlayerIn(playerID):
|
| | | QueryPlayerResult_PlayerMirror(curPlayer, "PackDataSyncState", {"PackData":1})
|
| | | return
|
| | |
|
| | | def SetNeedPackData(playerIDList):
|
| | |
| | | pullPlayerIDList = []
|
| | | packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
|
| | | for playerID in playerIDList:
|
| | | if playerID in packDataMgr.playerPackDataDict:
|
| | | if packDataMgr.IsPlayerIn(playerID):
|
| | | continue
|
| | | pullPlayerIDList.append(playerID)
|
| | |
|
| | |
| | |
|
| | | # pullFrom 0-跨服拉子服; >0-子服通过跨服拉子服
|
| | | if GameWorld.IsCrossServer():
|
| | | PlayerViewCache.SetNeedViewCache(pullPlayerIDList) # 拉打包数据的时候默认需要缓存数据
|
| | | # 广播给子服拉数据
|
| | | msgInfo["pullFrom"] = 0
|
| | | dataMsg = {"pullPlayerIDList":pullPlayerIDList, "msgInfo":msgInfo}
|
| | |
| | | if not curPlayer:
|
| | | GameWorld.DebugLog("玩家不在线的调用打包db数据! playerID=%s" % (playerID), playerID)
|
| | | data = str(msgInfo)
|
| | | GameWorld.GetGameWorld().SendDBLogic(ChConfig.gstDBLogic_PlayerPackData, playerID, data, len(data))
|
| | | GameWorld.GetGameWorld().SendDBLogic(ChConfig.gstDBLogic_PlayerPackDataReq, playerID, data, len(data))
|
| | | return
|
| | | GameWorld.DebugLog("玩家在线的发给地图打包数据! playerID=%s" % (playerID), playerID)
|
| | | # 在线的转发给地图
|
| | |
| | | msgType = msgInfo.get("msgType")
|
| | | # 镜像战斗
|
| | | if msgType == "MirrorBattle":
|
| | | sceneMapID = msgInfo.get("sceneMapID", 0)
|
| | | playerID = msgInfo.get("playerID", 0)
|
| | | # 玩家发起的
|
| | | if playerID:
|
| | | playerID = msgInfo["playerID"]
|
| | | curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
|
| | | if not curPlayer:
|
| | | return
|
| | | tagMapID = GameWorld.GetQueryPlayerMapID(curPlayer)
|
| | | routeIndex = curPlayer.GetRouteServerIndex()
|
| | | else:
|
| | | tagMapID = msgInfo.get("requestMapID", 0)
|
| | | routeIndex = -1
|
| | | routeIndex = -1
|
| | | # # 玩家发起的
|
| | | # if playerID:
|
| | | # playerID = msgInfo["playerID"]
|
| | | # curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
|
| | | # if not curPlayer:
|
| | | # return
|
| | | # sceneMapID = GameWorld.GetQueryPlayerMapID(curPlayer)
|
| | | # routeIndex = curPlayer.GetRouteServerIndex()
|
| | | # else:
|
| | | # routeIndex = -1
|
| | |
|
| | | sendMsg = str([msgInfo, packDataDict])
|
| | | GameWorld.DebugLog("MapServer_QueryPlayer tagMapID=%s,len=%s" % (tagMapID, len(sendMsg)), playerID)
|
| | | GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, playerID, tagMapID, "PlayerMirror", sendMsg, len(sendMsg), routeIndex)
|
| | | GameWorld.DebugLog("MapServer_QueryPlayer sceneMapID=%s,len=%s" % (sceneMapID, len(sendMsg)), playerID)
|
| | | GameWorld.GetPlayerManager().MapServer_QueryPlayer(0, 0, playerID, sceneMapID, "PlayerMirror", sendMsg, len(sendMsg), routeIndex)
|
| | |
|
| | | # 其他功能可再扩展
|
| | | else:
|
| | |
| | | ## 收到子服同步的玩家打包数据
|
| | | playerID = msgData["playerID"]
|
| | | packData = msgData["packData"]
|
| | | cacheBase = msgData.get("cacheBase", {})
|
| | | if cacheBase:
|
| | | PlayerViewCache.UpdCrossCacheBase(playerID, cacheBase)
|
| | | PyDataManager.GetDBPlayerPackDataManager().UpdPlayerPackData(playerID, packData)
|
| | |
|
| | | msgInfo = msgData.get("msgInfo", {})
|
| | |
| | |
|
| | | msgInfo = msgData["msgInfo"]
|
| | | pullPlayerIDList = msgData["pullPlayerIDList"]
|
| | | dbPackDataIDList = msgData.get("dbPackDataIDList", []) # db标记的有打包数据的玩家ID
|
| | |
|
| | | otherServerPlayerIDList = []
|
| | | packDataDict = {}
|
| | | packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
|
| | | for playerID in pullPlayerIDList:
|
| | | packObj = packDataMgr.GetPlayerPackObj(playerID)
|
| | | packData = packDataMgr.GetPlayerPackdata(playerID)
|
| | | # 已经有的数据先推送回去
|
| | | if packObj:
|
| | | packDataDict[playerID] = packObj.PackData
|
| | | dataMsg = {"playerID":playerID, "packData":packObj.PackData, "msgInfo":msgInfo}
|
| | | if packData or playerID in dbPackDataIDList:
|
| | | GameWorld.DebugLog("跨服GameServer或db有缓存玩家打包数据,直接推给子服! playerID=%s" % playerID)
|
| | | dataMsg = {"playerID":playerID, "packData":packData, "msgInfo":msgInfo}
|
| | | CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PushPlayerPackData, dataMsg, [serverGroupID])
|
| | | else:
|
| | | otherServerPlayerIDList.append(playerID)
|
| | |
|
| | | # 还没有数据的,广播给其他子服拉数据
|
| | | if otherServerPlayerIDList:
|
| | | PlayerViewCache.SetNeedViewCache(otherServerPlayerIDList) # 拉打包数据的时候默认需要缓存数据
|
| | | dataMsg = {"pullPlayerIDList":otherServerPlayerIDList, "msgInfo":msgInfo}
|
| | | CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PullPlayerPackData, dataMsg)
|
| | |
|
| | |
| | | curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
|
| | | if not curPlayer:
|
| | | return
|
| | | isCross, isNeed = 1, 1
|
| | | QueryPlayerResult_PlayerMirror(curPlayer, "PackDataSyncState", [isCross, isNeed])
|
| | | QueryPlayerResult_PlayerMirror(curPlayer, "PackDataSyncState", msgData)
|
| | | return
|
| | |
|
| | | def CrossServerMsg_PullPlayerPackData(msgData):
|
| | |
| | | msgInfo = msgData["msgInfo"]
|
| | | pullPlayerIDList = msgData["pullPlayerIDList"]
|
| | |
|
| | | needPullPlayerIDList = []
|
| | | packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
|
| | | for playerID in pullPlayerIDList:
|
| | | packObj = packDataMgr.GetPlayerPackObj(playerID)
|
| | | if packObj:
|
| | | # 本服有数据,直接推给跨服
|
| | | dataMsg = {"playerID":playerID, "packData":packObj.PackData, "msgInfo":msgInfo}
|
| | | packData = packDataMgr.GetPlayerPackdata(playerID)
|
| | | if packData:
|
| | | GameWorld.DebugLog("本服有缓存玩家打包数据,直接推给跨服! playerID=%s" % playerID)
|
| | | dataMsg = {"playerID":playerID, "packData":packData, "msgInfo":msgInfo}
|
| | | CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PlayerPackData, dataMsg)
|
| | | else:
|
| | | needPullPlayerIDList.append(playerID)
|
| | | DoPullPlayerPackData(playerID, msgInfo)
|
| | |
|
| | | DoPullPlayerPackData(needPullPlayerIDList, msgInfo)
|
| | | return
|
| | |
|
| | | def CrossServerMsg_PushPlayerPackData(msgData):
|
| | |
| | | curPlayer.MapServer_QueryPlayerResult(0, 0, "PlayerMirror", sysMsg, len(sysMsg))
|
| | | return
|
| | |
|
| | | def OnMGUpdatePlayerPackData(curPlayer, curPackData):
|
| | | def OnMGUpdatePlayerPackData(curPlayer, curPackData, msgInfo):
|
| | | ## 地图同步更新的玩家打包数据
|
| | | if GameWorld.IsCrossServer():
|
| | | return
|
| | |
| | | packData = curPackData.PackData
|
| | | if not packDataSyncState or not packData:
|
| | | return
|
| | | msgInfo = eval(curPackData.PackMsg) if curPackData.PackMsg else {} # 打包数据附带的信息
|
| | |
|
| | | # 本服需要,先更新数据
|
| | | if packDataSyncState % 10:
|
| | | # 本服需要,先更新数据;跨服需要则也默认本服需要
|
| | | if packDataSyncState&pow(2, 0) or packDataSyncState&pow(2, 1):
|
| | | PyDataManager.GetDBPlayerPackDataManager().UpdPlayerPackData(playerID, packData)
|
| | | GameWorld.GetGameWorld().SendDBLogic(ChConfig.gstDBLogic_PlayerPackDataUpd, playerID, packData, len(packData))
|
| | |
|
| | | # 跨服需要,同步给跨服,由跨服服务器再进一步处理
|
| | | if packDataSyncState / 10:
|
| | | cacheBase = PlayerViewCache.GetSyncCrossCacheBase(curPlayer) if curPlayer else {}
|
| | | dataMsg = {"playerID":playerID, "packData":packData, "cacheBase":cacheBase, "msgInfo":msgInfo}
|
| | | if packDataSyncState&pow(2, 1):
|
| | | dataMsg = {"playerID":playerID, "packData":packData, "msgInfo":msgInfo}
|
| | | CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PlayerPackData, dataMsg)
|
| | |
|
| | | # 本服需要的功能
|
| | |
| | | CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PlayerPackData, dataMsg)
|
| | | return
|
| | |
|
| | | PyDataManager.GetDBPlayerPackDataManager().UpdPlayerPackData(playerID, packData)
|
| | | # 本服需要,汇总结果
|
| | | ReuestPlayerPackDataRet(msgInfo, playerID, packData)
|
| | | return
|
| | |
| | | requestID = msgInfo["requestID"]
|
| | | mirrorIDList = msgInfo["mirrorIDList"]
|
| | | for mirrorID in mirrorIDList:
|
| | | packObj = packDataMgr.GetPlayerPackObj(mirrorID)
|
| | | if packObj:
|
| | | packDataDict[mirrorID] = packObj.PackData
|
| | | packData = packDataMgr.GetPlayerPackdata(mirrorID)
|
| | | if packData:
|
| | | packDataDict[mirrorID] = packData
|
| | | continue
|
| | | pullPlayerIDList.append(mirrorID)
|
| | |
|