ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
@@ -16,225 +16,396 @@
# @change: "2016-05-18 16:00" hxp 战盟有官员成员缓存不清除
#---------------------------------------------------------------------
#"""Version = 2016-05-18 16:00"""
#------------------------------------------------------------------------------
#---------------------------------------------------------------------
import GameWorld
import ChPyNetSendPack
import IPY_PlayerDefine
import PlayerFamilyAction
import GameWorship
import GameXiangong
import PlayerControl
import NetPackCommon
import ReadChConfig
import PlayerFamily
import IPY_GameServer
import GameWorldArena
import ChPyNetSendPack
import ChGameToMapPyPack
import PlayerFBHelpBattle
import GameWorldSkyTower
import CrossChampionship
import CrossBattlefield
import CrossRealmPlayer
import PyGameDataStruct
import IpyGameDataPY
import PyDataManager
import CrossRealmPK
import ShareDefine
import ChPlayer
import ChConfig
import time
import json
import time
import random
ViewCacheMgr = GameWorld.GameWorldData.GetPlayerViewCacheMgr()
# 优先取缓存数据,后取可保存数据
def GetItemData(curCache):
    result = curCache.GetItemDataNoSave()
    if not result:
        return curCache.GetItemData()
    return result
def GetPlusData(curCache):
    result = curCache.GetPlusDataNoSave()
    if not result:
        return curCache.GetPlusData()
    return result
##更新缓存数据
#  @param PlayerID, PropData, ItemData, PlusData, isSaveDB
#  @return None
def UpdatePlayerCache(PlayerID, PropData, ItemData, PlusData, isSaveDB=False):
    curCache = ViewCacheMgr.FindCache(PlayerID)
    if not curCache:
        curCache = ViewCacheMgr.AddNewCache(PlayerID)
    curCache.SetUpdateTime(GameWorld.GetCurrentDataTimeStr())
    GameWorld.DebugLog('ViewCache### UpdatePlayerCache PlayerID %s, \
                        PropData(len %s): %s, \
                        ItemData(len %s):  %s, \
                        PlusData(len %s):  %s'%
           (PlayerID, len(PropData), PropData,len(ItemData), ItemData, len(PlusData), PlusData)
                        )
    #2017-12-21 由于保存数据库的数据(realtime)过多根据需求分SetItemData和SetItemDataNoSave
    # 关服尽量只保存基础数据,默认使用不保存接口 SetItemDataNoSave
    curCache.SetPropData(PropData,len(PropData))
    if curCache.GetItemData() or (isSaveDB and IsNeedSaveViewCacheAllInfo(PlayerID)):
        curCache.SetItemData(ItemData,len(ItemData))
        curCache.SetPlusData(PlusData,len(PlusData))
        curCache.SetItemDataNoSave("",0) # 避免占用内存
        curCache.SetPlusDataNoSave("",0)
    else:
        # 低级号不处理保存
        curCache.SetItemDataNoSave(ItemData,len(ItemData))
        curCache.SetPlusDataNoSave(PlusData,len(PlusData))
    curCache.SetNeedSaveDB(isSaveDB) #设置需要保存到数据库
    #暂时关闭
    #===========================================================================
    # FamilyIDKey = "FamilyID"
    # if FamilyIDKey in PropData:
    #    PropDataDict = eval(PropData)
    #    familyID = PropDataDict[FamilyIDKey]
    #    if familyID > 0:
    #        PlayerFamilyAction.UpdFamilyOfficerModelEquip(familyID, PlayerID)
    #===========================================================================
    return
##玩家下线缓存数据
#  @param PlayerID, PlayerLV, PropData, ItemData, PlusData
#  @return None
def OnPlayerLogout(PlayerID, PlayerLV, PropData, ItemData, PlusData):
    #不需要保存离线数据的,直接删除缓存数据
    if not IsNeedSaveLogoutPlayer(PlayerID, PlayerLV):
        ViewCacheMgr.DeleteCache(PlayerID)
        return
    #更新数据,并设置需要保存数据库
    UpdatePlayerCache(PlayerID, PropData, ItemData, PlusData, True)
def DoOnDayEx():
    DelOutofTimeViewCacheData()
    return
## 根据规则判定是否需要继续保存离线玩家数据
#  @param PlayerID, PlayerLV
#  @return None
def IsNeedSaveLogoutPlayer(PlayerID, PlayerLV):
    SaveDBLimitLV, NeedCheckBillBoardType, HighLadderLimitOrder = ReadChConfig.GetEvalChConfig("CacheSaveLimit")
    #校验玩家等级
    if PlayerLV < SaveDBLimitLV:
def IsSaveDBViewCache(viewCache):
    ## 缓存数据是否入库
    if not viewCache:
        return False
    
    playerID = viewCache.PlayerID
    if PlayerFBHelpBattle.IsInHelpBattleCheckInList(playerID):
        return True
    if GameWorldArena.IsArenaBattlePlayer(playerID):
        return True
    if CrossBattlefield.IsBattlefieldCallPlayer(playerID):
        return True
    if CrossChampionship.IsChampionshipPlayer(playerID):
        return True
    if GameWorship.IsWorshipPlayer(playerID):
        return True
    if PyDataManager.GetDBPyFuncTeamManager().IsTeamPlayer(playerID):
        return True
    if GameXiangong.IsXiangongPlayer(playerID):
        return True
    if GameWorldSkyTower.IsSkyTowerPassPlayer(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
        if CrossRealmPK.IsCrossRealmPKPlayer(playerID, checkPreSeason=True):
            return True
    else:
        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
    # 以上是相关功能需要用到的数据,必定不能删除的
    # 以下是保留近期活跃玩家,等级限制
    playerLV = viewCache.LV
    offTime = viewCache.OffTime
    if not playerLV and not offTime:
        # 跨服服务器之前某些情况没有存储LV及OffTime,防止误删,做旧数据兼容用
        return True
    SaveDBLimitLV = IpyGameDataPY.GetFuncCfg("PlayerViewCache", 1)
    if playerLV >= SaveDBLimitLV:
        maxDays = IpyGameDataPY.GetFuncCfg("PlayerViewCache", 3)
        if not maxDays:
            maxDays = 7 # 默认7天
        MaxTime = maxDays * 3600 * 24
        curTime = int(time.time())
        passTime = curTime - viewCache.OffTime
        if passTime < MaxTime:
            return True
    return True
# 上榜用户
def IsNeedSaveViewCacheAllInfo(PlayerID):
    SaveDBLimitLV, NeedCheckBillBoardType, HighLadderLimitOrder = ReadChConfig.GetEvalChConfig("CacheSaveLimit")
    #校验玩家是否上排行榜
    billboardMgr = GameWorld.GetBillboard()
    for BillBoardType in NeedCheckBillBoardType:
        curBillboard = billboardMgr.FindBillboard(BillBoardType)
        if not curBillboard:
            continue
        if curBillboard.FindByID(PlayerID):
            return True
def DelOutofTimeViewCacheData():
    ## 删除过期的查看缓存数据
    
    return False
#    #校验玩家是否上排行榜
#    billboardMgr = GameWorld.GetBillboard()
#    for BillBoardType in NeedCheckBillBoardType:
#        curBillboard = billboardMgr.FindBillboard(BillBoardType)
#        if not curBillboard:
#            continue
#        if curBillboard.FindByID(PlayerID):
#            return True
#
#    #校验玩家竞技场是否进入排名
#    hightLadderMgr = GameWorld.GetHightLadderMgr()
#    hightLadderData = hightLadderMgr.FindPlayerData(PlayerID)
#    if hightLadderData:
#        if hightLadderData.GetOrder() < HighLadderLimitOrder:
#            return True
#
#    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(PlayerID)
#    if curPlayer:
#        # 非普通成员需保存
#        if PlayerFamily.GetPlayerFamilyMemberLV(curPlayer) != IPY_GameServer.fmlMember:
#            return True
#
#    return False
## //04 01 地图同步玩家数据到GameServer#tagMGUpdatePlayerCache
#  @param routeIndex, mapID, curPackData, tick
#  @return None
def OnMGUpdatePlayerCache(routeIndex, mapID, curPackData, tick):
    GameWorld.DebugLog('ViewCache### OnMGUpdatePlayerCache in %s'%curPackData.OutputString())
    PlayerID = curPackData.PlayerID
    PlayerLV = curPackData.PlayerLV
    if curPackData.IsLogouting:
        OnPlayerLogout(PlayerID, PlayerLV, \
                       curPackData.PropData, curPackData.ItemData, curPackData.PlusData)
    else:
        # 此处保存设置为True是为安全防范,比如突然断电,宕机等情况 导致误以为不保存,故等级可设置高一点
        UpdatePlayerCache(PlayerID, curPackData.PropData, \
                          curPackData.ItemData, curPackData.PlusData, True if PlayerLV > 150 else False)
    GameWorld.DebugLog('ViewCache### OnMGUpdatePlayerCache out')
    pyViewCacheMgr = PyDataManager.GetPlayerViewCachePyManager()
    playerViewCachePyDict = pyViewCacheMgr.playerViewCachePyDict
    for playerID, viewCache in playerViewCachePyDict.items():
        if IsSaveDBViewCache(viewCache):
            continue
        playerViewCachePyDict.pop(playerID)
    return
## //04 02 地图查询玩家缓存数据#tagMGQueryPlayerCache
#  @param routeIndex, mapID, curPackData, tick
#  @return None
def DeleteViewCache(playerID):
    ## 删除玩家缓存
    pyViewCacheMgr = PyDataManager.GetPlayerViewCachePyManager()
    playerViewCachePyDict = pyViewCacheMgr.playerViewCachePyDict
    playerViewCachePyDict.pop(playerID, None)
    GameWorld.DebugLog("删除查看缓存!", playerID)
    return
def FindViewCache(playerID, isAddNew=False, newPropData={}):
    ## 查找玩家缓存
    # @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]
    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 服
            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,
                           }
        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
    return curCache
def GetCachePropDataDict(curCache):
    ## 获取缓存基础属性字典信息
    if not curCache:
        return {}
    if not hasattr(curCache, "PropDataDict"):
        curCache.PropDataDict = {}
    if not curCache.PropDataDict and curCache.PropData:
        curCache.PropDataDict = eval(curCache.PropData)
    return curCache.PropDataDict
def GetShotCacheDict(playerID, *exAttrs):
    ## 获取玩家简短的缓存信息字典
    viewCache = FindViewCache(playerID)
    cacheDict = GetCachePropDataDict(viewCache)
    if not cacheDict:
        return {}
    shotCacheDict = {
                     "Name":cacheDict["Name"],
                     "Job":cacheDict["Job"],
                     "LV":cacheDict["LV"],
                     "RealmLV":cacheDict["RealmLV"],
                     }
    for attrName in exAttrs:
        if attrName == "PlayerID":
            shotCacheDict["PlayerID"] = playerID
        elif attrName == "ServerID":
            shotCacheDict["ServerID"] = GameWorld.GetAccIDServerID(cacheDict["AccID"])
        elif attrName == "OfflineValue":
            olMgr = ChPlayer.GetOnlinePlayerMgr()
            shotCacheDict["OfflineValue"] = olMgr.GetOfflineValue(playerID, viewCache)
        # 附带外观模型展示相关
        elif attrName == "Model":
            shotCacheDict.update({
                                  "TitleID":cacheDict.get("TitleID", 0),
                                  "EquipShowSwitch":cacheDict.get("EquipShowSwitch", 0),
                                  "EquipShowID":cacheDict.get("EquipShowID", []),
                                  })
        elif attrName in cacheDict:
            shotCacheDict[attrName] = cacheDict[attrName]
    return shotCacheDict
def GetSyncCrossCacheBase(curPlayer):
    ## 获取同步跨服基础查看缓存,主要用于个别功能需要提前先同步玩家基础缓存到跨服,因为跨服不一定有玩家缓存,需要提前同步
    playerID = curPlayer.GetPlayerID()
    cacheDict = GetCachePropDataDict(FindViewCache(playerID))
    cacheBase = {
                 "AccID":curPlayer.GetAccID(),
                 "LV":curPlayer.GetLV(),
                 "RealmLV":curPlayer.GetOfficialRank(),
                 "Job":curPlayer.GetJob(),
                 "VIPLV":curPlayer.GetVIPLv(),
                 "Name":CrossRealmPlayer.GetCrossPlayerName(curPlayer),
                 "Face":curPlayer.GetFace(),
                 "FacePic":curPlayer.GetFacePic(),
                 "FamilyID":curPlayer.GetFamilyID(),
                 "FamilyName":cacheDict.get("FamilyName", ""),
                 "TitleID":cacheDict.get("TitleID", 0),
                 "FightPower":PlayerControl.GetFightPower(curPlayer),
                 "EquipShowSwitch":cacheDict.get("EquipShowSwitch", 0),
                 "EquipShowID":cacheDict.get("EquipShowID", []),
                 "ServerGroupID":PlayerControl.GetPlayerServerGroupID(curPlayer),
                 }
    return cacheBase
def UpdCrossCacheBase(playerID, cacheBase, isLogout=False):
    ## 更新同步跨服基础查看缓存
    #更新跨服在线状态,只要有同步即视为在线,除了指定是Logout的
    olMgr = ChPlayer.GetOnlinePlayerMgr()
    olMgr.SetOnlineState(playerID, not isLogout, cacheBase.get("ServerGroupID", 0))
    curCache = FindViewCache(playerID, True)
    if not curCache:
        return {}
    curCache.LV = cacheBase.get("LV", 0)
    curCache.OffTime = int(time.time()) # 每次都更新,最后一次可视为跨服玩家的最近一次离线时间
    cacheDict = GetCachePropDataDict(curCache)
    if not cacheBase:
        return cacheDict
    for k, v in cacheBase.items():
        cacheDict[k] = v
    if isLogout:
        if not IsSaveDBViewCache(curCache):
            DeleteViewCache(playerID)
            return {}
    return cacheDict
#//04 01 地图同步玩家缓存数据到GameServer#tagMGUpdatePlayerCache
#
#struct    tagMGUpdatePlayerCache
#{
#    tagHead        Head;
#    DWORD        PlayerID;        //玩家ID
#    WORD        PlayerLV;        //玩家等级
#    BYTE        IsLogouting;        //本次是否为下线同步
#    DWORD        OffTime;        // 下线时间戳
#    WORD        PropDataSize;
#    char        PropData[PropDataSize];    //属性记录
#    WORD        PlusDataSize;
#    char        PlusData[PlusDataSize];    //扩展记录
#    WORD        ItemDataSize1;
#    char        ItemData1[ItemDataSize1];    //1阶装备数据
#    ...         ...
#    WORD        ItemDataSize20;
#    char        ItemData20[ItemDataSize20];
#};
def OnMGUpdatePlayerCache(routeIndex, mapID, curPackData, tick):
    playerID = curPackData.PlayerID
    #playerLV = curPackData.PlayerLV
    isLogout = curPackData.IsLogouting
    GameWorld.DebugLog('ViewCache### OnMGUpdatePlayerCache isLogout=%s' % isLogout, playerID)
    isSaveAll = True # 是否保存所有数据
    curCache = FindViewCache(playerID, True)
    if not curCache:
        return
    curCache.LV = curPackData.PlayerLV
    curCache.OffTime = curPackData.OffTime
    curCache.PropDataDict = {} # 每次更新数据时,重置字典缓存,下次获取时重新eval缓存
    curCache.PropData = curPackData.PropData
    curCache.PropDataSize = curPackData.PropDataSize
    curCache.PlusData = curPackData.PlusData
    curCache.PlusDataSize = curPackData.PlusDataSize
    #GameWorld.DebugLog("    更新Prop数据: size=%s, %s" % (curCache.PropDataSize, curCache.PropData), playerID)
    #GameWorld.DebugLog("    更新Plus数据: size=%s, %s" % (curCache.PlusDataSize, curCache.PlusData), playerID)
    # 装备数据存储,不保存装备数据的话则清空
    for classLV in xrange(1, 20 + 1):
        if not isSaveAll:
            itemDataSize = 0
            itemData = ""
        else:
            itemDataSize = getattr(curPackData, "ItemDataSize%s" % classLV)
            if not itemDataSize:
                continue
            itemData = getattr(curPackData, "ItemData%s" % classLV)
        setattr(curCache, "ItemData%s" % classLV, itemData)
        setattr(curCache, "ItemDataSize%s" % classLV, itemDataSize)
        #GameWorld.DebugLog("    更新Item数据: classLV=%s,size=%s, %s" % (classLV, itemDataSize, itemData), playerID)
    if isLogout:
        #不需要保存离线数据的,直接删除缓存数据
        if not IsSaveDBViewCache(curCache):
            DeleteViewCache(playerID)
            return
        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(playerID)
        if curPlayer:
            curCache.GeTuiID = curPlayer.GetGeTuiClientID()
            curCache.GeTuiIDSize = len(curCache.GeTuiID)
    #GameWorld.DebugLog("    %s" % curCache.outputString())
    # 同步更新助战信息
    if PlayerFBHelpBattle.IsInHelpBattleCheckInList(playerID):
        PropDataDict = GetCachePropDataDict(curCache)
        fightPower = PropDataDict.get("FightPower", 0)
        familyID = PropDataDict.get("FamilyID", 0)
        playerName = PropDataDict.get("Name", "")
        PlayerFBHelpBattle.UpdateCheckInPlayerInfo(playerID, fightPower, familyID, playerName)
    return
#//04 02 地图查询玩家缓存数据#tagMGQueryPlayerCache
#struct tagMGQueryPlayerCache
#{
#    tagHead        Head;
#    DWORD        PlayerID;        //玩家ID
#    DWORD        FindPlayerID;    //要查询的玩家ID
#    BYTE        EquipClassLV;    //大于0为查看指定境界阶装备信息,  0为查看默认信息
#    BYTE        CallMap;        //是否需要通知地图
#};
def OnMGQueryPlayerCache(routeIndex, mapID, curPackData, tick):
    GameWorld.DebugLog('ViewCache### OnMGQueryPlayerCache in')
    curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(curPackData.PlayerID)
    findPlayerID = curPackData.FindPlayerID
    curCache = ViewCacheMgr.FindCache(findPlayerID)
    equipClassLV = curPackData.EquipClassLV
    callMap = curPackData.CallMap
    curCache = FindViewCache(findPlayerID)
    if not curCache:
        PlayerControl.NotifyCode(curPlayer, "ViewPlayer_OffLine")
        if callMap:
            sendPack = ChGameToMapPyPack.tagGMPlayerCache()
            sendPack.PlayerID = curPlayer.GetPlayerID()
            sendPack.FindPlayerID = findPlayerID
            sendPack.PropData = ""
            sendPack.PropDataSize = len(sendPack.PropData)
            sendPack.PlusData = ""
            sendPack.PlusDataSize = len(sendPack.PlusData)
            NetPackCommon.SendPyPackToMapServer(routeIndex, mapID, sendPack)
        return
    Sync_PlayerCache(curPlayer, curCache, equipClassLV)
    if callMap:
        sendPack = ChGameToMapPyPack.tagGMPlayerCache()
        sendPack.PlayerID = curPlayer.GetPlayerID()
        sendPack.FindPlayerID = findPlayerID
        sendPack.PropData = curCache.PropData
        sendPack.PropDataSize = len(sendPack.PropData)
        sendPack.PlusData = curCache.PlusData
        sendPack.PlusDataSize = len(sendPack.PlusData)
        NetPackCommon.SendPyPackToMapServer(routeIndex, mapID, sendPack)
    return
def Sync_PlayerCache(curPlayer, curCache, equipClassLV=0):
    ## 同步玩家缓存
    if equipClassLV:
        itemData = ""
        if hasattr(curCache, "ItemDataSize%s" % equipClassLV):
            itemData = getattr(curCache, "ItemData%s" % equipClassLV)
        sendPack = ChPyNetSendPack.tagSCPlayerEquipCacheResult()
        sendPack.PlayerID = curCache.PlayerID
        sendPack.EquipClassLV = equipClassLV
        sendPack.ItemData = itemData
        sendPack.ItemDataSize = len(sendPack.ItemData)
        NetPackCommon.SendFakePack(curPlayer, sendPack)
        return
    
    #回包客户端
    sendPack = ChPyNetSendPack.tagSCQueryPlayerCacheResult()
    sendPack.PlayerID = findPlayerID
    if not curCache:
        #失败回包 空数据
        GameWorld.DebugLog("PlayerCache## OnMGQueryPlayerCache %s no found"%findPlayerID)
        sendPack.PropData = ""
        sendPack.PropDataSize = len(sendPack.PropData)
        sendPack.ItemData = ""
        sendPack.ItemDataSize = len(sendPack.ItemData)
        sendPack.PlusData = ""
        sendPack.PlusDataSize = len(sendPack.PlusData)
    else:
        #成功回包 缓存数据
        sendPack.PropData = curCache.GetPropData()
        sendPack.PropDataSize = len(sendPack.PropData)
        sendPack.ItemData = GetItemData(curCache)
        sendPack.ItemDataSize = len(sendPack.ItemData)
        sendPack.PlusData = GetPlusData(curCache)
        sendPack.PlusDataSize = len(sendPack.PlusData)
    sendPack.PlayerID = curCache.PlayerID
    sendPack.PropData = curCache.PropData
    sendPack.PropDataSize = len(sendPack.PropData)
    sendPack.PlusData = curCache.PlusData
    sendPack.PlusDataSize = len(sendPack.PlusData)
    NetPackCommon.SendFakePack(curPlayer, sendPack)
    GameWorld.DebugLog('ViewCache### OnMGQueryPlayerCache out')
    return
## 获取玩家缓存模型装备信息
def GetPlayerCacheEquipView(findPlayerID):
    curCache = ViewCacheMgr.FindCache(findPlayerID)
    if not curCache:
        return
    itemData = GetItemData(curCache)
    if not itemData:
        return
    playerEquipList = []
    equipItemList = eval(itemData)
    for equipItemDict in equipItemList:
        equipIndex = equipItemDict["ItemIndex"]
        if equipIndex not in ShareDefine.RoleEquipType:
            continue
        itemID = equipItemDict["ItemID"]
        if not itemID:
            continue
        playerEquipList.append([itemID, equipIndex, equipItemDict.get("StarLV", 0), 0])
    return playerEquipList
#===============================================================================
# //B3 06 查询玩家的简短信息 #tagCGViewPlayerShortInfo
@@ -250,7 +421,7 @@
    answerPack = ChPyNetSendPack.tagGCAnswerPlayerShortInfo()
    answerPack.Clear()
    if not tagPlayer:
        curCache = ViewCacheMgr.FindCache(clientPack.PlayerID)
        curCache = FindViewCache(clientPack.PlayerID)
        if not curCache:
            # 实在找不到设置为初始化数据
            answerPack.PlayerID = clientPack.PlayerID
@@ -259,16 +430,24 @@
            answerPack.LV = 1
            answerPack.RealmLV = 1
            answerPack.OnlineType = ChConfig.Def_Offline
            answerPack.ServerGroupID = 0
            answerPack.Face = 0
            answerPack.FacePic = 0
        else:
            cacheDict = eval(curCache.GetPropData())
            cacheDict = GetCachePropDataDict(curCache)
            answerPack.PlayerID = clientPack.PlayerID
            answerPack.PlayerName = cacheDict["Name"]
            answerPack.Job = cacheDict["Job"]
            answerPack.LV = cacheDict["LV"]
            answerPack.RealmLV = cacheDict["RealmLV"]
            answerPack.OnlineType = ChConfig.Def_Offline
            answerPack.Face = cacheDict.get("Face", 0)
            answerPack.FacePic = cacheDict.get("FacePic", 0)
            
            if GameWorld.IsCrossServer():
                answerPack.ServerGroupID = cacheDict.get("ServerGroupID", 0)
            else:
                answerPack.ServerGroupID = GameWorld.GetServerGroupID()
    else:
        answerPack.PlayerID = clientPack.PlayerID
        answerPack.PlayerName = tagPlayer.GetName()
@@ -277,24 +456,24 @@
        answerPack.RealmLV = tagPlayer.GetOfficialRank()
        answerPack.OnlineType = ChConfig.Def_Online
        answerPack.IsInTeam = tagPlayer.GetTeamID() > 0
        answerPack.ServerGroupID = PlayerControl.GetPlayerServerGroupID(tagPlayer)
        answerPack.Face = tagPlayer.GetFace()
        answerPack.FacePic = tagPlayer.GetFacePic()
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    NetPackCommon.SendFakePack(curPlayer, answerPack)
    return
def OnPlayerLeaveFamily(playerID):
    GameWorld.DebugLog("ViewCache->OnPlayerLeaveFamily", playerID)
    curCache = ViewCacheMgr.FindCache(playerID)
def OnPlayerFamilyChange(playerID, familyID, familyName):
    GameWorld.DebugLog("ViewCache->OnPlayerFamilyChange", playerID)
    curCache = FindViewCache(playerID)
    if not curCache:
        return
    PropData = eval(curCache.GetPropData())
    PropData["FamilyID"] = 0
    PropData["FamilyName"] = ""
    playerLV = PropData["LV"]
    PropData = json.dumps(PropData, ensure_ascii=False)
    ItemData = curCache.GetItemData()
    PlusData = curCache.GetPlusData()
    UpdatePlayerCache(playerID, PropData, ItemData, PlusData, True if playerLV > 150 else False)
    PropData = GetCachePropDataDict(curCache)
    PropData["FamilyID"] = familyID
    PropData["FamilyName"] = familyName
    PropData = json.dumps(PropData, ensure_ascii=False).replace(" ", "")
    curCache.PropData = PropData
    curCache.PropDataSize = len(curCache.PropData)
    return