Files
JJBB/Assets/Project/Script/Obj/MainPlayer/Obj_MainPlayer_Team.cs

965 lines
41 KiB
C#
Raw Permalink Normal View History

2024-08-23 15:49:34 +08:00
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不同这个传送会限定changeTypeteleportId等等参数
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();
}
}
}
}
}
}
}
}
}