-- 处理主城移动 以及 进出关卡相关事务 local SyncMoveManager = {} local private = {} local SyncMoveManagerExt = require "Battle/Logic/MainLoop/SyncMoveManagerExt" local TownCartManager = require "Battle/Logic/MainLoop/SyncMoveManager/TownCartManager" local LuaUpdater = require "Main/LuaUpdater" local role_move_pb = require('Proto/role_move_pb') local scene_line_pb = require('Proto/scene_line_pb') local enums_pb = require("Proto/enums_pb") local common_pb = require("Proto/common_pb") local EventSystem = require('Event/EventSystem') local PetSystem = require "Battle/Logic/Entity/System/PetSystem" local _checkMoveTime = 0 local _tempUnAddSceneEntityList = {} local _tempUnAddSceneObjectList = {} local _tempUnAddSceneObjectTargetPos = {} local hasSentStopRequest = false local hasSentMoveRequest = false local hasSendRoleTimes = 0 local _entityTargetPosDir = {} local _objectTargetPosDic = {} -- 存储那个单位要移动到哪里的信息 local EFFECT_PATH = ConstAssetPathConfig.EFFECT_PATH SyncMoveManager.CanChangeLine = true SyncMoveManager.TownRoleList = {} --key是acid, 不会存本玩家的信息,只会存其他玩家的信息 SyncMoveManager.TownObjectDic = {} --key是uniqId, 存放所有的objectList ,除盗洞外的其他Object(当前有也不包括玩家),包括npc ,镖车 {entity = entity ,info = ObjectSceneBasic} SyncMoveManager.CurLine = 0 local newV2 = FP.newV2 local LuaConst = LuaConst local FPConst_One = FP.Const.One local FPConst_Zero = FP.Const.Zero local tonumberV2 = FP.tonumberV2 local tonumberV1 = FP.tonumberV1 local LuaConst_AttrType_spd = LuaConst.AttrType.spd local Const_StatueSize = 2.1 local MIN_DISTANCE = 0.05 local TOO_FAR_DIST_SQR = 900 local TRAIN_FOLLOW_TOO_FAR_DIST = 40 --进入火车跟随状态后,跟随的人如果跟自己的车厢位置超过这个距离,就瞬移到车厢位置 local MIN_DISTANCE_HORSE = 0.5 -- 太小的话会导致抖动 local math_sqrt = math.sqrt --保存每个单位的移动信息,这些信息通常用来优化移动表现 --key是entityID,value是一个table,保存各种移动信息 local moveInfoDic = {} local HORSE_TO_IDLE_NEED_FRAME = 10 local IDLE_NEED_FRAME = 2 function SyncMoveManager.Init() EventSystem.Regist(EventID.ModulesLaunch, private.OnModulesLaunch) EventSystem.Regist(EventID.ModulesShutdown, private.OnModulesShutdown) EventSystem.Regist(EventID.ChildTaskFinish, private.OnTaskFinish) private.checkMoveFrame = LuaConst.CheckMoveFrame end function private.RegistMessage() SyncMoveManager.isMsgRegisted = true NetManager.RegisterMsgCB(MessageEnums.MessageS2CRolesAct,private.S2CRolesActResp) NetManager.RegisterMsgCB(MessageEnums.MessageS2CNpcMove,private.OnS2CObjectMoveResp) NetManager.RegisterMsgCB(MessageEnums.MessageS2CAddRoleScreen,private.S2CAddRoleScreenResp) NetManager.RegisterMsgCB(MessageEnums.MessageS2CRemoveRoleScreen,private.S2CRemoveRoleScreenResp) NetManager.RegisterMsgCB(MessageEnums.MessageS2CRoleEnterScene,private.S2CRoleEnterSceneResp) NetManager.RegisterMsgCB(MessageEnums.MessageS2CRoleChangeInfo,private.S2CRoleChangeInfoResp) NetManager.RegisterMsgCB(MessageEnums.MessageS2CSetPosition,private.S2CSetPositionResp) NetManager.RegisterMsgCB(MessageEnums.MessageChangeSceneLine,private.ChangeSceneLineResp) NetManager.RegisterMsgCB(MessageEnums.MessageGetSceneLine,private.GetSceneLineResp) NetManager.RegisterMsgCB(MessageEnums.MessageChangeSceneAndLine,private.ChangeSceneAndLineResp) NetManager.RegisterMsgCB(MessageEnums.MessageS2CFubenEnemyInfo,private.S2CFubenEnemyInfoResp) NetManager.RegisterMsgCB(MessageEnums.MessageG2CBattlePlayerAddBuff, private.OnG2CBattlePlayerAddBuff) NetManager.RegisterMsgCB(MessageEnums.MessageS2CCollectionInfoChange, private.OnNpcStateInfoChange) NetManager.RegisterMsgCB(MessageEnums.MessageS2CPetInfoChange, private.OnPetInfoChange) EventSystem.Regist(EventID.Level_InitLevel, private.OnInitLevel) EventSystem.Regist(EventID.UI_AddBattleModelUI, private.OnBattleModelUIAdd) EventSystem.Regist(EventID.TeamMemberChanged, private.OnTeamMemberChanged) TownCartManager.RegistMessage() end function private.OnInitLevel() if LevelManager.IsSceneQuizTown() then private.checkMoveFrame = 4 else private.checkMoveFrame = LuaConst.CheckMoveFrame end end --向服务端同步当前位置信息 --state 0停止 1移动 function SyncMoveManager.C2SRoleMoveOrStop(state) if state == 0 then hasSentMoveRequest = false if hasSentStopRequest == false then private.C2SRoleMoveOrStopRequest(state) hasSentStopRequest = true end else hasSentStopRequest = false --移动 if hasSentMoveRequest == false then private.C2SRoleMoveOrStopRequest(1) hasSentMoveRequest = true end private.C2SRoleCheck() end end --方向改变直接同步 function SyncMoveManager.ForceC2SRoleMove(forceSend) if hasSentMoveRequest == true or forceSend then private.C2SRoleMoveOrStopRequest(1) end end --传送门发送一遍Check function SyncMoveManager.ForceC2SRoleCheck() hasSendRoleTimes = 1 private.C2SRoleMoveOrStopRequest(2) end function private.C2SRoleCheck() if (LogicUpdateManager._clientHandleFrame - _checkMoveTime) >= private.checkMoveFrame then private.C2SRoleMoveOrStopRequest(2) end end --玩家移动/停止,发送给服务端 --state 0停止 1移动 2定时上报 function private.C2SRoleMoveOrStopRequest(state) hasSendRoleTimes = hasSendRoleTimes + 1 --刚进场景初始化位置,第一次stop没必要同步位置 if hasSendRoleTimes<=1 then return end if LogicUpdateManager._curEntity and LevelManager.IsNoBattleLevel() then --在主城才发送同步位置协议 local msg = role_move_pb.C2SRoleMove() local msgPos, msgDir = msg.Pos, msg.Dir local moveCompomtent = LogicUpdateManager._curEntity.components.move local pos = moveCompomtent.LogicPos local dir = moveCompomtent.LogicRotateDir --坐标Y目前没用到,暂时传0吧 msgPos.X, msgPos.Y, msgPos.Z = pos.x[1], 0, pos.z[1] msgDir.X, msgDir.Z = dir.x[1], dir.z[1] msg.SceneId = LevelManager.CurUniqueSceneID if state == 0 then NetManager.SendMessage(MessageEnums.MessageC2SRoleStop,msg) elseif state == 1 then NetManager.SendMessage(MessageEnums.MessageC2SRoleMove,msg) else NetManager.SendMessage(MessageEnums.MessageC2SRoleCheck,msg) end --上报过位置后,重置下检查帧 _checkMoveTime = LogicUpdateManager._clientHandleFrame end end --广播九屏玩家 --其他玩家的单位进入视野(自己不会走这) function private.S2CAddRoleScreenResp(msgResp) --现在的机制是在看剧情时,已经切了地图,但是服务器并不知道,可能还会广播玩家,因此这个时候信息给忽略掉 --剧情结束的时候会再次请求切入地图,恢复信息 if LevelManager.LevelType == LuaConst.LevelType.NONE or LevelManager.LevelType == LuaConst.LevelType.SpecialLevelType then return end --这里把广播过来的玩家放到table中,后续做分帧的加载玩家 for _,info in ipairs(msgResp.roleList) do if not SyncMoveManager.TownRoleList[info.accid] then -- 优化S2CAddRoleScreenResp相关包装数据结构 _tempUnAddSceneEntityList[info.accid] = info end end if msgResp.objectList then for index, sceneObj in ipairs(msgResp.objectList) do _tempUnAddSceneObjectList[sceneObj.uniqId] = sceneObj end end LuaUpdater.StartUpdate(private.OnLogicUpdate) end --做一个分帧处理玩家的机制,每帧只处理一个玩家 function private.OnLogicUpdate(deltaTime, timeSinceUpdate) if not LevelManager.HasLoadedData() or not LevelManager.IsNoBattleLevel() then return end for _,info in pairs(_tempUnAddSceneEntityList)do private.AddEntityScreen(info) return end for uniqId, sceneObj in pairs(_tempUnAddSceneObjectList)do private.AddOneObjectScreen(sceneObj) _tempUnAddSceneObjectList[uniqId] = nil if _tempUnAddSceneObjectTargetPos[uniqId] then private.ExcuteObjectMoveInfo(_tempUnAddSceneObjectTargetPos[uniqId]) _tempUnAddSceneObjectTargetPos[uniqId] = nil end return end LuaUpdater.StopUpdate(private.OnLogicUpdate) end function SyncMoveManager.DisableFollowIndexCacheByAcid(accid) for _,info in pairs(_tempUnAddSceneEntityList)do if info.accid == accid then -- 优化S2CAddRoleScreenResp相关包装数据结构 info.snakeIndex = 0 end end end function private.OnModulesLaunch() if not SyncMoveManager.isMsgRegisted then private.RegistMessage() end end function private.OnModulesShutdown() end function private.AddEntityScreen(info) if LevelManager.IsSyncLevel() then --这个加个保险。因为现在客户端和服务器互相不知道对方的具体状态,所以有时候服务器会在联机关卡发添加单位的消息过来,所以这里加个判断作为保护。否则会引发联机关卡的不一致 --logging.error(LTAG.ERROR, "HYW : 试图在同步关卡添加视野单位!(测试可忽略)") --不再打log了,发现会从private.HandleUnAddEntity调过来,_tempUnAddSceneEntityList是缓存,切关的时候没有清空,所以会进到这里 return end if info and SyncMoveManager.TownRoleList[info.accid] == nil then --设置entity名字需要从这个列表取数据,需要先存储数据,但此时entity还未创建,无法取到entityID,在创建之后设置entityID SyncMoveManager.TownRoleList[info.accid] = { roleInfo = { accid = info.accid, name = info.Name, guildEmblemContent = info.guildShow.emblemContent, guildEmblemFrame = info.guildShow.emblemFrame, guildID = info.guildShow.guildId, guildName = info.guildShow.guildName, guildJob = info.guildShow.jobTitle, guildIdentity = info.guildShow.identity, officialTitle = info.officialTitle, level = info.level, HeroId = info.HeroId, portraitId = info.portraitId, frameId = info.frameId, serId = info.serverShowId, mergeServerId = info.MergeServerId, countryId = info.countryInfo.countryId, countryJobId = info.countryInfo.countryJobId, leaderId = info.leaderId, gs = info.gs, --战力 sex = info.sex, --性别 teamId = info.teamId, --队伍ID teamWarName = info.teamWarName, -- 战团名字 basicBuff = info.basicBuff, basicExtraHero = info.basicExtraHero.heroInfo, }, entityID = -1, } _tempUnAddSceneEntityList[info.accid] = nil -- 优化S2CAddRoleScreenResp相关包装数据结构 local posV2 = newV2(0,0):Rawset(info.SceneInfo.Pos.X,info.SceneInfo.Pos.Z) local dirV2 = newV2(0,0):Rawset(info.SceneInfo.Dir.X,info.SceneInfo.Dir.Z) --0代表无效值,忽略即可。 负数和正数都代表有效值,-1代表取消跟随 if info.snakeIndex ~= 0 then MDL.Team.SetFollowIndex(info.accid, info.snakeIndex, info.leaderId) end EntityFactory.SetParams("AttrTable", info.attr, "Name", info.Name) local heroId=info.HeroId --cheat 使用同一个英雄测试 if MDL.Cheat.Get_isUseSameActor() then heroId =2 end EntityFactory.SetType_ID(LuaConst.CharacterType.Hero, heroId) EntityFactory.SetPos_Dir(posV2, dirV2) EntityFactory.SetEffectBreak_Weapon(info.heroBreakNums, info.isActiveMagicWeapon,info.weaponBreak) EntityFactory.SetHorse_ID(info.horseId, info.horseAppearanceId) EntityFactory.SetPet_Info(info.petInfo.petId, info.petInfo.stage, info.petInfo.petName, info.petInfo.petSkill) if not BattleDataGetter.CheckCurLevelType(LuaConst.LevelType.DragonArteryRegistArea) then EntityFactory.SetTitle_ID(info.titleID) EntityFactory.SetPet_TitleInfo(info.petInfo.isLineUp, info.petInfo.runeSkillLevelSum, info.petInfo.aptitudeSum) end EntityFactory.SetCart_Quality(info.cartQuality) EntityFactory.SetLightEffect_ID(info.lightEffectIds) EntityFactory.SetWeaponSoulInfo(info.weaponSoulInfo) EntityFactory.SetAcid(info.accid) EntityFactory.SetHeroAppearance_ID(info.heroAppearanceId) -- 设置时装 ,这个 appearanceId 和 heroAppearanceId 是有区别的:临时变装、时装; 千万注意别搞错了。 EntityFactory.SetWeaponAppearance_ID(info.weaponAppearanceId) EntityFactory.SetDyeAppearanceList(info.dyeCurPartList) local entity = EntityFactory.DoCreateSyncMoveEntity() if info.appearanceId > 0 then NotSyncBattleSetter.ChangeAppearanceId(entity,info.appearanceId) end if info.riding and ((info.horseId and info.horseId > 0) or info.horseAppearanceId > 0) then NotSyncBattleSetter.RideHorse(entity) end SyncMoveManager.TownRoleList[info.accid].entityID = entity.EntityID if not string.isNilOrEmpty(info.followUid) then -- 有时间的话改为抽象的单独模块管理 TownCartManager.SetFollowInfo(info.accid, info.followUid, entity) end if BattleDataGetter.CheckCurLevelType(LuaConst.LevelType.DragonArteryRegistArea) then local name = UIUtils.GetLocalizedTxt(Const_IDS["IDS_DragonArtey_PlayerName"]) NotSyncBattleSetter.RefreshEntityUIName(entity, name) end SyncMoveManager.AddBasicBuffToEntity(entity, info.basicBuff, SyncMoveManager.TownRoleList[info.accid]) end EventSystem.Dispatch(EventID.Country_RefreshBattleList) end function SyncMoveManager.AddBasicBuffToEntity(entity, basicBuffList, roleInfo) -- basicBuffList 一定是全量 ,只要有一个变化就发全量 -- basicBuffList:增:全量 ; 删:[全部删除-1; 不全删除:剩余buff全量] ;改:全量 。 不变:#basicBuffList=0 if basicBuffList and #basicBuffList > 0 then --删除老buff if roleInfo.basicBuffList then for i,oldBasicBuffID in ipairs(roleInfo.basicBuffList) do if oldBasicBuffID > 0 then NotSyncBattleSetter.DeleteBuffOfEntity(entity, oldBasicBuffID) end end end -- 每次变化都尝试删除下随从 NotSyncBattleSetter.TryClearRetinue(entity) --添加新buff if basicBuffList[1] ~= -1 then for i,basicBuffID in ipairs(basicBuffList) do if basicBuffID > 0 then --服务器有时候会发0过来,客户端这边加个过滤省得报错 NotSyncBattleSetter.AddBuffToEntity(entity, basicBuffID) end end end roleInfo.basicBuffList = basicBuffList end end function private.AddOneObjectScreen(objectSceneBasic) local entity = nil if objectSceneBasic.objectType == common_pb.DigDoor then --盗洞 private.AddDigDoorByInfo(objectSceneBasic) else -- 非盗洞的统一管理 if objectSceneBasic.objectType == common_pb.Cart then entity = TownCartManager.CreateCartEntity(objectSceneBasic) else entity = private.CreateNormalNPC(objectSceneBasic) end if entity then entity.components.record:VariableSet("townUniqId" ,objectSceneBasic.uniqId) -- entity 记录自己的唯一id,一般用于告知服务器 end SyncMoveManager.TownObjectDic[objectSceneBasic.uniqId] = {info = objectSceneBasic, entity = entity} end --创建entity完毕后,处理额外的信息 if objectSceneBasic.objectType == common_pb.Cart then --统计创建的镖车 if objectSceneBasic.cartInfo.speed ~= 0 then private.OnS2CObjectMoveResp({uniqId = objectSceneBasic.uniqId, speed = objectSceneBasic.cartInfo.speed, destPos = objectSceneBasic.cartInfo.destPos}) end TownCartManager.AddNewCartInfo(objectSceneBasic,entity) if objectSceneBasic.ownerAcid == CTL.Team.GetTeamLeaderId() or objectSceneBasic.ownerAcid == BattleDataGetter.GetAcID() then EventSystem.Dispatch(EventID.GuildEscort_MyCartBorn, objectSceneBasic.uniqId) end elseif objectSceneBasic.objectType == common_pb.Collection then entity.components.record:VariableSet("collectServerDataId" ,objectSceneBasic.collInfo.collectServerDataId) -- entity 记录自己的归属于哪条collectServerDataId if CTL.CountryWantedTask.HasWantedTask(objectSceneBasic.collInfo.collectServerDataId) then --SystemManager.ShowPSEffect(entity, "Battle/Buff/Buff_ZhangFei_kuangbao", true)-- todo:等待正式添加特效 entity.ExpEntity:PlayEffectByType(LuaConst.EffectType.HeroSighEnemy) -- todo:等待正式添加特效 end elseif objectSceneBasic.objectType == common_pb.Pet then entity.components.record:VariableSet("petIsInCapturing" ,objectSceneBasic.scenePetInfo.petIsInCapturing) -- entity 记录自己是否被捕捉中 if objectSceneBasic.scenePetInfo.petIsInCapturing then --entity.ExpEntity:PlayEffectByType(LuaConst.EffectType.PetCapturing, 0, 3, 0) else SystemManager.SetAIByID(entity , LuaConst.TownPetNPC) end end end function private.OnTaskFinish() for uid, object in pairs(SyncMoveManager.TownObjectDic) do local objectSceneBasic = object.info if objectSceneBasic.objectType == common_pb.Collection then if not CTL.CountryWantedTask.HasWantedTask(objectSceneBasic.collInfo.collectServerDataId) then --SystemManager.StopPSEffect(entity, "Battle/Buff/Buff_ZhangFei_kuangbao", true)-- todo:等待正式添加特效 object.entity.ExpEntity:StopEffectByType(LuaConst.EffectType.HeroSighEnemy) -- todo:等待正式添加特效 end end end end -- 添加雕像通过协议结构体common.RoleSceneBasic(不进入到SyncMoveManager.TownRoleList列表) function SyncMoveManager.AddStatueByRoleSceneBasic(info, pos, dir, titleID, scale) if LevelManager.IsSyncLevel() then return nil end if info then local posV2 = pos:cloneV2() local dirV2 = dir:cloneV2() EntityFactory.SetParams("Name", info.Name) EntityFactory.SetType_ID(LuaConst.CharacterType.Hero, info.HeroId) EntityFactory.SetPos_Dir(posV2, dirV2) EntityFactory.SetEffectBreak_Weapon(info.heroBreakNums, info.isActiveMagicWeapon,info.weaponBreak) EntityFactory.SetTitle_ID(titleID) EntityFactory.SetAcid(info.accid) EntityFactory.SetHeroAppearance_ID(info.heroAppearanceId) -- 设置时装 ,这个 appearanceId 和 heroAppearanceId 是有区别的:临时变装、时装; 千万注意别搞错了。 EntityFactory.SetWeaponAppearance_ID(info.weaponAppearanceId) EntityFactory.SetParams("ForceVisualPriority", 50001)--视觉设置为比玩家高 EntityFactory.SetParams("IsStatue", true)--设置为雕像 EntityFactory.SetParams("ExpModelScaleRate", scale or Const_StatueSize)--设置为雕像大小系数 local entity = EntityFactory.DoCreateEntity() --去(停)掉动作,设置替换优先级 NotSyncBattleSetter.AddTimeScale(entity,"statue",0,-1,LuaConst.TimeScaleBreakType.NeverBreak,LuaConst.ETimeScaleChannel.SKILL_ANIM_SOUND_ENTITY_POS_ROT) return entity.EntityID, entity end end --离开视野 function private.S2CRemoveRoleScreenResp(msgResp) if msgResp.isLeaveScene then BIManager.RecordNoBattleLevelPlayerCount(LogicUpdateManager.GetPlayerCount()) end for _, info in ipairs(msgResp.roleList) do if _tempUnAddSceneEntityList[info] then _tempUnAddSceneEntityList[info] = nil else local infoData = SyncMoveManager.TownRoleList[info] if infoData ~= nil then local entityId = infoData.entityID if entityId then CTL.PlayerInteract.OnPlayerRemove(entityId) local entity = LogicUpdateManager._entityDic[entityId] if entity then SystemManager.DeadQuit(entity) end SyncMoveManager.TownRoleList[info] = nil TownCartManager.RemoveFollowInfo(info) end end end end -- 删除其他物体,先判断是否在临时存储队列中,还没加到场景 local isExistOnScene = true if _tempUnAddSceneObjectList then for _, str in ipairs(msgResp.objectList) do for i, object in ipairs(_tempUnAddSceneObjectList) do if object.uniqId == str then table.remove(_tempUnAddSceneObjectList,i) _tempUnAddSceneObjectTargetPos[str] = nil isExistOnScene = false break end end end end if isExistOnScene then for _,str in ipairs(msgResp.objectList) do SyncMoveManager.RemoveObjectFromScreen(str) _objectTargetPosDic[str] = nil end private.TryRemoveDigDoorScreen(msgResp.objectList) end EventSystem.Dispatch(EventID.Country_RefreshBattleList) end --广播移动停止 function private.S2CRolesActResp(msgResp) for i = 1, #msgResp.RoleId do local roleId = msgResp.RoleId[i] local pos = msgResp.Pos[i] local dir = msgResp.Dir[i] local state = msgResp.ActType[i] if TownCartManager.AcidIsFollowingNPC(roleId) then -- 在我视野中如果此人已跟着NPC了,则不要额外移动了 return end if roleId == CTL.Team.GetTeamLeaderId() then MDL.Team.RawsetTeamLeaderPos(pos.X, pos.Z) end if _tempUnAddSceneEntityList[roleId] then -- 优化S2CAddRoleScreenResp相关包装数据结构 --还没加载时移动了 _tempUnAddSceneEntityList[roleId].SceneInfo.Pos.X = pos.X _tempUnAddSceneEntityList[roleId].SceneInfo.Pos.Z = pos.Z _tempUnAddSceneEntityList[roleId].SceneInfo.Dir.X = dir.X _tempUnAddSceneEntityList[roleId].SceneInfo.Dir.Z = dir.Z else local roleData = SyncMoveManager.TownRoleList[roleId] if roleData ~= nil then local EntityId = roleData.entityID if EntityId then local Entity = LogicUpdateManager._entityDic[EntityId] if Entity then if _entityTargetPosDir[Entity] then _entityTargetPosDir[Entity][1] = pos _entityTargetPosDir[Entity][2] = dir _entityTargetPosDir[Entity][3] = tonumberV1(Entity.components.attr:GetAttrValue(LuaConst_AttrType_spd)) else _entityTargetPosDir[Entity] = { [1] = pos, [2] = dir, [3] = tonumberV1(Entity.components.attr:GetAttrValue(LuaConst_AttrType_spd)) } end end end end end end end local TRAIN_FOLLOW_GAP = 1 local TRAIN_HORSE_FOLLOW_GAP = 3 function SyncMoveManager.HandleEntityMove() if not SyncMoveManager.IsEntityMoveEnable then return end local followIndex local followTargetPos local followTargetEntity for k,entity in pairs(LogicUpdateManager._entityDic) do if entity:IsHero() and (not entity._logicInitData.isStatue) then followTargetPos = nil entity.components.move:SetMoveStateHandledFlag(false) --先重置flag followIndex = MDL.Team.GetFollowIndexOfEntity(entity) local onHorse = entity:CheckHasBuffState(LuaConst.SpecialBuffs.InRiding) if followIndex and followIndex > 0 then followTargetPos, followTargetEntity = MDL.Team.GetTrainFollowTargetPos(followIndex, MDL.Team.GetFollowTeamLeaderId(SyncMoveManager.GetAcIdOfEntity(entity))) end if followTargetPos then --处于组队跟随开火车阶段的单位,由本客户端根据队长的位置计算出这些人应该处于的位置,在后面的代码里 --这种做法可以解决网络延迟带来的开火车时间隔不整齐的问题 --跟随的那个人的位置(不是跟随的目标点位置) local dir = followTargetPos - entity:GetLogicPos() local distance = tonumberV1(dir:Magnitude()) if distance > TRAIN_FOLLOW_TOO_FAR_DIST then -- 火车阶段如果距离太远,需要直接传送到leader身上的位置,否则会穿墙 entity.components.move:SetLogicPos(followTargetPos) else dir:Normalize() local targetDirX, targetDirZ = tonumberV2(dir) local gap = (onHorse or (followTargetEntity and followTargetEntity:CheckHasBuffState(LuaConst.SpecialBuffs.InRiding))) and TRAIN_HORSE_FOLLOW_GAP or TRAIN_FOLLOW_GAP local followPos = dir:Mul(-gap):Add(followTargetPos)--(跟随的目标点位置,在跟随的那个人的后面一点,距离那个人gap米) local targetPosX, targetPosZ = tonumberV2(followPos) local standardSpd = nil local teamLeaderEntity = MDL.Team.GetTeamLeaderEntityByAcID(SyncMoveManager.GetAcIdOfEntity(entity)) if teamLeaderEntity then if teamLeaderEntity:CheckHasBuffState(LuaConst.SpecialBuffs.InRiding) then standardSpd = teamLeaderEntity:GetAttrValueNum(LuaConst.AttrType.ridespd) if entity:IsPlayerSelf() then if not entity:CheckHasBuffState(LuaConst.SpecialBuffs.InRiding) then if MDL.WarHorse.GetIsActiveHorse() then NotSyncBattleSetter.RideHorse(BattleDataGetter.GetCurEntity()) end end end if entity.components.pet then entity.components.pet.townFollowHorseSpd = standardSpd end else if entity:CheckHasBuffState(LuaConst.SpecialBuffs.InRiding) then NotSyncBattleSetter.OffHorse(entity) if entity.components.pet then entity.components.pet.townFollowHorseSpd = nil end end standardSpd = teamLeaderEntity:GetAttrValueNum(LuaConst.AttrType.spd) end else if entity:CheckHasBuffState(LuaConst.SpecialBuffs.InRiding) then standardSpd = entity:GetAttrValueNum(LuaConst.AttrType.ridespd) else standardSpd = entity:GetAttrValueNum(LuaConst.AttrType.spd) end end local speed = math.max((distance / gap - 1) * 0.5 + 1, 1) * standardSpd --根据距离在一定范围内自适应速度,让跟随者能够快速跟上目标 --local speed = math.min(distance / gap, 1) * standardSpd --根据距离在一定范围内自适应速度,让运动更平滑 --local speed = math.max(math.min(distance / gap, 1.5), 0.5) * standardSpd --根据距离在一定范围内自适应速度,让运动更平滑 private.MoveTowards(entity, targetPosX, targetPosZ, targetDirX, targetDirZ, speed, onHorse, teamLeaderEntity) end else local vo = _entityTargetPosDir[entity] if vo then --不处于组队跟随开火车阶段的单位,才根据发来的位置进行位置 --服务器这里下发的坐标和方向,都是乘以定点数倍数以后的值 local targetPosX, targetPosZ = vo[1].X / 1000, vo[1].Z / 1000 local targetDirX, targetDirZ = vo[2].X / 1000, vo[2].Z / 1000 local speed = vo[3] if onHorse then speed = entity:GetAttrValueNum(LuaConst.AttrType.ridespd) local acc = entity:GetAttrValueNum(LuaConst.AttrType.ridespdacc) local moveInfo = private.GetMoveInfo(entity) moveInfo.horseMoveTime = moveInfo.horseMoveTime + LuaConst.TimeSpan speed = math.min( speed/acc * moveInfo.horseMoveTime,speed) end private.MoveTowards(entity, targetPosX, targetPosZ, targetDirX, targetDirZ, speed, onHorse) end end if entity ~= LogicUpdateManager._curEntity and entity.components.pet then PetSystem.OnLogicUpdate(entity) end end end for uid,info in pairs(_objectTargetPosDic) do private.ObjectMove(uid, info.entity, info.endPosX, info.endPosZ, info.speedFrame, info.moveDirX, info.moveDirZ) end TownCartManager.OnLogicUpdate() end function SyncMoveManager.ClearEntityMoveTargetPos(entity) _entityTargetPosDir[entity] = nil end local BIG_ANGLE_ROTATE_INTERVAL = 2 --大角度旋转的间隔帧数 function private.CanRotate(moveInfo, dirDot) --return dirDot > FPConst_Zero or not moveInfo.lastDirDot or moveInfo.lastDirDot <= FPConst_Zero return dirDot > FPConst_Zero or not moveInfo.lastDirDot or moveInfo.lastDirDotCount > BIG_ANGLE_ROTATE_INTERVAL --角度特别大时,隔几帧才旋转一次,否则会疯乱转向 end function private.TryRotate(moveComponent, moveInfo, dirDot, dirX, dirZ) if dirX ~=0 or dirZ ~= 0 then if private.CanRotate(moveInfo, dirDot) then --角度特别大时,隔几帧才旋转一次,否则会疯乱转向 moveComponent:SetLogicRotateDirXZ(dirX, dirZ) moveInfo.lastDirDotCount = 0 else moveInfo.lastDirDotCount = moveInfo.lastDirDotCount or 0 moveInfo.lastDirDotCount = moveInfo.lastDirDotCount + 1 end end end function private.GetMoveInfo(entity) local moveInfo = moveInfoDic[entity.EntityID] if moveInfo == nil then moveInfo = {} moveInfo.idleFrameCount = 0 moveInfo.lastDirDotCount = 0 moveInfo.horseMoveTime = 0 moveInfoDic[entity.EntityID] = moveInfo end return moveInfo end function private.MoveTowards(entity, targetPosX, targetPosZ, targetDirX, targetDirZ, speed ,onHorse, teamLeaderEntity, isInTeam) local moveComponent = entity.components.move moveComponent:SetMoveStateHandledFlag(true)--标记这个单位的move在非cmd的代码中被处理过 local aiBaseComponent = entity.components.aiBase local logicPosX,logicPosZ = tonumberV2(moveComponent.LogicPos) local offsetX = targetPosX - logicPosX local offsetZ = targetPosZ - logicPosZ local distanceSqr = offsetX * offsetX + offsetZ * offsetZ if distanceSqr > 0 then if aiBaseComponent.CurStateType ~= LuaConst.StateType.Move then SystemManager.SetNextState(LuaConst.StateType.Move, entity, 0) end end local minDis =MIN_DISTANCE if onHorse then minDis = MIN_DISTANCE_HORSE end local offsetDir = FP.newV2(offsetX, offsetZ) offsetDir:Normalize() local dirDot = FP.V2.Dot(moveComponent.LogicRotateDir, offsetDir) local moveInfo = private.GetMoveInfo(entity) if distanceSqr > 0 then moveInfo.idleFrameCount = 0 end if distanceSqr > minDis and distanceSqr < TOO_FAR_DIST_SQR then --没到目标位置时,朝目标点方向行走 local normalizedX = offsetX / math_sqrt(distanceSqr) local normalizedZ = offsetZ / math_sqrt(distanceSqr) local offsetDisX = normalizedX * speed * LuaConst.TimeSpan local offsetDisZ = normalizedZ * speed * LuaConst.TimeSpan private.TryRotate(moveComponent, moveInfo, dirDot, normalizedX, normalizedZ) if offsetDisX * offsetDisX + offsetDisZ * offsetDisZ > distanceSqr then moveComponent.LastLogicPos:Reset(moveComponent.LogicPos) moveComponent:SetLogicPosXZ(targetPosX, targetPosZ) else moveComponent.LastLogicPos:Reset(moveComponent.LogicPos) moveComponent:SetLogicPosXZ(logicPosX + offsetDisX, logicPosZ + offsetDisZ) end if onHorse then ExpSystemManager.TryUpdateHorseAnim(entity, FPConst_One, FPConst_Zero) end else private.TryRotate(moveComponent, moveInfo, dirDot, targetDirX, targetDirZ) moveComponent.LastLogicPos:Reset(moveComponent.LogicPos) moveComponent:SetLogicPosXZ(targetPosX, targetPosZ) _entityTargetPosDir[entity] = nil if onHorse then if teamLeaderEntity then if distanceSqr == 0 then moveInfo.idleFrameCount = moveInfo.idleFrameCount + 1 local rate = FPConst_One / HORSE_TO_IDLE_NEED_FRAME * moveInfo.idleFrameCount ExpSystemManager.TryUpdateHorseAnim(entity, rate, rate) else moveInfo.idleFrameCount = 0 ExpSystemManager.TryUpdateHorseAnim(entity, FPConst_One, FPConst_Zero) end --骑马跟随情况下,隔HORSE_TO_IDLE_NEED_FRAME帧才让马动画停止 if moveInfo.idleFrameCount > HORSE_TO_IDLE_NEED_FRAME then if entity.components.aiBase.CurStateType ~= LuaConst.StateType.Idle then SystemManager.SetNextState(LuaConst.StateType.Idle, entity, 0) end ExpSystemManager.TryUpdateHorseAnim(entity, FPConst_Zero, FPConst_Zero, FP.Const.Vector2_Zero) end else SystemManager.SetNextState(LuaConst.StateType.Idle, entity, 0) ExpSystemManager.TryUpdateHorseAnim(entity, FPConst_Zero, FPConst_Zero, FP.Const.Vector2_Zero) end moveInfo.horseMoveTime = 0 else --组队中 if not teamLeaderEntity or moveInfo.idleFrameCount >= IDLE_NEED_FRAME then if entity.components.aiBase.CurStateType ~= LuaConst.StateType.Idle then SystemManager.SetNextState(LuaConst.StateType.Idle, entity, 0) end end if distanceSqr == 0 then moveInfo.idleFrameCount = moveInfo.idleFrameCount + 1 end end end moveInfo.lastDirDot = dirDot if entity:IsPlayerSelf() and entity ~= teamLeaderEntity and distanceSqr ~= 0 then SyncMoveManager.ForceC2SRoleMove(true) end return distanceSqr > 0 end function private.OnG2CBattlePlayerAddBuff(msg) NotSyncBattleSetter.RequestAddSeverPlayerBuff(msg.playerBuff) end function private.S2CFubenEnemyInfoResp(msgResp) LevelPlayerManager.BeforeStorePlayerInfo() private.SkipClearPlayersArmy = true -- 一定注意: 以下代码有任何变化一定要 检查BattleSimulator中的private.HandleRoleEnterSceneAndFrame 设置敌人信息的代码 local playerInfo = { name = msgResp.name, setting = { [1] = false }, officialPosition = msgResp.officialTitle } private.SyncRoleGuildInfo(playerInfo, msgResp.guildShow.emblemContent, msgResp.guildShow.emblemFrame, msgResp.guildShow.guildId, msgResp.guildShow.guildName, msgResp.guildShow.jobTitle, msgResp.guildShow.identity, msgResp.serId, msgResp.portraitId, msgResp.frameId) local robotEnemyRecommendGS = msgResp.isRobot and msgResp.recommendGS1 or nil NotSyncBattleSetter.SetPlayerArmyTable(LuaConst.STANDALONE_ENEMYPLAYER1_PLAYID, msgResp.enemyHeroLineUpInfos, playerInfo, false, msgResp.stratagemDevelopEffects, robotEnemyRecommendGS) end --自己进入场景,主城、单机类关卡走这 function private.S2CRoleEnterSceneResp(msgResp) if LevelManager.IsReplayBattle() then -- 保底代码 ,防止玩家在回放时,服务器有什么问题直接下发切场景 CTL.Replay.EndPlay(true) logging.error(LTAG.ERROR, "[切场景错误]: 目前还在看回放呢,怎么就直接退出了呢? 做下保底保护") end if LevelManager.IsSyncLevel() and not LevelManager.CurLevelFunc:GetHadStopLevel() then logging.error(LTAG.ERROR, "[切场景错误] :目前是同步玩法中,且同步玩法还没停StopLevel ,怎可能去其他场景呢 !找服务器询问", msgResp.mapCfgId, LevelManager.GetCurLevelID()) end --封装到一个文件中的目的 :这个涉及到了单机校验,所以需要特别注意,每次修改都要检查BattleSimulator脚本。为了防随意修改,对这个函数加上githook限制。 SyncMoveManagerExt.S2CRoleEnterSceneResp(msgResp,private) end function private.S2CRoleChangeInfoResp(msgResp) private._S2CRoleChangeInfoResp(msgResp) end function private._S2CRoleChangeInfoResp(msgResp) logging.log(LTAG.LOG, "S2CRoleChangeInfoResp" , msgResp.roleShowInfo) local roleAcid = msgResp.acid local roleShowInfo = msgResp.roleShowInfo local info = SyncMoveManager.TownRoleList[roleAcid] if info then if roleShowInfo.level > 0 then info.roleInfo.level = roleShowInfo.level end if roleShowInfo.HeroId > 0 then info.roleInfo.HeroId = roleShowInfo.HeroId end if not string.isNilOrEmpty(roleShowInfo.Name) then info.roleInfo.name = roleShowInfo.Name end if roleShowInfo.sex > 0 then info.roleInfo.sex = roleShowInfo.sex end if roleShowInfo.gs > 0 then info.roleInfo.gs = roleShowInfo.gs end --组队ID有离队改成空的情况,不能判空 info.roleInfo.teamId = roleShowInfo.teamId end local Entity = private.GetEntityByAcId(roleAcid) if Entity then local roleVo = SyncMoveManager.TownRoleList[roleAcid] local needChangeName --更换主城中的时装 if roleShowInfo.updateHeroAppearanceId then Entity._logicInitData.HeroAppearanceID = roleShowInfo.heroAppearanceId if roleShowInfo.heroAppearanceId == 0 then NotSyncBattleSetter.ReplaceModelSkin(Entity,0) else local heroAppearanceData = DataSheetManager.HeroAppearance:GetDataByID(roleShowInfo.heroAppearanceId) if heroAppearanceData then local replaceModelID = heroAppearanceData.BattleModel NotSyncBattleSetter.ReplaceModelSkin(Entity,replaceModelID) else logging.error(LTAG.ERROR , "【策划注意】时装发现没有配置数据,时装id = " ,roleShowInfo.heroAppearanceId) end end end if IsServerDataNotNil(roleShowInfo.basicExtraHero) then --这个要在 if IsServerDataNotNil(roleShowInfo.basicBuff) then 之前 if Entity:IsPlayerSelf() then LevelPlayerManager.PlayersArmyTable[LuaConst.STANDALONE_PLAYER_PlayID].townExtraHeroInfo = roleShowInfo.basicExtraHero.heroInfo else if roleVo then roleVo.roleInfo.basicExtraHero = roleShowInfo.basicExtraHero.heroInfo end end end if IsServerDataNotNil(roleShowInfo.basicBuff) then if Entity:IsPlayerSelf() then SyncMoveManager.AddBasicBuffToEntity(Entity, roleShowInfo.basicBuff, LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(LuaConst.STANDALONE_PLAYER_PlayID)) else if roleVo then SyncMoveManager.AddBasicBuffToEntity(Entity, roleShowInfo.basicBuff, roleVo) end end end -- 更换头像 if roleVo and roleShowInfo.needUpdatePortrait then roleVo.roleInfo.portraitId = roleShowInfo.portraitID end -- 更换头像框 if roleVo and roleShowInfo.needUpdateFrame then roleVo.roleInfo.frameId = roleShowInfo.frameID end --切换模型ID if roleShowInfo.needUpdateAppearanceId then NotSyncBattleSetter.ChangeAppearanceId(Entity,roleShowInfo.AppearanceId) end --切换角色 if roleShowInfo.HeroId > 0 then NotSyncBattleSetter.TownChangeHero(Entity,roleShowInfo) if roleShowInfo.needUpdatePetInfo then NotSyncBattleSetter.ChangePetInfo(Entity,roleShowInfo.petInfo) end return end --更换神兵外显(神兵默认的时装id=heroID,其他时装id = heroID + xxxx) if roleShowInfo.weaponAppearanceId > 0 then NotSyncBattleSetter.ChangeMagicWeaponID(Entity, roleShowInfo.weaponAppearanceId) return end --武将突破 if roleShowInfo.heroBreakNums > 0 then NotSyncBattleSetter.ChangeHeroBreakNum(Entity,roleShowInfo.heroBreakNums) end --神兵激活、升级变换(神兵的特效相关) if roleShowInfo.weaponBreak > 0 or roleShowInfo.isActiveMagicWeapon then NotSyncBattleSetter.ChangeMagicWeaponBreak(Entity, roleShowInfo.weaponBreak, roleShowInfo.isActiveMagicWeapon) end --换马 or 换马的皮肤 if roleShowInfo.horseId > 0 or roleShowInfo.horseAppearanceId ~= 0 then if roleAcid == BattleDataGetter.GetAcID() then MDL.WarHorse.SetCurShowId(msgResp.roleShowInfo.horseId) MDL.WarHorse.SetCurAppearanceShowID(msgResp.roleShowInfo.horseAppearanceId) end NotSyncBattleSetter.ChangeHorse(Entity,roleShowInfo.horseId, roleShowInfo.horseAppearanceId) end --更改名字 local name = roleShowInfo.Name if name and string.isNilOrEmpty(name) == false then NotSyncBattleSetter.ChangeEntityName(Entity, name) needChangeName = true end --更改官职 if roleShowInfo.officialTitle > 0 then if roleVo then roleVo.roleInfo.officialTitle = roleShowInfo.officialTitle else local townPlayerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(Entity:GetPlayerID()) townPlayerInfo.officialPosition = roleShowInfo.officialTitle end needChangeName = true end --更改国家 if roleShowInfo.needUpdateCountryId then needChangeName = BattleDataGetter.IsShowHeadUI_Country() if roleVo then roleVo.roleInfo.countryId = roleShowInfo.countryId else local townPlayerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(Entity:GetPlayerID()) townPlayerInfo.countryId = roleShowInfo.countryId end end if roleShowInfo.needUpdateCountryJobId then needChangeName = BattleDataGetter.IsShowHeadUI_Country() if roleVo then roleVo.roleInfo.countryJobId = roleShowInfo.countryJobId else local townPlayerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(Entity:GetPlayerID()) townPlayerInfo.countryJobId = roleShowInfo.countryJobId end end --势力信息 if roleShowInfo.needUpdateGuildShow then local guildInfo = not string.isNilOrEmpty(roleShowInfo.guildShow.guildId) and roleShowInfo.guildShow or nil local lastGuildID = "" local nowGuildID = guildInfo and guildInfo.guildId or "" if roleAcid == BattleDataGetter.GetAcID() then --更改主城内主角自己的头顶势力信息 local townPlayerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(Entity:GetPlayerID()) lastGuildID = townPlayerInfo.guildID if guildInfo then private.SyncRoleGuildInfo(townPlayerInfo, guildInfo.emblemContent, guildInfo.emblemFrame, guildInfo.guildId, guildInfo.guildName, guildInfo.jobTitle, guildInfo.identity) else private.SyncRoleGuildInfo(townPlayerInfo) end else local info = SyncMoveManager.TownRoleList[roleAcid] if info then lastGuildID = info.roleInfo.guildID if guildInfo then private.SyncRoleGuildInfo(info.roleInfo, guildInfo.emblemContent, guildInfo.emblemFrame, guildInfo.guildId, guildInfo.guildName, guildInfo.jobTitle, guildInfo.identity) else private.SyncRoleGuildInfo(info.roleInfo) end end end NotSyncBattleSetter.RefreshEntityHeadGuildShow(Entity) private.UpdateEntityNameColorByGuildID(Entity, lastGuildID, nowGuildID) end -- 战团信息(只有在天地3v3的等待区才有用) if roleShowInfo.needUpdateTeamWarName then if roleAcid == BattleDataGetter.GetAcID() then local townPlayerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(Entity:GetPlayerID()) townPlayerInfo.teamWarName = roleShowInfo.teamWarName elseif info then info.roleInfo.teamWarName = roleShowInfo.teamWarName end NotSyncBattleSetter.RefreshEntityHeadGuildShow(Entity) end --上下马 if Entity ~= LogicUpdateManager._curEntity then if roleShowInfo.riding == 1 then NotSyncBattleSetter.RideHorse(Entity) elseif roleShowInfo.riding == 2 then NotSyncBattleSetter.OffHorse(Entity) end end --更改称号(如果有镖车 则优先显示镖车) if roleShowInfo.needUpdateCartQuality then NotSyncBattleSetter.ChangeEntityGuildEscort(Entity, roleShowInfo.cartQuality) end -- 需要在镖车头顶版下方 if roleShowInfo.needUpdateTitle then NotSyncBattleSetter.ChangeEntityTitle(Entity, roleShowInfo.titleID) end if roleShowInfo.pickUpBox == 1 then NotSyncBattleSetter.SetNextState(LuaConst.StateType.Interact, Entity, -1, "collect_loop") elseif roleShowInfo.pickUpBox == 2 then NotSyncBattleSetter.SetNextState(LuaConst.StateType.Idle, Entity) end if needChangeName then NotSyncBattleSetter.RefreshEntityUIName(Entity, Entity.ExpEntity:GetPlayerModelName()) --国家的UI设置要在名字后边,需要依赖名字的长度计算UI位置 if BattleDataGetter.IsShowHeadUI_Country() then --如果在显示国家的场景里,国家数据更换需要同时更新名字,因为国家职位在名字的label中 if roleVo then ExpSystemManager.ChangeEntityCountry(Entity, roleVo.roleInfo.countryId, roleVo.roleInfo.countryJobId) else local townPlayerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(Entity:GetPlayerID()) ExpSystemManager.ChangeEntityCountry(Entity, townPlayerInfo.countryId, townPlayerInfo.countryJobId) end end end --更新光效 if #roleShowInfo.lightEffectIds > 0 then NotSyncBattleSetter.ChangeHeroLightEffect(Entity,roleShowInfo.lightEffectIds) end -- 更换宠物 if roleShowInfo.needUpdatePetInfo then NotSyncBattleSetter.ChangePetInfo(Entity,roleShowInfo.petInfo) end --神兵铸魂天命 if IsProtoDataNotNil(roleShowInfo.weaponSoulInfo) then NotSyncBattleSetter.TownChangeWeaponSoulInfo(Entity, roleShowInfo.weaponSoulInfo) end -- 典藏幻色 if roleShowInfo.needUpdateDyeCurPart then NotSyncBattleSetter.ChangeDyeCurPart(Entity, roleShowInfo.dyeCurPartList) end else -- 无entity则改数据 if roleAcid == BattleDataGetter.GetAcID() then if roleShowInfo.needUpdateCartQuality then LevelPlayerManager.SetMyTownPlayerInfo("cartQuality", roleShowInfo.cartQuality) end end end --0代表无效值,忽略即可。 负数和正数都代表有效值,-1代表取消跟随 if roleShowInfo.snakeIndex ~= 0 then MDL.Team.SetFollowIndex(roleAcid, msgResp.roleShowInfo.snakeIndex, roleShowInfo.leaderId) --logging.error(LTAG.ERROR, "HYW : SnakeIndex : ", roleShowInfo.snakeIndex, "acid : ", roleAcid, " leaderId : ", roleShowInfo.leaderId) end EventSystem.Dispatch(EventID.Country_RefreshBattleList) end function private.SyncRoleGuildInfo(roleInfo, emblemContent, emblemFrame, guildId, guildName, jobTitle, identity, serId, portraitId, frameId) roleInfo.guildEmblemContent = emblemContent roleInfo.guildEmblemFrame = emblemFrame roleInfo.guildID = guildId roleInfo.guildName = guildName roleInfo.guildJob = jobTitle roleInfo.guildIdentity = identity roleInfo.serId = serId roleInfo.portraitId = portraitId roleInfo.frameId = frameId end --有entity势力变更,可能需要更新字色显示 function private.UpdateEntityNameColorByGuildID(entity, lastGuildID, nowGuildID) if lastGuildID == nowGuildID then return end if entity == BattleDataGetter.GetCurEntity() then --自己变化,需要刷新前后变化的有关系的entity的字色 for _, v in pairs(SyncMoveManager.TownRoleList) do local guildId = v.roleInfo.guildId if guildId == lastGuildID or guildId == nowGuildID then local others = LogicUpdateManager._entityDic[v.entityID] if others then NotSyncBattleSetter.RefreshEntityUIName(others, others.ExpEntity:GetPlayerModelName()) end end end else --别人变化,只需要判断跟"我"的关系 if MDL.Guild.IsSameGuild(lastGuildID) or MDL.Guild.IsSameGuild(nowGuildID) then NotSyncBattleSetter.RefreshEntityUIName(entity, entity.ExpEntity:GetPlayerModelName()) end end end --队员变化,需要修改与“我”的关系 function private.OnTeamMemberChanged(acid) local entity = private.GetEntityByAcId(acid) if entity then NotSyncBattleSetter.RefreshEntityUIName(entity, entity.ExpEntity:GetPlayerModelName()) end end --“我”离开或者加入了队伍 function private.OnTeamMyselfChange(acids) for i, acid in ipairs(acids) do local entity = private.GetEntityByAcId(acid) if entity then NotSyncBattleSetter.RefreshEntityUIName(entity, entity.ExpEntity:GetPlayerModelName()) end end end function private.GetEntityByAcId(acid) local result = nil if PlayerInfoManager.AcID == acid then result = LogicUpdateManager._curEntity else local roleData = SyncMoveManager.TownRoleList[acid] if roleData ~= nil then local EntityId = roleData.entityID if EntityId then result = LogicUpdateManager._entityDic[EntityId] end end end return result end function private.S2CSetPositionResp(msgResp) if LevelManager.CurUniqueSceneID == msgResp.SceneId and LogicUpdateManager._curEntity then SystemManager.PlayPsEffect(EFFECT_PATH) local px, pz = msgResp.Pos.X, msgResp.Pos.Z LogicUpdateManager._curEntity.components.move.LogicPos:Rawset(px, pz) LogicUpdateManager._curEntity.components.move.ServerPos:Rawset(px, pz) local rx, rz = msgResp.Dir.X, msgResp.Dir.Z if rx ~= 0 or rz ~= 0 then LogicUpdateManager._curEntity.components.move.LogicRotateDir:Rawset(rx, rz) end ExpSystemManager.DelayReactiveCamera(0.1) --这句是为了让相机追背 end end --处理分包未下完的情况,下完对应的分包资源,然后 function private.ProcessStageUnDownload() --如果在组队跟随状态下,取消跟随 local teamInfo = MDL.Team.GetSelfMemberInfo() if teamInfo and teamInfo.state == MDL.Team.MemberState.Following then MDL.Team.TeamFollowReq(false) end CTL.HotFix.ForceOpenStageDownload(private.OnStageDownloadFinish) end function private.OnStageDownloadFinish() --重新进游戏 MDL.Login.SendEnterWorld(false, 0) end --region 主城分线 function SyncMoveManager.ChangeSceneLineRequest(line, mapId) if SyncMoveManager.CanChangeLine == false then return end if mapId then local msg = scene_line_pb.ChangeSceneAndLineReq() msg.mapId = mapId msg.lineNum = line NetManager.SendMessage(MessageEnums.MessageChangeSceneAndLine,msg) else if SyncMoveManager.CurLine == line then return end SyncMoveManager.CanChangeLine = false local msg = scene_line_pb.ChangeSceneLineReq() msg.LineNum = line NetManager.SendMessage(MessageEnums.MessageChangeSceneLine,msg) end end function private.ChangeSceneLineResp(msgResp) if msgResp.Resp.Code == 0 then local errorCode = msgResp.Code --0成功 1人满 2分线不存在 --if errorCode == 0 then -- private.OnSwitchBranch() --else if errorCode == 1 then EventSystem.Dispatch(EventID.UI_AddTipsMsg,Const_IDS["IDS_MapLineFull"]) SyncMoveManager.CanChangeLine = true elseif errorCode == 2 then EventSystem.Dispatch(EventID.UI_AddTipsMsg,Const_IDS["IDS_MapLineNotExist"]) SyncMoveManager.CanChangeLine = true end end end function private.ChangeSceneAndLineResp(msgResp) if msgResp.Resp.Code == 0 then local errorCode = msgResp.code --0成功 1人满 2分线不存在 if errorCode == 1 then EventSystem.Dispatch(EventID.UI_AddTipsMsg,Const_IDS["IDS_MapLineFull"]) elseif errorCode == 2 then EventSystem.Dispatch(EventID.UI_AddTipsMsg,Const_IDS["IDS_MapLineNotExist"]) end end end function private.OnSwitchBranch() for id,entityData in pairs(SyncMoveManager.TownRoleList) do local entity = LogicUpdateManager._entityDic[entityData.entityID] if entity then SystemManager.DeadQuit(entity) end SyncMoveManager.TownRoleList[id] = nil end for uniqId,object in pairs(SyncMoveManager.TownObjectDic) do SyncMoveManager.RemoveObjectFromScreen(uniqId) end SyncMoveManager.TownObjectDic = {} -- 盗洞特殊,单独管理 for pos,doorList in pairs(SyncMoveManager.DigDoorDic) do for i,info in ipairs(doorList) do private.DeleteDigDoor(info) end end SyncMoveManager.DigDoorDic = {} end function SyncMoveManager.GetSceneLineRequest() local msg = scene_line_pb.GetSceneLineReq() NetManager.SendMessage(MessageEnums.MessageGetSceneLine,msg) end function SyncMoveManager.GetEntityIDByAcid(acid) if acid == BattleDataGetter.GetAcID() then --因为SyncMoveManager.TownRoleList不会存玩家自身的信息,所以这里得这样写才能返回自身的entityId return BattleDataGetter.GetCurEntityID() else local info = SyncMoveManager.TownRoleList[acid] if info then return info.entityID end end end function SyncMoveManager.GetEntityByAcid(acid) return private.GetEntityByAcId(acid) end function SyncMoveManager.GetNpcEntityByUniqId(uniqId) local object = SyncMoveManager.TownObjectDic[uniqId] if object then return object.entity end return nil end function SyncMoveManager.GetAcIdOfEntity(entity) if entity == LogicUpdateManager._curEntity then return BattleDataGetter.GetAcID() else return entity._logicInitData.Acid end end function private.GetSceneLineResp(msgResp) if msgResp.Resp.Code == 0 then EventSystem.Dispatch(EventID.UI_UpdateLineInfo,msgResp.SceLine) end end function private.OnBattleModelUIAdd() local entity = BattleDataGetter.GetCurEntity() if entity then SystemManager.TopEntityTitle(entity) end end --endregion function SyncMoveManager.SetEntityMoveEnable(isEnable) SyncMoveManager.IsEntityMoveEnable = isEnable end function SyncMoveManager.GetTownRoleInfo(entityID) for _,v in pairs(SyncMoveManager.TownRoleList) do if v.entityID == entityID then return v end end return nil end function SyncMoveManager.GetTownRoleInfoByAcid(acid) local info = SyncMoveManager.TownRoleList[acid] if info then return info.roleInfo end return nil end function SyncMoveManager.ExitLevel() _checkMoveTime = 0 hasSentStopRequest = false hasSentMoveRequest = false hasSendRoleTimes = 0 LuaUpdater.StopUpdate(private.OnLogicUpdate) table.clear(_tempUnAddSceneEntityList) table.clear(_tempUnAddSceneObjectList) table.clear(_tempUnAddSceneObjectTargetPos) table.clear(SyncMoveManager.TownRoleList) table.clear(SyncMoveManager.TownObjectDic) table.clear(_entityTargetPosDir) table.clear(_objectTargetPosDic) table.clear(SyncMoveManager.DigDoorDic) SyncMoveManager.CanChangeLine = true TownCartManager.Clear() end -- 移除通用的场景物件 function SyncMoveManager.RemoveObjectFromScreen(uniqId) local object = SyncMoveManager.TownObjectDic[uniqId] if object then if object.entity then SystemManager.DeadQuit(object.entity) object.entity = nil end SyncMoveManager.TownObjectDic[uniqId] = nil if object.info.objectType == common_pb.Cart then TownCartManager.AfterRemoveCartByInfo(object) end end end function private.CreateNormalNPC(objectSceneBasic) local posX,posZ = objectSceneBasic.SceneInfo.Pos.X,objectSceneBasic.SceneInfo.Pos.Z local npcID = objectSceneBasic.configId local positionV2 = FP.newV2(0,0):Rawset(posX,posZ) local forwardV2 = newV2(0,0):Rawset(objectSceneBasic.SceneInfo.Dir.X,objectSceneBasic.SceneInfo.Dir.Z) if forwardV2 == FP.Const.Vector2_Zero then forwardV2:Reset(0,1) end EntityFactory.SetPos_Dir(positionV2, forwardV2) EntityFactory.SetType_ID(LuaConst.CharacterType.NPC, npcID) local entity = EntityFactory.DoCreateEntity() if objectSceneBasic.state == common_pb.Dead then NotSyncBattleSetter.SetNpcEntityState(entity, objectSceneBasic.state) if objectSceneBasic.objectType == common_pb.Collection then if objectSceneBasic.collInfo.aliveCountDown > 0 then-- 显示复活时间 entity.ExpEntity:SetModelUIVisible(true) entity.ExpEntity:SetModelCDTimerVisible(true,objectSceneBasic.collInfo.aliveCountDown) -- 单位:秒 end end end return entity end function private.OnNpcStateInfoChange(msg) local entity = SyncMoveManager.GetNpcEntityByUniqId(msg.npcUniqId) if entity then if msg.isDead then -- 死亡 NotSyncBattleSetter.SetNpcEntityState(entity, common_pb.Dead) if msg.aliveCountDown > 0 then-- 显示复活时间 entity.ExpEntity:SetModelUIVisible(true) entity.ExpEntity:SetModelCDTimerVisible(true,msg.aliveCountDown) -- aliveCountDown 单位:秒 end else-- 复活 NotSyncBattleSetter.SetNpcEntityState(entity, common_pb.Alive) end end end function private.OnPetInfoChange(msg) local entity = SyncMoveManager.GetNpcEntityByUniqId(msg.npcUniqId) if entity then entity.components.record:VariableSet("petIsInCapturing" ,msg.petIsInCapturing) if msg.petIsInCapturing then SystemManager.SetAIByID(entity , LuaConst.IdleAIID) --entity.ExpEntity:PlayEffectByType(LuaConst.EffectType.PetCapturing, 0, 3, 0) else SystemManager.SetAIByID(entity , LuaConst.TownPetNPC) --entity.ExpEntity:StopEffectByType(LuaConst.EffectType.PetCapturing) end EventSystem.Dispatch(EventID.Pet_IsInCapturingChange, entity, msg.petIsInCapturing) end end -- 收到移动场景物件协议(不包含盗洞) function private.OnS2CObjectMoveResp(msg) local uniqId = msg.uniqId local objectInfo = SyncMoveManager.TownObjectDic[uniqId] if objectInfo == nil then if _tempUnAddSceneObjectList[uniqId] then _tempUnAddSceneObjectTargetPos[uniqId] = msg else logging.error(LTAG.ERROR, "[gws]:场景中没有找到要移动的物体,uniqId = ", uniqId) end return end private.ExcuteObjectMoveInfo(msg) end function private.ExcuteObjectMoveInfo(msg) local uniqId = msg.uniqId local objectInfo = SyncMoveManager.TownObjectDic[uniqId] local entity = objectInfo.entity local targetPosX,targetPosZ = msg.destPos.X / 1000, msg.destPos.Z / 1000 local speed = msg.speed local speedFrame = speed * LuaConst.TimeSpan -- 每逻辑帧的移动向量 local moveComponent = entity.components.move local logicPosX,logicPosZ = tonumberV2(moveComponent.LogicPos) local offsetX = targetPosX - logicPosX local offsetZ = targetPosZ - logicPosZ local isStop = false if msg.speed == 0 or math.abs(offsetX) < 0.1 and math.abs(offsetX) < 0.1 then isStop = true end if isStop then _objectTargetPosDic[uniqId] = nil SystemManager.SetNextState(LuaConst.StateType.Idle, entity) local object = SyncMoveManager.TownObjectDic[uniqId] if object and object.info.objectType == common_pb.Cart then TownCartManager.OnCartStopMove(uniqId) end --logging.error(LTAG.ERROR, "临时log : 运镖车 停! ") else local distance = math_sqrt(offsetX * offsetX + offsetZ * offsetZ) local moveDirX = offsetX / distance -- 在初始的时候定下行走方向 ,但是在float相加时,误差越来越大的话,那么可能到目标点会有偏差了,就需要每次都计算朝向了(实时制导和) local moveDirZ = offsetZ / distance moveComponent.LastLogicRotateDir:Reset(moveComponent.LogicRotateDir) moveComponent:SetLogicRotateDirXZ(moveDirX, moveDirZ) if not _objectTargetPosDic[uniqId] then _objectTargetPosDic[uniqId] = {entity = entity, endPosX = targetPosX, endPosZ = targetPosZ, speedFrame = speedFrame, moveDirX = moveDirX, moveDirZ = moveDirZ} else _objectTargetPosDic[uniqId].endPosX = targetPosX _objectTargetPosDic[uniqId].endPosZ = targetPosZ _objectTargetPosDic[uniqId].speedFrame = speedFrame _objectTargetPosDic[uniqId].moveDirX = moveDirX _objectTargetPosDic[uniqId].moveDirZ = moveDirZ end --logging.log(LTAG.LOG, "临时log : 运镖车 开始移动! pos=",targetPosX,targetPosZ, ",uid =", uniqId) local object = SyncMoveManager.TownObjectDic[uniqId] if object and object.info.objectType == common_pb.Cart then TownCartManager.OnCartTargetPosChange(uniqId, speed, targetPosX, targetPosZ, moveDirX, moveDirZ, isStop) end end end -- 获取一个物体的移动目标点 function SyncMoveManager.GetObjectMoveTargetPosAndSpeed(uniqId) if _objectTargetPosDic[uniqId] then return _objectTargetPosDic[uniqId].endPosX, _objectTargetPosDic[uniqId].endPosZ, _objectTargetPosDic[uniqId].speedFrame else local object = SyncMoveManager.TownObjectDic[uniqId] if object.entity then local x, z = tonumberV2(object.entity:GetLogicPos()) return x, z, 0 end return 0,0,0 end end -- 场景物体移动 function private.ObjectMove(uid, entity, targetPosX, targetPosZ, speedFrame, moveDirX, moveDirZ) local moveComponent = entity.components.move local aiBaseComponent = entity.components.aiBase local logicPosX,logicPosZ = tonumberV2(moveComponent.LogicPos) local offsetX = targetPosX - logicPosX local offsetZ = targetPosZ - logicPosZ local distanceSqr = offsetX * offsetX + offsetZ * offsetZ --local distance = math_sqrt(distanceSqr) --local moveDirX = offsetX / distance -- 实时制导 --local moveDirZ = offsetZ / distance if distanceSqr >= speedFrame * speedFrame then if aiBaseComponent.CurStateType ~= LuaConst.StateType.Move then SystemManager.SetNextState(LuaConst.StateType.Move, entity) entity.components.move:SetMoveStateHandledFlag(true) --先重置flag end moveComponent.LastLogicPos:Reset(moveComponent.LogicPos) moveComponent:SetLogicPosXZ(logicPosX + speedFrame * moveDirX, logicPosZ + speedFrame * moveDirZ) else --logging.log(LTAG.LOG, "临时log : 运镖车 停!pos=", targetPosX,targetPosZ ,", uid =", uid) --logging.log(LTAG.LOG, "临时log : 停的信息:距离 =",distanceSqr, "限制:", minDis* minDis) if aiBaseComponent.CurStateType ~= LuaConst.StateType.Idle then SystemManager.SetNextState(LuaConst.StateType.Idle, entity) end moveComponent.LastLogicPos:Reset(moveComponent.LogicPos) moveComponent:SetLogicPosXZ(targetPosX, targetPosZ) _objectTargetPosDic[uid] = nil end end ---挖宝传送门功能↓ SyncMoveManager.DigDoorDic = {} --key是posxposz, value = 此位置的digDoorList 。eg: [posx*1000 + posz]={ digDoorInfo , digDoorInfo } private.DigDoorMaxLimit = 5 -- 每个位置的盗门的最大数量 function private.AddDigDoorByInfo(objectSceneBasic) local doorId = objectSceneBasic.uniqId local posX,posZ = objectSceneBasic.SceneInfo.Pos.X,objectSceneBasic.SceneInfo.Pos.Z local acid,playerName = objectSceneBasic.ownerAcid,objectSceneBasic.ownerName local modelId = objectSceneBasic.configId local key = posX * 1000 + posZ local digDoorInfo = {doorId = doorId,acid = acid,playerName = playerName,modelId = modelId ,posX = posX, posZ = posZ} local digDoorList = SyncMoveManager.DigDoorDic[key] if digDoorList then for _,info in ipairs(digDoorList) do if info.doorId == doorId then logging.error(LTAG.ERROR ,"[服务器] :场景添加盗洞信息的时候,发现之前已经存在了。name = " ,playerName ,",uniqId =",doorId) return end end table.insert(digDoorList,digDoorInfo) else digDoorList = {digDoorInfo} SyncMoveManager.DigDoorDic[key] = digDoorList end -- 创建盗门 (条件:总数量不够5一定创建 ;当时我(队)的门时一定创建) local count = #digDoorList if count <= private.DigDoorMaxLimit then private.CreateDigDoor(digDoorInfo) elseif acid == CTL.Team.GetTeamLeaderId() then -- 我(队)的盗门要显示 。删除第1个门 。我和第一个门换下list中的顺序 private.DeleteDigDoor(digDoorList[1]) digDoorList[count] = digDoorList[1] digDoorList[1] = digDoorInfo private.CreateDigDoor(digDoorInfo) end end function private.TryRemoveDigDoorScreen(objectList) for _,doorId in pairs(objectList) do for key,list in pairs(SyncMoveManager.DigDoorDic) do local find = false local count = #list for i = count,1 , -1 do local info = list[i] if info.doorId == doorId then find = true table.remove(list,i) if info.entity then private.DeleteDigDoor(info) end break end end if find then break end end end for key,list in pairs(SyncMoveManager.DigDoorDic) do for i,info in ipairs(list) do if i <= private.DigDoorMaxLimit and info.entity == nil then private.CreateDigDoor(info) end end end end function private.CreateDigDoor(digDoorInfo) local positionV2 = newV2(0,0):Rawset(digDoorInfo.posX,digDoorInfo.posZ) local forwardV2 = FP.newV2(0,1) EntityFactory.SetPos_Dir(positionV2, forwardV2) EntityFactory.SetType_ID(LuaConst.CharacterType.NPC, digDoorInfo.modelId) local entity = EntityFactory.DoCreateEntity() digDoorInfo.entity = entity entity.components.record:VariableSet("digDoorID" ,digDoorInfo.doorId) local name = string.FormatByIdsKey("IDS_DigTreasure_TreasureCaveName",digDoorInfo.playerName) NotSyncBattleSetter.RefreshEntityUIName(entity, name) if digDoorInfo.acid ~= PlayerInfoManager.AcID then SystemManager.DisableInteract(entity) end end -- 销毁盗门 function private.DeleteDigDoor(digDoorInfo) local entity = digDoorInfo.entity if entity then SystemManager.DeadQuit(entity) digDoorInfo.entity = nil end end ---挖宝传送门功能↑ function SyncMoveManager.StopFollowNPC(entity, isNoTask) TownCartManager.StopFollowNPC(entity, isNoTask) end function SyncMoveManager.IsFollowingNPC(entity) return TownCartManager.IsFollowingNPC(entity) end -- 是否有需要跟随的npc (目前只有镖车) function SyncMoveManager.HaveNeedFollowNPC() return TownCartManager.MyCartUniqid ~= nil end -- 正在追寻NPC ,无论npc 或者 entity 是否存在 ,都要正确的判断 function SyncMoveManager.IsChasingAndFollowingNPC(acid) return TownCartManager.FollowDic[acid] ~= nil end -- 获取一个物体的entity 和 ObjectSceneBasic function SyncMoveManager.GetObjectEntityAndBasicInfo(uniqId) local object = SyncMoveManager.TownObjectDic[uniqId] if object and object.entity then return object.entity, object.info end return nil end return SyncMoveManager