using System.Collections.Generic; using Games.GlobeDefine; using Games.Scene; using GCGame.Table; using Module.Log; using UnityEngine; using UnityEngine.AI; namespace Games.LogicObj { public partial class Obj_MainPlayer { public static int fubenId { get { return GameManager.gameManager.PlayerDataPool.EnterSceneCache.EnterCopySceneID; } } // 队员距离队长超过这个距离就开始骑马 private const float _mountDistance = 15f; // 队员最大传送时间 private const float _maxMemberTeleportTime = 5f; // 组队跟随状态更新 private const float _updateFollowInterval = 0.2f; // 组队跟随位置差值 private const float _followDistance = 1.5f; // 模拟器在Obj存在时允许的偏差量 private const float _objSimulatorDiffer = 3f; // 模拟器最大偏移量 - 同实际角色偏差超过这个数值,就补正位置 private const float _maxSimulatorDiffer = 5f; // 预测队员移动距离的参数 private const float _updateFollowPredictTime = 0.3f; // 组队跳跃容忍误差 private const float _jumpSimulatorDiffer = 1f; // 队员进入自动战斗的距离 public const float memberEnterAutoCombatDistance = (GlobeVar.MAX_TEAM_MEMBER - 1) * _followDistance + 4f; // 队员离开自动战斗的距离 public const float memberLeaveAutoCombatDistance = memberEnterAutoCombatDistance + 15f; // 队长路径。注:队长保持这个路径更新,即使没有玩家处于组队跟随状态 private readonly List<Vector3> _leaderPosList = new List<Vector3>(GlobeVar.MAX_TEAM_MEMBER); // 上次切换跟随状态时间 private float _enterFollowTime; private float _nextUpdateFollowTime; // 结束组队跟随时,是否进入自动战斗 public bool debugTeamTeleport; public List<TeamMemberMoveSimulator> moveSimulatorList = new List<TeamMemberMoveSimulator>(); /// <summary> /// 检查主角是否处于组队跟随状态 /// </summary> public bool IsFollowTeam { get { return GameManager.gameManager.PlayerDataPool.IsFollowTeam; } } public int FollowState { get { return GameManager.gameManager.PlayerDataPool.TeamInfo.GetFollowState(); } } public int sceneAutoType { get { if (_sceneAutoType == null) _sceneAutoType = CommonUtility.FubenAutoType(); return _sceneAutoType.Value; } } private int? _sceneAutoType; //邀请某个玩家入队 public void ReqInviteTeam(ulong playerGuid) { //检查被邀请者GUID是否为空(由于可以创建单人队伍,所以发空guid说明是单人组队,可以认为合法) //if (GlobeVar.INVALID_GUID == playerGuid) //{ // return; //} //判断队伍是否已满 if (GameManager.gameManager.PlayerDataPool.IsHaveTeam()) if (GameManager.gameManager.PlayerDataPool.TeamInfo.IsFull()) SendNoticMsg(false, "#{1145}"); //非单人组队,增加提示“邀请已发送” //if (playerGuid != GlobeVar.INVALID_GUID) //{ // SendNoticMsg(false, "#{3170}"); //} //向服务器发送邀请某人加入队伍消息 var msg = (CG_REQ_TEAM_INVITE) PacketDistributed.CreatePacket(MessageID.PACKET_CG_REQ_TEAM_INVITE); msg.Guid = playerGuid; msg.SendPacket(); } //申请加入队伍 public void ReqJoinTeam(int teamId) { //if (teamID <= 0) //{ // GUIData.AddNotifyData(StrDictionary.GetClientDictionaryString("{#5141}")); // return; //} //有队伍则不得申请 if (GameManager.gameManager.PlayerDataPool.IsHaveTeam()) { if (teamId == GameManager.gameManager.PlayerDataPool.TeamInfo.TeamID) return; //SendNoticMsg(false, "#{2179}"); MessageBoxLogic.OpenOKCancelBox(StrDictionary.GetClientDictionaryString("#{4605}"), "", ReqJoinLeaveOldOK, ReqJoinLeaveOldCancel); return; } //GUIData.AddNotifyData(StrDictionary.GetClientDictionaryString("{#5142}")); //向服务器发送申请加入队伍消息 var msg = (CG_REQ_TEAM_JOIN) PacketDistributed.CreatePacket(MessageID.PACKET_CG_REQ_TEAM_JOIN); msg.Teamid = teamId; msg.SendPacket(); } public void ReqJoinLeaveOldOK() { var msg = (CG_REQ_TEAM_LEAVE) PacketDistributed.CreatePacket(MessageID.PACKET_CG_REQ_TEAM_LEAVE); msg.TeamID = GameManager.gameManager.PlayerDataPool.TeamInfo.TeamID; //msg.NewTeamMember = m_NewTeamMemberBuffer; msg.SendPacket(); } public void ReqJoinLeaveOldCancel() { } //申请离开队伍 public void ReqLeaveTeam() { //向服务器发送申请离队消息 var msg = (CG_REQ_TEAM_LEAVE) PacketDistributed.CreatePacket(MessageID.PACKET_CG_REQ_TEAM_LEAVE); msg.SetTeamID(GameManager.gameManager.PlayerDataPool.TeamInfo.TeamID); msg.SendPacket(); } //申请踢人 public void ReqKickTeamMember(ulong teamMemberGuid) { if (GlobeVar.INVALID_GUID == teamMemberGuid) return; var msg = (CG_REQ_TEAM_KICK_MEMBER) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_TEAM_KICK_MEMBER); msg.SetTeamMemberGuid(teamMemberGuid); msg.SendPacket(); } //申请变换队长 public void ReqChangeTeamLeader(ulong teamMemberGuid) { if (GlobeVar.INVALID_GUID == teamMemberGuid) return; var msg = (CG_REQ_TEAM_CHANGE_LEADER) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_TEAM_CHANGE_LEADER); msg.SetTeamMemberGuid(teamMemberGuid); msg.SendPacket(); } //更新某个组员信息,第三位为是否只更新HP标记 public void UpdateTeamMemberInfo(int nIndex, GC_TEAM_SYNC_MEMBERINFO packet) { //下标判断 if (nIndex < 0 || nIndex >= GlobeVar.MAX_TEAM_MEMBER) return; //更新数据 GameManager.gameManager.PlayerDataPool.TeamInfo.UpdateMember(nIndex, packet); //更新UI数据 if (TeamList.Instance() == null) return; TeamList.Instance().UpdateTeamMember(); } //收到离开队伍消息 public void LeaveTeam() { //清理队伍数据 GameManager.gameManager.PlayerDataPool.TeamInfo.CleanUp(); //通知UI清理队伍数据 TeamList.Instance().ClearTeamListUI(); //更新队长头像 if (null != PlayerFrameLogic.Instance()) { //PlayerFrameLogic.Instance().SetTeamCaptain(false); } //退出组队跟随状态 LeaveTeamFollow(); } //MainPlayer是否为队长 public bool IsTeamLeader() { if (GlobeVar.INVALID_ID == GameManager.gameManager.PlayerDataPool.TeamInfo.TeamID) return false; return GUID == GameManager.gameManager.PlayerDataPool.TeamInfo.GetTeamMember(0).Guid; } //否个Guid是否为队长 public bool IsTeamLeader(ulong guid) { if (GlobeVar.INVALID_ID == GameManager.gameManager.PlayerDataPool.TeamInfo.TeamID || GlobeVar.INVALID_GUID == guid) return false; return guid == GameManager.gameManager.PlayerDataPool.TeamInfo.GetTeamMember(0).Guid; } public void EnterTeamFollow() { //没有队伍,无法进入组队跟随状态 if (GlobeVar.INVALID_ID == GameManager.gameManager.PlayerDataPool.TeamInfo.TeamID) return; if (Singleton<ObjManager>.Instance.MainPlayer.IsInPaoShang() && !GameManager.gameManager.PlayerDataPool.TeamInfo.IsCaptain()) { GUIData.AddNotifyData(StrDictionary.GetClientDictionaryString("{#34007}")); return; } //BOSS之家的判断 //if (InHomeBoss()) // return; SetTeamFollowState(TeamFollowState.followMove); } //跟随进入BOSS之家时需要判断队员是否都满足条件 private bool InHomeBoss() { if (GameManager.gameManager.PlayerDataPool.TeamInfo.IsCaptain() == false) { TeamMember captain = GameManager.gameManager.PlayerDataPool.TeamInfo.GetTeamMember(0); if (captain.IsValid() == false) return false; if (WorldBossData.Instance.IsInHomeBossFuben(captain.SceneClassID) == false) return false; int sceneVipLevel = WorldBossData.Instance.SceneVipLevel(captain.SceneClassID); if (sceneVipLevel > WorldBossData.Instance.VipCanUseLevel) { GUIData.AddNotifyData(StrDictionary.GetClientDictionaryString("{#49152}",GameManager.gameManager.PlayerDataPool.MainPlayerBaseAttr.RoleName, sceneVipLevel)); } } else { if (WorldBossData.Instance.IsInHomeBossFuben(GameManager.gameManager.RunningScene) == false) return false; int sceneVipLevel = WorldBossData.Instance.SceneVipLevel(GameManager.gameManager.RunningScene); for (var i = 1; i < GlobeVar.MAX_TEAM_MEMBER; i++) { TeamMember member = GameManager.gameManager.PlayerDataPool.TeamInfo.GetTeamMember(i); if (member.IsValid() == false) continue; if (WorldBossData.Instance.IsInHomeBossFuben(member.SceneClassID) == false) continue; if (sceneVipLevel > 0) { GUIData.AddNotifyData(StrDictionary.GetClientDictionaryString("{#49152}", member.MemberName, sceneVipLevel)); } } } return true; } public void TeamEnterAutoCombat() { SetTeamFollowState(TeamFollowState.followCombat); } public void TeamLeaderEndCombat() { var teamMembers = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember; for (var i = 1; i < teamMembers.Length; i++) if (teamMembers[i].IsValid()) { if (teamMembers[i].FollowState == TeamFollowState.followCombat) SetTeamFollowState(TeamFollowState.followMove, teamMembers[i].Guid); } else { break; } } public void BreakTeamTeleport() { if (GameManager.gameManager.PlayerDataPool.TeamInfo.IsCaptain()) { var leader = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember[0]; if (leader.IsValid()) { leader.teleportFreezeTime = 0f; for (var i = 1; i < GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember.Length; ++i) { var member = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember[i]; if (member.FollowLeader()) TryMatchSceneWithLeader(member, leader); } } } } //结束组队跟随状态 public void LeaveTeamFollow() { SetTeamFollowState(TeamFollowState.notFollow); } private void SetTeamFollowState(int followState, ulong? guid = null) { if (guid == null) guid = GUID; var packet = (CG_REQ_CHANGE_TEAM_MEMBER_FOLLOWSTATE) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_CHANGE_TEAM_MEMBER_FOLLOWSTATE); packet.SetOpguid(guid.Value); packet.SetFollowstate(followState); packet.SendPacket(); } /// <summary> /// 主角在进入一个新场景时,试图根据当前场景配置自动战斗情况 /// </summary> public void RefreshPlayerAutoCombat() { var autoType = CommonUtility.FubenAutoType(GameManager.gameManager.PlayerDataPool.EnterSceneCache.EnterCopySceneID); // 是否执行组队队员更新策略 var teamMemberUpdate = false; if (GameManager.gameManager.PlayerDataPool.IsHaveTeam()) if (!GameManager.gameManager.PlayerDataPool.TeamInfo.IsCaptain()) teamMemberUpdate = true; if (autoType == FubenAutoType.auto) { if (!isAutoCombat) { if (LoadingWindow._IsLoadingScene) EnterAutoCombatAfterLoading(); else EnterAutoCombat(); } } else { LeveAutoCombat(); } if (teamMemberUpdate) { if (autoType == FubenAutoType.noAuto) { var lastFuben = GameManager.gameManager.PlayerDataPool.EnterSceneCache.LastFuben; // 如果副本为退出后跟随副本,则进入跟随状态 if (lastFuben != null && lastFuben.FollowAfterQuit > 0) SetTeamFollowState(TeamFollowState.followMove); } else { SetTeamFollowState(TeamFollowState.notFollow); } } } /// <summary> /// 试图让队员传送到队长的场景 /// </summary> /// <returns>队员是否处于传送中</returns> // 注:这个函数仅仅允许队长调用,队员调用会出错 private bool TryMatchSceneWithLeader(TeamMember member, TeamMember leader) { var result = false; // 队长处于传送状态,不发送消息 if (leader.teleportFreezeTime > Time.realtimeSinceStartup) { result = true; } // 队员处于传送状态,不接受新的传送指令 else if (member.teleportFreezeTime > Time.realtimeSinceStartup) { // 队长不传送,队员和队长在同一场景时,取消传送 result = member.SceneClassID != fubenId || member.SceneInstID != SceneData.SceneInst; } // 队长不处于副本场景中 else if (member.SceneClassID != fubenId) { if (AllowCallIn(fubenId, member.SceneClassID)) { StartTeleportProcess(member, fubenId, leader.SceneInstID); result = true; } } else if (member.SceneInstID != SceneData.SceneInst) { if (AllowCallIn(fubenId, member.SceneClassID)) { StartInstProcess(member, SceneData.SceneInst); result = true; } } return result; } public static bool AllowCallIn(int leaderSceneId, int memberSceneId) { return AllowCallIn(leaderSceneId) && AllowCallIn(memberSceneId); } private static bool AllowCallIn(int fubenId) { var result = true; var fuben = TableManager.GetFubenByID(fubenId, 0); if (fuben != null) result = fuben.Type < 2 || fuben.CallTeam > 0; return result; } /// <summary> /// 开始传送到队长所在场景 /// </summary> // 注:这一套流程只允许队长执行,非队长执行将会导致问题 private void StartTeleportProcess(TeamMember member, int fubenId, int sceneInst) { if (debugTeamTeleport) { LogModule.DebugLog(string.Format("Teleport Scene {0} Inst {1}", fubenId, sceneInst)); LogModule.DebugLog(string.Format("Member Scene {0} Inst {1}", member.SceneClassID, member.SceneInstID)); LogModule.WarningLog("Teleport Start"); } // 确保都转入组队移动状态 if (member.FollowState != TeamFollowState.followMove) SetTeamFollowState(TeamFollowState.followMove); var packet = (CG_REQ_MEMBER_CHANGE_SCENE) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_MEMBER_CHANGE_SCENE); packet.SetMemberguid((long) member.Guid); packet.SetCtype((int) AutoSearchPoint.ChangeMap_Type.WORLDMAP); packet.SetTeleportid(-1); packet.SetSceneclassid(fubenId); packet.SetSceneinstid(sceneInst); packet.SetPosX(0); packet.SetPosZ(0); packet.SendPacket(); member.teleportFreezeTime = Time.realtimeSinceStartup + _maxMemberTeleportTime; } /// <summary> /// 切换到队长世界线 /// </summary> private void StartInstProcess(TeamMember member, int sceneInst) { if (debugTeamTeleport) { LogModule.DebugLog(string.Format("Inst Update {0}", sceneInst)); LogModule.DebugLog(string.Format("Member Scene {0} Inst {1}", member.SceneClassID, member.SceneInstID)); LogModule.WarningLog("Inst Update Start"); } // 确保都转入组队移动状态 if (member.FollowState != TeamFollowState.followMove) SetTeamFollowState(TeamFollowState.followMove); var packet = (CG_REQ_MEMBER_SCENE_CHANGEINST) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_MEMBER_SCENE_CHANGEINST); packet.SetMemberguid((long) member.Guid); packet.SetSceneInst(sceneInst); packet.SendPacket(); member.teleportFreezeTime = Time.realtimeSinceStartup + _maxMemberTeleportTime; } /// <summary> /// 玩家试图进入帮会场景 /// </summary> // 同样只有队长调用,非队长调用会出现问题 // 注:进入帮会由服务器发起,因此不予以处理 private void TeamEnterGuildMap() { var leader = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember[0]; if (leader.IsValid()) leader.teleportFreezeTime = Time.realtimeSinceStartup + _maxMemberTeleportTime; } // 注:这个方法只能主角队长调用,非主角队长调用会出问题 // 同TryMatchSceneWithLeader不同,这个传送会限定changeType,teleportId等等参数 public void TeamChangeSceneFollow(int changeType, int teleportId, int sceneId, int sceneInst, int safeX, int safeZ) { var leader = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember[0]; if (leader.IsValid()) { for (var i = 1; i < GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember.Length; ++i) { var member = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember[i]; if (member.FollowLeader()) { // 特殊处理:如果队长不处于副本中, if (debugTeamTeleport) { LogModule.DebugLog(string.Format("Teleport Scene {0} Inst {1}", sceneId, sceneInst)); LogModule.DebugLog(string.Format("Member Scene {0} Inst {1}", member.SceneClassID, member.SceneInstID)); LogModule.WarningLog("Teleport Start"); } // 确保都转入组队移动状态 //if (member.FollowState != TeamFollowState.followMove) // SetTeamFollowState(TeamFollowState.followMove); var packet = (CG_REQ_MEMBER_CHANGE_SCENE) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_MEMBER_CHANGE_SCENE); packet.SetMemberguid((long) member.Guid); packet.SetCtype(changeType); packet.SetTeleportid(teleportId); packet.SetSceneclassid(sceneId); packet.SetSceneinstid(sceneInst); packet.SetPosX(safeX); packet.SetPosZ(safeZ); packet.SendPacket(); member.teleportFreezeTime = Time.realtimeSinceStartup + _maxMemberTeleportTime; } } leader.teleportFreezeTime = Time.realtimeSinceStartup + _maxMemberTeleportTime; } } // 注:这个方法只能队长调用 public void TeamChangeInstFollow(int sceneId, int sceneInst) { var leader = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember[0]; for (var i = 1; i < GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember.Length; ++i) { var member = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember[i]; if (member.FollowLeader() && AllowCallIn(sceneId, member.SceneClassID)) { if (debugTeamTeleport) { LogModule.DebugLog(string.Format("Teleport Scene {0} Inst {1}", sceneId, sceneInst)); LogModule.DebugLog(string.Format("Member Scene {0} Inst {1}", member.SceneClassID, member.SceneInstID)); LogModule.WarningLog("Teleport Start"); } // 确保都转入组队移动状态 if (member.FollowState != TeamFollowState.followMove) SetTeamFollowState(TeamFollowState.followMove); if (member.SceneClassID == sceneId) { if (member.SceneInstID != sceneInst) { var packet = (CG_REQ_MEMBER_SCENE_CHANGEINST) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_MEMBER_SCENE_CHANGEINST); packet.SetMemberguid((long) member.Guid); packet.SetSceneInst(sceneInst); packet.SendPacket(); member.teleportFreezeTime = Time.realtimeSinceStartup + _maxMemberTeleportTime; } } else { var packet = (CG_REQ_MEMBER_CHANGE_SCENE) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_MEMBER_CHANGE_SCENE); packet.SetMemberguid((long) member.Guid); packet.SetCtype((int) CG_REQ_CHANGE_SCENE.CHANGETYPE.WORLDMAP); packet.SetTeleportid(-1); packet.SetSceneclassid(sceneId); packet.SetSceneinstid(sceneInst); packet.SetPosX(0); packet.SetPosZ(0); packet.SendPacket(); member.teleportFreezeTime = Time.realtimeSinceStartup + _maxMemberTeleportTime; } } } leader.teleportFreezeTime = Time.realtimeSinceStartup + _maxMemberTeleportTime; } public void TeamLeaderRideUpdate() { var teamMembers = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember; for (var i = 0; i < teamMembers.Length; i++) teamMembers[i].ridingMatchLead = false; } /// <summary> /// 队员经过跳跃点执行跳跃 /// </summary> public void WrapTeamMember(ulong guid, int jumpId) { if (GameManager.gameManager.PlayerDataPool.TeamInfo.IsCaptain() && guid != GUID) { var teamMember = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember.Find(a => a.Guid == guid); if (teamMember != null && teamMember.FollowState == TeamFollowState.followMove) { var jumpData = TableManager.GetJumpByID(jumpId, 0); float warpTime; jumpData = jumpData.GetFinialJumpData(out warpTime); var position = ActiveScene.GetTerrainPosition(new Vector3(jumpData.EndPosX, Position.y, jumpData.EndPosZ)); // Hack:强制处理记录,防止几帧内不同步导致位置回滚,下一次同步位置应该校正到传送后位置 teamMember.ScenePos = position.RemoveY(); var simulator = GetMoveSimulator(teamMember.Guid); if (simulator != null) simulator.WarpToPosition(teamMember, position, warpTime); } } } private TeamMemberMoveSimulator GetMoveSimulator(ulong? guid) { TeamMemberMoveSimulator result = null; for (var i = 0; i < moveSimulatorList.Count; i++) if (moveSimulatorList[i].Guid == guid) { result = moveSimulatorList[i]; break; } return result; } private void UpdateTeamFollow() { // 更新队员跟随位置 PushLeaderPos(Position); if (_nextUpdateFollowTime > Time.unscaledTime || Time.realtimeSinceStartup < AutoSearchAgent.unlockTime) return; if (GameManager.gameManager == null || !GameManager.gameManager.PlayerDataPool.IsHaveTeam()) return; var leader = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember[0]; if (!leader.IsValid()) return; _nextUpdateFollowTime = Time.unscaledTime + _updateFollowInterval; // 队长控制 if (leader.Guid == ObjManager.Instance.MainPlayer.GUID) { // 试图为每一个队员预测一个应该走向的位置 var posIndex = 1; for (var i = 1; i < GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember.Length; i++) { var member = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember[i]; if (member.IsValid() && member.FollowState != TeamFollowState.notFollow && !TryMatchSceneWithLeader(member, leader)) { // 同队长处于同一场景 // Hack: 队长的信息可能会慢一个周期更新,因此暂时处理为直接使用玩家本身的信息 if (InTheSameScene(member)) { switch (member.FollowState) { case TeamFollowState.followMove: // 注:如果主角从来没有移动过,仅仅存在Index为0的点 posIndex = Mathf.Min(posIndex, _leaderPosList.Count - 1); SetTeamMemberPos(member, _leaderPosList[posIndex]); posIndex++; // 骑乘状态重置时,执行一次骑乘切换 if (!member.ridingMatchLead) { member.ridingMatchLead = true; SetTeamMemberRide(member, AdcaneMountId >= 0 || (member.ScenePos - leader.ScenePos).sqrMagnitude > _mountDistance.ToSquare()); } break; case TeamFollowState.followCombat: if ((member.ScenePos - Position.RemoveY()).sqrMagnitude > memberLeaveAutoCombatDistance.ToSquare()) SetTeamFollowState(TeamFollowState.followMove, member.Guid); break; } } // 同队长不在一个场景 else { if (member.FollowState == TeamFollowState.followCombat) SetTeamFollowState(TeamFollowState.followMove, member.Guid); } } } // 试图移除不需要的移动模拟器 for (var i = moveSimulatorList.Count - 1; i >= 0; i--) { var simulator = moveSimulatorList[i]; if (simulator.Guid != null) { var member = GameManager.gameManager.PlayerDataPool.TeamInfo.teamMember.Find(a => a.Guid == simulator.Guid); if (member == null || member.FollowState != TeamFollowState.followMove || !InTheSameScene(member)) moveSimulatorList[i].Deactivate(); } } } } private static bool InTheSameScene(TeamMember member) { return fubenId == member.SceneClassID && SceneData.SceneInst == member.SceneInstID; } private void PushLeaderPos(Vector3 pos) { // 如果主角处于跳跃和无敌斩状态,不缓存当前位置 if (MovementState == MoveState.Leap || MovementState == MoveState.OnmiSlash) return; // 每一米推送一个位置 if (_leaderPosList.Count == 0 || (_leaderPosList[0] - pos).sqrMagnitude > _followDistance.ToSquare()) { if (_leaderPosList.Count >= GlobeVar.MAX_TEAM_MEMBER) _leaderPosList.RemoveAt(_leaderPosList.Count - 1); _leaderPosList.Insert(0, pos); } } private void SetTeamMemberPos(TeamMember teamMember, Vector3 targetPos) { var simulator = GetMoveSimulator(teamMember.Guid); if (simulator == null) { // 试图重用一个未激活的模拟器 simulator = GetMoveSimulator(null); if (simulator == null) { // 构造新的模拟器 simulator = new TeamMemberMoveSimulator(); moveSimulatorList.Add(simulator); } simulator.Init(teamMember); } simulator.MoveToPosition(teamMember, targetPos); } /// <summary> /// 队长起跳时,需要清空跳跃效果 /// </summary> private void UpdatePositionForLeap(Tab_Jump jumpTable) { jumpTable = jumpTable.GetFinialJumpData(); _leaderPosList.Clear(); _leaderPosList.Add( ActiveScene.GetTerrainPosition(new Vector3(jumpTable.EndPosX, Position.y, jumpTable.EndPosZ))); } private void SetTeamMemberRide(TeamMember teamMember, bool isRide) { if (isRide) { var packet = (CG_REQ_TEAM_MEMBER_SINGLE_MOUNT) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_TEAM_MEMBER_SINGLE_MOUNT); packet.SetMemberguid(teamMember.Guid); packet.SendPacket(); } } /// <summary> /// 队友运动模拟器 /// </summary> // 注:Team里面,队友位置并不满足0.2s内更新,因此只能使用这个组件来进行高精度追踪 public class TeamMemberMoveSimulator { private NavMeshAgent _agent; public ulong? Guid { get; private set; } public void Init(TeamMember teamMember) { Guid = teamMember.Guid; var position = GetTeamMemberPos(teamMember); var agentName = "TeamMemberSimulator_" + Guid; if (_agent == null) { var gameObject = new GameObject(agentName); gameObject.transform.position = position; gameObject.transform.rotation = Quaternion.identity; gameObject.transform.localScale = Vector3.one; _agent = gameObject.AddComponent<NavMeshAgent>(); SetBasicNavAgentParameter(_agent); SetNavAgentAreaMask(_agent, true); _agent.angularSpeed = 30000f; _agent.speed = teamMember.MoveSpeed; } else { _agent.gameObject.name = agentName; _agent.gameObject.SetActive(true); _agent.ResetPath(); _agent.Warp(position); } } private static Vector3 GetTeamMemberPos(TeamMember teamMember) { var obj = ObjManager.Instance.FindOtherPlayerByGuid(teamMember.Guid); var position = obj == null ? ActiveScene.GetTerrainPosition(teamMember.ScenePos.InsertY()) : obj.Position; return position; } public void Deactivate() { Guid = null; if (_agent != null) { _agent.gameObject.name = "TeamMemberSimulator_Inactive"; _agent.gameObject.SetActive(false); } } /// <summary> /// 队员经由跳跃点传送到目标位置 /// </summary> public void WarpToPosition(TeamMember teamMember, Vector3 position, float warpTime) { if (warpTime > 0f) teamMember.warpFreezeTime = Time.unscaledTime + Mathf.Min(_maxMemberTeleportTime, warpTime); else teamMember.warpFreezeTime = 0f; _agent.Warp(position); } public void MoveToPosition(TeamMember teamMember, Vector3 position) { // 动态修改移动速度 _agent.speed = teamMember.MoveSpeed; if (Time.unscaledTime > teamMember.warpFreezeTime) { var obj = ObjManager.Instance.FindOtherPlayerByGuid(teamMember.Guid); var sourcePos = obj == null ? ActiveScene.GetTerrainPosition(teamMember.ScenePos.InsertY()) : obj.Position; var differDist = obj == null ? _maxSimulatorDiffer : _objSimulatorDiffer; // 角色距离差值超过容忍范围 if ((sourcePos.RemoveY() - _agent.transform.position.RemoveY()).sqrMagnitude > differDist.ToSquare()) { LogModule.WarningLog(string.Format("Team Member {0}, Pos {1} is too far from {2}", teamMember.Guid, _agent.transform.position.ToPreciseString(), sourcePos.ToPreciseString())); _agent.Warp(sourcePos); teamMember.warpFreezeTime = 0f; } // 特殊处理跳跃等待情况,防止预测机锁死在OffmeshLink if (!_agent.isOnOffMeshLink) { if (!_agent.isOnNavMesh) _agent.Warp(sourcePos); if (_agent.isOnNavMesh) { var path = _agent.path; if ((position - _agent.transform.position).RemoveY().sqrMagnitude > navAgentPercision.ToSquare()) { Vector3 predictPos; if (_agent.CalculatePath(position, path)) { var moveDelta = _agent.speed * _updateFollowPredictTime; predictPos = path.GetPointOnPath(_agent.transform.position, moveDelta); _agent.SetPath(path); } else { _agent.isStopped = true; predictPos = _agent.transform.position; } // 角色执行常规移动 var packet = (CG_REQ_TEAM_MEMBER_MOVE) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_TEAM_MEMBER_MOVE); packet.SetMemberguid((long) teamMember.Guid); packet.SetPoscount(1); packet.AddPosx(predictPos.x.ToServerPos()); packet.AddPosy(predictPos.y.ToServerPos()); packet.AddPosz(predictPos.z.ToServerPos()); packet.SetIsmoving(1); packet.SendPacket(); } } else { LogModule.ErrorLog(string.Format("Cannot fix TeamMember {0} at Pos {1} onto NavMesh at Scene {2}!", teamMember.Guid, teamMember.ScenePos.ToPreciseString(), GameManager.gameManager == null ? "Null" : fubenId.ToString())); } } else { // 非队长移动使用OffmeshLink进行判断 // 仅仅在服务器位置处于容错范围内时,才正式开始跳跃;否则呼叫角色走到跳跃点位置 if ((teamMember.ScenePos - _agent.transform.position.RemoveY()).sqrMagnitude > _jumpSimulatorDiffer.ToSquare()) { var packet = (CG_REQ_TEAM_MEMBER_MOVE) PacketDistributed.CreatePacket(MessageID .PACKET_CG_REQ_TEAM_MEMBER_MOVE); packet.SetMemberguid((long) teamMember.Guid); packet.SetPoscount(1); packet.AddPosx(_agent.transform.position.x.ToServerPos()); packet.AddPosy(_agent.transform.position.y.ToServerPos()); packet.AddPosz(_agent.transform.position.z.ToServerPos()); packet.SetIsmoving(1); packet.SendPacket(); } else { teamMember.warpFreezeTime = Time.unscaledTime + MainPlayerJumpWait.maxWaitTime; var offMeshLink = _agent.currentOffMeshLinkData.offMeshLink; if (offMeshLink != null) { var jumpPoint = offMeshLink.GetComponent<Obj_JumpPoint>(); if (jumpPoint != null) { var jumpProtocol = (CG_JUMP) PacketDistributed.CreatePacket(MessageID.PACKET_CG_JUMP); // 注:无视这个警告,Guid不存在时,根本不会更新 jumpProtocol.SetTargetguid(Guid.Value); jumpProtocol.SetJumpid(jumpPoint.GetJumpId()); jumpProtocol.SetTag(0); jumpProtocol.SendPacket(); jumpPoint.GetJumpId(); } } } } } } } } }