From 5878f2872607b9b9186ad5ce3623aff88bbcef6b Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期二, 04 三月 2025 16:34:07 +0800
Subject: [PATCH] 5563 【英文】【BT】跨服服务器维护优化(打包数据改为db自己管理存取)

---
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossChampionship.py                                     |   13 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/MirrorAttack.py                             |    7 
 ServerPython/db/PyMongoDataServer/__init__.py                                                                          |    0 
 ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py                                                           |   16 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetCrossPK.py                          |   16 
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/PlayerMirror.py                                             |  103 +----
 ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py                                                        |   44 --
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py                                                |  295 ++-------------
 ServerPython/db/PyMongoDataServer/GM/Commands/__init__.py                                                              |    0 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PlayerMirror.py                        |    5 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py                                                            |    7 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmPK.py                                          |   84 ++--
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/QueryDBLogicResult.py                                    |    8 
 ServerPython/db/PyMongoDataServer/GM/__init__.py                                                                       |    0 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py                                               |  232 ++++++++++-
 ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py                                                             |    6 
 ServerPython/db/PyMongoDataServer/GM/Commands/PlayerMirror.py                                                          |  108 ++++++
 ServerPython/db/PyMongoDataServer/GM/GMShell.py                                                                        |  112 ++++++
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerXMZZ.py                                                    |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_MirrorBattle.py |   15 
 20 files changed, 617 insertions(+), 459 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
index bf17296..88bf6d7 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -448,8 +448,10 @@
 # GameWorld.GetGameWorld().SendDBLogic(BYTE queryType, DWORD id, char* sData, int nDataLen)
 # GameServer请求db逻辑类型,db接受 OnGameServerToDBLogic,回调 RecvDGDBLogicResult
 (
-gstDBLogic_PlayerPackData, # 请求打包玩家数据 0
-) = range(1)
+gstDBLogic_PlayerPackDataReq, # 请求打包玩家数据,仅子服用 0
+gstDBLogic_PlayerPackDataUpd, # 更新打包玩家数据,仅子服用,跨服通过拦截消息处理即可 1
+gstDBLogic_GMCmd, # 更新打包玩家数据 2
+) = range(3)
 
 #GM工具回复值
 Def_GMTool_Succeed = 1
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/PlayerMirror.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/PlayerMirror.py
index f4d9a4b..7ac46d8 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/PlayerMirror.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/PlayerMirror.py
@@ -15,31 +15,20 @@
 #"""Version = 2024-12-26 17:00"""
 #-------------------------------------------------------------------------------
 
-import ChConfig
-import ShareDefine
-import PyDataManager
-import PlayerPackData
-import ReadChConfig
+import PlayerViewCache
 import GameWorld
 
 import base64
 import random
+import PyDataManager
 
 ## 执行逻辑
 #  @param curPlayer 当前玩家
 #  @param gmList []
 #  @return None
 def OnExec(curPlayer, gmList):
-    if not gmList:
-        return
-    value = gmList[0]
-    if value == "a":
-        __addFackPackData(gmList[1:])
-    elif value == "d":
-        __delFackPackData()
-    elif value == "p":
-        __printPackData(gmList[1:])
-    return
+    isSendToDB = True
+    return isSendToDB
 
 def OnGetMergeParam(curPlayer):
     return []
@@ -56,89 +45,53 @@
     return
 
 def __addFackPackData(gmList):
-    ## 添加假的打包数据,一般用于开发测试功能用
-    FakeName = "假名字".decode(ShareDefine.Def_Game_Character_Encoding).encode(GameWorld.GetCharacterEncoding())
-    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
-    #GameWorld.DebugAnswer(curPlayer, "添加镜像: PlayerMirror a 个数 [起始ID 战力 区服ID 模版key]")
+    ## 添加假的打包数据,一般用于开发测试功能用,打包数据在db添加,GameServer添加查看缓存
+    #GameWorld.DebugAnswer(None, "跨服GameServer玩家查看数据数:%s" % PyDataManager.GetPlayerViewCachePyManager().GetCount())
+    #return
     addCount = gmList[0] if len(gmList) > 0 else 1
     startID = gmList[1] if len(gmList) > 1 else 1
     fightPower = gmList[2] if len(gmList) > 2 else 0
     serverID = gmList[3] if len(gmList) > 3 else 0
-    packDataTempKey = gmList[4] if len(gmList) > 4 else ""
-    
-    jobFackPackDataDict = ReadChConfig.GetEvalChConfig("FackPackData")
+    #packDataTempKey = gmList[4] if len(gmList) > 4 else ""
     
     addOKCount = 0
     for index in range(addCount):
         fackID = startID + index
-        if packDataMgr.IsPlayerIn(fackID):
+        curCache = PlayerViewCache.FindViewCache(fackID, True)
+        if not curCache:
             continue
+        propDict = PlayerViewCache.GetCachePropDataDict(curCache)
         
-        job = random.randint(1, 2)
-        tempKey = packDataTempKey if packDataTempKey else "job%s" % job
-        if tempKey not in jobFackPackDataDict:
-            GameWorld.DebugAnswer(None, "配置FackPackData.txt没有该模版key:%s" % tempKey)
-            return
-        packDataTeam = jobFackPackDataDict[tempKey]
-        packDataTeamBuff = base64.b64decode(packDataTeam)
-        
-        tempDBPlayer = PlayerPackData.GetDBPlayerByPackData(packDataTeam)
-        tempDBPlayer.PlayerID = fackID
-        tempDBPlayer.PlayerName = "%s%s" % (FakeName, fackID)
-        curServerID = serverID if serverID else fackID / 100
-        if not curServerID:
-            curServerID = 9999
-        tempDBPlayer.AccID = "fack%s@test@s%s" % (fackID, curServerID)
-        # 没有指定模版,则随机数据
-        if not packDataTempKey:
-            tempDBPlayer.Job = job
-            tempDBPlayer.LV = random.randint(tempDBPlayer.LV, tempDBPlayer.LV + 2)
-            tempDBPlayer.OfficialRank = random.randint(tempDBPlayer.OfficialRank, tempDBPlayer.OfficialRank + 2)
+        if serverID:
+            propDict["AccID"] = "fake%s@test@s%s" % (fackID, serverID)
             
-        curFightPower = fightPower if fightPower else (tempDBPlayer.FightPowerEx * ChConfig.Def_PerPointValue + tempDBPlayer.FightPower)
-        curFightPower += index
-        tempDBPlayer.FightPower = curFightPower % ChConfig.Def_PerPointValue
-        tempDBPlayer.FightPowerEx = curFightPower / ChConfig.Def_PerPointValue
-        
-        updBuff = tempDBPlayer.getBuffer() + packDataTeamBuff[tempDBPlayer.getLength():]
-        updPackData = base64.b64encode(updBuff)
-        packDataMgr.UpdPlayerPackData(fackID, updPackData)
+        if fightPower:
+            propDict["FightPower"] = fightPower + index
+            
         addOKCount += 1
         
-    packDataMgr.Sort()
-    
-    GameWorld.DebugAnswer(None, "添加假玩家打包数据数:%s,总:%s" % (addOKCount, packDataMgr.GetCount()))
+    GameWorld.DebugAnswer(None, "跨服GameServer添加假玩家查看数据数:%s,%s~%s,总:%s" 
+                          % (addOKCount, startID, fackID, PyDataManager.GetPlayerViewCachePyManager().GetCount()))
     return
 
 def __delFackPackData():
     
     delCount = 0
-    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
-    for index in range(packDataMgr.GetCount())[::-1]:
-        packObj = packDataMgr.At(index)
-        if packObj.playerID >= 10000:
+    cacheMgr = PyDataManager.GetPlayerViewCachePyManager()
+    for index in range(cacheMgr.GetCount())[::-1]:
+        viewCache = cacheMgr.At(index)
+        if viewCache.PlayerID >= 10000:
             continue
-        packDataMgr.DelPlayerPackData(packObj.playerID)
+        cacheMgr.DelPlayerViewCache(viewCache.PlayerID)
         delCount += 1
         
-    GameWorld.DebugAnswer(None, "删除假玩家打包数据数:%s,剩:%s" % (delCount, packDataMgr.GetCount()))
+    GameWorld.DebugAnswer(None, "删除假玩家数据数:%s" % delCount)
     return
 
 def __printPackData(gmList):
-    startIndex = gmList[0] if len(gmList) > 0 else 0
-    printCount = gmList[1] if len(gmList) > 1 else 100
-    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
-    packDataMgr.Sort()
-    dataCount = packDataMgr.GetCount()
-    GameWorld.DebugLog("=== 打包数据总数: dataCount=%s,startIndex=%s" % (dataCount, startIndex))
-    for index in range(startIndex, startIndex + printCount):
-        if index >= dataCount:
-            break
-        packObj = packDataMgr.At(index)
-        playerID = packObj.playerID
-        fightPower = packObj.fightPower
-        serverID = packObj.serverID
-        GameWorld.DebugLog("index=%s,playerID=%s,serverID=%s,fightPower=%s,%s" % (index, playerID, serverID, fightPower, packObj.GetBaseDict()))
-    GameWorld.DebugAnswer(None, "输出完毕详见GameServer日志!总:%s" % (dataCount))
+    GameWorld.DebugAnswer(None, "跨服GameServer缓存条数:%s,打包条数:%s" 
+                          % (PyDataManager.GetPlayerViewCachePyManager().GetCount(), 
+                             PyDataManager.GetDBPlayerPackDataManager().GetCount()
+                             ))
     return
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py
index a9dfa02..c7b5484 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/GMShell.py
@@ -102,7 +102,7 @@
             callFunc = GameWorld.GetExecFunc(Commands, "%s.%s"%(callFunName, "OnGetMergeParam"))
             if callFunc != None:
                 extendParamList = callFunc(curPlayer)
-                CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_GMCMD, alist + extendParamList)
+                CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_GMCMD, {"cmdMsgList":alist + extendParamList})
                 
         callFunc = GameWorld.GetExecFunc(Commands, "%s.%s"%(callFunName, "OnExec"))
         if callFunc == None:
@@ -111,8 +111,11 @@
             GameWorld.DebugAnswer(curPlayer, 'no cmd !!!')
             return
         
-        callFunc(curPlayer, alist[1:])
-        
+        isSendToDB = callFunc(curPlayer, alist[1:])
+        if isSendToDB:
+            msg = str(alist)
+            GameWorld.GetGameWorld().SendDBLogic(ChConfig.gstDBLogic_GMCmd, 0, msg, len(msg))
+            
     except BaseException:
         GameWorld.DebugAnswer(curPlayer, "执行GM命令错误, 请查看GameServer日志!")
         errorMsg = str(traceback.format_exc())
@@ -241,7 +244,12 @@
     return cmdDict
 
 ## 收到子服务器发送的GM命令
-def ClientServerMsg_GMCMD(cmdMsgList, tick):
+def ClientServerMsg_GMCMD(msgData, tick):
+    cmdMsgList = msgData["cmdMsgList"]
+    dbAnswerList = msgData.get("dbAnswerList", [])
+    for dbAnswer in dbAnswerList:
+        GameWorld.DebugAnswer(None, dbAnswer)
+        
     if len(cmdMsgList) == 0:
         return 
     
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
index d7ad0ea..3bdf3f6 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py
@@ -1248,6 +1248,13 @@
     text = text.decode(ShareDefine.Def_Game_Character_Encoding).encode(GetCharacterEncoding())
     if curPlayer:
         curPlayer.DebugAnswer(text)
+    else:
+        playerManager = GetPlayerManager()
+        for i in xrange(playerManager.GetActivePlayerCount()):
+            player = playerManager.GetActivePlayerAt(i)
+            if player == None:
+                continue
+            player.DebugAnswer(text)
     return
 
 def CrossServerMsg_DebugAnswer(msgData):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossChampionship.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossChampionship.py
index 294786f..6caac90 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossChampionship.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossChampionship.py
@@ -353,19 +353,6 @@
     if not obj or not hasattr(obj, "playerName"):
         return
     
-    packDataObj = PyDataManager.GetDBPlayerPackDataManager().GetPlayerPackObj(playerID)
-    # 如果有打包数据,以打包数据为准
-    if packDataObj:
-        obj.accID = packDataObj.accID
-        obj.playerName = packDataObj.playerName
-        obj.job = packDataObj.job
-        obj.lv = packDataObj.lv
-        obj.fightPower = packDataObj.fightPower
-        obj.realmLV = packDataObj.realmLV
-        obj.face = packDataObj.face
-        obj.facePic = packDataObj.facePic
-        return
-    
     if playerID < 10000:
         if obj.playerName:
             return
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmPK.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmPK.py
index af170b4..5fe4e8d 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmPK.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmPK.py
@@ -22,6 +22,7 @@
 import ChPyNetSendPack
 import PyGameDataStruct
 import PlayerDBGSEvent
+import PlayerViewCache
 import CrossBillboard
 import PyDataManager
 import NetPackCommon
@@ -450,9 +451,10 @@
     playerID = playerInfoDict["playerID"] # 角色ID
     fightPower = playerInfoDict["fightPower"]
     requestType = playerInfoDict.get("requestType", 0)
+    gmMatchIDList = playerInfoDict.get("gmMatchIDList", [])
     
     isRefresh = requestType == 1
-    OnRefreshPKMatch(zoneID, seasonID, playerID, fightPower, serverGroupID, isRefresh)
+    OnRefreshPKMatch(zoneID, seasonID, playerID, fightPower, serverGroupID, isRefresh, gmMatchIDList)
     return
 
 def ClientServerMsg_PKOver(serverGroupID, playerInfoDict, tick):
@@ -512,9 +514,8 @@
     
     # 通知子服
     pkScore = updScore
-    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
-    tagPackObj = packDataMgr.GetPlayerPackObj(tagPlayerID)
-    tagPlayerName = tagPackObj.playerName if tagPackObj else ""
+    tagCacheDict = PlayerViewCache.GetCachePropDataDict(PlayerViewCache.FindViewCache(tagPlayerID))
+    tagPlayerName = tagCacheDict.get("Name", "")
     winnerID = playerID if isWinner else tagPlayerID
     timeStr = GameWorld.GetCurrentDataTimeStr()
     playerOverDict = {}
@@ -526,30 +527,27 @@
     OnRefreshPKMatch(zoneID, seasonID, playerID, fightPower, serverGroupID, True)
     return
 
-def OnRefreshPKMatch(zoneID, seasonID, playerID, fightPower, serverGroupID, isRefresh):
+def OnRefreshPKMatch(zoneID, seasonID, playerID, fightPower, serverGroupID, isRefresh, gmMatchIDList=None):
     # 刷新匹配数据
     # @param isRefresh: 是否强制重新刷新
     
     if isRefresh or playerID not in PyGameData.g_crossPKMatchDict:
         # 执行匹配逻辑
-        matchIDList = __DoPKMatch(zoneID, seasonID, playerID, fightPower)
-        if matchIDList: # 有新结果才替换
-            PyGameData.g_crossPKMatchDict[playerID] = matchIDList
-            
-    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
+        __DoPKMatch(zoneID, seasonID, playerID, fightPower, gmMatchIDList)
+        
     matchIDList = PyGameData.g_crossPKMatchDict.get(playerID, [])
     matchInfoDict = {}
     for matchID in matchIDList:
-        packObj = packDataMgr.GetPlayerPackObj(matchID)
-        if not packObj:
+        viewCache = PlayerViewCache.FindViewCache(matchID)
+        if not viewCache:
             continue
-        matchInfoDict[matchID] = packObj.GetBaseDict()
+        matchInfoDict[matchID] = viewCache.getBuffer()
         
     dataMsg = {"playerID":playerID, "matchIDList":matchIDList, "matchInfoDict":matchInfoDict}
     CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PKMatchReqRet, dataMsg, [serverGroupID])
     return
 
-def __DoPKMatch(zoneID, seasonID, playerID, fightPower):
+def __DoPKMatch(zoneID, seasonID, playerID, fightPower, gmMatchIDList=None):
     ## 执行匹配
     
     if not IsCrossRealmPKMatchState():
@@ -630,12 +628,22 @@
         matchIDList[-1] = robotID
         GameWorld.DebugLog("没有匹配到机器人,概率直接匹配到机器人: robotID=%s" % robotID, playerID)
         
-    GameWorld.DebugLog("最终匹配结果: matchIDList=%s" % str(matchIDList), playerID)
+    #GM指定匹配
+    if gmMatchIDList:
+        GameWorld.DebugLog("GM指定匹配目标玩家ID: gmMatchIDList=%s" % gmMatchIDList, playerID)
+        for gmMatchID in gmMatchIDList:
+            if matchIDList:
+                matchIDList.pop(0)
+            matchIDList.append(gmMatchID)
+                
+    GameWorld.DebugLog("最终匹配结果: matchIDList=%s" % str(matchIDList), playerID)    
+    if matchIDList: # 有新结果才替换
+        PyGameData.g_crossPKMatchDict[playerID] = matchIDList
     return matchIDList
 
 def __addRandMatchID(playerID, matchIndex, rankRange, randIDList, matchIDList, loopPlayerIDList, sign):
     ## 根据所有可循环玩家ID列表,添加对应匹配轮次可随机匹配的玩家
-    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
+    pyViewCacheMgr = PyDataManager.GetPlayerViewCachePyManager()
     indexStart = matchIndex * rankRange
     indexEnd = indexStart + rankRange - 1
     loopIDCount = len(loopPlayerIDList)
@@ -653,8 +661,8 @@
         if dataID in matchIDList:
             GameWorld.DebugLog("        不可添加已匹配过玩家: dataID=%s,randIDList=%s,matchIDList=%s" % (dataID, randIDList, matchIDList), playerID)
             continue
-        if not packDataMgr.IsPlayerIn(dataID):
-            GameWorld.DebugLog("        不匹配无打包数据玩家: dataID=%s,randIDList=%s" % (dataID, randIDList), playerID)
+        if not pyViewCacheMgr.IsPlayerIn(dataID):
+            GameWorld.DebugLog("        不匹配无缓存数据玩家: dataID=%s,randIDList=%s" % (dataID, randIDList), playerID)
             continue
         randIDList.append(dataID)
         GameWorld.DebugLog("        添加可以随机匹配玩家: dataID=%s,randIDList=%s" % (dataID, randIDList), playerID)
@@ -666,10 +674,9 @@
     crossZoneName = GameWorld.GetCrossZoneName()
     zoneIpyData = IpyGameDataPY.GetIpyGameData("CrossZonePK", crossZoneName, zoneID)
     if zoneIpyData:
-        packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
-        packDataMgr.Sort()
         serverIDList = zoneIpyData.GetServerGroupIDList()
-        zonePackPlayerIDList = packDataMgr.GetPlayerIDListByServerIDInfo(zoneIpyData.GetServerGroupIDList())
+        pyViewCacheMgr = PyDataManager.GetPlayerViewCachePyManager()
+        zonePackPlayerIDList = pyViewCacheMgr.GetPlayerIDListByServerIDInfo(serverIDList)
         GameWorld.DebugLog("    获得赛区活跃打包数据玩家: zoneID=%s,serverIDList=%s,%s,%s" 
                            % (zoneID, serverIDList, len(zonePackPlayerIDList), zonePackPlayerIDList), playerID)
         return zonePackPlayerIDList
@@ -824,22 +831,27 @@
     matchOKPack.MatchPlayer = []
     for matchID in matchIDList:
         matchPlayer = ChPyNetSendPack.tagGCCrossRealmPKMatchPlayer()
-        if matchID not in matchInfoDict:
-            matchPlayer.PlayerID = matchID
-            matchOKPack.MatchPlayer.append(matchPlayer)
-            continue
-        matchInfo = matchInfoDict[matchID]
-        matchPlayer.PlayerID = matchInfo["playerID"]
-        matchPlayer.PlayerName = matchInfo["playerName"]
-        matchPlayer.NameLen = len(matchPlayer.PlayerName)
-        matchPlayer.Job = matchInfo["job"]
-        matchPlayer.LV = matchInfo["lv"]
-        matchPlayer.RealmLV = matchInfo["realmLV"]
-        matchPlayer.Face = matchInfo["face"]
-        matchPlayer.FacePic = matchInfo["facePic"]
-        matchPlayer.FightPower = matchInfo["fightPower"] % ChConfig.Def_PerPointValue
-        matchPlayer.FightPowerEx = matchInfo["fightPower"] / ChConfig.Def_PerPointValue
+        matchPlayer.PlayerID = matchID
         matchOKPack.MatchPlayer.append(matchPlayer)
+        if matchID not in matchInfoDict:
+            continue
+        cacheBuffer = matchInfoDict[matchID]
+        curCache = PlayerViewCache.ReadCacheBufferToCacheObj(matchID, cacheBuffer)
+        if not curCache:
+            continue
+        PlayerViewCache.Sync_PlayerCache(curPlayer, curCache)
+        cacheDict = PlayerViewCache.GetCachePropDataDict(curCache) 
+        matchPlayer.PlayerID = matchID
+        matchPlayer.PlayerName = cacheDict.get("Name", "")
+        matchPlayer.NameLen = len(matchPlayer.PlayerName)
+        matchPlayer.Job = cacheDict.get("Job", 1)
+        matchPlayer.LV = cacheDict.get("LV", 1)
+        matchPlayer.RealmLV = cacheDict.get("RealmLV", 0)
+        matchPlayer.Face = cacheDict.get("Face", 0)
+        matchPlayer.FacePic = cacheDict.get("FacePic", 0)
+        matchPlayer.FightPower = cacheDict.get("FightPower", 0) % ChConfig.Def_PerPointValue
+        matchPlayer.FightPowerEx = cacheDict.get("FightPower", 0) / ChConfig.Def_PerPointValue
+        #matchOKPack.MatchPlayer.append(matchPlayer)
     matchOKPack.MatchPlayerCount = len(matchOKPack.MatchPlayer)
     NetPackCommon.SendFakePack(curPlayer, matchOKPack)
     return
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/QueryDBLogicResult.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/QueryDBLogicResult.py
index b58cd0b..d8aca7c 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/QueryDBLogicResult.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/QueryDBLogicResult.py
@@ -9,6 +9,7 @@
 import PlayerPackData
 import IPY_GameServer
 import ChConfig
+import GameWorld
 
 #-------------------------------------------------------------------------
 
@@ -36,11 +37,16 @@
         return
     queryType = dbResultPack.GetQueryType()
     
-    if queryType == ChConfig.gstDBLogic_PlayerPackData:
+    if queryType == ChConfig.gstDBLogic_PlayerPackDataReq:
         mirrorID = dbResultPack.GetID()
         playerData = dbResultPack.GetResultSet()
         msgInfo = eval(dbResultPack.GetData())
         PlayerPackData.OnDBPlayerPackData(mirrorID, playerData, msgInfo)
         
+    elif queryType == ChConfig.gstDBLogic_GMCmd:
+        dbAnswerList = eval(dbResultPack.GetResultSet())
+        for dbAnswer in dbAnswerList:
+            GameWorld.DebugAnswer(None, dbAnswer)
+            
     return
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py
index 49e8ab3..8775a48 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerPackData.py
@@ -24,25 +24,25 @@
 #            如切磋一下,玩家可以在任意场景对任意本服或跨服玩家发起切磋,与其镜像进行一场友谊PK,纯娱乐
 #            这种为被动式,即目标玩家可能不存在打包数据表中,需要取拉取
 #
+# 由于打包数据较大,影响开关服及备档的速度,还会导致内存不足,故改为db直接管理打包数据获取及入库
+# GameServer仅保留单次启动后有同步/获取的玩家数据,一般比db少,只保留打包数据信息,玩家基本信息改为从ViewCahce中获取
 #-------------------------------------------------------------------------------
 #"""Version = 2024-10-17 15:00"""
 #-------------------------------------------------------------------------------
 
-import CommFunc
 import GameWorld
 import PyDataManager
 import PlayerViewCache
 import PyGameDataStruct
-import CrossChampionship
 import CrossRealmMsg
 import PlayerControl
 import ShareDefine
 import PyGameData
 import ChConfig
 
-import time
 import base64
 
+Def_CahceCountMax = 100 # 最大缓存个数,注:GameServer缓不缓存这个数据都无所谓(改为在db缓存),保留原取数据逻辑不变,暂时缓存个x条,方便本服的直接取
 TempDBPlayer = PyGameDataStruct.tagDBPlayer()
 
 def GetDBPlayerByPackData(packData):
@@ -51,249 +51,48 @@
     if packData:
         TempDBPlayer.readData(base64.b64decode(packData))
     return TempDBPlayer
-
-class PlayerPackDataObj():
-    
-    def __init__(self):
-        self.dbPlayerPackData = None
-        self.playerID = 0
-        self.playerName = ""
-        self.accID = ""
-        self.lv = 0
-        self.job = 0
-        self.realmLV = 0
-        self.face = 0
-        self.facePic = 0
-        self.fightPower = 0
-        self.serverID = 0
-        return
-    
-    def GetBaseDict(self):
-        return {"playerID":self.playerID, "playerName":self.playerName, "lv":self.lv, "job":self.job, 
-                "realmLV":self.realmLV, "face":self.face, "facePic":self.facePic, "fightPower":self.fightPower}
-        
-    def UpdPackData(self, packData):
-        if not packData:
-            return
-        if not self.dbPlayerPackData:
-            self.dbPlayerPackData = PyGameDataStruct.tagDBPlayerPackData()
-        self.dbPlayerPackData.PlayerID = self.playerID
-        self.dbPlayerPackData.PackData = packData
-        self.dbPlayerPackData.PackDataSize = len(self.dbPlayerPackData.PackData)
-        self.dbPlayerPackData.UpdTime = int(time.time())
-        self.Unpack()
-        return
-    
-    def Unpack(self):
-        if not self.dbPlayerPackData:
-            return
-        dbPlayer = GetDBPlayerByPackData(self.dbPlayerPackData.PackData)
-        self.playerID = dbPlayer.PlayerID
-        self.accID = dbPlayer.AccID
-        self.playerName = dbPlayer.PlayerName
-        self.lv = dbPlayer.LV
-        self.job = dbPlayer.Job
-        self.realmLV = dbPlayer.OfficialRank
-        self.face = dbPlayer.Face
-        self.facePic = dbPlayer.FacePic
-        self.fightPower = dbPlayer.FightPowerEx * ChConfig.Def_PerPointValue + dbPlayer.FightPower
-        self.serverID = GameWorld.GetAccIDServerID(self.accID)
-        return
-    
-    def GetPackData(self): return self.dbPlayerPackData.PackData if self.dbPlayerPackData else ""
-    def GetUpdTime(self): return self.dbPlayerPackData.UpdTime if self.dbPlayerPackData else 0
     
 class DBPlayerPackDataManager():
-    ## 玩家打包数据管理
+    ## 玩家打包数据管理 - 这里仅管理本次启动后的热数据缓存,不入库
     
     def __init__(self):
         self.Clear()
         return
     
     def Clear(self):
-        self.__packDataList = [] # [PlayerPackDataObj, ...]
-        self.__idIndexDict = {} # {playerID:index, ...}
-        self.__needSort = False
-        self.__serverIDRangePlayerIDDict = {} # {serverIDRangeTuple:[playerID, ...], ....}
+        self.__packDataDcit = {} # {playerID:packData, ...}
+        self.__packDataPlayerIDList = [] # [playerID, ...] # 限制缓存数,先进先出
         return
-    
-    def GetPlayerPackObj(self, playerID, isAddNew=False):
-        packDataObj = None
-        self.__refreshIDIndex()
-        if playerID in self.__idIndexDict:
-            index = self.__idIndexDict[playerID]
-            if index < len(self.__packDataList):
-                packDataObj = self.__packDataList[index]
-                
-        if not packDataObj and isAddNew:
-            packDataObj = PlayerPackDataObj()
-            packDataObj.playerID = playerID
-            self.__packDataList.append(packDataObj)
-            self.__idIndexDict[playerID] = len(self.__packDataList) - 1
-            self.__needSort = True
-            
-        return packDataObj
-    
-    def GetPlayerIDListByServerIDInfo(self, serverIDList):
-        ## 根据服务器ID列表信息获取对应服务器ID范围的玩家ID战力排序列表
-        self.Sort()
-        key = tuple(serverIDList)
-        if key not in self.__serverIDRangePlayerIDDict:
-            playerIDList = []
-            for dataObj in self.__packDataList:
-                playerID = dataObj.playerID
-                serverID = dataObj.serverID
-                for idInfo in serverIDList:
-                    if (isinstance(idInfo, int) and serverID == idInfo) \
-                        or ((isinstance(idInfo, tuple) or isinstance(idInfo, list)) \
-                            and len(idInfo) == 2 and idInfo[0] <= serverID <= idInfo[1]):
-                        playerIDList.append(playerID)
-            GameWorld.DebugLog("重新加载区服打包玩家ID列表: %s, %s, %s" % (key, len(playerIDList), playerIDList))
-            self.__serverIDRangePlayerIDDict[key] = playerIDList
-        return self.__serverIDRangePlayerIDDict[key]
-    
+        
     def IsPlayerIn(self, playerID):
-        self.__refreshIDIndex()
-        return playerID in self.__idIndexDict
+        return playerID in self.__packDataDcit
     
-    def __refreshIDIndex(self):
-        if not self.__idIndexDict:
-            self.__idIndexDict = {}
-            for index, dataObj in enumerate(self.__packDataList):
-                self.__idIndexDict[dataObj.playerID] = index
-        return self.__idIndexDict
+    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.UpdPackData(packData)
-        self.__needSort = True
-        return packObj
-    
-    def DelPlayerPackData(self, playerID):
-        self.__refreshIDIndex()
-        index = self.__idIndexDict.pop(playerID, -1)
-        if index >= 0 and index < len(self.__packDataList):
-            self.__packDataList.pop(index)
-        for playerIDList in self.__serverIDRangePlayerIDDict.values():
-            if playerID in playerIDList:
-                playerIDList.remove(playerID)
-                
-        #只要有删除,需重置index映射
-        self.__idIndexDict = {}
-        self.__serverIDRangePlayerIDDict = {}
+        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
-    
-    def GetCount(self): return len(self.__packDataList)    
-    def At(self, index):
-        dataObj = self.__packDataList[index]
-        if not dataObj and False:
-            dataObj = PlayerPackDataObj() # 不会执行到,只为了.出代码提示
-        return dataObj
-    
-    def Sort(self):
-        ## 默认按战力倒序排
-        if not self.__needSort:
-            return
-        self.__needSort = False
-        self.__packDataList.sort(key=lambda d: (d.fightPower), reverse=True)
-        self.__idIndexDict = {}
-        self.__serverIDRangePlayerIDDict = {}
-        self.__refreshIDIndex()
-        return
-    
-    # 保存数据 存数据库和realtimebackup
-    def GetSaveData(self):
-        savaData = ""
-        cntData = ""
-        cnt = 0
-        
-        for index in xrange(self.GetCount()):
-            dataObj = self.At(index)
-            if not dataObj.dbPlayerPackData:
-                continue
-            cnt += 1
-            savaData += dataObj.dbPlayerPackData.getBuffer()
-            if cnt >= 10:
-                break
-            
-        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)
-            playerID = dbData.PlayerID
-            
-            packObj = self.GetPlayerPackObj(playerID, True)
-            packObj.dbPlayerPackData = dbData
-            packObj.Unpack()
-            
-        self.Sort()
-        return pos
-
-def IsSaveDB(packDataObj):
-    ## 是否入库
-    if not packDataObj:
-        return False
-    
-    playerID = packDataObj.playerID
-    
-    if CrossChampionship.IsChampionshipPlayer(playerID):
-        return True
-    
-    #跨服榜单上的默认保留
-    if GameWorld.IsCrossServer():
-        billboardMgr = PyDataManager.GetCrossBillboardManager()
-        for billboardType in ShareDefine.CrossBillboardTypeList:
-            groupList = billboardMgr.GetBillboardGroupList(billboardType)
-            for billboardType, groupValue1, groupValue2 in groupList:
-                billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
-                if billboardObj.FindByID(playerID):
-                    return True
-                
-    else:
-        pass
-#        NeedCheckBillBoardType = IpyGameDataPY.GetFuncEvalCfg("PlayerViewCache", 2)
-#        #校验玩家是否上排行榜
-#        billboardMgr = GameWorld.GetBillboard()
-#        for BillBoardType in NeedCheckBillBoardType:
-#            curBillboard = billboardMgr.FindBillboard(BillBoardType)
-#            if not curBillboard:
-#                continue
-#            if curBillboard.FindByID(playerID):
-#                return True
-            
-    # 以上是相关功能需要用到的数据,必定不能删除的
-    
-    maxDays = 7 # 默认7天
-    MaxTime = maxDays * 3600 * 24
-    curTime = int(time.time())
-    passTime = curTime - packDataObj.GetUpdTime()
-    if passTime < MaxTime:
-        return True
-    
-    return False
-
-def DelOutofTimePackData():
-    ## 删除过期
-    
-    packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
-    for index in range(packDataMgr.GetCount())[::-1]: # 可能删数据,倒序遍历
-        packDataObj = packDataMgr.At(index)
-        if IsSaveDB(packDataObj):
-            continue
-        packDataMgr.DelPlayerPackData(packDataObj.playerID)
-        
-    return
 
 def IsPackDataPlayer(playerID):
     return PyDataManager.GetDBPlayerPackDataManager().IsPlayerIn(playerID)
@@ -341,6 +140,7 @@
     
     # pullFrom 0-跨服拉子服; >0-子服通过跨服拉子服
     if GameWorld.IsCrossServer():
+        PlayerViewCache.SetNeedViewCache(pullPlayerIDList) # 拉打包数据的时候默认需要缓存数据
         # 广播给子服拉数据
         msgInfo["pullFrom"] = 0
         dataMsg = {"pullPlayerIDList":pullPlayerIDList, "msgInfo":msgInfo}
@@ -371,7 +171,7 @@
     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)
     # 在线的转发给地图
@@ -442,9 +242,6 @@
     ## 收到子服同步的玩家打包数据
     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", {})
@@ -469,21 +266,23 @@
     
     msgInfo = msgData["msgInfo"]
     pullPlayerIDList = msgData["pullPlayerIDList"]
+    dbPackDataIDList = msgData.get("dbPackDataIDList", []) # db标记的有打包数据的玩家ID
     
     otherServerPlayerIDList = []
     packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
     for playerID in pullPlayerIDList:
-        packObj = packDataMgr.GetPlayerPackObj(playerID)
+        packData = packDataMgr.GetPlayerPackdata(playerID)
         # 已经有的数据先推送回去
-        if packObj:
-            GameWorld.DebugLog("跨服有缓存玩家打包数据,直接推给子服! playerID=%s" % playerID)
-            dataMsg = {"playerID":playerID, "packData":packObj.GetPackData(), "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)
         
@@ -508,10 +307,10 @@
     
     packDataMgr = PyDataManager.GetDBPlayerPackDataManager()
     for playerID in pullPlayerIDList:
-        packObj = packDataMgr.GetPlayerPackObj(playerID)
-        if packObj:
+        packData = packDataMgr.GetPlayerPackdata(playerID)
+        if packData:
             GameWorld.DebugLog("本服有缓存玩家打包数据,直接推给跨服! playerID=%s" % playerID)
-            dataMsg = {"playerID":playerID, "packData":packObj.GetPackData(), "msgInfo":msgInfo}
+            dataMsg = {"playerID":playerID, "packData":packData, "msgInfo":msgInfo}
             CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PlayerPackData, dataMsg)
         else:
             DoPullPlayerPackData(playerID, msgInfo)
@@ -541,14 +340,14 @@
     if not packDataSyncState or not packData:
         return
     
-    # 本服需要,先更新数据
-    if packDataSyncState&pow(2, 0):
+    # 本服需要,先更新数据;跨服需要则也默认本服需要
+    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&pow(2, 1):
-        cacheBase = PlayerViewCache.GetSyncCrossCacheBase(curPlayer) if curPlayer else {}
-        dataMsg = {"playerID":playerID, "packData":packData, "cacheBase":cacheBase, "msgInfo":msgInfo}
+        dataMsg = {"playerID":playerID, "packData":packData, "msgInfo":msgInfo}
         CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PlayerPackData, dataMsg)
         
     # 本服需要的功能
@@ -585,9 +384,9 @@
     requestID = msgInfo["requestID"]
     mirrorIDList = msgInfo["mirrorIDList"]
     for mirrorID in mirrorIDList:
-        packObj = packDataMgr.GetPlayerPackObj(mirrorID)
-        if packObj:
-            packDataDict[mirrorID] = packObj.GetPackData()
+        packData = packDataMgr.GetPlayerPackdata(mirrorID)
+        if packData:
+            packDataDict[mirrorID] = packData
             continue
         pullPlayerIDList.append(mirrorID)
         
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
index ee23ee1..7620a80 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
@@ -37,6 +37,7 @@
 import CrossRealmMsg
 import ShareDefine
 import PyGameData
+import CommFunc
 import ChPlayer
 import ChConfig
 
@@ -46,6 +47,146 @@
 
 TempCache = PyGameDataStruct.tagPlayerViewCachePy()
 
+#玩家缓存管理,该类只做数据缓存存取,不写功能逻辑,防止重读脚本时功能逻辑脚本不生效
+class PlayerViewCachePyManager(object):
+    
+    def __init__(self):
+        self.__viewCacheList = [] # [tagPlayerViewCachePy, ...]
+        self.__idIndexDict = {} # {playerID:index, ...}
+        self.__needSort = False
+        self.__serverIDRangePlayerIDDict = {} # {serverIDRangeTuple:[playerID, ...], ....}
+        return
+    
+    def GetPlayerViewCache(self, playerID):
+        self.__refreshIDIndex()
+        viewCache = None
+        if playerID in self.__idIndexDict:
+            index = self.__idIndexDict[playerID]
+            if index < len(self.__viewCacheList):
+                viewCache = self.__viewCacheList[index]
+                
+        return viewCache
+    
+    def AddPlayerViewCache(self, playerID, viewCache):
+        self.__refreshIDIndex()
+        if playerID in self.__idIndexDict:
+            return
+        viewCache.PlayerID = playerID
+        self.__viewCacheList.append(viewCache)
+        self.__idIndexDict[playerID] = len(self.__viewCacheList) - 1
+        self.__needSort = True
+        return
+    
+    def GetPlayerIDListByServerIDInfo(self, serverIDList):
+        ## 根据服务器ID列表信息获取对应服务器ID范围的玩家ID战力排序列表
+        if serverIDList == None:
+            return []
+        self.Sort()
+        key = tuple(serverIDList)
+        if key not in self.__serverIDRangePlayerIDDict:
+            playerIDList = []
+            for viewCache in self.__viewCacheList:
+                playerID = viewCache.PlayerID
+                cacheDict = GetCachePropDataDict(viewCache)
+                if not cacheDict:
+                    continue
+                serverID = GameWorld.GetAccIDServerID(cacheDict["AccID"])
+                for idInfo in serverIDList:
+                    if (isinstance(idInfo, int) and serverID == idInfo) \
+                        or ((isinstance(idInfo, tuple) or isinstance(idInfo, list)) \
+                            and len(idInfo) == 2 and idInfo[0] <= serverID <= idInfo[1]):
+                        playerIDList.append(playerID)
+            GameWorld.DebugLog("重新加载区服玩家查看缓存ID列表: %s, %s, %s" % (key, len(playerIDList), playerIDList))
+            self.__serverIDRangePlayerIDDict[key] = playerIDList
+        return self.__serverIDRangePlayerIDDict[key]
+    
+    def IsPlayerIn(self, playerID):
+        self.__refreshIDIndex()
+        return playerID in self.__idIndexDict
+    
+    def __refreshIDIndex(self):
+        if not self.__idIndexDict:
+            self.__idIndexDict = {}
+            for index, viewCache in enumerate(self.__viewCacheList):
+                self.__idIndexDict[viewCache.PlayerID] = index
+        return self.__idIndexDict
+    
+    def DelPlayerViewCache(self, playerID):
+        self.__refreshIDIndex()
+        index = self.__idIndexDict.pop(playerID, -1)
+        if index >= 0 and index < len(self.__viewCacheList):
+            self.__viewCacheList.pop(index)
+        for playerIDList in self.__serverIDRangePlayerIDDict.values():
+            if playerID in playerIDList:
+                playerIDList.remove(playerID)
+                
+        self.__idIndexDict = {}
+        self.__serverIDRangePlayerIDDict = {}
+        return
+    
+    def GetCount(self): return len(self.__viewCacheList)    
+    def At(self, index):
+        viewCache = self.__viewCacheList[index]
+        if not viewCache and False:
+            viewCache = PyGameDataStruct.tagPlayerViewCachePy() # 不会执行到,只为了.出代码提示
+        return viewCache
+    
+    def Sort(self):
+        ## 默认按战力倒序排
+        if not self.__needSort:
+            return
+        self.__needSort = False
+        self.__viewCacheList.sort(cmp=self.__cmp)
+        self.__idIndexDict = {}
+        self.__serverIDRangePlayerIDDict = {}
+        self.__refreshIDIndex()
+        return
+    
+    def __cmp(self, a, b):
+        ## 按战力倒序, cmp模式排序效率较低,如果需要再改为key模式
+        aFightPower = 0
+        cacheDict = GetCachePropDataDict(a)
+        if cacheDict:
+            aFightPower = cacheDict.get("FightPower", 0)
+            
+        bFightPower = 0
+        cacheDict = GetCachePropDataDict(b)
+        if cacheDict:
+            bFightPower = cacheDict.get("FightPower", 0)
+            
+        return cmp(bFightPower, aFightPower)
+    
+    # 保存数据 存数据库和realtimebackup
+    def GetSaveData(self):
+        savaData = ""
+        cntData = ""
+        cnt = 0
+        
+        for dbData in self.__viewCacheList:
+            #if dbData.PlayerID < 10000:
+                # 假人玩家不存储
+            #    continue
+            cnt += 1
+            savaData += dbData.getBuffer()
+            
+        GameWorld.Log("Save PlayerViewCachePy 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 PlayerViewCachePy count :%s" % cnt)
+        
+        for _ in xrange(cnt):
+            dbData = PyGameDataStruct.tagPlayerViewCachePy()
+            dbData.clear()
+            pos += dbData.readData(datas, pos, dataslen)
+            
+            self.AddPlayerViewCache(dbData.PlayerID, dbData)
+            
+        self.Sort()
+        return pos
+    
 def DoOnDayEx():
     DelOutofTimeViewCacheData()
     return
@@ -129,14 +270,12 @@
 def DelOutofTimeViewCacheData():
     ## 删除过期的查看缓存数据
     
-    PlayerPackData.DelOutofTimePackData()
-    
     pyViewCacheMgr = PyDataManager.GetPlayerViewCachePyManager()
-    playerViewCachePyDict = pyViewCacheMgr.playerViewCachePyDict
-    for playerID, viewCache in playerViewCachePyDict.items():
+    for index in range(pyViewCacheMgr.GetCount())[::-1]: # 有删除需倒序遍历
+        viewCache = pyViewCacheMgr.At(index)
         if IsSaveDBViewCache(viewCache):
             continue
-        playerViewCachePyDict.pop(playerID)
+        pyViewCacheMgr.DelPlayerViewCache(viewCache.PlayerID)
         
     PyGameData.g_crossPlayerViewCache = {} # 每日直接清空跨服玩家查看缓存
     return
@@ -144,50 +283,56 @@
 def DeleteViewCache(playerID):
     ## 删除玩家缓存
     pyViewCacheMgr = PyDataManager.GetPlayerViewCachePyManager()
-    playerViewCachePyDict = pyViewCacheMgr.playerViewCachePyDict
-    playerViewCachePyDict.pop(playerID, None)
+    pyViewCacheMgr.DelPlayerViewCache(playerID)
     GameWorld.DebugLog("删除查看缓存!", playerID)
     return
 
-def FindViewCache(playerID, isAddNew=False, newPropData={}):
+def FindViewCache(playerID, isAddNew=False, newPropData=None):
     ## 查找玩家缓存
     # @param newPropData: 新数据初始PropData {}, key: LV,RealmLV,Job,VIPLV,Name,FamilyID,FamilyName,FightPower
-    curCache = None
     pyViewCacheMgr = PyDataManager.GetPlayerViewCachePyManager()
-    playerViewCachePyDict = pyViewCacheMgr.playerViewCachePyDict
-    if playerID in playerViewCachePyDict:
-        curCache = playerViewCachePyDict[playerID]
+    curCache = pyViewCacheMgr.GetPlayerViewCache(playerID)
+    if curCache:
+        pass
     elif isAddNew or playerID < 10000:
         # 内网测试假玩家
-        if playerID < 10000 and not newPropData:
-            openJobList = IpyGameDataPY.GetFuncEvalCfg("OpenJob", 1)
-            fakeName = "神秘道友".decode(ShareDefine.Def_Game_Character_Encoding).encode(GameWorld.GetCharacterEncoding())
-            fakeName = "%s%s" % (fakeName, playerID)
-            serverID = playerID % 200 + 1 # 1 ~ 200 服
+        if playerID < 10000:
+            if not newPropData:
+                newPropData = {}
+            fakeName = newPropData.get("Name", "")
+            if not fakeName:
+                fakeName = "神秘道友".decode(ShareDefine.Def_Game_Character_Encoding).encode(GameWorld.GetCharacterEncoding())
+                fakeName = "%s%s" % (fakeName, playerID)
+            accID = newPropData.get("AccID", "")
+            if not accID:
+                serverID = playerID % 100 + 1 # 1 ~ 100 服
+                accID = "fake%s@test@s%s" % (playerID, serverID)
+            else:
+                serverID = GameWorld.GetAccIDServerID(accID)
             serverGroupID = serverID
             if serverID < 50:
                 serverGroupID = serverGroupID / 10 + 1 # 前50服每10服1主服
             isOnline = True if playerID % 2 == 0 else False
             olMgr = ChPlayer.GetOnlinePlayerMgr()
             olMgr.SetOnlineState(playerID, isOnline, serverGroupID)
-            accID = "fake%s@test@s%s" % (playerID, serverID)
-            newPropData = {
-                           "AccID":accID, 
-                           "PlayerID":playerID, 
-                           "Name":fakeName, 
-                           "Job":random.choice(openJobList) if openJobList else 1, 
-                           "LV":random.randint(100, 200), 
-                           "RealmLV":random.randint(5, 15),
-                           "FightPower":random.randint(1000000, 100000000), 
-                           "ServerGroupID":serverGroupID,
-                           }
+            
+            job = newPropData.get("Job", 0)
+            if not job:
+                openJobList = IpyGameDataPY.GetFuncEvalCfg("OpenJob", 1)
+                job = random.choice(openJobList) if openJobList else 1
+            lv = newPropData.get("LV", random.randint(100, 200))
+            realmLV = newPropData.get("RealmLV", random.randint(5, 15))
+            fightPower = newPropData.get("FightPower", random.randint(1000000, 100000000))
+            
+            newPropData.update({"AccID":accID, "PlayerID":playerID, "Name":fakeName, "Job":job, "LV":lv, 
+                                "RealmLV":realmLV, "FightPower":fightPower, "ServerGroupID":serverGroupID,})
         curCache = PyGameDataStruct.tagPlayerViewCachePy()
         curCache.PlayerID = playerID
         curCache.OffTime = int(time.time())
         if newPropData:
             curCache.PropData = json.dumps(newPropData, ensure_ascii=False).replace(" ", "")
             curCache.PropDataSize = len(curCache.PropData)
-        playerViewCachePyDict[playerID] = curCache
+        pyViewCacheMgr.AddPlayerViewCache(playerID, curCache)
     return curCache
 
 def GetCachePropDataDict(curCache):
@@ -241,7 +386,7 @@
                  "RealmLV":curPlayer.GetOfficialRank(),
                  "Job":curPlayer.GetJob(),
                  "VIPLV":curPlayer.GetVIPLv(),
-                 "Name":CrossRealmPlayer.GetCrossPlayerName(curPlayer),
+                 "Name":curPlayer.GetName(), # 此处不用跨服名称,如前端需要展示跨服名称,可通过ServerID或AccID取得ServerID展示
                  "Face":curPlayer.GetFace(),
                  "FacePic":curPlayer.GetFacePic(),
                  "FamilyID":curPlayer.GetFamilyID(),
@@ -421,6 +566,19 @@
         OnQueryPlayerCache(curPlayer, tagPlayerID, isShort=1)
     return
 
+def SetNeedViewCache(playerIDList):
+    ## 设置需要缓存数据,跨服专用
+    if not GameWorld.IsCrossServer():
+        return
+    
+    for playerID in playerIDList:
+        curCache = FindViewCache(playerID)
+        if curCache:
+            continue
+        dataMsg = {"tagPlayerID":playerID}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PullPlayerViewCache, dataMsg)
+    return
+
 def OnQueryPlayerCache(curPlayer, tagPlayerID, equipClassLV=0, isShort=0):
     '''查询玩家缓存,支持直接在本服或跨服查询任意服务器玩家
     @param tagPlayerID: 目标玩家ID
@@ -564,7 +722,7 @@
         GameWorld.DebugLog("子服推送的玩家缓存数据为空! playerID=%s" % playerID, serverGroupID)
     else:
         curCache = FindViewCache(playerID, True)
-        __updCacheBufferToCacheObj(playerID, cacheBuffer, curCache)
+        ReadCacheBufferToCacheObj(playerID, cacheBuffer, curCache)
         
     if not msgInfo:
         return
@@ -587,9 +745,10 @@
     Sync_PlayerCache(curPlayer, curCache, equipClassLV, isShort)
     return
 
-def __updCacheBufferToCacheObj(playerID, cacheBuffer, cacheObj):
+def ReadCacheBufferToCacheObj(playerID, cacheBuffer, cacheObj=None):
     try:
         TempCache.clear()
+        setattr(TempCache, "PropDataDict", {})
         if TempCache.readData(cacheBuffer) == -1:
             GameWorld.ErrLog("玩家缓存数据readData失败! playerID=%s" % playerID)
             return
@@ -599,6 +758,9 @@
     if TempCache.PlayerID != playerID:
         GameWorld.ErrLog("玩家缓存数据readData后玩家ID不一致! playerID=%s != cachePlayerID=%s" % (playerID, TempCache.PlayerID))
         return
+    
+    if not cacheObj:
+        return TempCache
     
     cacheObj.PropDataDict = {} # 每次更新数据时,重置字典缓存,下次获取时重新eval缓存
     cacheObj.PlayerID = TempCache.PlayerID
@@ -618,7 +780,7 @@
         setattr(cacheObj, "ItemData%s" % classLV, itemData)
         setattr(cacheObj, "ItemDataSize%s" % classLV, itemDataSize)
         
-    return True
+    return cacheObj
 
 def CrossServerMsg_ViewPlayerCacheRet(msgData, tick):
     ## 收到跨服服务器回复的查看玩家信息
@@ -634,7 +796,7 @@
             curCache = PyGameData.g_crossPlayerViewCache[tagPlayerID][0]
         else:
             curCache = PyGameDataStruct.tagPlayerViewCachePy()
-        if __updCacheBufferToCacheObj(tagPlayerID, cacheBuffer, curCache):
+        if ReadCacheBufferToCacheObj(tagPlayerID, cacheBuffer, curCache):
             PyGameData.g_crossPlayerViewCache[tagPlayerID] = [curCache, tick] # 更新信息
         
     curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
@@ -644,7 +806,7 @@
 
 def CrossServerMsg_PullPlayerViewCache(msgData):
     ## 收到跨服服务器拉取玩家玩家缓存数据
-    msgInfo = msgData["msgInfo"]
+    msgInfo = msgData.get("msgInfo", {})
     tagPlayerID = msgData["tagPlayerID"]
     DoPullPlayerViewCache(tagPlayerID, msgInfo)
     return
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerXMZZ.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerXMZZ.py
index 283e6b7..58a23dc 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerXMZZ.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerXMZZ.py
@@ -648,8 +648,9 @@
         underList2, aboveList2 = [], [] #大范围
         
         pyViewCacheMgr = PyDataManager.GetPlayerViewCachePyManager()
-        playerViewCachePyDict = pyViewCacheMgr.playerViewCachePyDict
-        for playerID, curCache in playerViewCachePyDict.items():
+        for index in range(pyViewCacheMgr.GetCount()):
+            curCache = pyViewCacheMgr.At(index)
+            playerID = curCache.PlayerID
             if myPlayerID == playerID:
                 #不和自己pk
                 continue
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py b/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
index 32db39d..d4581aa 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/PyDataManager.py
@@ -28,6 +28,7 @@
 import PlayerAssist
 import GameRecData
 import PlayerRecData
+import PlayerViewCache
 import GameWorldMineArea
 import PyGameDataStruct
 import PlayerPackData
@@ -134,43 +135,6 @@
                 self.playerAssistDict[PlayerID] = []
             playerAssistList = self.playerAssistDict[PlayerID]
             playerAssistList.append(dbData)
-            
-        return pos
-    
-#玩家缓存管理,该类只做数据缓存存取,不写功能逻辑,防止重读脚本时功能逻辑脚本不生效
-class PlayerViewCachePyManager(object):
-    
-    def __init__(self):
-        self.playerViewCachePyDict = {} # 玩家缓存 {playerID:tagPlayerViewCachePy, ...}
-        return
-    
-    # 保存数据 存数据库和realtimebackup
-    def GetSaveData(self):
-        savaData = ""
-        cntData = ""
-        cnt = 0
-        
-        for dbData in self.playerViewCachePyDict.values():
-            if dbData.PlayerID < 10000:
-                # 假人玩家不存储
-                continue
-            cnt += 1
-            savaData += dbData.getBuffer()
-            
-        GameWorld.Log("Save PlayerViewCachePy 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 PlayerViewCachePy count :%s" % cnt)
-        
-        for _ in xrange(cnt):
-            dbData = PyGameDataStruct.tagPlayerViewCachePy()
-            dbData.clear()
-            pos += dbData.readData(datas, pos, dataslen)
-            
-            self.playerViewCachePyDict[dbData.PlayerID] = dbData
             
         return pos
     
@@ -317,7 +281,7 @@
 
 class PyGameDataManager(object):
     def __init__(self):
-        self.DBPlayerPackDataManager = PlayerPackData.DBPlayerPackDataManager()
+        self.DBPlayerPackDataManager = PlayerPackData.DBPlayerPackDataManager() # 该表GameServer只做内存处理,不从db取,也不发db入库,由db自行处理
         self.DBGameRecDataManager = GameRecData.DBGameRecDataManager()
         self.DBPyFuncTeamManager = PlayerFuncTeam.DBPyFuncTeamManager()
         self.DBPyFuncTeamMemManager = PlayerFuncTeam.DBPyFuncTeamMemManager()
@@ -333,7 +297,7 @@
         self.CrossBillboardManager = CrossBillboard.CrossBillboardManager()
         self.PlayerAssistThanksPyManager = PlayerAssistThanksPyManager()
         self.PlayerAssistPyManager = PlayerAssistPyManager()
-        self.PlayerViewCachePyManager = PlayerViewCachePyManager()
+        self.PlayerViewCachePyManager = PlayerViewCache.PlayerViewCachePyManager()
         self.AuctionAttentionManager = AuctionAttentionManager()
         self.AuctionRecordManager = AuctionRecordManager()
         self.AuctionItemManager = AuctionItemManager()
@@ -354,7 +318,6 @@
 
     def GetSaveData(self):
         buff = ""
-        buff += self.DBPlayerPackDataManager.GetSaveData()
         buff += self.DBGameRecDataManager.GetSaveData()
         buff += self.DBPyFuncTeamManager.GetSaveData()
         buff += self.DBPyFuncTeamMemManager.GetSaveData()
@@ -390,7 +353,6 @@
         return buff
     
     def LoadGameData(self, gameBuffer, pos):
-        pos = self.DBPlayerPackDataManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
         pos = self.DBGameRecDataManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
         pos = self.DBPyFuncTeamManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
         pos = self.DBPyFuncTeamMemManager.LoadPyGameData(gameBuffer, pos, len(gameBuffer))
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/MirrorAttack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/MirrorAttack.py
index 2cec016..83f8293 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/MirrorAttack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/MirrorAttack.py
@@ -37,6 +37,7 @@
 import PlayerState
 import SkillShell
 import CommFunc
+import FBCommon
 import PlayerFB
 import GameMap
 import FBLogic
@@ -115,6 +116,7 @@
         self.stateTick = tick        
         self.stateTickRemain = self.GetStateTickMax()
         self.SyncFBStepTime(tick)
+        FBCommon.SetFBStep(state, tick)
         return
         
     def CaclStateTick(self, tick):
@@ -574,6 +576,11 @@
     if not curPlayer or curPlayer.IsEmpty() or not curPlayer.GetMapLoadOK():
         return
     
+    fbStep = GameWorld.GetGameFB().GetFBStep()
+    if fbStep != ChConfig.Def_MirrorBatState_Init:
+        GameWorld.ErrLog("镜像战斗该阶段已经不能初始化了! fbStep=%s" % fbStep, curPlayer.GetPlayerID())
+        return
+    
     battle = GetMirrorBattle(curPlayer)
     if battle:
         GameWorld.DebugLog("镜像战斗玩家断线重连成功!", curPlayer.GetPlayerID())
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PlayerMirror.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PlayerMirror.py
index b189e3e..e2132aa 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PlayerMirror.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PlayerMirror.py
@@ -34,11 +34,14 @@
         GameWorld.DebugAnswer(curPlayer, "更新镜像: PlayerMirror 5")
         GameWorld.DebugAnswer(curPlayer, "加假数据: PlayerMirror a 个数 [起始ID 战力 区服ID 模版key]")
         GameWorld.DebugAnswer(curPlayer, "删假数据: PlayerMirror d")
-        GameWorld.DebugAnswer(curPlayer, "输出数据: PlayerMirror p [起始索引 个数 ]")
+        #GameWorld.DebugAnswer(curPlayer, "导入数据: PlayerMirror i 模版key账号")
+        #GameWorld.DebugAnswer(curPlayer, "输出数据: PlayerMirror p [起始索引 个数 ]")
         GameWorld.DebugAnswer(curPlayer, "多对多阵营分配ID为前后前后即AABB")
         GameWorld.DebugAnswer(curPlayer, "后台战斗时ID阵营分配为[AABB]")
         GameWorld.DebugAnswer(curPlayer, "切图战斗时ID阵营分配为[自己ABB]")
         GameWorld.DebugAnswer(curPlayer, "玩家ID不填时默认自己跟自己打")
+        GameWorld.DebugAnswer(curPlayer, "模版key:在db/TestPackData文件夹下")
+        
         return
     
     tick = GameWorld.GetGameWorld().GetTick()
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetCrossPK.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetCrossPK.py
index feab5e2..92e7667 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetCrossPK.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetCrossPK.py
@@ -35,6 +35,19 @@
         __PrintHelp(curPlayer)
         return
     
+    if msgList[0] == "m":
+        gmMatchIDList = msgList[1:]
+        dataMsg = {
+                   "requestType":1,
+                   "seasonID":GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKSeasonID), # 赛季ID
+                   "zoneID":GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_CrossPKZoneID), # PK赛区
+                   "playerID":curPlayer.GetPlayerID(),
+                   "fightPower":PlayerControl.GetFightPower(curPlayer),
+                   "gmMatchIDList":gmMatchIDList,
+                   }
+        GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PKMatch, dataMsg)
+        return
+    
     if msgList[0] == "b":        
         zoneID = msgList[1] if len(msgList) > 1 else 0
         seasonID = msgList[2] if len(msgList) > 2 else 0
@@ -139,10 +152,11 @@
     GameWorld.DebugAnswer(curPlayer, "设置数据: SetCrossPK 类型  值")
     GameWorld.DebugAnswer(curPlayer, "类型:0-积分,2-段位,3-PK次数,4-胜利次数,5-连胜次数,6-连败次数")
     GameWorld.DebugAnswer(curPlayer, "7-今日PK次数,8-今日胜利次数,9-今日购买次数,10-今日刷新次数")
-    GameWorld.DebugAnswer(curPlayer, "设置历史记录: SetCrossPK 赛季ID 类型 数值")
+    GameWorld.DebugAnswer(curPlayer, "设置历史: SetCrossPK 赛季ID 类型 数值")
     GameWorld.DebugAnswer(curPlayer, "类型:0-段位,1-名次,2-积分,3-奖励等级")
     GameWorld.DebugAnswer(curPlayer, "当前连败次数: %s" % curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CrossPK_CLoseCount))
     GameWorld.DebugAnswer(curPlayer, "设置上榜: SetCrossPK b 分区 赛季 段位 [积分 连胜]")
+    GameWorld.DebugAnswer(curPlayer, "指定匹配: SetCrossPK m [playerID ...]")
     return
 
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_MirrorBattle.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_MirrorBattle.py
index 6673827..14f30c4 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_MirrorBattle.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_MirrorBattle.py
@@ -21,6 +21,7 @@
 import PlayerControl
 import IpyGameDataPY
 import PlayerCrossRealmPK
+import GameWorldProcess
 import CrossRealmPlayer
 import PlayerArena
 import GameWorld
@@ -45,6 +46,20 @@
     MirrorAttack.DoPlayerLeaveFB(curPlayer, tick)
     return
 
+## 副本定时器
+def OnProcess(tick):
+    fbStep = GameWorld.GetGameFB().GetFBStep()
+
+    # 等待镜像初始化阶段
+    if fbStep == ChConfig.Def_MirrorBatState_Init:
+        if tick - GameWorld.GetGameFB().GetFBStepTick() < 20 * 1000:
+            return
+        FBCommon.SetFBStep(ChConfig.Def_MirrorBatState_Over, tick)
+        GameWorld.ErrLog("没有等到镜像创建,直接关闭副本!")
+        GameWorldProcess.CloseFB(tick)
+        
+    return
+
 def CheckPlayersRelation_IsFriend(curPlayer, curTagPlayer):
     return not CanAttackPlayer(curPlayer, curTagPlayer)
 
diff --git a/ServerPython/db/PyMongoDataServer/GM/Commands/PlayerMirror.py b/ServerPython/db/PyMongoDataServer/GM/Commands/PlayerMirror.py
new file mode 100644
index 0000000..9769ce3
--- /dev/null
+++ b/ServerPython/db/PyMongoDataServer/GM/Commands/PlayerMirror.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package PyMongoDataServer.GM.Commands.PlayerMirror
+#
+# @todo:玩家镜像数据
+# @author hxp
+# @date 2025-03-04
+# @version 1.0
+#
+# 详细描述: 玩家镜像数据
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2025-03-04 16:30"""
+#-------------------------------------------------------------------------------
+
+from Common import mylog
+import DBCommon.CommonDefine as CommonDefine
+from Collections import DataServerPlayerData
+from LogicProcess import CtrlDBManager
+from DBCommon import GlobalFunctions
+import PyGameData
+import base64
+import os
+
+def OnDBExec(gmList, dbAnswerList):
+    ## db收到GameServer同步的命令处理
+    #mylog.debug("db打包数据: %s" % gmList)
+    dbAnswerList.append("db收到GM命令测试回复")
+    return
+
+def OnCrossDBExec(gmList, dbAnswerList):
+    ## 跨服db收到子服同步的命令处理
+    if not gmList:
+        return
+    value = gmList[0]
+    if value == "a":
+        __addFackPackData(gmList[1:], dbAnswerList)
+    elif value == "d":
+        __delFackPackData(dbAnswerList)
+    return
+
+def __addFackPackData(gmList, dbAnswerList):
+    ## 添加假的打包数据,一般用于开发测试功能用
+    
+    addCount = gmList[0] if len(gmList) > 0 else 1
+    startID = gmList[1] if len(gmList) > 1 else 1
+    #fightPower = gmList[2] if len(gmList) > 2 else 0
+    serverID = gmList[3] if len(gmList) > 3 else 0
+    packDataTempKey = gmList[4] if len(gmList) > 4 else ""
+    
+    appPath = GlobalFunctions.getAppPath()
+    fullPath = os.path.join(appPath, "TestPackData", packDataTempKey, "PackData.json")
+    if not os.path.isfile(fullPath):
+        dbAnswerList.append("跨服db/TestPackData不存在该模版文件夹:%s" % packDataTempKey)
+        return
+    mylog.debug("打包数据模板文件:%s" % fullPath)
+    
+    fileObj = open(fullPath, 'rb')
+    content = fileObj.read()
+    fileObj.close()
+    packDataDict = eval(content)
+    packData = packDataDict.get("PackData", "")
+    if not packData:
+        dbAnswerList.append("跨服db/TestPackData/%s没有打包数据" % (packDataTempKey))
+        return
+    
+    packDataTeamBuff = base64.b64decode(packData)
+    tempDBPlayer = DataServerPlayerData.tagDBPlayer()
+    tempDBPlayer.readData(packDataTeamBuff)
+    otherDataBuff = packDataTeamBuff[tempDBPlayer.getLength():]
+    
+    userCtrlDB = CtrlDBManager.getCtrlMgr().getCtrlDBByName('UserCtrlDB')
+    
+    FakeName = "FakeName"
+    addOKCount = 0
+    for index in range(addCount):
+        playerID = fackID = startID + index
+        
+        tempDBPlayer.PlayerID = fackID
+        tempDBPlayer.PlayerName = "%s%s" % (FakeName, fackID)
+        curServerID = serverID if serverID else (playerID % 100 + 1) # 1 ~ 100 服
+        tempDBPlayer.AccID = "fack%s@test@s%s" % (fackID, curServerID)
+        
+        updBuff = tempDBPlayer.getBuffer() + otherDataBuff
+        updPackData = base64.b64encode(updBuff)
+        
+        #mylog.debug("updPackData:%s" % updPackData)
+        userCtrlDB.updPlayerPackData(playerID, updPackData)
+        addOKCount += 1
+        
+    mylog.debug("添加假玩家打包数据数:%s" % addOKCount)
+    dbAnswerList.append("跨服db添加假玩家打包数据数:%s,总:%s" % (addOKCount, len(PyGameData.g_packDataDict)))
+    return
+
+def __delFackPackData(dbAnswerList):
+    delCount = 0
+    for playerID in PyGameData.g_packDataDict.keys():
+        if playerID > 10000:
+            continue
+        del PyGameData.g_packDataDict[playerID]
+        delCount += 1
+    mylog.debug("删除假打包数据: delCount:%s" % delCount)
+    dbAnswerList.append("跨服db删除假玩家打包数据数:%s,剩:%s" % (delCount, len(PyGameData.g_packDataDict)))
+    return
+
+
diff --git a/ServerPython/db/PyMongoDataServer/GM/Commands/__init__.py b/ServerPython/db/PyMongoDataServer/GM/Commands/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ServerPython/db/PyMongoDataServer/GM/Commands/__init__.py
diff --git a/ServerPython/db/PyMongoDataServer/GM/GMShell.py b/ServerPython/db/PyMongoDataServer/GM/GMShell.py
new file mode 100644
index 0000000..2a90c9b
--- /dev/null
+++ b/ServerPython/db/PyMongoDataServer/GM/GMShell.py
@@ -0,0 +1,112 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package PyMongoDataServer.GM.GMShell
+#
+# @todo:db执行GM命令
+# @author hxp
+# @date 2025-03-04
+# @version 1.0
+#
+# 详细描述: db执行GM命令
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2025-03-04 16:30"""
+#-------------------------------------------------------------------------------
+
+
+from DBCommon import GlobalFunctions
+from Common import mylog
+import Commands
+import os
+
+## 导入GM全部命令
+#  @param importDir 路径名
+#  @return None
+#  @remarks 函数详细说明.
+def ImportCommandAll(importDir):
+    curPath = GlobalFunctions.getAppPath()
+    for root, dirs, files in os.walk("%s\\%s"%(curPath, importDir)):
+        for file in files:
+            fileName = os.path.join(root, file)
+            fileName = fileName.replace(curPath, "")
+            fileName = fileName[1:len(fileName)]
+            if fileName.find("__init__") >= 0:
+                continue
+            
+            curFileList = fileName.split(".")
+            fileName = curFileList[0]
+            ext = curFileList[1]
+            if ext not in ['pyc', 'py']:
+                continue
+            
+            fileName = fileName.replace("\\",".")
+            __import__(fileName)
+
+ImportCommandAll("GM\\Commands")
+
+## 函数调用
+#  @param curCallObj 实例(可能是某个文件名) 
+#  @param callName 实例的某个属性
+#  @return 属性
+def ParseNameGetObj(curCallObj, callName):
+    callList = callName.split(".")
+    if len(callList) <= 1:
+        return None
+    
+    for curCallName in callList:
+        if hasattr(curCallObj, curCallName) != True:
+            #无此属性
+            return None
+        
+        curCallObj = getattr(curCallObj, curCallName)
+        
+    return curCallObj
+
+## 外部调用的获取属性,且是可以call的
+#  @param curCallObj 实例(可能是某个文件名) 
+#  @param callName 实例的某个属性
+#  @return 可以call的属性
+#  @remarks 函数详细说明.
+def GetExecFunc(curCallObj, callName):
+    curCallObj = ParseNameGetObj(curCallObj, callName)
+    
+    if curCallObj == None:
+        return None
+        
+    if callable(curCallObj) != True:
+        #不可调用
+        return None
+    
+    return curCallObj   
+
+def ClientGMCommand(msgData):
+    mylog.debug('跨服DB收到子服GM命令: %s' % msgData)
+    cmdMsgList = msgData.get("cmdMsgList", [])
+    if not cmdMsgList:
+        return []
+    dbAnswerList = []
+    cmdName = cmdMsgList[0]
+    callName = "%s.%s"%(cmdName, "OnCrossDBExec")
+    callFunc = GetExecFunc(Commands, callName)
+    if callFunc != None:
+        callFunc(cmdMsgList[1:], dbAnswerList)
+    return dbAnswerList
+
+def DBGMCommand(cmdMsg):
+    mylog.debug('DB收到GameServer的GM命令: %s' % cmdMsg)
+    if not cmdMsg:
+        return []
+    dbAnswerList = []
+    try:
+        cmdMsgList = eval(cmdMsg)
+        cmdName = cmdMsgList[0]
+        callName = "%s.%s"%(cmdName, "OnDBExec")
+        callFunc = GetExecFunc(Commands, callName)
+        if callFunc != None:
+            callFunc(cmdMsgList[1:], dbAnswerList)
+    except:
+        pass
+    return dbAnswerList
+
diff --git a/ServerPython/db/PyMongoDataServer/GM/__init__.py b/ServerPython/db/PyMongoDataServer/GM/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ServerPython/db/PyMongoDataServer/GM/__init__.py
diff --git a/ServerPython/db/PyMongoDataServer/__init__.py b/ServerPython/db/PyMongoDataServer/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ServerPython/db/PyMongoDataServer/__init__.py

--
Gitblit v1.8.0