Initial Commit
This commit is contained in:
parent
53eb92e9af
commit
270ab7d11f
15341 changed files with 700234 additions and 0 deletions
|
@ -0,0 +1,308 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using MLAPI.Messaging;
|
||||
using MLAPI.Serialization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MLAPI.Prototyping
|
||||
{
|
||||
/// <summary>
|
||||
/// A prototype component for syncing animations
|
||||
/// </summary>
|
||||
[AddComponentMenu("MLAPI/NetworkAnimator")]
|
||||
public class NetworkAnimator : NetworkBehaviour
|
||||
{
|
||||
private struct AnimParams : INetworkSerializable
|
||||
{
|
||||
public Dictionary<int, (AnimatorControllerParameterType Type, object Boxed)> Parameters;
|
||||
|
||||
public void NetworkSerialize(NetworkSerializer serializer)
|
||||
{
|
||||
int paramCount = serializer.IsReading ? 0 : Parameters.Count;
|
||||
serializer.Serialize(ref paramCount);
|
||||
|
||||
var paramArray = serializer.IsReading ? new KeyValuePair<int, (AnimatorControllerParameterType Type, object Boxed)>[paramCount] : Parameters.ToArray();
|
||||
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++)
|
||||
{
|
||||
int paramId = serializer.IsReading ? 0 : paramArray[paramIndex].Key;
|
||||
serializer.Serialize(ref paramId);
|
||||
|
||||
byte paramType = serializer.IsReading ? (byte)0 : (byte)paramArray[paramIndex].Value.Type;
|
||||
serializer.Serialize(ref paramType);
|
||||
|
||||
object paramBoxed = null;
|
||||
switch (paramType)
|
||||
{
|
||||
case (byte)AnimatorControllerParameterType.Float:
|
||||
float paramFloat = serializer.IsReading ? 0 : (float)paramArray[paramIndex].Value.Boxed;
|
||||
serializer.Serialize(ref paramFloat);
|
||||
paramBoxed = paramFloat;
|
||||
break;
|
||||
case (byte)AnimatorControllerParameterType.Int:
|
||||
int paramInt = serializer.IsReading ? 0 : (int)paramArray[paramIndex].Value.Boxed;
|
||||
serializer.Serialize(ref paramInt);
|
||||
paramBoxed = paramInt;
|
||||
break;
|
||||
case (byte)AnimatorControllerParameterType.Bool:
|
||||
bool paramBool = serializer.IsReading ? false : (bool)paramArray[paramIndex].Value.Boxed;
|
||||
serializer.Serialize(ref paramBool);
|
||||
paramBoxed = paramBool;
|
||||
break;
|
||||
}
|
||||
|
||||
if (serializer.IsReading)
|
||||
{
|
||||
paramArray[paramIndex] = new KeyValuePair<int, (AnimatorControllerParameterType, object)>(paramId, ((AnimatorControllerParameterType)paramType, paramBoxed));
|
||||
}
|
||||
}
|
||||
|
||||
if (serializer.IsReading)
|
||||
{
|
||||
Parameters = paramArray.ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float SendRate = 0.1f;
|
||||
|
||||
[SerializeField]
|
||||
private Animator m_Animator;
|
||||
|
||||
public Animator Animator => m_Animator;
|
||||
|
||||
[HideInInspector]
|
||||
[SerializeField]
|
||||
private uint m_TrackedParamFlags = 0;
|
||||
|
||||
public void SetParamTracking(int paramIndex, bool isTracking)
|
||||
{
|
||||
if (paramIndex >= 32) return;
|
||||
|
||||
if (isTracking)
|
||||
{
|
||||
m_TrackedParamFlags |= (uint)(1 << paramIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_TrackedParamFlags &= (uint)~(1 << paramIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetParamTracking(int paramIndex)
|
||||
{
|
||||
if (paramIndex >= 32) return false;
|
||||
|
||||
return (m_TrackedParamFlags & (uint)(1 << paramIndex)) != 0;
|
||||
}
|
||||
|
||||
public void ResetTrackedParams()
|
||||
{
|
||||
m_TrackedParamFlags = 0;
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (!IsOwner) return;
|
||||
|
||||
if (CheckSendRate())
|
||||
{
|
||||
SendTrackedParams();
|
||||
}
|
||||
|
||||
if (CheckStateChange(out int animStateHash, out float animStateTime))
|
||||
{
|
||||
SendAllParamsAndState(animStateHash, animStateTime);
|
||||
}
|
||||
}
|
||||
|
||||
private float m_NextSendTime = 0.0f;
|
||||
|
||||
private bool CheckSendRate()
|
||||
{
|
||||
var networkTime = NetworkManager.Singleton.NetworkTime;
|
||||
if (SendRate != 0 && m_NextSendTime < networkTime)
|
||||
{
|
||||
m_NextSendTime = networkTime + SendRate;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int m_LastAnimStateHash = 0;
|
||||
|
||||
private bool CheckStateChange(out int outAnimStateHash, out float outAnimStateTime)
|
||||
{
|
||||
var animStateInfo = Animator.GetCurrentAnimatorStateInfo(0);
|
||||
var animStateHash = animStateInfo.fullPathHash;
|
||||
var animStateTime = animStateInfo.normalizedTime;
|
||||
if (animStateHash != m_LastAnimStateHash)
|
||||
{
|
||||
m_LastAnimStateHash = animStateHash;
|
||||
|
||||
outAnimStateHash = animStateHash;
|
||||
outAnimStateTime = animStateTime;
|
||||
return true;
|
||||
}
|
||||
|
||||
outAnimStateHash = 0;
|
||||
outAnimStateTime = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
private AnimParams GetAnimParams(bool trackedOnly = false)
|
||||
{
|
||||
var animParams = new AnimParams();
|
||||
animParams.Parameters = new Dictionary<int, (AnimatorControllerParameterType, object)>(32);
|
||||
for (int paramIndex = 0; paramIndex < 32 && paramIndex < Animator.parameters.Length; paramIndex++)
|
||||
{
|
||||
if (trackedOnly && !GetParamTracking(paramIndex)) continue;
|
||||
|
||||
var animParam = Animator.parameters[paramIndex];
|
||||
var animParamHash = animParam.nameHash;
|
||||
var animParamType = animParam.type;
|
||||
|
||||
object animParamBoxed = null;
|
||||
switch (animParamType)
|
||||
{
|
||||
case AnimatorControllerParameterType.Float:
|
||||
animParamBoxed = Animator.GetFloat(animParamHash);
|
||||
break;
|
||||
case AnimatorControllerParameterType.Int:
|
||||
animParamBoxed = Animator.GetInteger(animParamHash);
|
||||
break;
|
||||
case AnimatorControllerParameterType.Bool:
|
||||
animParamBoxed = Animator.GetBool(animParamHash);
|
||||
break;
|
||||
}
|
||||
|
||||
animParams.Parameters.Add(animParamHash, (animParamType, animParamBoxed));
|
||||
}
|
||||
|
||||
return animParams;
|
||||
}
|
||||
|
||||
private void SetAnimParams(AnimParams animParams)
|
||||
{
|
||||
foreach (var animParam in animParams.Parameters)
|
||||
{
|
||||
switch (animParam.Value.Type)
|
||||
{
|
||||
case AnimatorControllerParameterType.Float:
|
||||
Animator.SetFloat(animParam.Key, (float)animParam.Value.Boxed);
|
||||
break;
|
||||
case AnimatorControllerParameterType.Int:
|
||||
Animator.SetInteger(animParam.Key, (int)animParam.Value.Boxed);
|
||||
break;
|
||||
case AnimatorControllerParameterType.Bool:
|
||||
Animator.SetBool(animParam.Key, (bool)animParam.Value.Boxed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SendTrackedParams()
|
||||
{
|
||||
var animParams = GetAnimParams( /* trackedOnly = */ true);
|
||||
|
||||
if (IsServer)
|
||||
{
|
||||
var clientRpcParams = new ClientRpcParams
|
||||
{
|
||||
Send = new ClientRpcSendParams
|
||||
{
|
||||
TargetClientIds = NetworkManager.Singleton.ConnectedClientsList
|
||||
.Where(c => c.ClientId != NetworkManager.Singleton.ServerClientId)
|
||||
.Select(c => c.ClientId)
|
||||
.ToArray()
|
||||
}
|
||||
};
|
||||
UpdateTrackedParamsClientRpc(animParams, clientRpcParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateTrackedParamsServerRpc(animParams);
|
||||
}
|
||||
}
|
||||
|
||||
private void SendAllParamsAndState(int animStateHash, float animStateTime)
|
||||
{
|
||||
var animParams = GetAnimParams();
|
||||
|
||||
if (IsServer)
|
||||
{
|
||||
var clientRpcParams = new ClientRpcParams
|
||||
{
|
||||
Send = new ClientRpcSendParams
|
||||
{
|
||||
TargetClientIds = NetworkManager.Singleton.ConnectedClientsList
|
||||
.Where(c => c.ClientId != NetworkManager.Singleton.ServerClientId)
|
||||
.Select(c => c.ClientId)
|
||||
.ToArray()
|
||||
}
|
||||
};
|
||||
UpdateAnimStateClientRpc(animStateHash, animStateTime, clientRpcParams);
|
||||
UpdateTrackedParamsClientRpc(animParams, clientRpcParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateAnimStateServerRpc(animStateHash, animStateTime);
|
||||
UpdateTrackedParamsServerRpc(animParams);
|
||||
}
|
||||
}
|
||||
|
||||
[ServerRpc]
|
||||
private void UpdateTrackedParamsServerRpc(AnimParams animParams, ServerRpcParams serverRpcParams = default)
|
||||
{
|
||||
if (IsOwner) return;
|
||||
SetAnimParams(animParams);
|
||||
|
||||
var clientRpcParams = new ClientRpcParams
|
||||
{
|
||||
Send = new ClientRpcSendParams
|
||||
{
|
||||
TargetClientIds = NetworkManager.Singleton.ConnectedClientsList
|
||||
.Where(c => c.ClientId != serverRpcParams.Receive.SenderClientId)
|
||||
.Select(c => c.ClientId)
|
||||
.ToArray()
|
||||
}
|
||||
};
|
||||
UpdateTrackedParamsClientRpc(animParams, clientRpcParams);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
private void UpdateTrackedParamsClientRpc(AnimParams animParams, ClientRpcParams clientRpcParams = default)
|
||||
{
|
||||
if (IsOwner) return;
|
||||
SetAnimParams(animParams);
|
||||
}
|
||||
|
||||
[ServerRpc]
|
||||
private void UpdateAnimStateServerRpc(int animStateHash, float animStateTime, ServerRpcParams serverRpcParams = default)
|
||||
{
|
||||
if (IsOwner) return;
|
||||
|
||||
Animator.Play(animStateHash, 0, animStateTime);
|
||||
|
||||
var clientRpcParams = new ClientRpcParams
|
||||
{
|
||||
Send = new ClientRpcSendParams
|
||||
{
|
||||
TargetClientIds = NetworkManager.Singleton.ConnectedClientsList
|
||||
.Where(c => c.ClientId != serverRpcParams.Receive.SenderClientId)
|
||||
.Select(c => c.ClientId)
|
||||
.ToArray()
|
||||
}
|
||||
};
|
||||
UpdateAnimStateClientRpc(animStateHash, animStateTime, clientRpcParams);
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
private void UpdateAnimStateClientRpc(int animStateHash, float animStateTime, ClientRpcParams clientRpcParams = default)
|
||||
{
|
||||
if (IsOwner) return;
|
||||
|
||||
Animator.Play(animStateHash, 0, animStateTime);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e8d0727d5ae3244e3b569694d3912374
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,118 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using MLAPI.Connection;
|
||||
using MLAPI.Messaging;
|
||||
|
||||
namespace MLAPI.Prototyping
|
||||
{
|
||||
/// <summary>
|
||||
/// A prototype component for syncing NavMeshAgents
|
||||
/// </summary>
|
||||
[AddComponentMenu("MLAPI/NetworkNavMeshAgent")]
|
||||
[RequireComponent(typeof(NavMeshAgent))]
|
||||
public class NetworkNavMeshAgent : NetworkBehaviour
|
||||
{
|
||||
private NavMeshAgent m_Agent;
|
||||
|
||||
/// <summary>
|
||||
/// Is proximity enabled
|
||||
/// </summary>
|
||||
public bool EnableProximity = false;
|
||||
|
||||
/// <summary>
|
||||
/// The proximity range
|
||||
/// </summary>
|
||||
public float ProximityRange = 50f;
|
||||
|
||||
/// <summary>
|
||||
/// The delay in seconds between corrections
|
||||
/// </summary>
|
||||
public float CorrectionDelay = 3f;
|
||||
|
||||
//TODO rephrase.
|
||||
/// <summary>
|
||||
/// The percentage to lerp on corrections
|
||||
/// </summary>
|
||||
[Tooltip("Everytime a correction packet is received. This is the percentage (between 0 & 1) that we will move towards the goal.")]
|
||||
public float DriftCorrectionPercentage = 0.1f;
|
||||
|
||||
/// <summary>
|
||||
/// Should we warp on destination change
|
||||
/// </summary>
|
||||
public bool WarpOnDestinationChange = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
m_Agent = GetComponent<NavMeshAgent>();
|
||||
}
|
||||
|
||||
private Vector3 m_LastDestination = Vector3.zero;
|
||||
private float m_LastCorrectionTime = 0f;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!IsOwner) return;
|
||||
|
||||
if (m_Agent.destination != m_LastDestination)
|
||||
{
|
||||
m_LastDestination = m_Agent.destination;
|
||||
if (!EnableProximity)
|
||||
{
|
||||
OnNavMeshStateUpdateClientRpc(m_Agent.destination, m_Agent.velocity, transform.position);
|
||||
}
|
||||
else
|
||||
{
|
||||
var proximityClients = new List<ulong>();
|
||||
foreach (KeyValuePair<ulong, NetworkClient> client in NetworkManager.Singleton.ConnectedClients)
|
||||
{
|
||||
if (client.Value.PlayerObject == null || Vector3.Distance(client.Value.PlayerObject.transform.position, transform.position) <= ProximityRange)
|
||||
{
|
||||
proximityClients.Add(client.Key);
|
||||
}
|
||||
}
|
||||
|
||||
OnNavMeshStateUpdateClientRpc(m_Agent.destination, m_Agent.velocity, transform.position, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = proximityClients.ToArray() } });
|
||||
}
|
||||
}
|
||||
|
||||
if (NetworkManager.Singleton.NetworkTime - m_LastCorrectionTime >= CorrectionDelay)
|
||||
{
|
||||
if (!EnableProximity)
|
||||
{
|
||||
OnNavMeshCorrectionUpdateClientRpc(m_Agent.velocity, transform.position);
|
||||
}
|
||||
else
|
||||
{
|
||||
var proximityClients = new List<ulong>();
|
||||
foreach (KeyValuePair<ulong, NetworkClient> client in NetworkManager.Singleton.ConnectedClients)
|
||||
{
|
||||
if (client.Value.PlayerObject == null || Vector3.Distance(client.Value.PlayerObject.transform.position, transform.position) <= ProximityRange)
|
||||
{
|
||||
proximityClients.Add(client.Key);
|
||||
}
|
||||
}
|
||||
|
||||
OnNavMeshCorrectionUpdateClientRpc(m_Agent.velocity, transform.position, new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = proximityClients.ToArray() } });
|
||||
}
|
||||
|
||||
m_LastCorrectionTime = NetworkManager.Singleton.NetworkTime;
|
||||
}
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
private void OnNavMeshStateUpdateClientRpc(Vector3 destination, Vector3 velocity, Vector3 position, ClientRpcParams rpcParams = default)
|
||||
{
|
||||
m_Agent.Warp(WarpOnDestinationChange ? position : Vector3.Lerp(transform.position, position, DriftCorrectionPercentage));
|
||||
m_Agent.SetDestination(destination);
|
||||
m_Agent.velocity = velocity;
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
private void OnNavMeshCorrectionUpdateClientRpc(Vector3 velocity, Vector3 position, ClientRpcParams rpcParams = default)
|
||||
{
|
||||
m_Agent.Warp(Vector3.Lerp(transform.position, position, DriftCorrectionPercentage));
|
||||
m_Agent.velocity = velocity;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 43b86c65774f4494ba4e5878d5df9bcd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,351 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using MLAPI.Messaging;
|
||||
|
||||
namespace MLAPI.Prototyping
|
||||
{
|
||||
/// <summary>
|
||||
/// A prototype component for syncing transforms
|
||||
/// </summary>
|
||||
[AddComponentMenu("MLAPI/NetworkTransform")]
|
||||
public class NetworkTransform : NetworkBehaviour
|
||||
{
|
||||
internal class ClientSendInfo
|
||||
{
|
||||
public float LastSent;
|
||||
public Vector3? LastMissedPosition;
|
||||
public Quaternion? LastMissedRotation;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The base amount of sends per seconds to use when range is disabled
|
||||
/// </summary>
|
||||
[Range(0, 120)]
|
||||
public float FixedSendsPerSecond = 20f;
|
||||
|
||||
/// <summary>
|
||||
/// Is the sends per second assumed to be the same across all instances
|
||||
/// </summary>
|
||||
[Tooltip("This assumes that the SendsPerSecond is synced across clients")]
|
||||
public bool AssumeSyncedSends = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enable interpolation
|
||||
/// </summary>
|
||||
[Tooltip("This requires AssumeSyncedSends to be true")]
|
||||
public bool InterpolatePosition = true;
|
||||
|
||||
/// <summary>
|
||||
/// The distance before snaping to the position
|
||||
/// </summary>
|
||||
[Tooltip("The transform will snap if the distance is greater than this distance")]
|
||||
public float SnapDistance = 10f;
|
||||
|
||||
/// <summary>
|
||||
/// Should the server interpolate
|
||||
/// </summary>
|
||||
public bool InterpolateServer = true;
|
||||
|
||||
/// <summary>
|
||||
/// The min meters to move before a send is sent
|
||||
/// </summary>
|
||||
public float MinMeters = 0.15f;
|
||||
|
||||
/// <summary>
|
||||
/// The min degrees to rotate before a send it sent
|
||||
/// </summary>
|
||||
public float MinDegrees = 1.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Enables extrapolation
|
||||
/// </summary>
|
||||
public bool ExtrapolatePosition = false;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount of expected send rates to extrapolate over when awaiting new packets.
|
||||
/// A higher value will result in continued extrapolation after an object has stopped moving
|
||||
/// </summary>
|
||||
public float MaxSendsToExtrapolate = 5;
|
||||
|
||||
/// <summary>
|
||||
/// The channel to send the data on
|
||||
/// </summary>
|
||||
[Tooltip("The channel to send the data on. Uses the default channel if left unspecified")]
|
||||
public string Channel = null;
|
||||
|
||||
private float m_LerpTime;
|
||||
private Vector3 m_LerpStartPos;
|
||||
private Quaternion m_LerpStartRot;
|
||||
private Vector3 m_LerpEndPos;
|
||||
private Quaternion m_LerpEndRot;
|
||||
|
||||
private float m_LastSendTime;
|
||||
private Vector3 m_LastSentPos;
|
||||
private Quaternion m_LastSentRot;
|
||||
|
||||
private float m_LastReceiveTime;
|
||||
|
||||
/// <summary>
|
||||
/// Enables range based send rate
|
||||
/// </summary>
|
||||
public bool EnableRange;
|
||||
|
||||
/// <summary>
|
||||
/// Checks for missed sends without provocation. Provocation being a client inside it's normal SendRate
|
||||
/// </summary>
|
||||
public bool EnableNonProvokedResendChecks;
|
||||
|
||||
/// <summary>
|
||||
/// The curve to use to calculate the send rate
|
||||
/// </summary>
|
||||
public AnimationCurve DistanceSendrate = AnimationCurve.Constant(0, 500, 20);
|
||||
|
||||
private readonly Dictionary<ulong, ClientSendInfo> m_ClientSendInfo = new Dictionary<ulong, ClientSendInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// The delegate used to check if a move is valid
|
||||
/// </summary>
|
||||
/// <param name="clientId">The client id the move is being validated for</param>
|
||||
/// <param name="oldPos">The previous position</param>
|
||||
/// <param name="newPos">The new requested position</param>
|
||||
/// <returns>Returns Whether or not the move is valid</returns>
|
||||
public delegate bool MoveValidationDelegate(ulong clientId, Vector3 oldPos, Vector3 newPos);
|
||||
|
||||
/// <summary>
|
||||
/// If set, moves will only be accepted if the custom delegate returns true
|
||||
/// </summary>
|
||||
public MoveValidationDelegate IsMoveValidDelegate = null;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
if (!AssumeSyncedSends && InterpolatePosition)
|
||||
InterpolatePosition = false;
|
||||
if (InterpolateServer && !InterpolatePosition)
|
||||
InterpolateServer = false;
|
||||
if (MinDegrees < 0)
|
||||
MinDegrees = 0;
|
||||
if (MinMeters < 0)
|
||||
MinMeters = 0;
|
||||
if (EnableNonProvokedResendChecks && !EnableRange)
|
||||
EnableNonProvokedResendChecks = false;
|
||||
}
|
||||
|
||||
private float GetTimeForLerp(Vector3 pos1, Vector3 pos2)
|
||||
{
|
||||
return 1f / DistanceSendrate.Evaluate(Vector3.Distance(pos1, pos2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers message handlers
|
||||
/// </summary>
|
||||
public override void NetworkStart()
|
||||
{
|
||||
m_LastSentRot = transform.rotation;
|
||||
m_LastSentPos = transform.position;
|
||||
|
||||
m_LerpStartPos = transform.position;
|
||||
m_LerpStartRot = transform.rotation;
|
||||
|
||||
m_LerpEndPos = transform.position;
|
||||
m_LerpEndRot = transform.rotation;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (IsOwner)
|
||||
{
|
||||
if (NetworkManager.Singleton.NetworkTime - m_LastSendTime >= (1f / FixedSendsPerSecond) && (Vector3.Distance(transform.position, m_LastSentPos) > MinMeters || Quaternion.Angle(transform.rotation, m_LastSentRot) > MinDegrees))
|
||||
{
|
||||
m_LastSendTime = NetworkManager.Singleton.NetworkTime;
|
||||
m_LastSentPos = transform.position;
|
||||
m_LastSentRot = transform.rotation;
|
||||
|
||||
if (IsServer)
|
||||
{
|
||||
ApplyTransformClientRpc(transform.position, transform.rotation.eulerAngles,
|
||||
new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = NetworkManager.Singleton.ConnectedClientsList.Where(c => c.ClientId != OwnerClientId).Select(c => c.ClientId).ToArray() } });
|
||||
}
|
||||
else
|
||||
{
|
||||
SubmitTransformServerRpc(transform.position, transform.rotation.eulerAngles);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//If we are server and interpolation is turned on for server OR we are not server and interpolation is turned on
|
||||
if ((IsServer && InterpolateServer && InterpolatePosition) || (!IsServer && InterpolatePosition))
|
||||
{
|
||||
if (Vector3.Distance(transform.position, m_LerpEndPos) > SnapDistance)
|
||||
{
|
||||
//Snap, set T to 1 (100% of the lerp)
|
||||
m_LerpTime = 1f;
|
||||
}
|
||||
|
||||
float sendDelay = (IsServer || !EnableRange || !AssumeSyncedSends || NetworkManager.Singleton.ConnectedClients[NetworkManager.Singleton.LocalClientId].PlayerObject == null) ? (1f / FixedSendsPerSecond) : GetTimeForLerp(transform.position, NetworkManager.Singleton.ConnectedClients[NetworkManager.Singleton.LocalClientId].PlayerObject.transform.position);
|
||||
m_LerpTime += Time.unscaledDeltaTime / sendDelay;
|
||||
|
||||
if (ExtrapolatePosition && Time.unscaledTime - m_LastReceiveTime < sendDelay * MaxSendsToExtrapolate)
|
||||
transform.position = Vector3.LerpUnclamped(m_LerpStartPos, m_LerpEndPos, m_LerpTime);
|
||||
else
|
||||
transform.position = Vector3.Lerp(m_LerpStartPos, m_LerpEndPos, m_LerpTime);
|
||||
|
||||
if (ExtrapolatePosition && Time.unscaledTime - m_LastReceiveTime < sendDelay * MaxSendsToExtrapolate)
|
||||
transform.rotation = Quaternion.SlerpUnclamped(m_LerpStartRot, m_LerpEndRot, m_LerpTime);
|
||||
else
|
||||
transform.rotation = Quaternion.Slerp(m_LerpStartRot, m_LerpEndRot, m_LerpTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsServer && EnableRange && EnableNonProvokedResendChecks)
|
||||
CheckForMissedSends();
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
private void ApplyTransformClientRpc(Vector3 position, Vector3 eulerAngles, ClientRpcParams rpcParams = default)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
ApplyTransformInternal(position, Quaternion.Euler(eulerAngles));
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyTransformInternal(Vector3 position, Quaternion rotation)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (InterpolatePosition && (!IsServer || InterpolateServer))
|
||||
{
|
||||
m_LastReceiveTime = Time.unscaledTime;
|
||||
m_LerpStartPos = transform.position;
|
||||
m_LerpStartRot = transform.rotation;
|
||||
m_LerpEndPos = position;
|
||||
m_LerpEndRot = rotation;
|
||||
m_LerpTime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.position = position;
|
||||
transform.rotation = rotation;
|
||||
}
|
||||
}
|
||||
|
||||
[ServerRpc]
|
||||
private void SubmitTransformServerRpc(Vector3 position, Vector3 eulerAngles, ServerRpcParams rpcParams = default)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (IsMoveValidDelegate != null && !IsMoveValidDelegate(rpcParams.Receive.SenderClientId, m_LerpEndPos, position))
|
||||
{
|
||||
//Invalid move!
|
||||
//TODO: Add rubber band (just a message telling them to go back)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsClient)
|
||||
{
|
||||
// Dedicated server
|
||||
ApplyTransformInternal(position, Quaternion.Euler(eulerAngles));
|
||||
}
|
||||
|
||||
if (EnableRange)
|
||||
{
|
||||
for (int i = 0; i < NetworkManager.Singleton.ConnectedClientsList.Count; i++)
|
||||
{
|
||||
if (!m_ClientSendInfo.ContainsKey(NetworkManager.Singleton.ConnectedClientsList[i].ClientId))
|
||||
{
|
||||
m_ClientSendInfo.Add(NetworkManager.Singleton.ConnectedClientsList[i].ClientId, new ClientSendInfo()
|
||||
{
|
||||
LastMissedPosition = null,
|
||||
LastMissedRotation = null,
|
||||
LastSent = 0
|
||||
});
|
||||
}
|
||||
|
||||
ClientSendInfo info = m_ClientSendInfo[NetworkManager.Singleton.ConnectedClientsList[i].ClientId];
|
||||
Vector3? receiverPosition = NetworkManager.Singleton.ConnectedClientsList[i].PlayerObject == null ? null : new Vector3?(NetworkManager.Singleton.ConnectedClientsList[i].PlayerObject.transform.position);
|
||||
Vector3? senderPosition = NetworkManager.Singleton.ConnectedClients[OwnerClientId].PlayerObject == null ? null : new Vector3?(NetworkManager.Singleton.ConnectedClients[OwnerClientId].PlayerObject.transform.position);
|
||||
|
||||
if ((receiverPosition == null || senderPosition == null && NetworkManager.Singleton.NetworkTime - info.LastSent >= (1f / FixedSendsPerSecond)) || NetworkManager.Singleton.NetworkTime - info.LastSent >= GetTimeForLerp(receiverPosition.Value, senderPosition.Value))
|
||||
{
|
||||
info.LastSent = NetworkManager.Singleton.NetworkTime;
|
||||
info.LastMissedPosition = null;
|
||||
info.LastMissedRotation = null;
|
||||
|
||||
ApplyTransformClientRpc(position, eulerAngles,
|
||||
new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = new[] { NetworkManager.Singleton.ConnectedClientsList[i].ClientId } } });
|
||||
}
|
||||
else
|
||||
{
|
||||
info.LastMissedPosition = position;
|
||||
info.LastMissedRotation = Quaternion.Euler(eulerAngles);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyTransformClientRpc(position, eulerAngles,
|
||||
new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = NetworkManager.Singleton.ConnectedClientsList.Where(c => c.ClientId != OwnerClientId).Select(c => c.ClientId).ToArray() } });
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckForMissedSends()
|
||||
{
|
||||
for (int i = 0; i < NetworkManager.Singleton.ConnectedClientsList.Count; i++)
|
||||
{
|
||||
if (!m_ClientSendInfo.ContainsKey(NetworkManager.Singleton.ConnectedClientsList[i].ClientId))
|
||||
{
|
||||
m_ClientSendInfo.Add(NetworkManager.Singleton.ConnectedClientsList[i].ClientId, new ClientSendInfo()
|
||||
{
|
||||
LastMissedPosition = null,
|
||||
LastMissedRotation = null,
|
||||
LastSent = 0
|
||||
});
|
||||
}
|
||||
|
||||
ClientSendInfo info = m_ClientSendInfo[NetworkManager.Singleton.ConnectedClientsList[i].ClientId];
|
||||
Vector3? receiverPosition = NetworkManager.Singleton.ConnectedClientsList[i].PlayerObject == null ? null : new Vector3?(NetworkManager.Singleton.ConnectedClientsList[i].PlayerObject.transform.position);
|
||||
Vector3? senderPosition = NetworkManager.Singleton.ConnectedClients[OwnerClientId].PlayerObject == null ? null : new Vector3?(NetworkManager.Singleton.ConnectedClients[OwnerClientId].PlayerObject.transform.position);
|
||||
|
||||
if ((receiverPosition == null || senderPosition == null && NetworkManager.Singleton.NetworkTime - info.LastSent >= (1f / FixedSendsPerSecond)) || NetworkManager.Singleton.NetworkTime - info.LastSent >= GetTimeForLerp(receiverPosition.Value, senderPosition.Value))
|
||||
{
|
||||
/* why is this??? ->*/
|
||||
Vector3? pos = NetworkManager.Singleton.ConnectedClients[OwnerClientId].PlayerObject == null ? null : new Vector3?(NetworkManager.Singleton.ConnectedClients[OwnerClientId].PlayerObject.transform.position);
|
||||
/* why is this??? ->*/
|
||||
Vector3? rot = NetworkManager.Singleton.ConnectedClients[OwnerClientId].PlayerObject == null ? null : new Vector3?(NetworkManager.Singleton.ConnectedClients[OwnerClientId].PlayerObject.transform.rotation.eulerAngles);
|
||||
|
||||
if (info.LastMissedPosition != null && info.LastMissedRotation != null)
|
||||
{
|
||||
info.LastSent = NetworkManager.Singleton.NetworkTime;
|
||||
|
||||
ApplyTransformClientRpc(info.LastMissedPosition.Value, info.LastMissedRotation.Value.eulerAngles,
|
||||
new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = new[] { NetworkManager.Singleton.ConnectedClientsList[i].ClientId } } });
|
||||
|
||||
info.LastMissedPosition = null;
|
||||
info.LastMissedRotation = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Teleports the transform to the given position and rotation
|
||||
/// </summary>
|
||||
/// <param name="position">The position to teleport to</param>
|
||||
/// <param name="rotation">The rotation to teleport to</param>
|
||||
public void Teleport(Vector3 position, Quaternion rotation)
|
||||
{
|
||||
if (InterpolateServer && IsServer || IsClient)
|
||||
{
|
||||
m_LerpStartPos = position;
|
||||
m_LerpStartRot = rotation;
|
||||
m_LerpEndPos = position;
|
||||
m_LerpEndRot = rotation;
|
||||
m_LerpTime = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e96cb6065543e43c4a752faaa1468eb1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "Unity.Multiplayer.MLAPI.Prototyping",
|
||||
"rootNamespace": "MLAPI.Prototyping",
|
||||
"references": [
|
||||
"Unity.Multiplayer.MLAPI.Runtime"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": []
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3b8ed52f1b5c64994af4c4e0aa4b6c4b
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue