From 94c9b0759bfa49e66bfce3f790c40f15d362ba1a Mon Sep 17 00:00:00 2001 From: hxp <ale99527@vip.qq.com> Date: 星期四, 10 一月 2019 15:17:26 +0800 Subject: [PATCH] 5722 【后端】【1.5】跨服BOSS开发(支持跨服复活) --- ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py | 397 ++++++++++++++++++++++++++------------------------------ 1 files changed, 185 insertions(+), 212 deletions(-) diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py index 902e680..7fef4cf 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py @@ -376,7 +376,7 @@ # !!!必要发送的数据要注意位置 if GameWorld.IsCrossServer(): curPlayer.SetForbiddenSyncClientState(False) - PlayerControl.SetCrossRealmState(curPlayer, 1) # 因为主服上传数据之前该值为0,所以登录跨服后在跨服服务器要设置为1 + PlayerControl.SetCrossRealmState(curPlayer, curPlayer.GetMapID()) # 因为主服上传数据之前该值为0,所以登录跨服后在跨服服务器要设置为1 return @@ -2323,31 +2323,76 @@ #根据玩家选择重生选项重生 sendPack = IPY_GameWorld.IPY_CCliectReborn() #复活类型 - playerRebornType = sendPack.GetType() + rebornType = sendPack.GetType() + GameWorld.DebugLog("玩家点击复活: rebornType=%s" % rebornType, curPlayer.GetPlayerID()) - if curPlayer.GetHP() > 0: - # 当血量大于0收到复活请求包时,一般是前后端复活状态不一致的情况下导致的 - # 由于前端需要根据复活状态判断复活界面相关逻辑,所以这里需要做一些特殊处理,防止某些情况下前后端复活状态不一致导致的一些异常问题 - - # 后端非死亡状态的情况,补同步一次复活包给前端 - if curPlayer.GetPlayerAction() != IPY_GameWorld.paDie: - SyncPlayerReborn(curPlayer, playerRebornType) - # 后端也是死亡状态的情况,直接重新触发一次复活 - else: - PlayerRebornByType(curPlayer, playerRebornType, tick) - #生命值不为0 , 不能重生 -# GameWorld.Log("玩家点击: 重生失败,生命值不为0 , 不能重生" , curPlayer.GetPlayerID()) + if GameWorld.IsCrossServer(): + GameWorld.DebugLog("跨服服务器不接受复活请求!") + return + + if PlayerControl.GetCrossRealmState(curPlayer): + OnReqCrossServerReborn(curPlayer, rebornType) return #FB中禁止复活 - if FBLogic.DoFBForbidReborn(curPlayer, playerRebornType): + if FBLogic.DoFBForbidReborn(curPlayer, rebornType): PlayerControl.NotifyCode(curPlayer, "Reborn_lhs_31379") return #玩家复活 - if PlayerRebornByType(curPlayer, playerRebornType, tick): + if PlayerRebornByType(curPlayer, rebornType, tick): #玩家复活成功,判断是否在副本中复活 - PlayerReborn_InFB(curPlayer, playerRebornType, tick) + PlayerReborn_InFB(curPlayer, rebornType, tick) + + return + +def OnReqCrossServerReborn(curPlayer, rebornType): + ## 请求跨服服务器复活玩家 + + crossMapID = curPlayer.NomalDictGetProperty(ChConfig.Def_PlayerKey_CrossMapID) + if not crossMapID: + GameWorld.DebugLog("当前无跨服地图!") + return + + if not __CheckCanReborn(curPlayer, rebornType): + return + + msgDict = {"PlayerID":curPlayer.GetPlayerID(), "RebornType":rebornType} + GameWorld.SendMsgToCrossServer(ShareDefine.ClientServerMsg_Reborn, msgDict) + GameWorld.DebugLog("跨服中请求复活, crossMapID=%s,msgDict=%s" % (crossMapID, msgDict), curPlayer.GetPlayerID()) + return + +def ClientServerMsg_Reborn(curPlayer, msgData, serverGroupID, tick): + ## 收到子服请求复活信息 + + rebornType = msgData["RebornType"] + gameMap = GameWorld.GetMap() + if not __CheckCanReborn(curPlayer, rebornType, gameMap): + return + + isAddReviveTired = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_IsAddReviveTired) + # 跨服服务器不执行消耗,复活后同步消息回主服扣除消耗 + __DoPlayerReborn(curPlayer, rebornType, tick) + + # 发送回本服复活结果 + msgInfo = {"Result":1, "ReviveTired":isAddReviveTired} + msgInfo.update(msgData) + GameWorld.SendMsgToClientServer(ShareDefine.CrossServerMsg_RebornRet, msgInfo, [serverGroupID]) + return + +def CrossServerMsg_RebornRet(curPlayer, msgData, tick): + ## 收到跨服服务器复活结果 + + result = msgData["Result"] + if result != 1: + return + + rebornType = msgData["RebornType"] + isAddReviveTired = msgData["ReviveTired"] + __RebornCost(curPlayer, rebornType, True) + + if isAddReviveTired: + __AddReviveTired(curPlayer, tick) return @@ -2662,7 +2707,8 @@ #取消自动运镖状态 PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_AutoTruck, 0) - PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_RoomID, 0) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PlayerKey_CrossRegisterMap, 0) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PlayerKey_IsCrossPKMatching, 0) #下线召回宠物 PetControl.ReCallFightPet(curPlayer) @@ -3895,20 +3941,23 @@ # curPlayer.GameServer_LineState() return - - -##获取死亡冷却时间 -#@param curPlayer 玩家实例 -#@param playerRebornType 复活类型 -#@return 死亡冷却时间 -def GetRebronTime(curPlayer, playerRebornType): - mapType = GameWorld.GetMap().GetMapFBType() +def GetRebronTime(curPlayer, rebornType): + ''' 死亡状态才验证时间,本服跨服通用 + 跨服服务器死亡的复活也是先发到本服,正常情况下本服是活着的,无法验证 + 所以可否复活由跨服服务器死亡状态下的玩家实例判断,简单讲就是哪个服务器死亡的哪个服务器判断 + 所以该函数可以直接使用玩家所在的地图判断 + ''' - if playerRebornType in [ChConfig.rebornType_Health, ChConfig.rebornType_UseItem]: - #原地复活、道具复活不用CD + # 非死亡状态下,也就是哪个服务器角色死亡由哪个服务器判断 + if curPlayer.GetHP() > 0 and curPlayer.GetPlayerAction() != IPY_GameWorld.paDie: + return 0 + + # 回城复活的才需要CD + if rebornType not in [ChConfig.rebornType_City, ChConfig.rebornType_MainCity]: return 0 # 副本地图CD + mapType = GameWorld.GetMap().GetMapFBType() if mapType != IPY_GameWorld.fbtNull: fbRebornTimeDict = IpyGameDataPY.GetFuncEvalCfg('DuplicatesRebornTime', 1) curMapID = GameWorld.GetMap().GetMapID() @@ -3922,30 +3971,6 @@ if findBuff.GetSkill().GetSkillLV() == findBuff.GetSkill().GetSkillMaxLV(): return IpyGameDataPY.GetFuncEvalCfg('RebornArguments', 1)[1] return 0 - -# playerRebornTimeDict = ReadChConfig.GetEvalChConfig('PlayerRebornTime') -# -# curMapID = GameWorld.GetMap().GetMapID() -# -# #不在配表的地图ID中取默认的 -# if curMapID not in playerRebornTimeDict.keys(): -# curMapID = 0 -# -# rebronTimeByTypeDict = playerRebornTimeDict.get(curMapID, {}) -# -# if not rebronTimeByTypeDict: -# GameWorld.ErrLog("GetRebronTime rebronTimeByTypeDict=%s,,curMapID=%s" % -# (rebronTimeByTypeDict, curMapID)) -# return 0 -# -# #公式参数 -# playerLV = curPlayer.GetLV() -# playerDeadCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_PlayerDeadCnt) -# -# rebornTime = int(eval(rebronTimeByTypeDict.get(playerRebornType, "0"))) -# -# return rebornTime - ## 死亡冷却时间是否完了 #@param curPlayer 玩家实例 @@ -3961,116 +3986,90 @@ #--------------------------------------------------------------------- -##自定义函数, 玩家复活 -#@param curPlayer 玩家实例 -#@param playerRebornType 复活类型 -#@param tick 时间戳 -#@param mapBornPlace 复活位置,默认0为原地 -#@return 返回值无意义 -#@remarks 自定义函数, 玩家复活 -def PlayerRebornByType(curPlayer, playerRebornType, tick, mapBornPlace=0, isAddSuperBuff=True): - curPlayerID = curPlayer.GetID() - curVipLv = curPlayer.GetVIPLv() + +def __CheckCanReborn(curPlayer, rebornType, gameMap=None): + ''' 检查可否复活,为了逻辑统一,这里不适用玩家所在的地图,支持跨服状态下判断跨服地图 + 本函数不验证玩家死亡状态等,因为有可能前后端复活状态不一致,如果这里拦住可能导致前端躺尸复活不了 + ''' - gameMap = GameWorld.GetMap() + if rebornType not in ChConfig.Def_RebornTypeList: + return - #需要支付的银子数量 - moneyPrice = 0 - #复活恢复血量、魔的万分比 - resetHpPercent = ChConfig.Def_MaxRateValue - resetMpPercent = ChConfig.Def_MaxRateValue + ## 由于本服及跨服地图数据不互通,所以这里根据是否有地图数据进行判断处理 + if gameMap: + playerID = curPlayer.GetPlayerID() + if rebornType in [ChConfig.rebornType_Health, ChConfig.rebornType_UseItem] and not gameMap.GetLocalReborn(): + GameWorld.ErrLog("该地图不可原地复活! mapID=%s,rebornType=%s" % (gameMap.GetMapID(), rebornType), curPlayer.GetPlayerID()) + return - #复活冷却时间(秒) - rebornTime = GetRebronTime(curPlayer, playerRebornType) - #冷却时间到了 - if playerRebornType != ChConfig.rebornType_System and not CanRebornByTimeOver(curPlayer, rebornTime): - PlayerControl.NotifyCode(curPlayer, 'RebornCD') - return False + # 验证复活CD + rebornCD = GetRebronTime(curPlayer, rebornType) + if rebornCD: + curTime = int(time.time()) + deadTime = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_DeadTime) + if curTime - deadTime < rebornCD: + PlayerControl.NotifyCode(curPlayer, "RebornCD") + GameWorld.Log("复活冷却时间中,无法复活! curTime(%s) - deadTime(%s) < rebornCD(%s)" % (curTime, deadTime, rebornCD), playerID) + return + + # 验证复活消耗,在本服验证,跨服服务器只验证状态 + if not GameWorld.IsCrossServer(): + if not __RebornCost(curPlayer, rebornType, False): + return + + return True + +def __RebornCost(curPlayer, rebornType, isDoCost): + ## 扣除复活消耗 + # @param isDoCost: 是否执行消耗 + playerID = curPlayer.GetPlayerID() + if rebornType == ChConfig.rebornType_Health: + rebornCfg = IpyGameDataPY.GetFuncEvalCfg('RebornArguments', 1) + moneyPrice = rebornCfg[2] + costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, ShareDefine.TYPE_Price_Gold_Paper_Money, moneyPrice) + if not costMoneyList: + GameWorld.ErrLog("货币不足,无法原地复活! moneyPrice=%s" % (moneyPrice), playerID) + return + + if isDoCost: + for moneyType, moneyCnt in costMoneyList: + if not PlayerControl.PayMoney(curPlayer, moneyType, moneyCnt, ChConfig.Def_Cost_Revive): + return + + elif rebornType == ChConfig.rebornType_UseItem: + rebornItem = ItemCommon.FindItemInPackByEffectEx(curPlayer, ChConfig.Def_Effect_Reborn) + if not rebornItem: + GameWorld.ErrLog("复活道具不足,无法原地复活! ", playerID) + return + + if isDoCost: + ItemCommon.DelItem(curPlayer, rebornItem, 1, True, "Reborn") + + return True + +def __DoPlayerReborn(curPlayer, rebornType, tick, mapBornPlace=0, isAddSuperBuff=True): + ## 执行玩家复活逻辑,该函数没有执行验证是否可复活等,不可直接调用 + if curPlayer.GetHP() > 0 and curPlayer.GetPlayerAction() != IPY_GameWorld.paDie: + # 当血量大于0收到复活请求时,一般是前后端复活状态不一致的情况下导致的 + # 由于前端需要根据复活状态判断复活界面相关逻辑,所以这里需要做一些特殊处理,防止某些情况下前后端复活状态不一致导致的一些异常问题 + # 后端非死亡状态的情况,补同步一次复活包给前端 + SyncPlayerReborn(curPlayer, rebornType) + return + + resetHpPercent = ChConfig.Def_MaxRateValue isFBReborn = False - #-----------------------------------------回城复活(切换地图)----------------------------------- - if playerRebornType == ChConfig.rebornType_City: + if rebornType == ChConfig.rebornType_City: if FBLogic.OnPlayerReborn(): isFBReborn = True else: PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_IsReBorn, 1) - -#=============================================================================== -# #不在特殊的地图中,玩家副本中复活相关 -# if not FBLogic.OnPlayerReborn(): -# #输出系统提示 -# __NotifyReBornToPlace( curPlayer ) -#=============================================================================== - - - #----------------------------------------------其他复活(不切换地图)------------------------------------ - #技能复活 - elif playerRebornType == ChConfig.rebornType_Skill: - - if not gameMap.GetSkillReborn(): - return False - - reBornSkill = GameWorld.GetGameData().GetSkillBySkillID(ChConfig.Def_SkillID_SkillReBorn) - #恢复血量万分比 - resetHpPercent = reBornSkill.GetEffect(1).GetEffectValue(0) - #恢复魔万分比 - resetMpPercent = reBornSkill.GetEffect(2).GetEffectValue(0) - - BuffSkill.DelBuffBySkillID(curPlayer, ChConfig.Def_SkillID_SkillReBorn, tick) - - #原地健康复活 - elif playerRebornType == ChConfig.rebornType_Health: - #if not PlayerVip.GetVipCanOriginalReborn(curVipLv): - # #vip等级限制 - # return - if not gameMap.GetLocalReborn(): - GameWorld.DebugLog(' 地图配置不能原地复活') - return False - - if not __HealthRebornPayMoney(curPlayer): - return False - - #使用道具(还阳咒)复活 - elif playerRebornType == ChConfig.rebornType_UseItem: - - if not gameMap.GetLocalReborn(): - return False - - if not __RebornDelItem(curPlayer): - return False - - # 副本复活 - elif playerRebornType in [ChConfig.rebornType_FBGold, ChConfig.rebornType_FBUseItem]: - isFBReborn = True - freeBorn = FBLogic.DecFreeRebornCount(curPlayer) - if not freeBorn: - if not gameMap.GetLocalReborn(): - return False - if playerRebornType == ChConfig.rebornType_FBGold: - #if not PlayerVip.GetVipCanOriginalReborn(curVipLv): - # #vip等级限制 - # return False - - if not __HealthRebornPayMoney(curPlayer): - return False - - elif playerRebornType == ChConfig.rebornType_FBUseItem: - if not __RebornDelItem(curPlayer): - return False - elif playerRebornType == ChConfig.rebornType_MainCity: + elif rebornType == ChConfig.rebornType_MainCity: PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_IsReBorn, 2) - - elif playerRebornType == ChConfig.rebornType_System: - pass - - else: - #封包错误 -# GameWorld.Log("重生封包类型 = %s错误"%(playerRebornType), curPlayerID ) - return False - + #通知客户端玩家复活成功 - curPlayer.Reborn(playerRebornType) + curPlayer.Reborn(rebornType) #执行玩家副本复活 if isFBReborn: @@ -4081,16 +4080,8 @@ SkillCommon.AddBuffBySkillType_NoRefurbish(curPlayer , ChConfig.Def_SkillID_LimitSuperBuff, tick) #复活疲劳BUff if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_IsAddReviveTired): - findBuff = SkillCommon.FindBuffByID(curPlayer, ChConfig.Def_SkillID_ReviveTired)[0] - if findBuff: - buffSkillLV = findBuff.GetSkill().GetSkillLV() - if findBuff.GetSkill().GetSkillMaxLV() != buffSkillLV: - buffSkillLV = buffSkillLV + 1 - else: - buffSkillLV = 1 - SkillCommon.AddBuffBySkillType_NoRefurbish(curPlayer , ChConfig.Def_SkillID_ReviveTired, tick, buffSkillLV) - GameWorld.DebugLog(' 复活疲劳BUff buffSkillLV=%s'%(buffSkillLV)) - PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_IsAddReviveTired,0) + __AddReviveTired(curPlayer, tick) + #复活后清除角色身上的打BOSS和PK状态 validTime = IpyGameDataPY.GetFuncCfg("PKConfig", 4) * 1000 if PlayerState.IsInPKState(curPlayer): @@ -4109,15 +4100,16 @@ PlayerControl.SetProDef(curPlayer, PlayerControl.GetMaxProDef(curPlayer)) #玩家复活后副本处理 - FBLogic.OnPlayerRebornOver(curPlayer, playerRebornType) - + FBLogic.OnPlayerRebornOver(curPlayer, rebornType) + + gameMap = GameWorld.GetMap() #障碍点中原地复活, 打回重生点 - if (playerRebornType == ChConfig.rebornType_City and not isFBReborn)\ - or not GameWorld.GetMap().CanMove(curPlayer.GetPosX(), curPlayer.GetPosY()) \ - or (playerRebornType == ChConfig.rebornType_MainCity and gameMap.GetRebornMapID() == curPlayer.GetMapID()): + if (rebornType == ChConfig.rebornType_City and not isFBReborn) \ + or not GameWorld.GetMap().CanMove(curPlayer.GetPosX(), curPlayer.GetPosY()) \ + or (rebornType == ChConfig.rebornType_MainCity and gameMap.GetRebornMapID() == curPlayer.GetMapID()): #玩家切换到重生点 playerControl.SetToBornPlace() - elif playerRebornType == ChConfig.rebornType_MainCity: + elif rebornType == ChConfig.rebornType_MainCity: #直接取db中配置的复活点 PlayerControl.PlayerResetWorldPos(curPlayer, gameMap.GetRebornMapID(), gameMap.GetRebornMapX(), gameMap.GetRebornMapY(), False) #重新召唤宠物 @@ -4125,57 +4117,38 @@ #复活成功,重置状态 PlayerControl.ChangePlayerAction(curPlayer, IPY_GameWorld.paNull) - return True + return -##复活扣除元宝 -#@param curPlayer 玩家实例 -#@return 是否扣除成功 -def __HealthRebornPayMoney(curPlayer): - rebornCfg = IpyGameDataPY.GetFuncEvalCfg('RebornArguments', 1) - moneyPrice = rebornCfg[2] - #异常 - if not moneyPrice: - return True - costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, ShareDefine.TYPE_Price_Gold_Paper_Money, moneyPrice) - if not costMoneyList: - return False - infoDict = {} - for moneyType, moneyCnt in costMoneyList: - if not PlayerControl.PayMoney(curPlayer, moneyType, moneyCnt, ChConfig.Def_Cost_Revive, infoDict): - return False +def __AddReviveTired(curPlayer, tick): + ## 增加复活疲劳 + findBuff = SkillCommon.FindBuffByID(curPlayer, ChConfig.Def_SkillID_ReviveTired)[0] + if findBuff: + buffSkillLV = findBuff.GetSkill().GetSkillLV() + if findBuff.GetSkill().GetSkillMaxLV() != buffSkillLV: + buffSkillLV = buffSkillLV + 1 + else: + buffSkillLV = 1 + SkillCommon.AddBuffBySkillType_NoRefurbish(curPlayer , ChConfig.Def_SkillID_ReviveTired, tick, buffSkillLV) + GameWorld.DebugLog(' 复活疲劳BUff buffSkillLV=%s'%(buffSkillLV)) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_IsAddReviveTired,0) + return + +def PlayerRebornByType(curPlayer, rebornType, tick, mapBornPlace=0, isAddSuperBuff=True): + ''' 玩家复活 + ''' + gameMap = GameWorld.GetMap() + if not __CheckCanReborn(curPlayer, rebornType, gameMap): + return - GameWorld.Login_Interface_GoldRec(curPlayer , 0 , 0 , 'HealthReborn' , moneyType , moneyPrice) + if not GameWorld.IsCrossServer(): + if not __RebornCost(curPlayer, rebornType, True): + return + + __DoPlayerReborn(curPlayer, rebornType, tick, mapBornPlace, isAddSuperBuff) return True - -##复活扣除道具 -#@param curPlayer 玩家实例 -#@return 是否扣除成功 -def __RebornDelItem(curPlayer): - rebornItem = ItemCommon.FindItemInPackByEffectEx(curPlayer, ChConfig.Def_Effect_Reborn) - if not rebornItem: - #GeRen_chenxin_143504 对不起,您没有XXX! - #PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_143504", [ChConfig.Def_ItemID_Reborn]) - return False - - #调用通用接口删除道具 - ItemCommon.DelItem(curPlayer, rebornItem, 1, True, "Reborn") - return True - #--------------------------------------------------------------------- -#=============================================================================== -# def __NotifyReBornToPlace( curPlayer ): -# #普通地图 -# if GameWorld.GetMap().GetMapFBType() == IPY_GameWorld.fbtNull: -# #Revival_Home <n color="0,255,0">提示:您可以在各大主城的杂货店消除身上携带的虚弱状态!</n> 256 - -# PlayerControl.NotifyCode( curPlayer, "Revival_Home" ) -# #副本中 -# elif not FBLogic.DoNotifyReBorn( curPlayer ): -# #输出默认提示 -# PlayerControl.NotifyCode( curPlayer, "Revival_Home" ) -# -# return -#=============================================================================== + ##副本接口:玩家复活 #@param curPlayer 玩家实例 #@param tick 时间戳 -- Gitblit v1.8.0