ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/CrossPlayerData.py
@@ -21,7 +21,13 @@
import base64
import ChConfig
import PyGameData
import PlayerDienstgrad
import IpyGameDataPY
import PlayerHorse
import PlayerPet
import traceback
import ShareDefine
import md5
# 发送格式: 类型+(数量)+数据
# 向跨服发送的数据类型
(
@@ -29,7 +35,24 @@
MergeData_Item,     # 对比处理 只算属性的背包 装备 宠物 
MergeData_Skill,    # 只处理ID
MergeData_Buff,     # 即时发送
) = range(0, 4)
CrossData_PetState, # 即时发送 宠物出战
CrossData_HorseChange, # 即时发送 骑乘坐骑变更
CrossData_RideHorse, # 即时发送 上下马
) = range(0, 7)
## 写数据类型定义
(
WDT_BYTE,
WDT_WORD,
WDT_DWORD,
WDT_String,
) = range(4)
CrossDataInfo = {
                 CrossData_PetState:[[WDT_DWORD, WDT_BYTE, WDT_BYTE], lambda curObj, valueList:PlayerPet.CrossServer_DoChangePetState(curObj, valueList)],
                 CrossData_HorseChange:[[WDT_DWORD], lambda curObj, valueList:PlayerHorse.CrossServer_ChangeHorse(curObj, valueList)],
                 CrossData_RideHorse:[[WDT_BYTE], lambda curObj, valueList:PlayerHorse.CrossServer_RideHorse(curObj, valueList)],
                 }
# 影响跨服战力属性列表
CrossFightPowerAttrList = [
@@ -37,6 +60,7 @@
    [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.GetLV(), lambda curObj, value:curObj.SetLV(value)], # 等级
    [lambda curObj:curObj.GetOfficialRank(), lambda curObj, value:curObj.SetOfficialRank(value)], # 境界
    [lambda curObj:curObj.GetVIPLv(), lambda curObj, value:curObj.SetVIPLv(value)], # VIP等级
                           ]
@@ -78,33 +102,105 @@
        # 非跨服
        return
    
    # 跨服服务器处理
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    pdata = base64.b64decode(curPlayer.GetMergePlayerData())
    pos = 0
    dataType, pos = CommFunc.ReadBYTE(pdata, pos)
    if dataType == MergeData_Buff:
        buffID, pos = CommFunc.ReadDWORD(pdata, pos)
        curSkill = GameWorld.GetGameData().GetSkillBySkillID(buffID)
        if not curSkill:
            return
    try:
        # 跨服服务器处理
        curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
        pdata = base64.b64decode(curPlayer.GetMergePlayerData())
        
        plusValueList = []
        cnt, pos = CommFunc.ReadBYTE(pdata, pos)
        for i in range(cnt):
            value, pos = CommFunc.ReadDWORD(pdata, pos)
            plusValueList.append(value)
        pos = 0
        dataType, pos = CommFunc.ReadBYTE(pdata, pos)
        if dataType == MergeData_Buff:
            buffID, pos = CommFunc.ReadDWORD(pdata, pos)
            curSkill = GameWorld.GetGameData().GetSkillBySkillID(buffID)
            if not curSkill:
                return
            
        buffType = SkillCommon.GetBuffType(curSkill)
        BuffSkill.AddBuffNoRefreshState(curPlayer, buffType, curSkill, tick, plusValueList)
    elif dataType == MergeData_Player:
        __ReadMainServerSyncPlayerData(curPlayer, curPlayer.GetMergePlayerData(), pos)
            plusValueList = []
            cnt, pos = CommFunc.ReadBYTE(pdata, pos)
            for i in range(cnt):
                value, pos = CommFunc.ReadDWORD(pdata, pos)
                plusValueList.append(value)
            buffType = SkillCommon.GetBuffType(curSkill)
            BuffSkill.AddBuffNoRefreshState(curPlayer, buffType, curSkill, tick, plusValueList)
        elif dataType == MergeData_Player:
            __ReadMainServerSyncPlayerData(curPlayer, curPlayer.GetMergePlayerData(), pos)
        else:
            __ReadCrossData(curPlayer, dataType, curPlayer.GetMergePlayerData(), pos)
    except BaseException:
        errorMsg = str(traceback.format_exc())
        GameWorld.ErrLog('接收跨服变更玩家数据错误 - > %s' % errorMsg, curPlayer.GetPlayerID())
        if GameWorld.GetGameWorld().GetDebugLevel():
            raise Exception(errorMsg)
        
    return
## ----------------------------------------------------------------------------------------------
def SendDataToCrossServer(curPlayer, dataType, dataList):
    ## 通用的根据类型向跨服发送数据
    if dataType not in CrossDataInfo:
        return
    if not IsNeedProcessCrossPlayer(curPlayer):
        return
    dataInfo = CrossDataInfo[dataType][0]
    if len(dataList) != len(dataInfo):
        return
    data = ''
    data = CommFunc.WriteBYTE(data, dataType)
    for i, wDType in enumerate(dataInfo):
        value = dataList[i]
        if wDType == WDT_BYTE:
            data = CommFunc.WriteBYTE(data, value)
        elif wDType == WDT_WORD:
            data = CommFunc.WriteWORD(data, value)
        elif wDType == WDT_DWORD:
            data = CommFunc.WriteDWORD(data, value)
        elif wDType == WDT_String:
            sLen = len(value)
            data = CommFunc.WriteBYTE(data, sLen)
            data = CommFunc.WriteString(data, sLen, value)
    #直接用字节流会报错
    data = base64.b64encode(data)
    curPlayer.SendMergePlayerData(data)
    GameWorld.DebugLog("发送数据到跨服服务器: dataType=%s,dataList=%s" % (dataType, dataList), curPlayer.GetPlayerID())
    return
def __ReadCrossData(curPlayer, dataType, pdata, pos):
    if dataType not in CrossDataInfo:
        return
    dataInfo, callFunc = CrossDataInfo[dataType]
    if not callFunc:
        return
    dataList = []
    pdata = base64.b64decode(pdata)
    for wDType in dataInfo:
        if wDType == WDT_BYTE:
            value, pos = CommFunc.ReadBYTE(pdata, pos)
        elif wDType == WDT_WORD:
            value, pos = CommFunc.ReadWORD(pdata, pos)
        elif wDType == WDT_DWORD:
            value, pos = CommFunc.ReadDWORD(pdata, pos)
        elif wDType == WDT_String:
            sLen, pos = CommFunc.ReadBYTE(pdata, pos)
            value, pos = CommFunc.ReadString(pdata, pos, sLen)
        else:
            continue
        dataList.append(value)
    GameWorld.DebugLog("收到主服数据: dataType=%s,dataList=%s" % (dataType, dataList), curPlayer.GetPlayerID())
    callFunc(curPlayer, dataList)
    return
def IsNeedProcessCrossPlayer(curPlayer):
    ## 是否需要处理同步跨服中的玩家数据
@@ -121,6 +217,9 @@
    if crossMapID in [ChConfig.Def_FBMapID_CrossRealmPK]:
        return
    
    if not IpyGameDataPY.GetFuncCfg("CrossSyncPlayerData", 1):
        return
    return True
def ClearCrossSyncDataCache(curPlayer):
@@ -129,6 +228,9 @@
    PyGameData.g_crossRegPlayerAttrDict.pop(playerID, None)
    PyGameData.g_crossSyncTickDict.pop(playerID, None)
    PyGameData.g_crossPlayerDictChangeInfo.pop(playerID, None)
    PyGameData.g_crossPlayerDienstgradChangeInfo.pop(playerID, None)
    PyGameData.g_crossPlayerItemsChangeInfo.pop(playerID, None)
    PyGameData.g_crossPlayerSkillsChangeInfo.pop(playerID, None)
    GameWorld.DebugLog("清除同步跨服数据的临时缓存", playerID)
    return
@@ -144,6 +246,68 @@
        attrList.append(attrInfo[0](curPlayer))
    playerID = curPlayer.GetPlayerID()
    PyGameData.g_crossRegPlayerAttrDict[playerID] = attrList
    OnPlayerCrossRegItems(curPlayer)     # 物品
    OnPlayerCrossRegSkills(curPlayer)   # 技能
    return
# 物品数据更新
def OnPlayerCrossRegItems(curPlayer):
    # 影响战力的物品,新功能注意添加,下次需要加上诛仙塔
    PyGameData.g_crossPlayerItemsChangeInfo[curPlayer.GetPlayerID()] = GetPlayerCrossRegItems(curPlayer)
    return
def GetPlayerCrossRegItems(curPlayer):
    itemsDict = {}
    # 影响战力的物品,新功能注意添加,下次需要加上诛仙塔
    packList = [IPY_GameWorld.rptEquip, ShareDefine.rptPet, ShareDefine.rptDogzEquip, ShareDefine.rptZhuXianEquip]
    for packIndex in packList:
        curPack = curPlayer.GetItemManager().GetPack(packIndex)
        for i in range(curPack.GetCount()):
            curItem = curPack.GetAt(i)
            if not curItem or curItem.IsEmpty():
                continue
            itemMark = (curItem.GetItemPlaceType(), curItem.GetItemPlaceIndex())
            itemsDict[itemMark] = md5.md5(curItem.GetB64ItemData()).hexdigest()
    return itemsDict
# 技能数据更新
def OnPlayerCrossRegSkills(curPlayer):
    PyGameData.g_crossPlayerSkillsChangeInfo[curPlayer.GetPlayerID()] = GetPlayerCrossRegSkills(curPlayer)
def GetPlayerCrossRegSkills(curPlayer):
    skills = []
    skillManager = curPlayer.GetSkillManager()
    for i in range(0 , skillManager.GetSkillCount()):
        curSkill = skillManager.GetSkillByIndex(i)
        skills.append(curSkill.GetSkillID())
    return skills
#===============================================================================
# def test(curPlayer):
#    curPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptEquip)
#    curItem = curPack.GetAt(1)
#    curItem.GetB64ItemData()
#    curSingleItem = GameWorld.GetItemFactory().AddItem(curItem.GetB64ItemData())
#    if not curSingleItem:
#        return
#
#    curItem2 = curPack.GetAt(2)
#    curItem2.AssignItem(curSingleItem)
#===============================================================================
def OnDienstgradChange(curPlayer, dienstgradID, state):
    ## 称号变更
    if not IsNeedProcessCrossPlayer(curPlayer):
        return
    playerID = curPlayer.GetPlayerID()
    dienstgradStateDict = PyGameData.g_crossPlayerDienstgradChangeInfo.get(playerID, {})
    dienstgradStateDict[dienstgradID] = state
    PyGameData.g_crossPlayerDienstgradChangeInfo[playerID] = dienstgradStateDict
    return
def OnPlayerFightPowerChange(curPlayer):
@@ -167,23 +331,33 @@
    if playerID not in PyGameData.g_crossSyncTickDict:
        return
    setTick = PyGameData.g_crossSyncTickDict[playerID]
    if tick - setTick < 5000:
    if tick - setTick < IpyGameDataPY.GetFuncCfg("CrossSyncPlayerData", 1) * 1000:
        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)
    try:
        # 这里只做可能引起战力变化所需要同步的数据
        data = ""
        data = CommFunc.WriteBYTE(data, MergeData_Player)
        data = __WriteSyncPlayerAttrData(curPlayer, data) # 玩家属性
        data = __WriteSyncPlayerDictData(curPlayer, data) # 字典
        data = __WriteSyncPlayerDienstgradData(curPlayer, data) # 称号
        data = __WriteSyncPlayerItems(curPlayer, data)# 物品
        data = __WriteSyncPlayerSkills(curPlayer, data)# 技能
        #直接用字节流会报错
        data = base64.b64encode(data)
        curPlayer.SendMergePlayerData(data)
    except BaseException:
        errorMsg = str(traceback.format_exc())
        GameWorld.ErrLog('打包跨服变更玩家数据错误 - > %s' % errorMsg, curPlayer.GetPlayerID())
        if GameWorld.GetGameWorld().GetDebugLevel():
            raise Exception(errorMsg)
    return
def __ReadMainServerSyncPlayerData(curPlayer, pdata, pos):
    ## 读取子服同步的玩家战力变更相关属性
@@ -192,9 +366,9 @@
    
    pos = __ReadSyncPlayerAttrData(curPlayer, pdata, pos) # 玩家属性
    pos = __ReadSyncPlayerDictData(curPlayer, pdata, pos) # 字典
    # 物品
    # 技能
    pos = __ReadSyncPlayerDienstgradData(curPlayer, pdata, pos) # 称号
    pos = __ReadSyncPlayerItems(curPlayer, pdata, pos)  # 物品
    pos = __ReadSyncPlayerSkills(curPlayer, pdata, pos)# 技能
    
    # 强刷一次属性
    PlayerControl.PlayerControl(curPlayer).ReCalcAllState()
@@ -203,7 +377,6 @@
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)
@@ -251,7 +424,7 @@
    ## 写入需要同步的玩家字典
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_crossPlayerDictChangeInfo:
        return CommFunc.WriteBYTE(data, 0)
        return CommFunc.WriteWORD(data, 0)
    changeDict = PyGameData.g_crossPlayerDictChangeInfo.pop(playerID)
    
    count = len(changeDict)
@@ -283,7 +456,180 @@
        
    return pos
def __WriteSyncPlayerDienstgradData(curPlayer, data):
    ## 写入需要同步的玩家称号
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_crossPlayerDienstgradChangeInfo:
        return CommFunc.WriteBYTE(data, 0)
    changeDienstgradDict = PyGameData.g_crossPlayerDienstgradChangeInfo.pop(playerID)
    count = len(changeDienstgradDict)
    GameWorld.DebugLog("变更的玩家称号个数: %s" % count)
    data = CommFunc.WriteBYTE(data, count)
    for dienstgradID, state in changeDienstgradDict.items():
        data = CommFunc.WriteDWORD(data, dienstgradID)
        data = CommFunc.WriteBYTE(data, state)
        GameWorld.DebugLog("    dienstgradID=%s, state=%s" % (dienstgradID, state))
    return data
def __ReadSyncPlayerDienstgradData(curPlayer, pdata, pos):
    ## 读取同步的玩家称号
    pdata = base64.b64decode(pdata)
    count, pos = CommFunc.ReadBYTE(pdata, pos)
    GameWorld.DebugLog("变更的玩家称号个数: %s" % count)
    for _ in xrange(count):
        dienstgradID, pos = CommFunc.ReadDWORD(pdata, pos)
        state, pos = CommFunc.ReadBYTE(pdata, pos)
        GameWorld.DebugLog("    dienstgradID=%s, state=%s" % (dienstgradID, state))
        if state:
            PlayerDienstgrad.PlayerAddDienstgrad(curPlayer, dienstgradID, isRefreshAttr=False)
        else:
            PlayerDienstgrad.PlayerDelDienstgrad(curPlayer, dienstgradID, False)
    return pos
def __WriteSyncPlayerItems(curPlayer, data):
    ## 写入需要同步的玩家物品,包含删除
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_crossPlayerItemsChangeInfo:
        data = CommFunc.WriteBYTE(data, 0)  # 删除
        data = CommFunc.WriteBYTE(data, 0)  # 增改
        return data
    lastItems = PyGameData.g_crossPlayerItemsChangeInfo[playerID]
    # 对比数据区分增改和删除
    nowItems = GetPlayerCrossRegItems(curPlayer)
    delItems = []
    addItems = []
    # --删除物品
    for indexs in lastItems:
        if indexs not in nowItems:
            delItems.append(indexs)
    data = CommFunc.WriteBYTE(data, len(delItems))  # 删除数量
    for indexs in delItems:
        data = CommFunc.WriteBYTE(data, indexs[0])
        data = CommFunc.WriteBYTE(data, indexs[1])
    # --添加修改物品
    for indexs in nowItems:
        if indexs not in lastItems:
            addItems.append(indexs)
        elif lastItems[indexs] != nowItems[indexs]:
            addItems.append(indexs)
    tmpData = ""
    cnt = 0
    for indexs in addItems:
        curPack = curPlayer.GetItemManager().GetPack(indexs[0])
        curItem = curPack.GetAt(indexs[1])
        if not curItem or curItem.IsEmpty():
            continue
        itemData = base64.b64decode(curItem.GetB64ItemData())
        tmpData = CommFunc.WriteWORD(tmpData, len(itemData))    # 物品数据长度
        tmpData = CommFunc.WriteString(tmpData, len(itemData), itemData)
        cnt += 1
    data = CommFunc.WriteBYTE(data, cnt)  # 增改数量
    data += tmpData
    # 同步最新物品数据
    PyGameData.g_crossPlayerItemsChangeInfo[playerID] = nowItems
    return data
def __ReadSyncPlayerItems(curPlayer, pdata, pos):
    ## 读取同步的玩家物品
    pdata = base64.b64decode(pdata)
    count, pos = CommFunc.ReadBYTE(pdata, pos)
    GameWorld.DebugLog("删除的玩家物品个数: %s" % count)
    # 删除物品
    for _ in xrange(count):
        packType, pos = CommFunc.ReadBYTE(pdata, pos)
        itemIndex, pos = CommFunc.ReadBYTE(pdata, pos)
        curPack = curPlayer.GetItemManager().GetPack(packType)
        curItem = curPack.GetAt(itemIndex)
        if not curItem or curItem.IsEmpty():
            continue
        curItem.Clear()
    # 增改物品
    count, pos = CommFunc.ReadBYTE(pdata, pos)
    GameWorld.DebugLog("增改的玩家物品个数: %s" % count)
    for _ in xrange(count):
        #def ReadString(buf, pos, _len):
        itemDataLen, pos = CommFunc.ReadWORD(pdata, pos)
        itemData, pos = CommFunc.ReadString(pdata, pos, itemDataLen)
        curSingleItem = GameWorld.GetItemFactory().AddItem(base64.b64encode(itemData))
        if not curSingleItem or curSingleItem.GetItemTypeID() == 0:
            continue
        curPack = curPlayer.GetItemManager().GetPack(curSingleItem.GetItemPlaceType())
        curItem = curPack.GetAt(curSingleItem.GetItemPlaceIndex())
        curItem.AssignItem(curSingleItem)
    return pos
def __WriteSyncPlayerSkills(curPlayer, data):
    ## 写入需要同步的玩家技能,包含删除
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_crossPlayerSkillsChangeInfo:
        data = CommFunc.WriteBYTE(data, 0)  # 删除
        data = CommFunc.WriteBYTE(data, 0)  # 添加
        return data
    # 对比数据区分添加和删除
    lastSkills = PyGameData.g_crossPlayerSkillsChangeInfo[playerID]
    nowSkills = GetPlayerCrossRegSkills(curPlayer)
    delSkills = []
    # --删除物品
    for skillID in lastSkills:
        if skillID not in nowSkills:
            delSkills.append(skillID)
    data = CommFunc.WriteBYTE(data, len(delSkills))  # 删除数量
    for skillID in delSkills:
        data = CommFunc.WriteDWORD(data, skillID)
    # --添加修改物品
    addSkills = []
    for skillID in nowSkills:
        if skillID not in lastSkills:
            addSkills.append(skillID)
    data = CommFunc.WriteBYTE(data, len(addSkills))  # 增加数量
    for skillID in addSkills:
        data = CommFunc.WriteDWORD(data, skillID)
    # 同步最新技能数据
    PyGameData.g_crossPlayerSkillsChangeInfo[playerID] = nowSkills
    return data
def __ReadSyncPlayerSkills(curPlayer, pdata, pos):
    ## 读取同步的玩家技能
    skillManager = curPlayer.GetSkillManager()
    pdata = base64.b64decode(pdata)
    count, pos = CommFunc.ReadBYTE(pdata, pos)
    GameWorld.DebugLog("删除的玩家技能个数: %s" % count)
    # 删除技能
    for _ in xrange(count):
        skillID, pos = CommFunc.ReadDWORD(pdata, pos)
        skillManager.DeleteSkillBySkillID(skillID, False)
    count, pos = CommFunc.ReadBYTE(pdata, pos)
    GameWorld.DebugLog("增加的玩家技能个数: %s" % count)
    # 添加技能
    for _ in xrange(count):
        skillID, pos = CommFunc.ReadDWORD(pdata, pos)
        skillManager.LearnSkillByID(skillID, False)
    return pos