hxp
2024-11-15 79a0b7a92d3dfbcc326fd9465b70f05cc3cbdf92
ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
@@ -62,11 +62,72 @@
import GMShell
import IPY_PlayerDefine
import GameWorldArena
import CrossLuckyCloudBuy
import CrossRealmPK
import CrossChampionship
import AuctionHouse
import PlayerAssist
import PlayerFB
import PlayerLove
import PlayerCharm
import CrossRealmPlayer
import CrossBattlefield
import CrossActAllRecharge
import CrossYaomoBoss
import CrossRealmMsg
import PlayerViewCache
import PlayerFuncTeam
import PyDataManager
import GameWorldMineArea
import PlayerPackData
import PlayerRecData
import GameWorship
import GameXiangong
#---------------------------------------------------------------------
#---------------------------------------------------------------------
class OnlinePlayerMgr():
    ''' 在线玩家管理,子服跨服通用
            注:跨服服务器时,玩家不一定在跨服服务器,只是表示有同步到跨服服务器的在线玩家,且不是所有玩家都有同步
    '''
    def __init__(self):
        self.onlinePlayerDict = {} # 在线玩家 {playerID:serverGroupID, ...}
        return
    def IsOnline(self, playerID): return playerID in self.onlinePlayerDict
    def __SetOnline(self, playerID, serverGroupID):
        self.onlinePlayerDict[playerID] = serverGroupID
        return
    def __SetOffline(self, playerID, serverGroupID):
        self.onlinePlayerDict.pop(playerID, None)
        return
    def SetOnlineState(self, playerID, isOnline, serverGroupID=0):
        if isOnline:
            self.__SetOnline(playerID, serverGroupID)
        else:
            self.__SetOffline(playerID, serverGroupID)
        return
    def GetOfflineValue(self, playerID, viewCache=None):
        ## 离线值:0-在线;1-离线;>1-上次离线时间戳,可用于计算离线多久了;当取不到玩家信息时用1代表已离线;
        if playerID in self.onlinePlayerDict:
            return 0
        offlineValue = 1
        if viewCache and viewCache.OffTime:
            offlineValue = viewCache.OffTime
        return offlineValue
def GetOnlinePlayerMgr():
    mgr = PyGameData.g_onlinePlayerMgr
    if mgr == None:
        mgr = OnlinePlayerMgr()
        PyGameData.g_onlinePlayerMgr = mgr
    return mgr
#---------------------------------------------------------------------
@@ -121,6 +182,8 @@
    if GameWorld.IsCrossServer():
        #跨服PK
        CrossRealmPK.OnPlayerLoginCrossServer(curPlayer)
        #协助
        PlayerAssist.OnPlayerLoginCrossServer(curPlayer)
        return
    
    #玩家家族刷新
@@ -128,8 +191,9 @@
    PlayerFamily.PlayerLoginRefreshFamily(curPlayer, tick)
    #玩家队伍初始化
    PlayerTeam.OnPlayerLoginRefreshTeam(curPlayer, tick)
    PlayerCompensation.NotifyPlayerCompensation(curPlayer)
    #PlayerCompensation.NotifyPlayerCompensation(curPlayer)
    __UpdOnedayJobPlayerLoginoffTime(curPlayer)
    CrossRealmPlayer.OnPlayerLogin(curPlayer)
    
    if not PlayerControl.GetIsTJG(curPlayer):
        # 只有通知逻辑的应该放此处减少IO,如有逻辑处理存储等不可放在此处
@@ -169,8 +233,6 @@
        PlayerStore.OnPlayerLogin(curPlayer)
        #通知世界boss信息
        GameWorldBoss.OnPlayerLogin(curPlayer)
        #家族副本boss状态通知
        PlayerFamilyBoss.OnLogin(curPlayer)
        #渡劫
        PlayerDuJie.OnPlayerLogin(curPlayer)
        #守卫人皇
@@ -186,20 +248,65 @@
        GameWorldArena.OnPlayerLogin(curPlayer)
        #跨服PK
        CrossRealmPK.OnPlayerLogin(curPlayer)
        #幸运云购
        CrossLuckyCloudBuy.OnPlayerLogin(curPlayer)
        #诛仙BOSS
        PlayerZhuXianBoss.OnPlayerLogin(curPlayer)
        #骑宠boss状态通知
        PlayerHorsePetBoss.OnLogin(curPlayer)
        #协助
        PlayerAssist.OnPlayerLogin(curPlayer, False)
        PlayerAssist.OnPlayerLogin(curPlayer)
        #天星塔
        GameWorldSkyTower.OnPlayerLogin(curPlayer)
        #福地
        GameWorldMineArea.OnPlayerLogin(curPlayer)
        GMT_CTG.OnPlayerLogin(curPlayer)
        
    else:
        #协助
        PlayerAssist.OnPlayerLogin(curPlayer, True)
        pass
        
    return
def DoPlayerRealLoginOK(curPlayer, loginMsg, tick):
    ''' 玩家最终登录成功处理, 由  MapServer  DoPlayerRealLoginOK  通知
        该函数为地图最终登录成功才会执行到,以后一些功能类的登录处理建议均写到这里
        旧的功能先不动( __DoPlayerLoginServer 函数中的功能),如果有登录相关的bug再考虑是否移动到此函数
    '''
    isMixServerFirstLogin = loginMsg[0]
    GameWorld.Log("GameServer->DoPlayerRealLoginOK, isMixServerFirstLogin=%s" % isMixServerFirstLogin, curPlayer.GetPlayerID())
    if GameWorld.IsCrossServer():
        return
    PyGameData.g_dbPlayerIDMap[curPlayer.GetPlayerID()] = curPlayer.GetAccID()
    if not PlayerControl.GetIsTJG(curPlayer):
        #家族副本boss状态通知
        PlayerFamilyBoss.OnLogin(curPlayer)
        #魅力
        PlayerCharm.OnPlayerLogin(curPlayer)
        #情缘
        PlayerLove.OnPlayerLogin(curPlayer)
        #膜拜
        GameWorship.OnPlayerLogin(curPlayer)
        #跨服战场
        CrossBattlefield.OnPlayerLogin(curPlayer)
        #跨服排位
        CrossChampionship.OnPlayerLogin(curPlayer, tick)
        #跨服全民充值
        CrossActAllRecharge.OnPlayerLogin(curPlayer)
        #跨服妖魔boss
        CrossYaomoBoss.OnPlayerLogin(curPlayer)
        #玩家记录
        PlayerRecData.OnPlayerLogin(curPlayer)
        PlayerPackData.OnPlayerLogin(curPlayer)
        #在线状态变更,放最后
        __OnPlayerOnlineStateChange(curPlayer, True)
    if isMixServerFirstLogin:
        PlayerCharm.OnMixServerFirstLogin(curPlayer)
    PyGameData.g_noPlayerLoginWarningMailState = 2
    return
def __UpdOnedayJobPlayerLoginoffTime(curPlayer):
@@ -534,7 +641,8 @@
    
    if GameWorld.IsCrossServer():
        PlayerFB.OnPlayerDisconnectCrossServer(curPlayer)
        return
    #跨服匹配PK
    CrossRealmPK.OnLeaveServer(curPlayer)
    
@@ -560,7 +668,113 @@
    if not PlayerControl.GetIsTJG(curPlayer):
        playerID = curPlayer.GetPlayerID()
        PyGameData.g_unTJLogoffTime[playerID] = int(time.time())
        PyGameData.g_xiangongCanLikeTimeDict.pop(playerID, None)
        
        #在线状态变更,放最后
        __OnPlayerOnlineStateChange(curPlayer, False)
    return
def __OnPlayerOnlineStateChange(curPlayer, isOnline):
    ## 在线状态变更
    if PlayerControl.GetIsTJG(curPlayer):
        return
    playerID = curPlayer.GetPlayerID()
    olMgr = GetOnlinePlayerMgr()
    olMgr.SetOnlineState(playerID, isOnline)
    #relatedPlayerIDList = [] # 本服相关玩家
    #offlineValue = olMgr.GetOfflineValue(playerID, PlayerViewCache.FindViewCache(playerID))
    #SyncRelatedPlayerOnlineState(playerID, offlineValue, relatedPlayerIDList)
    if curPlayer.GetLV() < 50:
        #GameWorld.DebugLog("跨服相关功能未开启,不同步在线状态到跨服服务器! LV=%s" % curPlayer.GetLV(), curPlayer.GetPlayerID())
        return
    cacheBase = PlayerViewCache.GetSyncCrossCacheBase(curPlayer)
    dataMsg = {"playerID":playerID, "isOnline":isOnline, "cacheBase":cacheBase}
    CrossRealmMsg.SendMsgToCrossServer(ShareDefine.ClientServerMsg_PlayerLoginout, dataMsg)
    return
def ClientServerMsg_PlayerLoginout(serverGroupID, msgData):
    ## 收到子服玩家上下线
    playerID = msgData["playerID"]
    isOnline = msgData["isOnline"]
    cacheBase = msgData["cacheBase"]
    isLogout = not isOnline
    olMgr = GetOnlinePlayerMgr()
    olMgr.SetOnlineState(playerID, isOnline, cacheBase.get("ServerGroupID", 0))
    PlayerViewCache.UpdCrossCacheBase(playerID, cacheBase, isLogout)
    serverID = GameWorld.GetAccIDServerID(cacheBase["AccID"])
    # 上线
    if isOnline:
        PlayerPackData.OnPlayerLogin_CrossLogic(serverGroupID, serverID, playerID)
        GameXiangong.OnPlayerLogin_CrossLogic(serverGroupID, serverID, playerID)
    # 下线
    else:
        pass
    SyncCrossPlayerOnlineStateToRelatedPlayer(playerID)
    return
def SyncCrossPlayerOnlineStateToRelatedPlayer(playerID):
    ## 同步跨服玩家在线状态给相关玩家
    relatedPlayerIDList = []
    # 功能队伍
    funcTeamMgr = PyDataManager.GetDBPyFuncTeamManager()
    playerTeamIDDict = funcTeamMgr.GetPlayerTeamIDDict(playerID)
    for _, teamID in playerTeamIDDict.items():
        funcTeam = funcTeamMgr.GetFuncTeam(teamID)
        if not funcTeam:
            continue
        relatedPlayerIDList += funcTeam.GetMemberIDList()
    # 其他...
    # 去重汇总
    relatedPlayerIDList = list(set(relatedPlayerIDList))
    if playerID in relatedPlayerIDList:
        relatedPlayerIDList.remove(playerID)
    if not relatedPlayerIDList:
        return
    offlineValue = GetOnlinePlayerMgr().GetOfflineValue(playerID, PlayerViewCache.FindViewCache(playerID))
    dataMsg = {"loginoutPlayerID":playerID, "offlineValue":offlineValue, "relatedPlayerIDList":relatedPlayerIDList}
    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_PlayerLoginout, dataMsg)
    return
def CrossServerMsg_PlayerLoginout(msgData):
    ## 收到跨服服务器信息 - 玩家上下线状态变更
    loginoutPlayerID = msgData["loginoutPlayerID"]
    offlineValue = msgData["offlineValue"]
    relatedPlayerIDList = msgData["relatedPlayerIDList"]
    SyncRelatedPlayerOnlineState(loginoutPlayerID, offlineValue, relatedPlayerIDList, 1)
    return
def SyncRelatedPlayerOnlineState(loginoutPlayerID, offlineValue, relatedPlayerIDList, isCross=0):
    clientPack = None
    playerMgr = GameWorld.GetPlayerManager()
    for playerID in relatedPlayerIDList:
        if not PlayerControl.GetDBPlayerAccIDByID(playerID):
            continue
        curPlayer = playerMgr.FindPlayerByID(playerID)
        if not curPlayer or not curPlayer.GetInitOK():
            continue
        if not clientPack:
            clientPack = ChPyNetSendPack.tagGCRelatedPlayerOnlineState()
            clientPack.PlayerID = loginoutPlayerID
            clientPack.OfflineValue = offlineValue
            clientPack.IsCross = isCross
        NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
## 设置玩家离线时间
@@ -625,6 +839,7 @@
    packValue = playerStatePack.GetValue()
    packValueEx = playerStatePack.GetValueEx()
    packType = playerStatePack.GetType()
    #packValueTotal = packValue + packValueEx * ChConfig.Def_PerPointValue
    
    #---特殊逻辑处理---
    if packType == ShareDefine.CDBPlayerRefresh_ForbidenTalk:
@@ -634,7 +849,11 @@
    if packType == ShareDefine.CDBPlayerRefresh_ExAttr17:
        PlayerControl.SetPlayerAccState(curPlayer, packValue)
        return
    if packType == ShareDefine.CDBPlayerRefresh_ExAttr19:
        PlayerControl.SetLeaveFamilyTimeEx(curPlayer, packValue)
        return
    if packType == IPY_GameServer.CDBPlayerRefresh_State:
        # 脱机在线
        PlayerControl.SetIsTJG(curPlayer, packValue)
@@ -670,13 +889,14 @@
        
    elif packType == IPY_GameServer.CDBPlayerRefresh_LV:
        curPlayer.SetLV(packValue)
        PlayerSocial.UpdateSocialInfo(curPlayer, packType, packValue)
        #玩家等级记录
        playerID = curPlayer.GetID()
        if playerID in PyGameData.g_todayPlayerLVDict:
            PyGameData.g_todayPlayerLVDict[playerID] = packValue
    elif packType == IPY_GameServer.CDBPlayerRefresh_Job:
        if packValue != curPlayer.GetJob():
            PlayerBillboard.DelJobFightPowerBillboard(curPlayer, curPlayer.GetJob())
        curPlayer.SetJob(packValue)
        
#    elif packType == IPY_GameServer.CDBPlayerRefresh_CurrentPlayerType:
@@ -704,7 +924,8 @@
        PlayerControl.SetCrossMapID(curPlayer, packValue, False)
        
    elif packType == IPY_GameServer.CDBPlayerRefresh_ExAttr9:
        PlayerControl.SetVIPExpireTime(curPlayer, packValue)
        curPlayer.SetExAttr9(packValue)
        #PlayerControl.SetVIPExpireTime(curPlayer, packValue)
        
    elif packType == IPY_GameServer.CDBPlayerRefresh_ExAttr10:
        PlayerControl.SetChatBubbleBox(curPlayer, packValue)
@@ -717,10 +938,18 @@
    
    elif packType == IPY_GameServer.CDBPlayerRefresh_OfficialRank:
        curPlayer.SetOfficialRank(packValue)
        PlayerSocial.UpdateSocialInfo(curPlayer, packType, packValue)
        #更新排行榜的境界
        PlayerBillboard.UpdateBillboardRealm(curPlayer)
    elif packType == IPY_GameServer.CDBPlayerRefresh_Face:
        curPlayer.SetFace(packValue)
        PlayerBillboard.UpdateBillboardFace(curPlayer)
    elif packType == IPY_GameServer.CDBPlayerRefresh_HairColor:
        #c++头像外框 用头发颜色通知  - 遗漏问题
        curPlayer.SetFacePic(packValue)
        PlayerBillboard.UpdateBillboardFacePic(curPlayer)
        
    #社交信息
    PlayerSocial.UpdateSocialInfo(curPlayer.GetID(), packType, packValue)
    #组队成员刷新
    PlayerTeam.PlayerTeamMemberRefresh(curPlayer, packType, packValue, tick)
    #家族刷新
@@ -1174,11 +1403,6 @@
#  @param tick 时间戳
#  @return None
def Sync_PyServerDataTimeToClient(curPlayer, tick):
    if not GameWorld.RefurbishPlayerTick(curPlayer, ChConfig.TYPE_Player_Tick_SyncClientTick, tick):
        #间隔未到
        return
    # 服务器时间
    serverTime = GameWorld.GetServerTime()
    if not serverTime:
@@ -1192,7 +1416,8 @@
    serverDateTime.Hour = serverTime.hour
    serverDateTime.Minute = serverTime.minute
    serverDateTime.Second = serverTime.second
    serverDateTime.MicSecond = serverTime.microsecond
    serverDateTime.MicSecond = serverTime.microsecond
    serverDateTime.CrossServerTime = GameWorld.GetCrossServerTimeStr()
    
    # 通知客户端同步时间
    NetPackCommon.SendFakePack(curPlayer, serverDateTime)