From 388823edfe6308cba6f76ca6dc4f20022c5cb2be Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期一, 30 六月 2025 19:03:50 +0800
Subject: [PATCH] 10431 【英文】看广告获得限时代金券

---
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerAssist.py | 1129 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 982 insertions(+), 147 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerAssist.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerAssist.py
index 91db9e4..0cff408 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerAssist.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerAssist.py
@@ -15,9 +15,13 @@
 #"""Version = 2019-12-06 21:00"""
 #-------------------------------------------------------------------------------
 
+import PlayerFriend
 import PyDataManager
+import IpyGameDataPY
 import NetPackCommon
+import CrossRealmMsg
 import PyGameDataStruct
+import PlayerFBHelpBattle
 import ChPyNetSendPack
 import PlayerControl
 import PlayerFamily
@@ -27,6 +31,7 @@
 import ChConfig
 
 import uuid
+import time
 
 # 协助类型
 (
@@ -35,89 +40,149 @@
 AssistType_TeamFB, # 组队副本
 ) = range(3)
 
+def RemoveOutofdateAssistThanks():
+    ## 移除过期的未完结感谢数据
+    
+    timeoutDate = GameWorld.GetDatetimeByDiffDays(-7)
+    assistThanksMgr = PyDataManager.GetPlayerAssistThanksPyManager()
+    maxDoCount = len(assistThanksMgr.allAssistThanksList)
+    syncPlayerIDList = []
+    removeCountTotal, delNoThanksCount, delUnGetThanksCount = 0, 0, 0
+    doCount = 0
+    while doCount < maxDoCount and assistThanksMgr.allAssistThanksList:
+        doCount += 1
+        thanks = assistThanksMgr.allAssistThanksList[0]
+        thanksDate = GameWorld.ChangeStrToDatetime(thanks.TimeStr)
+        if thanksDate > timeoutDate:
+            break
+        
+        removeCountTotal += 1
+        # 移除过期的感谢数据
+        popThanks = assistThanksMgr.allAssistThanksList.pop(0)
+        playerID = popThanks.PlayerID
+        GUID = popThanks.GUID
+        assistPlayerIDList = popThanks.AssistPlayerDict.keys()
+        
+        if playerID in assistThanksMgr.playerThanksDict:
+            playerThanksList = assistThanksMgr.playerThanksDict[playerID]
+            for i, thanks in enumerate(playerThanksList):
+                if GUID == thanks.GUID:
+                    delNoThanksCount += 1
+                    playerThanksList.pop(i)
+                    #GameWorld.DebugLog("    移除未感谢的数据: i=%s,GUID=%s,len=%s" % (i, thanks.GUID, len(playerThanksList)))
+                    break
+                
+        for assistPlayerID in assistPlayerIDList:
+            if assistPlayerID not in assistThanksMgr.assistPlayerThanksDict:
+                continue
+            assistThanksList = assistThanksMgr.assistPlayerThanksDict[assistPlayerID]
+            for i, thanks in enumerate(assistThanksList):
+                if GUID == thanks.GUID:
+                    delUnGetThanksCount += 1
+                    assistThanksList.pop(i)
+                    #GameWorld.DebugLog("    移除未接受感谢的数据: i=%s,GUID=%s,assistPlayerID=%s,len=%s" % (i, thanks.GUID, assistPlayerID, len(assistThanksList)))
+                    if assistPlayerID not in syncPlayerIDList:
+                        syncPlayerIDList.append(assistPlayerID)
+                    break
+                
+    playerMgr = GameWorld.GetPlayerManager()
+    for playerID in syncPlayerIDList:
+        assistPlayer = playerMgr.FindPlayerByID(playerID)
+        if assistPlayer:
+            SyncCanGetAssistThanksGiftCount(assistPlayer, isForce=True)
+            
+    if removeCountTotal:
+        GameWorld.DebugLog("移除过期的未完结感谢数据: doCount=%s,maxDoCount=%s,removeCountTotal=%s,delNoThanksCount=%s,delUnGetThanksCount=%s,remainCount=%s" 
+                           % (doCount, maxDoCount, removeCountTotal, delNoThanksCount, delUnGetThanksCount, len(assistThanksMgr.allAssistThanksList)))
+    return
 
-def OnPlayerLogin(curPlayer, isTJ=False):
+def OnPlayerLoginCrossServer(curPlayer):
+    # 跨服登录处理
+    
+    playerID = curPlayer.GetPlayerID()
+    tagPlayerID = PlayerControl.GetAssistTagPlayerID(curPlayer)
+    if tagPlayerID and not GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID):
+        serverGroupID = PlayerControl.GetPlayerServerGroupID(curPlayer)
+        sendMsg = {"queryType":"ResetPlayerAssist", "queryData":[playerID, tagPlayerID]}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossAssist, sendMsg, [serverGroupID])
+        
+    return
+    
+def OnPlayerLogin(curPlayer):
     ## 玩家上线
-    # @param isTJ: 是否脱机上线
+    
+    SyncCanGetAssistThanksGiftCount(curPlayer)
     
     familyID = curPlayer.GetFamilyID()
     playerID = curPlayer.GetPlayerID()
-    if not familyID:
-        return
     
     assistMgr = PyDataManager.GetPlayerAssistPyManager()
-    if playerID in assistMgr.playerNoSaveDBAssistDict:
-        playerNoSaveList = assistMgr.playerNoSaveDBAssistDict[playerID]
+    
+    # 将自己发布的重新激活并通知其他玩家
+    if playerID in assistMgr.playerAssistDict:
+        playerAssistList = assistMgr.playerAssistDict[playerID]
         
-        # 非脱机上线
-        if not isTJ:
-            GameWorld.DebugLog("玩家上线,恢复协助发布到仙盟列表!", playerID)
-            if familyID not in assistMgr.familyAssistDict:
-                assistMgr.familyAssistDict[familyID] = []
-            recoverList = []
-            familyAssistList = assistMgr.familyAssistDict[familyID]
-            for assistObj in playerNoSaveList:
+        serverAssistList, familyAssistList = [], []
+        for assistObj in playerAssistList:
+            assistObj.OffLineTime = 0 # 设置为非离线
+            if not assistObj.FamilyID:
+                serverAssistList.append(assistObj)
+            elif familyID and familyID == assistObj.FamilyID:
                 familyAssistList.append(assistObj)
-                recoverList.append(assistObj)
-                GameWorld.DebugLog("    恢复: %s" % assistObj.GUID)
                 
-            if recoverList:
-                # 通知本盟其他玩家
-                PlayerFamily.SendFamilyFakePack(familyID, GetAssistInfoListPack(recoverList), [playerID])
-                
-        # 脱机上线
-        else:
-            GameWorld.DebugLog("玩家脱机上线,强制取消发布的非存库协助!", playerID)
-            for assistObj in playerNoSaveList:
-                OnCancelPlayerRequestAssist(assistObj, "TJGLogin", True)
-                
-    if not isTJ:
-        SyncFamilyAssist(curPlayer)
+        if familyAssistList:
+            PlayerFamily.SendFamilyFakePack(familyID, GetAssistInfoListPack(familyAssistList), [playerID])
+        if serverAssistList:
+            SyncServerAssist(serverAssistList)
+    
+    # 全服服务器协助、仙盟协助 通知自己
+    syncAssistList = []
+    for assistObj in assistMgr.allAssistDict.values():
+        if assistObj.OffLineTime:
+            continue
+        if assistObj.FamilyID and assistObj.FamilyID != familyID:
+            continue
+        syncAssistList.append(assistObj)
+    if syncAssistList:
+        NetPackCommon.SendFakePack(curPlayer, GetAssistInfoListPack(syncAssistList))
         
     # 没有协助中的信息
     if playerID in assistMgr.playerAssistingDict:
         assistObj = assistMgr.playerAssistingDict[playerID]
-        if not isTJ:
-            tagPlayerID = assistObj.PlayerID
-            GameWorld.DebugLog("非脱机上线,继续协助!tagPlayerID=%s" % tagPlayerID, playerID)
-            
-            PlayerControl.SetAssistTagPlayerID(curPlayer, tagPlayerID)
-            assistPack = ChPyNetSendPack.tagGCAssistingInfo()
-            assistPack.AssistGUID = assistObj.GUID
-            NetPackCommon.SendFakePack(curPlayer, assistPack)
-            
-        # 脱机上线
-        else:
-            OnCancelPlayerAssist(curPlayer, playerID, assistObj, "TJGLogin", True)
-            
+        tagPlayerID = assistObj.PlayerID
+        
+        GameWorld.DebugLog("非脱机上线,继续协助!tagPlayerID=%s" % tagPlayerID, playerID)
+        
+        PlayerControl.SetAssistTagPlayerID(curPlayer, tagPlayerID)
+        assistPack = ChPyNetSendPack.tagGCAssistingInfo()
+        assistPack.AssistGUID = assistObj.GUID
+        NetPackCommon.SendFakePack(curPlayer, assistPack)
+        
     return
 
 def OnLeaveServer(curPlayer):
     ## 玩家离线
     familyID = curPlayer.GetFamilyID()
-    if not familyID:
-        return
     
     if PlayerControl.GetAssistTagPlayerID(curPlayer):
         PlayerControl.SetAssistTagPlayerID(curPlayer, 0)
         
     assistMgr = PyDataManager.GetPlayerAssistPyManager()
-    if familyID not in assistMgr.familyAssistDict:
-        return
-    
     playerID = curPlayer.GetPlayerID()
-    if playerID not in assistMgr.playerNoSaveDBAssistDict:
+    if playerID not in assistMgr.playerAssistDict:
         #GameWorld.DebugLog("玩家没有发布过协助,离线不处理!", playerID)
         return
-    playerNoSaveList = assistMgr.playerNoSaveDBAssistDict[playerID]    
-    familyAssistList = assistMgr.familyAssistDict[familyID]
+    playerAssistList = assistMgr.playerAssistDict[playerID]
     # 暂时移除离线玩家发布的不存库协助信息,不再让其他盟友继续前往协助,已经在协助的不影响
-    for assistObj in playerNoSaveList:
-        if assistObj not in familyAssistList:
+    for assistObj in playerAssistList:
+        if assistObj.IsSaveDB:
             continue
-        familyAssistList.remove(assistObj)
-        SyncFamilyClearAssist(familyID, assistObj.GUID)
-        GameWorld.DebugLog("玩家下线,暂时从仙盟协助列表移除玩家发布的协助: %s" % assistObj.GUID)
+        assistObj.OffLineTime = int(time.time())
+        if not assistObj.FamilyID:
+            SyncServerClearAssist(assistObj.GUID)
+        elif familyID and familyID == assistObj.FamilyID:
+            SyncFamilyClearAssist(familyID, assistObj.GUID)
+        GameWorld.DebugLog("玩家下线,暂时从协助列表移除玩家发布的协助: %s" % assistObj.GUID)
         
     return
 
@@ -128,22 +193,47 @@
     assistMgr = PyDataManager.GetPlayerAssistPyManager()
     
     # 玩家发布的
-    if leavePlayerID in assistMgr.playerNoSaveDBAssistDict:
-        playerAssistList = assistMgr.playerNoSaveDBAssistDict[leavePlayerID]
+    if leavePlayerID in assistMgr.playerAssistDict:
+        playerAssistList = assistMgr.playerAssistDict[leavePlayerID]
         for assistObj in playerAssistList[::-1]:
-            OnCancelPlayerRequestAssist(assistObj, "LeaveFamily", True)
+            if assistObj.FamilyID:
+                OnCancelPlayerRequestAssist(assistObj, "LeaveFamily", True)
             
     # 玩家协助中的
     if leavePlayerID in assistMgr.playerAssistingDict:
         assistObj = assistMgr.playerAssistingDict[leavePlayerID]
-        OnCancelPlayerAssist(leavePlayer, leavePlayerID, assistObj, "LeaveFamily", True)
+        if assistObj.FamilyID:
+            OnCancelPlayerAssist(leavePlayer, leavePlayerID, assistObj, "LeaveFamily", True)
         
     return
 
-def OnInitAssistData(dbData, isSaveDB):
+def OnPlayerTeamChange(curPlayer):
+    ## 玩家队伍变更
+    
+    if curPlayer.GetTeamID():
+        return
+    playerID = curPlayer.GetPlayerID()
+    
+    assistMgr = PyDataManager.GetPlayerAssistPyManager()
+    if playerID not in assistMgr.playerAssistDict:
+        return
+    playerAssistList = assistMgr.playerAssistDict[playerID]
+    
+    for assistObj in playerAssistList[::-1]:
+        gameMap = GameWorld.GetMap(assistObj.MapID)
+        if gameMap and gameMap.GetMapFBType() == ChConfig.fbtTeam:
+            OnCancelPlayerRequestAssist(assistObj, "LeaveTeam", True)
+            
+    return
+
+def OnInitAssistData(dbData, isSaveDB, serverGroupID=0):
     ## 加载协助数据额外处理
     setattr(dbData, "IsSaveDB", isSaveDB) # 是否保存数据库,离线可协助的需要存库,如挖矿类
     setattr(dbData, "ObjID", 0) # NPC实例ID
+    setattr(dbData, "ServerGroupID", serverGroupID)
+    setattr(dbData, "OffLineTime", 0) # 发布玩家离线时间戳
+    setattr(dbData, "Face", 0)
+    setattr(dbData, "FacePic", 0)
     
     assistType = AssistType_Unknown
     if dbData.NPCID:
@@ -155,6 +245,41 @@
             assistType = AssistType_TeamFB
     setattr(dbData, "AssistType", assistType) # 协助类型
     setattr(dbData, "AssistPlayerIDList", []) # 协助中的玩家ID列表
+    return
+
+def OnInitAssistThanksData(thanksMgr, dbData):
+    ## 初始化协助感谢数据额外处理
+    setattr(dbData, "Face", 0)
+    setattr(dbData, "FacePic", 0)
+    setattr(dbData, "AssistPlayerDict", {})
+    if dbData.AssistPlayer and dbData.AssistPlayer.startswith("{") and dbData.AssistPlayer.endswith("}"):
+        dbData.AssistPlayerDict = eval(dbData.AssistPlayer)
+        
+    thanksMgr.allAssistThanksList.append(dbData)
+    # 未感谢的
+    if not dbData.ThanksState:
+        playerID = dbData.PlayerID
+        if playerID not in thanksMgr.playerThanksDict:
+            thanksMgr.playerThanksDict[playerID] = []
+        playerThanksList = thanksMgr.playerThanksDict[playerID]
+        playerThanksList.append(dbData)
+        
+    for assistPlayerID, assistPlayerInfo in dbData.AssistPlayerDict.items():
+        if "IsGet" in assistPlayerInfo:
+            # 已经接受感谢奖励的不再处理
+            continue
+        
+        if assistPlayerID not in thanksMgr.assistPlayerThanksDict:
+            thanksMgr.assistPlayerThanksDict[assistPlayerID] = []
+        assistPlayerThanksList = thanksMgr.assistPlayerThanksDict[assistPlayerID]
+        assistPlayerThanksList.append(dbData)
+            
+    return
+
+def OnSaveAssistThanksData(dbData):
+    ## 协助感谢保存数据额外处理
+    dbData.AssistPlayer = str(dbData.AssistPlayerDict)
+    dbData.AssistPlayerLen = len(dbData.AssistPlayer)
     return
 
 #// B0 12 开始协助Boss #tagCGStartAssistBoss
@@ -180,25 +305,44 @@
         GameWorld.DebugLog("不能协助自己!")
         return
     
-    if assistObj.FamilyID != curPlayer.GetFamilyID():
-        GameWorld.DebugLog("非同盟玩家不能协助!")
-        return
-    
+    isCrossBoss = assistObj.MapID in ChConfig.Def_CrossMapIDList
+    if isCrossBoss:
+        pass
+    else:
+        if assistObj.FamilyID != curPlayer.GetFamilyID():
+            GameWorld.DebugLog("非同盟玩家不能协助!")
+            return
+        
+    playerMapID = curPlayer.GetMapID()
     mapID = assistObj.MapID
     lineID = assistObj.LineID
-    gameMap = GameWorld.GetMap(mapID)
-    if not gameMap:
+    playerMap = GameWorld.GetMap(playerMapID)
+    if not playerMap:
         return
-    if gameMap.GetMapFBType() != ChConfig.fbtNull:
-        playerMapID = curPlayer.GetMapID()
-        playerLineID = PlayerControl.GetFBFuncLineID(curPlayer)
+    if playerMap.GetMapFBType() != ChConfig.fbtNull:
+        if mapID == ChConfig.Def_FBMapID_SealDemon:
+            playerLineID = PlayerControl.GetFBFuncLineID(curPlayer)
+        else:
+            playerLineID = curPlayer.GetFBID()
         if playerMapID != mapID or playerLineID != lineID:
             #副本中无法协助
             PlayerControl.NotifyCode(curPlayer, "AssistFBLimit")
             return
         
+    if isCrossBoss:
+        tagPlayerID = assistObj.PlayerID
+        assistPlayerID = curPlayer.GetPlayerID()
+        assistPlayerName = curPlayer.GetName()
+        isFriend = PlayerFriend.IsFriend(assistPlayerID, tagPlayerID)
+        sendMsg = {"queryType":"StartAssistBoss", "queryData":[assistGUID, assistPlayerID, assistPlayerName, isFriend]}
+        CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_CrossAssist, sendMsg)
+        return
+    
     # 设定协助必须离开队伍
-    if gameMap.GetMapFBType() != ChConfig.fbtTeam:
+    tagMap = GameWorld.GetMap(mapID)
+    if not tagMap:
+        return
+    if tagMap.GetMapFBType() != ChConfig.fbtTeam:
         curTeam = curPlayer.GetTeam()
         if curTeam:
             PlayerTeam.DoPlayerLeaveTeam(curPlayer, curTeam, tick)
@@ -264,7 +408,8 @@
     if playerID not in assistObj.AssistPlayerIDList:
         assistObj.AssistPlayerIDList.append(playerID)
         
-    GameWorld.DebugLog("开始协助: tagPlayerID=%s,mapID=%s,lineID=%s,npcID=%s,objID=%s" % (tagPlayerID, mapID, lineID, npcID, objID), playerID)
+    GameWorld.DebugLog("开始协助: tagPlayerID=%s,mapID=%s,lineID=%s,npcID=%s,objID=%s" 
+                       % (tagPlayerID, mapID, lineID, npcID, objID), playerID)
     
     # 设置协助
     PlayerControl.SetAssistTagPlayerID(curPlayer, tagPlayerID)
@@ -277,13 +422,99 @@
     
     tagPlayerName = tagPlayer.GetName()
     tagTeamID = tagPlayer.GetTeamID()
-    assistData = [mapID, "Start", assistGUID, assistPlayerID, assistPlayerName, tagPlayerID, tagPlayerName, tagTeamID, lineID, objID, npcID]
+    isFriend = PlayerFriend.IsFriend(assistPlayerID, tagPlayerID)
+    serverGroupID = GameWorld.GetServerGroupID()
+    assistData = [mapID, "Start", assistGUID, assistPlayerID, assistPlayerName, isFriend, tagPlayerID, tagPlayerName, tagTeamID, lineID, objID, npcID, serverGroupID]
+    GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_AssistBoss, assistData)
+    return
+
+def ClientServerMsg_StartAssistBoss(serverGroupID, queryType, queryData):
+    ## 收到子服消息 - 开始协助boss
+    ## @return: 是否同步删除GUID
+    assistGUID, assistPlayerID, assistPlayerName, isFriend = queryData
+    
+    assistMgr = PyDataManager.GetPlayerAssistPyManager()
+    if assistGUID not in assistMgr.allAssistDict:
+        GameWorld.Log("不存在该协助!assistGUID=%s" % assistGUID)
+        reason, isGameServer = "AssistGUIDNotExist", True
+        sendMsg = {"queryType":"CancelPlayerRequestAssist", "queryData":[assistGUID, reason, isGameServer]}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossAssist, sendMsg, [serverGroupID])
+        return
+    assistObj = assistMgr.allAssistDict[assistGUID]
+    if assistObj.AssistType != AssistType_Boss:
+        return
+    if assistObj.PlayerID == assistPlayerID:
+        GameWorld.DebugLog("不能协助自己!")
+        return
+    
+    assistPlayer = GameWorld.GetPlayerManager().FindPlayerByID(assistPlayerID)
+    # 如果是在跨服服务器
+    if assistPlayer:
+        playerMapID = assistPlayer.GetMapID()
+        mapID = assistObj.MapID
+        lineID = assistObj.LineID
+        playerMap = GameWorld.GetMap(playerMapID)
+        if not playerMap:
+            return
+        if playerMap.GetMapFBType() != ChConfig.fbtNull:
+            playerLineID = assistPlayer.GetFBID()
+            if playerMapID != mapID or playerLineID != lineID:
+                #副本中无法协助
+                PlayerControl.NotifyCode(assistPlayer, "AssistFBLimit")
+                return
+            
+    tagPlayerID = assistObj.PlayerID
+    mapID = assistObj.MapID
+    lineID = assistObj.LineID
+    npcID = assistObj.NPCID
+    objID = assistObj.ObjID
+    
+    tagPlayer = GameWorld.GetPlayerManager().FindPlayerByID(tagPlayerID)
+    if not tagPlayer:
+        GameWorld.Log("玩家已离线,无法协助!tagPlayerID=%s" % (tagPlayerID))
+        OnCancelPlayerRequestAssist(assistObj, "CrossPlayerOffline", True)
+        return
+    
+    if tagPlayer.GetMapID() != mapID:
+        GameWorld.DebugLog("目标玩家已不在请求协助的地图,无法协助!tagPlayerID=%s" % (tagPlayerID))
+        return
+    
+    # 设置新协助之前需要先取消正在进行中的协助
+    if assistPlayerID in assistMgr.playerAssistingDict:
+        assistingObj = assistMgr.playerAssistingDict[assistPlayerID]
+        if assistGUID != assistingObj.GUID:
+            OnCancelPlayerAssist(assistPlayer, assistPlayerID, assistingObj, "StartNewAssistBoss", True)
+    assistMgr.playerAssistingDict[assistPlayerID] = assistObj
+    
+    if assistPlayerID not in assistObj.AssistPlayerIDList:
+        assistObj.AssistPlayerIDList.append(assistPlayerID)
+        
+    GameWorld.DebugLog("开始协助: tagPlayerID=%s,mapID=%s,lineID=%s,npcID=%s,objID=%s" 
+                       % (tagPlayerID, mapID, lineID, npcID, objID), assistPlayerID)
+    
+    # 设置协助
+    if assistPlayer:
+        PlayerControl.SetAssistTagPlayerID(assistPlayer, tagPlayerID)
+        
+    # 通知目标玩家
+    # xxx开始协助你
+    PlayerControl.NotifyCode(tagPlayer, "AssistStart", [assistPlayerName])
+    
+    tagPlayerName = tagPlayer.GetName()
+    tagTeamID = tagPlayer.GetTeamID()
+    assistData = [mapID, "Start", assistGUID, assistPlayerID, assistPlayerName, isFriend, tagPlayerID, tagPlayerName, tagTeamID, lineID, objID, npcID, serverGroupID]
     GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_AssistBoss, assistData)
     return
 
 def OnAddAssistBossPlayerOK(queryData):
     ## 添加协助Boss的玩家成功,通知协助玩家可以前往
-    assistGUID, assistPlayerID = queryData
+    assistGUID, assistPlayerID, tagPlayerID, serverGroupID = queryData
+    
+    if GameWorld.IsCrossServer():
+        sendMsg = {"queryType":"AddAssistBossPlayerOK", "queryData":[assistGUID, assistPlayerID, tagPlayerID]}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossAssist, sendMsg, [serverGroupID])
+        return
+    
     assistPlayer = GameWorld.GetPlayerManager().FindPlayerByID(assistPlayerID)
     if not assistPlayer:
         return
@@ -293,11 +524,35 @@
     NetPackCommon.SendFakePack(assistPlayer, assistPack)
     return
 
-def SetPlayerStartAssistTeamFB(curPlayer, queryData):
-    ## 开始协助组队副本 - 玩家进入副本后才真正进入协助状态
+def CrossServerMsg_AddAssistBossPlayerOK(queryType, queryData):
+    ## 收到跨服服务器 - 添加协助boss成功
+    assistGUID, assistPlayerID, tagPlayerID = queryData
     
-    #mapID, lineID, tagPlayerID = queryData
+    assistPlayer = GameWorld.GetPlayerManager().FindPlayerByID(assistPlayerID)
+    if not assistPlayer:
+        return
     
+    assistMgr = PyDataManager.GetPlayerAssistPyManager()
+    if assistGUID not in assistMgr.allAssistDict:
+        GameWorld.DebugLog("不存在该协助!assistGUID=%s" % assistGUID)
+        return
+    assistObj = assistMgr.allAssistDict[assistGUID]
+    
+    # 设置协助
+    PlayerControl.SetAssistTagPlayerID(assistPlayer, tagPlayerID)
+    
+    if assistPlayerID in assistMgr.playerAssistingDict:
+        assistingObj = assistMgr.playerAssistingDict[assistPlayerID]
+        if assistGUID != assistingObj.GUID:
+            OnCancelPlayerAssist(assistPlayer, assistPlayerID, assistingObj, "StartNewAssistBoss", True)
+    assistMgr.playerAssistingDict[assistPlayerID] = assistObj
+    
+    if assistPlayerID not in assistObj.AssistPlayerIDList:
+        assistObj.AssistPlayerIDList.append(assistPlayerID)
+        
+    assistPack = ChPyNetSendPack.tagGCAssistingInfo()
+    assistPack.AssistGUID = assistGUID
+    NetPackCommon.SendFakePack(assistPlayer, assistPack)
     return
 
 def MapServer_PlayerAssistLogic(curPlayer, msgList, tick):
@@ -322,17 +577,16 @@
     
     # 取消boss协助发布
     elif queryType == "OnCancelBossRequestAssist":
-        mapID, lineID, npcID, objID, reason, cancelPlayerIDList = queryData
+        mapID, lineID, npcID, objID, reason = queryData
         assistMgr = PyDataManager.GetPlayerAssistPyManager()
-        for cancelPlayerID in cancelPlayerIDList:
-            if cancelPlayerID in assistMgr.playerNoSaveDBAssistDict:
-                playerAssistList = assistMgr.playerNoSaveDBAssistDict[cancelPlayerID]
-                for assistObj in playerAssistList:
-                    if assistObj.MapID == mapID and assistObj.LineID == lineID and assistObj.NPCID == npcID and assistObj.ObjID == objID:
-                        OnCancelPlayerRequestAssist(assistObj, reason, False)
-                        break
+        if playerID in assistMgr.playerAssistDict:
+            playerAssistList = assistMgr.playerAssistDict[playerID]
+            for assistObj in playerAssistList:
+                if assistObj.MapID == mapID and assistObj.LineID == lineID and assistObj.NPCID == npcID and assistObj.ObjID == objID:
+                    OnCancelPlayerRequestAssist(assistObj, reason, False)
+                    break
         return
-        
+    
     # 取消协助Boss
     elif queryType == "OnCancelBossAssist":
         mapID, lineID, npcID, objID, reason = queryData
@@ -341,6 +595,16 @@
             assistObj = assistMgr.playerAssistingDict[playerID]
             if assistObj.MapID == mapID and assistObj.LineID == lineID and assistObj.NPCID == npcID and assistObj.ObjID == objID:
                 OnCancelPlayerAssist(curPlayer, playerID, assistObj, reason, False)
+        return
+    
+    # boss协助结束
+    elif queryType == "OnBossAssistOver":
+        __DoBossAssistOver(queryData)
+        return
+    
+    # 副本协助结束
+    elif queryType == "OnFBAssistOver":
+        __DoFBAssistOver(queryData)
         return
     
     ## -------------------------------------------------------------------------------------------
@@ -352,54 +616,171 @@
     
     # 开始协助组队副本
     elif queryType == "OnStartAssistTeamFB":
-        SetPlayerStartAssistTeamFB(curPlayer, queryData)
+        mapID, lineID, tagPlayerID = queryData
+        GameWorld.DebugLog("    开始协助副本: mapID=%s,lineID=%s,tagPlayerID=%s" % (mapID, lineID, tagPlayerID), playerID)
+        # 副本协助暂时只处理设置协助目标ID
+        PlayerControl.SetAssistTagPlayerID(curPlayer, tagPlayerID)
+        return
+    
+    # 取消协助组队副本
+    elif queryType == "OnCancelAssistTeamFB":
+        mapID, lineID, reason = queryData
+        GameWorld.DebugLog("    开始协助副本: mapID=%s,lineID=%s,reason=%s" % (mapID, lineID, reason), playerID)
+        # 副本协助暂时只处理设置协助目标ID
+        PlayerControl.SetAssistTagPlayerID(curPlayer, 0)
         return
     
     #QueryPlayerResult_PlayerAssist(curPlayer, queryType, queryData, result)
     return
 
-#def QueryPlayerResult_PlayerAssist(curPlayer, queryType, queryData, result=[]):
-#    if not curPlayer:
-#        return
-#    resultMsg = str([queryType, queryData, result])
-#    curPlayer.MapServer_QueryPlayerResult(0, 0, "PlayerAssist", resultMsg, len(resultMsg))
-#    GameWorld.DebugLog("协助信息发送 MapServer: playerID=%s,queryType=%s,queryData=%s" % (curPlayer.GetPlayerID(), queryType, queryData))
-#    return
+def QueryPlayerResult_PlayerAssist(curPlayer, queryType, queryData, result=[]):
+    if not curPlayer:
+        return
+    resultMsg = str([queryType, queryData, result])
+    curPlayer.MapServer_QueryPlayerResult(0, 0, "PlayerAssist", resultMsg, len(resultMsg))
+    GameWorld.DebugLog("协助信息发送 MapServer: playerID=%s,queryType=%s,queryData=%s" % (curPlayer.GetPlayerID(), queryType, queryData))
+    return
 
 def __DoRequestAssistBoss(curPlayer, queryData):
     ## 请求协助Boss
     
+    isCrossServer = GameWorld.IsCrossServer()
     familyID = curPlayer.GetFamilyID()
-    if not familyID:
+    if not familyID and not isCrossServer:
         return
-    mapID, lineID, npcID, objID = queryData
+    mapID, lineID, npcID, objID, npcLV, serverGroupID = queryData
     
     playerID = curPlayer.GetPlayerID()
     
-    assistObj = None
-    addNewAssist = True
+    reqAssistObj = None
+    addNewAssist = False
     assistMgr = PyDataManager.GetPlayerAssistPyManager()
-    if playerID in assistMgr.playerNoSaveDBAssistDict:
-        playerAssistList = assistMgr.playerNoSaveDBAssistDict[playerID]
+    if playerID in assistMgr.playerAssistDict:
+        playerAssistList = assistMgr.playerAssistDict[playerID]
         for assistObj in playerAssistList:
             if assistObj.AssistType != AssistType_Boss:
                 continue
             if npcID != assistObj.NPCID or lineID != assistObj.LineID or objID != assistObj.ObjID:
                 OnCancelPlayerRequestAssist(assistObj, "RequestNewAssistBoss", True)
             else:
-                addNewAssist = False
+                reqAssistObj = assistObj
             break
         
-    if addNewAssist:
-        assistObj = __AddNewAssist(assistMgr, curPlayer, mapID, lineID, npcID, objID)
+    if not reqAssistObj:
+        addNewAssist = True
+        reqAssistObj = __AddNewAssist(assistMgr, curPlayer, mapID, lineID, npcID, objID, serverGroupID=serverGroupID)
         
-    if not assistObj:
+    if not reqAssistObj:
         return
     
-    # 通知本仙盟玩家
-    PlayerFamily.SendFamilyFakePack(familyID, GetAssistInfoListPack([assistObj]))
     # 求助信息已发送,请等待盟友支援
     PlayerControl.NotifyCode(curPlayer, "AssistRequestOK")
+    
+    requestCount = 1
+    if not addNewAssist:
+        requestCount = min(curPlayer.GetDictByKey("AssistBossRequestCount") + 1, 999)
+    curPlayer.SetDict("AssistBossRequestCount", requestCount)
+    notifyNum = (requestCount - 1) % 3
+    
+    if isCrossServer:
+        GUID = reqAssistObj.GUID
+        sendMsg = {"queryType":"RequestAssistBoss", "queryData":[mapID, lineID, npcID, objID, npcLV, playerID, notifyNum, GUID]}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossAssist, sendMsg, [serverGroupID])
+    else:
+        # 通知本仙盟玩家
+        PlayerFamily.SendFamilyFakePack(familyID, GetAssistInfoListPack([reqAssistObj]))
+        # 广播仙盟请求
+        PlayerControl.FamilyNotify(familyID, "AssistBossRequest%s" % notifyNum, [curPlayer.GetName(), mapID, npcLV, npcID])
+        
+    return
+
+def CrossServerMsg_RequestAssistBoss(queryType, queryData):
+    
+    mapID, lineID, npcID, objID, npcLV, playerID, notifyNum, GUID = queryData
+    
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+    if not curPlayer:
+        return
+    
+    reqAssistObj = None
+    addNewAssist = False
+    assistMgr = PyDataManager.GetPlayerAssistPyManager()
+    if playerID in assistMgr.playerAssistDict:
+        playerAssistList = assistMgr.playerAssistDict[playerID]
+        for assistObj in playerAssistList:
+            if assistObj.AssistType != AssistType_Boss:
+                continue
+            if npcID != assistObj.NPCID or lineID != assistObj.LineID or objID != assistObj.ObjID:
+                OnCancelPlayerRequestAssist(assistObj, "RequestNewAssistBoss", True)
+            else:
+                reqAssistObj = assistObj
+            break
+        
+    if not reqAssistObj:
+        addNewAssist = True
+        reqAssistObj = __AddNewAssist(assistMgr, curPlayer, mapID, lineID, npcID, objID, assistGUID=GUID)
+        
+    GameWorld.Log("收到跨服请求协助boss: %s mapID=%s,lineID=%s,npcID=%s,objID=%s,addNewAssist=%s,GUID=%s" 
+                  % (queryType, mapID, lineID, npcID, objID, addNewAssist, GUID), playerID)
+    if not reqAssistObj:
+        return
+    
+    # 通知本服玩家
+    SyncServerAssist([reqAssistObj])
+            
+    # 广播请求
+    PlayerControl.WorldNotify(0, "AssistBossRequest%s" % notifyNum, [curPlayer.GetName(), mapID, npcLV, npcID])
+    return
+
+def CrossServerMsg_CrossAssist(msgData, tick):
+    ## 收到跨服服务器消息 - 协助信息
+    
+    queryType = msgData["queryType"]
+    queryData = msgData["queryData"]
+    
+    # 请求协助boss
+    if queryType == "RequestAssistBoss":
+        CrossServerMsg_RequestAssistBoss(queryType, queryData)
+        return
+    
+    # 添加协助boss成功
+    if queryType == "AddAssistBossPlayerOK":
+        CrossServerMsg_AddAssistBossPlayerOK(queryType, queryData)
+        return
+    
+    # 取消协助请求
+    if queryType == "CancelPlayerRequestAssist":
+        CrossServerMsg_CancelPlayerRequestAssist(queryType, queryData)
+        return
+    
+    # 取消协助
+    if queryType == "CancelPlayerAssist":
+        CrossServerMsg_CancelPlayerAssist(queryType, queryData)
+        return
+    
+    # boss协助结束
+    if queryType == "BossAssistOver":
+        CrossServerMsg_BossAssistOver(queryType, queryData)
+        return
+    
+    # 重置玩家协助
+    if queryType == "ResetPlayerAssist":
+        CrossServerMsg_ResetPlayerAssist(queryType, queryData)
+        return
+    
+    return
+
+def ClientServerMsg_CrossAssist(serverGroupID, msgData, tick):
+    ## 收到子服服务器消息 - 协助信息
+    
+    queryType = msgData["queryType"]
+    queryData = msgData["queryData"]
+    
+    # 开始协助boss
+    if queryType == "StartAssistBoss":
+        ClientServerMsg_StartAssistBoss(serverGroupID, queryType, queryData)
+        return
+    
     return
 
 def __DoRequestAssistTeamFB(curPlayer, queryData):
@@ -408,41 +789,50 @@
     familyID = curPlayer.GetFamilyID()
     if not familyID:
         return
-    mapID, lineID  = queryData
+    mapID, lineID = queryData
     
     playerID = curPlayer.GetPlayerID()
     
-    assistObj = None
+    reqAssistObj = None
     addNewAssist = False
     assistMgr = PyDataManager.GetPlayerAssistPyManager()
-    if playerID in assistMgr.playerNoSaveDBAssistDict:
-        playerAssistList = assistMgr.playerNoSaveDBAssistDict[playerID]
+    if playerID in assistMgr.playerAssistDict:
+        playerAssistList = assistMgr.playerAssistDict[playerID]
         for assistObj in playerAssistList:
             if assistObj.AssistType != AssistType_TeamFB:
                 continue
             if mapID != assistObj.MapID or lineID != assistObj.LineID:
                 OnCancelPlayerRequestAssist(assistObj, "RequestNewAssistTeamFB", True)
-                addNewAssist = True
-                break
-    else:
+            else:
+                reqAssistObj = assistObj
+            break
+        
+    if not reqAssistObj:
         addNewAssist = True
+        reqAssistObj = __AddNewAssist(assistMgr, curPlayer, mapID, lineID)
         
-    if addNewAssist:
-        assistObj = __AddNewAssist(assistMgr, curPlayer, mapID, lineID)
-        
-    if not assistObj:
+    if not reqAssistObj:
         return
     
     # 通知本仙盟玩家
-    PlayerFamily.SendFamilyFakePack(familyID, GetAssistInfoListPack([assistObj]))
+    PlayerFamily.SendFamilyFakePack(familyID, GetAssistInfoListPack([reqAssistObj]))
     # 求助信息已发送,请等待盟友支援
     PlayerControl.NotifyCode(curPlayer, "AssistRequestOK")
+    # 广播仙盟请求
+    requestCount = 1
+    if not addNewAssist:
+        requestCount = min(curPlayer.GetDictByKey("AssistFBRequestCount") + 1, 999)
+    curPlayer.SetDict("AssistFBRequestCount", requestCount)
+    notifyNum = (requestCount - 1) % 3
+    PlayerControl.FamilyNotify(familyID, "AssistFBRequest%s" % notifyNum, [curPlayer.GetName(), mapID])
     return
 
-def __AddNewAssist(assistMgr, curPlayer, mapID, lineID, npcID=0, objID=0, exData="", isSaveDB=0):
+def __AddNewAssist(assistMgr, curPlayer, mapID, lineID, npcID=0, objID=0, exData="", isSaveDB=0, assistGUID="", serverGroupID=0):
     ## 添加新协助请求
-    assistGUID = str(uuid.uuid1())
-    familyID = curPlayer.GetFamilyID()
+    if not assistGUID:
+        assistGUID = str(uuid.uuid1())
+    crossAssist = mapID in ChConfig.Def_CrossMapIDList
+    familyID = 0 if crossAssist else curPlayer.GetFamilyID()
     playerID = curPlayer.GetPlayerID()
     assistObj = PyGameDataStruct.tagDBAssist()
     assistObj.GUID = assistGUID
@@ -459,22 +849,19 @@
     assistObj.ExDataLen = len(exData)
     
     # 以下是非DB字段属性
-    OnInitAssistData(assistObj, isSaveDB)
+    OnInitAssistData(assistObj, isSaveDB, serverGroupID)
     assistObj.ObjID = objID
+    assistObj.Face = curPlayer.GetFace()
+    assistObj.FacePic = curPlayer.GetFacePic()
     
     #assistMgr = PyDataManager.GetPlayerAssistPyManager()
     assistMgr.allAssistDict[assistGUID] = assistObj
-    if familyID not in assistMgr.familyAssistDict:
-        assistMgr.familyAssistDict[familyID] = []
-    familyAssistList = assistMgr.familyAssistDict[familyID]
-    familyAssistList.append(assistObj)
     
-    if not isSaveDB:
-        if playerID not in assistMgr.playerNoSaveDBAssistDict:
-            assistMgr.playerNoSaveDBAssistDict[playerID] = []
-        playerAssistList = assistMgr.playerNoSaveDBAssistDict[playerID]
-        playerAssistList.append(assistObj)
-        
+    if playerID not in assistMgr.playerAssistDict:
+        assistMgr.playerAssistDict[playerID] = []
+    playerAssistList = assistMgr.playerAssistDict[playerID]
+    playerAssistList.append(assistObj)
+    
     GameWorld.DebugLog("    增加新协助请求: familyID=%s,mapID=%s,lineID=%s,npcID=%s,objID=%s,exData=%s,assistGUID=%s" 
                        % (familyID, mapID, lineID, npcID, objID, exData, assistGUID), playerID)
     return assistObj
@@ -485,10 +872,13 @@
     for assistObj in familyAssistList:
         assistInfo = ChPyNetSendPack.tagGCAssistInfo()
         assistInfo.AssistGUID = assistObj.GUID
+        assistInfo.PlayerID = assistObj.PlayerID
         assistInfo.PlayerName = assistObj.PlayerName
         assistInfo.Job = assistObj.Job
         assistInfo.LV = assistObj.LV
         assistInfo.RealmLV = assistObj.RealmLV
+        assistInfo.Face = assistObj.Face
+        assistInfo.FacePic = assistObj.FacePic
         assistInfo.MapID = assistObj.MapID
         assistInfo.LineID = assistObj.LineID
         assistInfo.NPCID = assistObj.NPCID
@@ -521,27 +911,21 @@
     lineID = assistObj.LineID
     npcID = assistObj.NPCID
     objID = assistObj.ObjID
+    serverGroupID = assistObj.ServerGroupID
     
-    GameWorld.DebugLog("取消发布的协助请求: mapID=%s,lineID=%s,npcID=%s,objID=%s,reason=%s,isGameServer=%s, %s" 
-                       % (mapID, lineID, npcID, objID, reason, isGameServer, assistGUID))
+    GameWorld.DebugLog("取消发布的协助请求: mapID=%s,lineID=%s,npcID=%s,objID=%s,reason=%s,isGameServer=%s, %s, serverGroupID=%s" 
+                       % (mapID, lineID, npcID, objID, reason, isGameServer, assistGUID, serverGroupID))
     
     assistMgr = PyDataManager.GetPlayerAssistPyManager()
     if assistGUID not in assistMgr.allAssistDict:
         return
     assistMgr.allAssistDict.pop(assistGUID)
     
-    if familyID in assistMgr.familyAssistDict:
-        familyAssistList = assistMgr.familyAssistDict[familyID]
-        if assistObj in familyAssistList:
-            familyAssistList.remove(assistObj)
-            
-    if playerID in assistMgr.playerNoSaveDBAssistDict:
-        playerAssistList = assistMgr.playerNoSaveDBAssistDict[playerID]
+    if playerID in assistMgr.playerAssistDict:
+        playerAssistList = assistMgr.playerAssistDict[playerID]
         if assistObj in playerAssistList:
             playerAssistList.remove(assistObj)
             
-    SyncFamilyClearAssist(familyID, assistGUID)
-    
     # 取消boss协助
     if assistType == AssistType_Boss:
         
@@ -562,6 +946,48 @@
         # 暂不需要处理
         pass
     
+    # 放最后
+    if familyID:
+        SyncFamilyClearAssist(familyID, assistGUID)
+        
+    if GameWorld.IsCrossServer() and serverGroupID:
+        sendMsg = {"queryType":"CancelPlayerRequestAssist", "queryData":[assistGUID, reason, isGameServer]}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossAssist, sendMsg, [serverGroupID])
+        
+    return
+
+def CrossServerMsg_CancelPlayerRequestAssist(queryType, queryData):
+    ## 收到跨服服务器 - 取消协助请求
+    
+    assistGUID, reason, isGameServer = queryData
+    
+    assistMgr = PyDataManager.GetPlayerAssistPyManager()
+    if assistGUID not in assistMgr.allAssistDict:
+        return
+    assistObj = assistMgr.allAssistDict.pop(assistGUID)
+    playerID = assistObj.PlayerID
+    assistType = assistObj.AssistType
+    
+    GameWorld.Log("收到跨服取消协助boss请求: %s assistGUID=%s,reason=%s,isGameServer=%s" % (queryType, assistGUID, reason, isGameServer), playerID)
+    
+    if playerID in assistMgr.playerAssistDict:
+        playerAssistList = assistMgr.playerAssistDict[playerID]
+        if assistObj in playerAssistList:
+            playerAssistList.remove(assistObj)
+            
+    # 取消boss协助
+    if assistType == AssistType_Boss:
+        # 强制取消正在协助中的玩家
+        playerMgr = GameWorld.GetPlayerManager()
+        for assPlayerID in assistObj.AssistPlayerIDList[::-1]:
+            assistObj.AssistPlayerIDList.remove(assPlayerID)
+            if assPlayerID in assistMgr.playerAssistingDict:
+                assistingObj = assistMgr.playerAssistingDict[assPlayerID]
+                if assistingObj.GUID == assistGUID:
+                    assPlayer = playerMgr.FindPlayerByID(assPlayerID)
+                    OnCancelPlayerAssist(assPlayer, assPlayerID, assistObj, reason, isGameServer, isNotify=False)
+                    
+    SyncServerClearAssist(assistGUID)
     return
 
 def OnCancelPlayerAssist(cancelPlayer, cancelPlayerID, assistObj, reason, isGameServer, isNotify=True):
@@ -585,6 +1011,7 @@
     lineID = assistObj.LineID
     npcID = assistObj.NPCID
     objID = assistObj.ObjID
+    serverGroupID = assistObj.ServerGroupID
     
     GameWorld.DebugLog("取消协助: tagPlayerID=%s,mapID=%s,lineID=%s,npcID=%s,objID=%s,reason=%s,isGameServer=%s, %s" 
                        % (tagPlayerID, mapID, lineID, npcID, objID, reason, isGameServer, assistGUID), cancelPlayerID)
@@ -597,7 +1024,14 @@
         assistObj.AssistPlayerIDList.remove(cancelPlayerID)
         
     if cancelPlayer:
+        isTagPlayerReason = reason.startswith("RequestPlayerCancel_")
         PlayerControl.SetAssistTagPlayerID(cancelPlayer, 0)
+        overPack = ChPyNetSendPack.tagGCAssistOver()
+        overPack.IsTagPlayerReason = isTagPlayerReason
+        overPack.Reason = reason[len("RequestPlayerCancel_"):] if isTagPlayerReason else reason 
+        overPack.ReasonLen = len(overPack.Reason)
+        overPack.AssistGUID = assistGUID
+        NetPackCommon.SendFakePack(cancelPlayer, overPack)
         
     # 取消boss协助
     if assistObj.AssistType == AssistType_Boss:
@@ -617,8 +1051,197 @@
     elif assistObj.AssistType == AssistType_TeamFB:
         pass
     
+    if GameWorld.IsCrossServer() and serverGroupID:
+        sendMsg = {"queryType":"CancelPlayerAssist", "queryData":[assistGUID, reason, isGameServer, cancelPlayerID]}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossAssist, sendMsg, [serverGroupID])
+        
     return
 
+def CrossServerMsg_CancelPlayerAssist(queryType, queryData):
+    ## 收到跨服服务器 - 取消玩家协助
+    
+    assistGUID, reason, isGameServer, cancelPlayerID = queryData
+    
+    assistMgr = PyDataManager.GetPlayerAssistPyManager()
+    if assistGUID not in assistMgr.allAssistDict:
+        return
+    
+    GameWorld.Log("收到跨服取消玩家协助: %s assistGUID=%s,reason=%s,isGameServer=%s" % (queryType, assistGUID, reason, isGameServer), cancelPlayerID)
+    
+    cancelPlayer = GameWorld.GetPlayerManager().FindPlayerByID(cancelPlayerID)
+    if not cancelPlayer:
+        return
+    
+    PlayerControl.SetAssistTagPlayerID(cancelPlayer, 0)
+    return
+
+def CrossServerMsg_ResetPlayerAssist(queryType, queryData):
+    ## 收到跨服服务器 - 重置玩家协助
+    ## 
+    
+    playerID, tagPlayerID = queryData
+    
+    GameWorld.Log("收到跨服重置玩家协助: playerID=%s,tagPlayerID=%s" % (playerID, tagPlayerID), playerID)
+    
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
+    if not curPlayer:
+        return
+    PlayerControl.SetAssistTagPlayerID(curPlayer, 0)
+    return
+
+def __DoBossAssistOver(queryData):
+    ## boss协助结束,一般是boss被击杀 或 被系统
+    mapID, lineID, npcID, objID, noAssistPlayerIDList, assistAwardItemID, assistAwardResult = queryData
+    isCrossServer = GameWorld.IsCrossServer()
+    assistMgr = PyDataManager.GetPlayerAssistPyManager()
+    for noAssistPlayerID in noAssistPlayerIDList:
+        if noAssistPlayerID not in assistMgr.playerAssistDict:
+            continue
+        playerAssistList = assistMgr.playerAssistDict[noAssistPlayerID]
+        for assistObj in playerAssistList:
+            if assistObj.MapID == mapID and assistObj.LineID == lineID and assistObj.NPCID == npcID and assistObj.ObjID == objID:
+                OnCancelPlayerRequestAssist(assistObj, "BossAssistOver", False)
+                
+                # 跨服服务器同步到子服结算奖励
+                if isCrossServer and noAssistPlayerID in assistAwardResult:
+                    assistPlayerDict = assistAwardResult[noAssistPlayerID]
+                    serverGroupID = assistObj.ServerGroupID
+                    sendMsg = {"queryType":"BossAssistOver", "queryData":[mapID, lineID, npcID, noAssistPlayerID, assistAwardItemID, assistPlayerDict]}
+                    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_CrossAssist, sendMsg, [serverGroupID])
+                break
+            
+    if not assistAwardItemID or not assistAwardResult:
+        return
+    
+    if isCrossServer:
+        return
+    
+    # 新增感谢数据
+    playerMgr = GameWorld.GetPlayerManager()
+    for playerID, assistPlayerDict in assistAwardResult.items():
+        curPlayer = playerMgr.FindPlayerByID(playerID)
+        if not curPlayer:
+            continue
+        AddNewAssistThanks(curPlayer, assistAwardItemID, mapID, lineID, assistPlayerDict, npcID)
+        
+    return
+
+def CrossServerMsg_BossAssistOver(queryType, queryData):
+    ## 收到跨服服务器 - boss协助结束
+    
+    mapID, lineID, npcID, noAssistPlayerID, assistAwardItemID, assistPlayerDict = queryData
+    
+    GameWorld.Log("收到跨服boss协助结束: mapID=%s,lineID=%s,npcID=%s,assistAwardItemID=%s,assistPlayerDict=%s" 
+                  % (mapID, lineID, npcID, assistAwardItemID, assistPlayerDict), noAssistPlayerID)
+    
+    # 新增感谢数据
+    playerMgr = GameWorld.GetPlayerManager()
+    curPlayer = playerMgr.FindPlayerByID(noAssistPlayerID)
+    if not curPlayer:
+        return
+    
+    AddNewAssistThanks(curPlayer, assistAwardItemID, mapID, lineID, assistPlayerDict, npcID)
+    
+    # 通知地图玩家给 协助礼盒
+    queryData = [assistAwardItemID]
+    QueryPlayerResult_PlayerAssist(curPlayer, "CrossNoAssistPlayerAward", queryData)
+    
+    # 通知地图玩家给 活跃积分
+    for assistPlayerID, assistInfo in assistPlayerDict.items():
+        assistPlayer = playerMgr.FindPlayerByID(assistPlayerID)
+        if not assistPlayer:
+            continue
+        if "AssistMoney" not in assistInfo:
+            continue
+        assistMoney = assistInfo["AssistMoney"]
+        isFriend = assistInfo["IsFriend"]
+        
+        queryData = [assistMoney, isFriend]
+        QueryPlayerResult_PlayerAssist(assistPlayer, "CrossAssistPlayerAward", queryData)
+        
+    return
+
+def __DoFBAssistOver(queryData):
+    ## 副本协助结束
+    mapID, lineID, noAssistPlayerID, assistAwardItemID, assistPlayerDict = queryData
+    assistMgr = PyDataManager.GetPlayerAssistPyManager()
+    if noAssistPlayerID not in assistMgr.playerAssistDict:
+        return
+    playerAssistList = assistMgr.playerAssistDict[noAssistPlayerID]
+    for assistObj in playerAssistList:
+        if assistObj.MapID == mapID and assistObj.LineID == lineID:
+            OnCancelPlayerRequestAssist(assistObj, "FBAssistOver", False)
+            break
+        
+    if not assistAwardItemID or not assistPlayerDict:
+        return
+    
+    # 新增感谢数据
+    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(noAssistPlayerID)
+    if curPlayer:
+        AddNewAssistThanks(curPlayer, assistAwardItemID, mapID, lineID, assistPlayerDict)
+        
+    return
+
+def AddNewAssistThanks(curPlayer, itemID, mapID, lineID, assistPlayerDict, npcID=0, exData=""):
+    ## 添加协助感谢数据
+    
+    playerID = curPlayer.GetPlayerID()
+    newThanks = PyGameDataStruct.tagDBAssistThanks()
+    newThanks.GUID = str(uuid.uuid1())
+    newThanks.ItemID = itemID
+    newThanks.FamilyID = curPlayer.GetFamilyID()
+    newThanks.PlayerID = playerID
+    newThanks.PlayerName = curPlayer.GetName()
+    newThanks.Job = curPlayer.GetJob()
+    newThanks.LV = curPlayer.GetLV()
+    newThanks.RealmLV = curPlayer.GetOfficialRank()
+    newThanks.MapID = mapID
+    newThanks.LineID = lineID
+    newThanks.NPCID = npcID
+    newThanks.ExData = exData
+    newThanks.ExDataLen = len(exData)
+    newThanks.DailyDateStr = GameWorld.GetDailyDateStr()
+    newThanks.TimeStr = GameWorld.GetCurrentDataTimeStr()
+    newThanks.AssistPlayer = str(assistPlayerDict)
+    newThanks.AssistPlayerLen = len(newThanks.AssistPlayer)
+    
+    assistThanksMgr = PyDataManager.GetPlayerAssistThanksPyManager()
+    OnInitAssistThanksData(assistThanksMgr, newThanks)
+    newThanks.Face = curPlayer.GetFace()
+    newThanks.FacePic = curPlayer.GetFacePic()
+    
+    GameWorld.DebugLog("增加协助感谢: itemID=%s,mapID=%s,lineID=%s,npcID=%s,exData=%s" % (itemID, mapID, lineID, npcID, exData), playerID)
+    return
+
+def AddNewAssistThanksEx(curPlayer, itemID, assistPlayerDict, mapID=0, lineID=0, npcID=0, exData=""):
+    ## 添加协助感谢数据,自动更新 TodayGiftCount 及 玩家信息
+    DailyDateStr = GameWorld.GetDailyDateStr()
+    assistThanksMgr = PyDataManager.GetPlayerAssistThanksPyManager()
+    for assistPlayerID, assistPlayerInfoDict in assistPlayerDict.items():
+        
+        # 查找今日该感谢物品已接受感谢次数
+        TodayGiftCount = 0
+        assistPlayerThanksList = assistThanksMgr.assistPlayerThanksDict.get(assistPlayerID, [])
+        for thanks in assistPlayerThanksList:
+            if DailyDateStr != thanks.DailyDateStr or itemID != thanks.ItemID:
+                continue
+            if assistPlayerID not in thanks.AssistPlayerDict:
+                continue
+            infoDict = thanks.AssistPlayerDict[assistPlayerID]
+            TodayGiftCount = infoDict.get("TodayGiftCount", 0)
+            break
+        
+        assistPlayerInfoDict["TodayGiftCount"] = TodayGiftCount
+        
+        # 更新玩家信息,之后有需要再扩展,可以从玩家缓存或直接取在线玩家实例赋值 name job 等信息
+        
+        GameWorld.DebugLog("获取今日接受感谢次数: itemID=%s,TodayGiftCount=%s" % (itemID, TodayGiftCount), assistPlayerID)
+    GameWorld.DebugLog("AddNewAssistThanksEx itemID=%s,assistPlayerDict=%s" % (itemID, assistPlayerDict), curPlayer.GetPlayerID())
+    AddNewAssistThanks(curPlayer, itemID, mapID, lineID, assistPlayerDict, npcID, exData)
+    return
+
+    
 #// B0 14 使用协助感谢礼盒 #tagCGUseAssistThanksGift
 #
 #struct    tagCGUseAssistThanksGift
@@ -626,34 +1249,212 @@
 #{
 #    tagHead        Head;
 #    DWORD        ItemID;
-#    char        GiftGUID[40];    //预览时GUID不发,确认使用时需发送预览返回的GUID
+#    BYTE        IsPreview;    //是否预览,非预览即确认使用
 #};
 def OnUseAssistThanksGift(index, clientData, tick):
     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
     itemID = clientData.ItemID
-    giftGUID = clientData.GiftGUID
+    isPreview = clientData.IsPreview
+    
+    playerID = curPlayer.GetPlayerID()
+    assistThanksMgr = PyDataManager.GetPlayerAssistThanksPyManager()
+    useThanks = None
+    if playerID not in assistThanksMgr.playerThanksDict:
+        GameWorld.ErrLog("玩家没有可使用的协助感谢礼盒!", playerID)
+    else:
+        playerThanksList = assistThanksMgr.playerThanksDict[playerID]
+        for thanks in playerThanksList:
+            if itemID == thanks.ItemID:
+                useThanks = thanks
+                break
+    if not useThanks:
+        GameWorld.ErrLog("玩家没有该协助感谢礼盒!itemID=%s" % (itemID), playerID)
+        #20210226 优化为找不到协助信息也可以使用,防止地图扣除物品失败导致协助礼盒一直留着而无法使用
+        #return
+    
+    GameWorld.DebugLog("玩家使用协助感谢礼盒!itemID=%s,isPreview=%s" % (itemID, isPreview), playerID)
+    # 预览
+    if isPreview:
+        previewPack = ChPyNetSendPack.tagGCUseAssistThanksGiftPreview()
+        if not useThanks:
+            previewPack.ItemID = itemID
+            previewPack.MapID = 31140 # 暂随意给一个可协助的地图ID
+            NetPackCommon.SendFakePack(curPlayer, previewPack)
+            return
+        previewPack.ItemID = useThanks.ItemID
+        previewPack.MapID = useThanks.MapID
+        previewPack.LineID = useThanks.LineID
+        previewPack.NPCID = useThanks.NPCID
+        previewPack.ExData = useThanks.ExData
+        previewPack.ExDataLen = useThanks.ExDataLen
+        previewPack.AssistPlayerList = []
+        for assistPlayerID, assistPlayerInfoDict in useThanks.AssistPlayerDict.items():
+            if "PlayerName" not in assistPlayerInfoDict:
+                continue
+            assistPlayerInfo = ChPyNetSendPack.tagGCAssistPlayerInfo()
+            assistPlayerInfo.PlayerID = assistPlayerID
+            assistPlayerInfo.PlayerName = assistPlayerInfoDict["PlayerName"]
+            assistPlayerInfo.Job = assistPlayerInfoDict["Job"]
+            assistPlayerInfo.LV = assistPlayerInfoDict["LV"]
+            assistPlayerInfo.RealmLV = assistPlayerInfoDict["RealmLV"]
+            assistPlayerInfo.Face = assistPlayerInfoDict.get("Face", 0)
+            assistPlayerInfo.FacePic = assistPlayerInfoDict.get("FacePic", 0)
+            previewPack.AssistPlayerList.append(assistPlayerInfo)
+        previewPack.AssistPlayerCount = len(previewPack.AssistPlayerList)
+        NetPackCommon.SendFakePack(curPlayer, previewPack)
+        return
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("AssistThanksGift", itemID)
+    if not ipyData:
+        return
+        
+    queryData = [itemID]
+    QueryPlayerResult_PlayerAssist(curPlayer, "UseAssistThanksGift", queryData)
+    
+    if not useThanks:
+        return
+    useThanks.ThanksState = 1 # 设置为已感谢
+    playerThanksList.remove(useThanks) # 移除已感谢
+    
+    # 通知协助玩家可接收的感谢个数
+    playerMgr = GameWorld.GetPlayerManager()
+    for assistPlayerID in useThanks.AssistPlayerDict.keys():
+        assistPlayer = playerMgr.FindPlayerByID(assistPlayerID)
+        if assistPlayer:
+            SyncCanGetAssistThanksGiftCount(assistPlayer)
     return
 
-#// B0 15 领取协助感谢礼物 #tagCGGetAssistThanksGift
+#// B0 15 接收协助感谢礼物 #tagCGGetAssistThanksGift
 #
 #struct    tagCGGetAssistThanksGift
 #
 #{
 #    tagHead        Head;
-#    char        GiftGUID[40];    //礼盒GUID
+#    BYTE        IsPreview;    //是否预览,非预览即确认领取,无额外奖励确认时也需要回复领取包代表已读
 #};
 def OnGetAssistThanksGift(index, clientData, tick):
     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
-    giftGUID = clientData.GiftGUID
+    isPreview = clientData.IsPreview
+    
+    playerID = curPlayer.GetPlayerID()
+    assistThanksMgr = PyDataManager.GetPlayerAssistThanksPyManager()
+    if playerID not in assistThanksMgr.assistPlayerThanksDict:
+        GameWorld.ErrLog("玩家没有可接收感谢的协助感谢礼盒!", playerID)
+        return
+    assistPlayerThanksList = assistThanksMgr.assistPlayerThanksDict[playerID]
+    getThanks = None
+    for thanks in assistPlayerThanksList:
+        if thanks.ThanksState:
+            getThanks = thanks
+            break
+    if not getThanks:
+        GameWorld.ErrLog("找不到玩家可接收感谢的协助感谢礼盒!", playerID)
+        return
+    itemID = getThanks.ItemID
+    ipyData = IpyGameDataPY.GetIpyGameData("AssistThanksGift", itemID)
+    if not ipyData:
+        return
+    if playerID not in getThanks.AssistPlayerDict:
+        return
+    assistPlayerInfoDict = getThanks.AssistPlayerDict[playerID]
+    todayGiftCount = assistPlayerInfoDict.get("TodayGiftCount", 0) # 该礼盒当日已领取额外奖励次数
+    isExtraAward = 1 if todayGiftCount < ipyData.GetAssistAwardCount() else 0
+    
+    GameWorld.DebugLog("接收协助感谢礼物: itemID=%s,isPreview=%s,isExtraAward=%s,DailyDateStr=%s" 
+                       % (itemID, isPreview, isExtraAward, getThanks.DailyDateStr), playerID)
+    
+    # 预览
+    if isPreview:
+        previewPack = ChPyNetSendPack.tagGCGetAssistThanksGiftPreview()
+        previewPack.ItemID = getThanks.ItemID
+        previewPack.PlayerID = getThanks.PlayerID
+        previewPack.PlayerName = getThanks.PlayerName
+        previewPack.Job = getThanks.Job
+        previewPack.LV = getThanks.LV
+        previewPack.RealmLV = getThanks.RealmLV
+        previewPack.Face = getThanks.Face
+        previewPack.FacePic = getThanks.FacePic
+        previewPack.MapID = getThanks.MapID
+        previewPack.LineID = getThanks.LineID
+        previewPack.NPCID = getThanks.NPCID
+        previewPack.ExData = getThanks.ExData
+        previewPack.ExDataLen = len(getThanks.ExData)
+        previewPack.TimeStr = getThanks.TimeStr
+        previewPack.ExtraAward = isExtraAward
+        NetPackCommon.SendFakePack(curPlayer, previewPack)
+        return
+        
+    assistPlayerInfoDict["IsGet"] = 1
+    isAllGet = True
+    for playerDict in getThanks.AssistPlayerDict.values():
+        if "IsGet" not in playerDict:
+            isAllGet = False
+            break
+        
+    # 所有人都接收感谢了,删除该协助感谢数据
+    if isAllGet:
+        GameWorld.DebugLog("    所有人都感谢了,移除该协助感谢!", playerID)
+        if getThanks in assistThanksMgr.allAssistThanksList:
+            assistThanksMgr.allAssistThanksList.remove(getThanks)
+            
+    assistPlayerThanksList.remove(getThanks) # 移除
+    
+    updateTodayGiftCount = todayGiftCount + 1
+    # 更新当天该礼盒ID已领取次数
+    for thanks in assistPlayerThanksList:
+        if getThanks.DailyDateStr != thanks.DailyDateStr or getThanks.ItemID != thanks.ItemID:
+            continue
+        if playerID not in thanks.AssistPlayerDict:
+            continue
+        assistPlayerInfoDict = thanks.AssistPlayerDict[playerID]
+        assistPlayerInfoDict["TodayGiftCount"] = updateTodayGiftCount
+        
+    SyncCanGetAssistThanksGiftCount(curPlayer, True)
+    
+    isCurDailyDate = getThanks.DailyDateStr == GameWorld.GetDailyDateStr()
+    
+    # 如果是镜像协助的,更新今日接收感谢礼盒次数
+    if isCurDailyDate:
+        if IpyGameDataPY.GetIpyGameDataNotLog("FBHelpBattle", getThanks.MapID, getThanks.LineID):
+            PlayerFBHelpBattle.UpdateGetThanksGiftCountDict(curPlayer, itemID, updateTodayGiftCount)
+            
+    # 通知地图
+    queryData = [itemID, isExtraAward, isCurDailyDate, updateTodayGiftCount]
+    QueryPlayerResult_PlayerAssist(curPlayer, "GetAssistThanksGift", queryData)
     return
 
+def SyncCanGetAssistThanksGiftCount(curPlayer, isForce=False):
+    ## 通知可接收协助感谢礼物个数
+    
+    playerID = curPlayer.GetPlayerID()
+    assistThanksMgr = PyDataManager.GetPlayerAssistThanksPyManager()
+    if playerID not in assistThanksMgr.assistPlayerThanksDict:
+        return
+    assistPlayerThanksList = assistThanksMgr.assistPlayerThanksDict[playerID]
+    canGetCount = 0
+    for thanks in assistPlayerThanksList:
+        if thanks.ThanksState:
+            canGetCount += 1
+            
+    if not canGetCount and not isForce:
+        return
+    
+    countPack = ChPyNetSendPack.tagGCCanGetAssistThanksGiftCount()
+    countPack.CanGetCount = canGetCount
+    NetPackCommon.SendFakePack(curPlayer, countPack)
+    return
+    
 def SyncFamilyAssist(curPlayer):
     ## 同步当前仙盟所有协助请求信息
     familyID = curPlayer.GetFamilyID()
     if not familyID:
         return
     assistMgr = PyDataManager.GetPlayerAssistPyManager()
-    familyAssistList = assistMgr.familyAssistDict.get(familyID, [])
+    familyAssistList = []
+    for assistObj in assistMgr.allAssistDict.values():
+        if not assistObj.FamilyID or familyID != assistObj.FamilyID or assistObj.OffLineTime:
+            continue
+        familyAssistList.append(assistObj)
     if not familyAssistList:
         return
     NetPackCommon.SendFakePack(curPlayer, GetAssistInfoListPack(familyAssistList))
@@ -666,3 +1467,37 @@
     PlayerFamily.SendFamilyFakePack(familyID, clearPack)
     return
 
+def SyncServerAssist(assistList):
+    # 通知本服玩家协助请求信息
+    funcLimitLV = PlayerControl.GetFuncLimitLV(ShareDefine.GameFuncID_PenglaiBoss)
+    clientPack = GetAssistInfoListPack(assistList)
+    playerManager = GameWorld.GetPlayerManager()
+    for i in xrange(playerManager.GetActivePlayerCount()):
+        player = playerManager.GetActivePlayerAt(i)
+        if player == None:
+            continue
+        if player.GetLV() < funcLimitLV:
+            continue
+        if PlayerControl.GetIsTJG(player):
+            continue
+        NetPackCommon.SendFakePack(player, clientPack)
+    return
+
+def SyncServerClearAssist(assistGUID):
+    # 通知本服玩家清除协助
+    clearPack = ChPyNetSendPack.tagGCClearAssist()
+    clearPack.AssistGUID = assistGUID
+    funcLimitLV = PlayerControl.GetFuncLimitLV(ShareDefine.GameFuncID_PenglaiBoss)
+    playerManager = GameWorld.GetPlayerManager()
+    for i in xrange(playerManager.GetActivePlayerCount()):
+        player = playerManager.GetActivePlayerAt(i)
+        if player == None:
+            continue
+        if player.GetLV() < funcLimitLV:
+            continue
+        if PlayerControl.GetIsTJG(player):
+            continue
+        NetPackCommon.SendFakePack(player, clearPack)
+    return
+
+

--
Gitblit v1.8.0