From ed55412a729dc711b908bef765e2465866b2c4e7 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期四, 17 一月 2019 23:07:52 +0800
Subject: [PATCH] 5722 【后端】【1.5】跨服BOSS开发(同步影响玩家战力的属性、字典到跨服服务器,暂定延迟5秒同步)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py                    |  197 ++++++++++++++++++++++++++++++++++++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossRealmReg.py |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py                                |    6 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py                      |   14 +++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py                        |    3 
 5 files changed, 220 insertions(+), 2 deletions(-)

diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py
index 7eadb42..ec3ae5c 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py
@@ -20,6 +20,7 @@
 import SkillCommon
 import base64
 import ChConfig
+import PyGameData
 
 # 发送格式: 类型+(数量)+数据
 # 向跨服发送的数据类型
@@ -30,8 +31,17 @@
 MergeData_Buff,     # 即时发送
 ) = range(0, 4)
 
-# 发送主服玩家数据给跨服
+# 影响跨服战力属性列表
+CrossFightPowerAttrList = [
+    [lambda curObj:curObj.GetBaseSTR(), lambda curObj, value:curObj.SetBaseSTR(value)], # 力量
+    [lambda curObj:curObj.GetBasePNE(), lambda curObj, value:curObj.SetBasePNE(value)], # 智力
+    [lambda curObj:curObj.GetBasePHY(), lambda curObj, value:curObj.SetBasePHY(value)], # 敏捷
+    [lambda curObj:curObj.GetBaseCON(), lambda curObj, value:curObj.SetBaseCON(value)], # 体质
+    [lambda curObj:curObj.GetOfficialRank(), lambda curObj, value:curObj.SetOfficialRank(value)], # 境界
+    [lambda curObj:curObj.GetVIPLv(), lambda curObj, value:curObj.SetVIPLv(value)], # VIP等级
+                           ]
 
+# 发送主服玩家数据给跨服
 def SendMergeData_Buff(curPlayer, buffID, plusValueList):
     if buffID in [ChConfig.Def_SkillID_LimitSuperBuff,
                   ChConfig.Def_SkillID_TJGSuperBuff]:
@@ -88,9 +98,192 @@
             
         buffType = SkillCommon.GetBuffType(curSkill)
         BuffSkill.AddBuffNoRefreshState(curPlayer, buffType, curSkill, tick, plusValueList)
-
+        
+    elif dataType == MergeData_Player:
+        __ReadMainServerSyncPlayerData(curPlayer, curPlayer.GetMergePlayerData(), pos)
         
     return
 
+## ----------------------------------------------------------------------------------------------
+
+def IsNeedProcessCrossPlayer(curPlayer):
+    ## 是否需要处理同步跨服中的玩家数据
+    if GameWorld.IsCrossServer():
+        return
+    
+    crossMapID = curPlayer.NomalDictGetProperty(ChConfig.Def_PlayerKey_CrossRegisterMap)
+    if not crossMapID:
+        crossMapID = PlayerControl.GetCrossMapID(curPlayer)
+    if not crossMapID or crossMapID not in ChConfig.Def_CrossMapIDList:
+        return
+    
+    # 不需要处理的跨服地图
+    if crossMapID in [ChConfig.Def_FBMapID_CrossRealmPK]:
+        return
+    
+    return True
+
+def ClearCrossSyncDataCache(curPlayer):
+    ## 清除同步跨服数据的临时缓存
+    playerID = curPlayer.GetPlayerID()
+    PyGameData.g_crossRegPlayerAttrDict.pop(playerID, None)
+    PyGameData.g_crossSyncTickDict.pop(playerID, None)
+    PyGameData.g_crossPlayerDictChangeInfo.pop(playerID, None)
+    GameWorld.DebugLog("清除同步跨服数据的临时缓存", playerID)
+    return
+
+def OnPlayerCrossReg(curPlayer):
+    ## 玩家跨服数据注册
+    
+    if not IsNeedProcessCrossPlayer(curPlayer):
+        return
+    
+    ClearCrossSyncDataCache(curPlayer)
+    attrList = []
+    for attrInfo in CrossFightPowerAttrList:
+        attrList.append(attrInfo[0](curPlayer))
+    playerID = curPlayer.GetPlayerID()
+    PyGameData.g_crossRegPlayerAttrDict[playerID] = attrList
+    return
+
+def OnPlayerFightPowerChange(curPlayer):
+    ## 玩家战力变更时
+    if not IsNeedProcessCrossPlayer(curPlayer):
+        return
+    playerID = curPlayer.GetPlayerID()
+    if playerID in PyGameData.g_crossSyncTickDict:
+        return
+    tick = GameWorld.GetGameWorld().GetTick()
+    PyGameData.g_crossSyncTickDict[playerID] = tick
+    #GameWorld.DebugLog("标记需要同步跨服玩家战力变更相关数据! tick=%s" % tick, curPlayer.GetPlayerID())
+    return
+
+def ProcessCrossPlayer(curPlayer, tick):
+    ## 跨服状态的本服玩家处理
+    if not IsNeedProcessCrossPlayer(curPlayer):
+        return
+    
+    playerID = curPlayer.GetPlayerID()
+    if playerID not in PyGameData.g_crossSyncTickDict:
+        return
+    setTick = PyGameData.g_crossSyncTickDict[playerID]
+    if tick - setTick < 5000:
+        return
+    PyGameData.g_crossSyncTickDict.pop(playerID)
+    GameWorld.DebugLog("开始同步本服变更的属性...", playerID)
+    
+    # 这里只做可能引起战力变化所需要同步的数据
+    data = ""
+    data = __WriteSyncPlayerAttrData(curPlayer, data) # 玩家属性
+    data = __WriteSyncPlayerDictData(curPlayer, data) # 字典
+    # 物品
+    
+    # 技能
+    
+    #直接用字节流会报错
+    data = base64.b64encode(data)
+    curPlayer.SendMergePlayerData(data)
+    return
+
+def __ReadMainServerSyncPlayerData(curPlayer, pdata, pos):
+    ## 读取子服同步的玩家战力变更相关属性
+    
+    GameWorld.DebugLog("收到子服同步的玩家变更数据:", curPlayer.GetPlayerID())
+    
+    pos = __ReadSyncPlayerAttrData(curPlayer, pdata, pos) # 玩家属性
+    pos = __ReadSyncPlayerDictData(curPlayer, pdata, pos) # 字典
+    # 物品
+    
+    # 技能
+    
+    # 强刷一次属性
+    PlayerControl.PlayerControl(curPlayer).ReCalcAllState()
+    return
+
+def __WriteSyncPlayerAttrData(curPlayer, data):
+    ## 写入需要同步的玩家属性
+    
+    data = CommFunc.WriteBYTE(data, MergeData_Player)
+    playerID = curPlayer.GetPlayerID()
+    if playerID not in PyGameData.g_crossRegPlayerAttrDict:
+        return CommFunc.WriteBYTE(data, 0)
+    attrList = PyGameData.g_crossRegPlayerAttrDict[playerID]
+    
+    if len(attrList) != len(CrossFightPowerAttrList):
+        return CommFunc.WriteBYTE(data, 0)
+        
+    changeAttrList = []
+    for i, attrInfo in enumerate(CrossFightPowerAttrList):
+        befValue = attrList[i]
+        curValue = attrInfo[0](curPlayer)
+        if befValue == curValue:
+            continue
+        changeAttrList.append([i, curValue])
+        attrList[i] = curValue # 更新记录的值
+        
+    if not changeAttrList:
+        return CommFunc.WriteBYTE(data, 0)
+    
+    count = len(changeAttrList)
+    GameWorld.DebugLog("变更的玩家属性个数: %s" % count)
+    data = CommFunc.WriteBYTE(data, count)
+    for index, curValue in changeAttrList:
+        data = CommFunc.WriteBYTE(data, index)
+        data = CommFunc.WriteDWORD(data, curValue)
+        GameWorld.DebugLog("    index=%s,value=%s" % (index, curValue))
+        
+    return data
+
+def __ReadSyncPlayerAttrData(curPlayer, pdata, pos):
+    ## 读取同步的玩家属性
+    pdata = base64.b64decode(pdata)
+    count, pos = CommFunc.ReadBYTE(pdata, pos)
+    GameWorld.DebugLog("变更的玩家属性个数: %s" % count)
+    for _ in range(count):
+        index, pos = CommFunc.ReadBYTE(pdata, pos)
+        value, pos = CommFunc.ReadDWORD(pdata, pos)
+        CrossFightPowerAttrList[index][1](curPlayer, value) # 设置更新值
+        GameWorld.DebugLog("    index=%s,value=%s" % (index, value))
+        
+    return pos
+
+def __WriteSyncPlayerDictData(curPlayer, data):
+    ## 写入需要同步的玩家字典
+    playerID = curPlayer.GetPlayerID()
+    if playerID not in PyGameData.g_crossPlayerDictChangeInfo:
+        return CommFunc.WriteBYTE(data, 0)
+    changeDict = PyGameData.g_crossPlayerDictChangeInfo.pop(playerID)
+    
+    count = len(changeDict)
+    GameWorld.DebugLog("变更的玩家字典个数: %s" % count)
+    data = CommFunc.WriteWORD(data, count)
+    for keyInfo, value in changeDict.items():
+        key, dType = keyInfo
+        keyLen = len(key)
+        data = CommFunc.WriteBYTE(data, keyLen)
+        data = CommFunc.WriteString(data, keyLen, key)
+        data = CommFunc.WriteDWORD(data, value)
+        data = CommFunc.WriteBYTE(data, dType)
+        GameWorld.DebugLog("    key=%s, value=%s, dType=%s" % (key, value, dType))
+    
+    return data
+
+def __ReadSyncPlayerDictData(curPlayer, pdata, pos):
+    ## 读取同步的玩家字典
+    pdata = base64.b64decode(pdata)
+    count, pos = CommFunc.ReadWORD(pdata, pos)
+    GameWorld.DebugLog("变更的玩家字典个数: %s" % count)
+    for _ in xrange(count):
+        keyLen, pos = CommFunc.ReadBYTE(pdata, pos)
+        key, pos = CommFunc.ReadString(pdata, pos, keyLen)
+        value, pos = CommFunc.ReadDWORD(pdata, pos)
+        dType, pos = CommFunc.ReadBYTE(pdata, pos)
+        PlayerControl.NomalDictSetProperty(curPlayer, key, value, dType)
+        GameWorld.DebugLog("    key=%s, value=%s, dType=%s" % (key, value, dType))
+        
+    return pos
+
+
+
 
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
index 6e7664b..8d1217a 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -86,6 +86,7 @@
 import PlayerCrossRealmPK
 import FunctionNPCCommon
 import CrossRealmPlayer
+import CrossPlayerData
 import ChNetSendPack
 import PlayerCoat
 import PlayerState
@@ -1208,6 +1209,9 @@
     PyGameData.g_needRefreshMapServerState = True # 有玩家离开地图设置需要刷新
     
     PlayerSuccess.FinishDelayAddSuccessProgress(curPlayer, tick)
+    
+    if not isDisconnect:
+        CrossPlayerData.ClearCrossSyncDataCache(curPlayer)
     return
 
 ##更新保存玩家在线时间
@@ -4787,6 +4791,7 @@
         PlayerBillboard.UpdatePlayerFPTotalBillboard(curPlayer)
         # 记录开服活动数据
         OpenServerCampaign.UpdOpenServerCampaignRecordData(curPlayer, ShareDefine.Def_Campaign_Type_FightPower, totalFightPower)
+        CrossPlayerData.OnPlayerFightPowerChange(curPlayer)
         return
     
     def __RefreshMoveSpeed(self, allAttrListBuffs):
@@ -5744,6 +5749,8 @@
 def GetCrossMapID(curPlayer): return curPlayer.GetExAttr5()
 def SetCrossMapID(curPlayer, value):
     curPlayer.SetExAttr5(value, False, True)
+    if not value:
+        CrossPlayerData.ClearCrossSyncDataCache(curPlayer)
     return
 
 ## 铜钱点, 支持铜钱超20亿
@@ -6798,6 +6805,13 @@
 #-------------------------------------------------------------------------------
 ## 设置玩家字典值, 存库
 def NomalDictSetProperty(curPlayer, key, value, dType=0):
+    if CrossPlayerData.IsNeedProcessCrossPlayer(curPlayer) and key not in \
+        [ChConfig.Def_PDict_FightPower_Total, ChConfig.Def_PlayerKey_CrossRegisterMap]:
+        playerID = curPlayer.GetPlayerID()
+        changeDict = PyGameData.g_crossPlayerDictChangeInfo.get(playerID, {})
+        changeDict[(key, dType)] = value
+        PyGameData.g_crossPlayerDictChangeInfo[playerID] = changeDict
+        
     if value == 0:
         curPlayer.NomalDictDelProperty(key, dType)
         return
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
index b936a48..c99aa27 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
@@ -52,6 +52,7 @@
 import PlayerTJG
 import AICommon
 import PlayerSuccess
+import CrossPlayerData
 import PassiveBuffEffMng
 import PlayerFamilyRedPacket
 import FormulaControl
@@ -1273,6 +1274,8 @@
     PlayerFlashSale.ProcessFlashSaleMail(curPlayer, tick)
     #地图经验
     ProcessAreaExp(curPlayer, tick)
+    #跨服数据同步,放最后
+    CrossPlayerData.ProcessCrossPlayer(curPlayer, tick)
     return
 
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossRealmReg.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossRealmReg.py
index 38697a6..70aff26 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossRealmReg.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_CrossRealmReg.py
@@ -20,6 +20,7 @@
 import CrossRealmPlayer
 import IPY_GameWorld
 import ChPyNetSendPack
+import CrossPlayerData
 import NetPackCommon
 import ChConfig
 
@@ -87,6 +88,7 @@
         prepareEnterCrossServer.DataMapID = registerMap
         NetPackCommon.SendFakePack(curPlayer, prepareEnterCrossServer)
     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PlayerKey_CrossRegisterMap, registerMap)
+    CrossPlayerData.OnPlayerCrossReg(curPlayer)
     #curPlayer.SendMergeRegisterPlayer(mapID, dataMapID, copyMapID, posX, posY)
     curPlayer.SendMergeRegisterPlayerAfterChange(CrossRealmPlayer.GetCrossPlayerName(curPlayer), mapID, dataMapID, copyMapID, posX, posY)
     GameWorld.Log("    发送跨服玩家数据注册: registerMap=%s,zoneID=%s,mapID=%s,dataMapID=%s,copyMapID=%s,posX=%s,posY=%s,GetVsRoomId=%s" 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
index 0c0ee25..ba5199f 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -80,3 +80,9 @@
 g_fbRobotJobDict = {} #副本机器人职业  {lineID:{objID:job, ...}, ...}
 
 g_gathersoulfbAwardDict = {} #聚魂副本奖励记录{playerID:[[itemID,itemCnt]]}
+
+g_crossRegPlayerAttrDict = {} #跨服注册时登记的会影响战力的属性值 {playerID:[value, ...], ...}
+g_crossSyncTickDict = {} #需要同步跨服数据的玩家同步tick字典 {playerID:tick, ...}
+g_crossPlayerDictChangeInfo = {} #跨服玩家字典变化信息 {playerID:{(key, dType):value, ...}, ...}
+
+

--
Gitblit v1.8.0