alap
This commit is contained in:
349
Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs
Normal file
349
Assets/Mirror/Components/Experimental/NetworkRigidbody2D.cs
Normal file
@ -0,0 +1,349 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror.Experimental
|
||||
{
|
||||
[AddComponentMenu("Network/ Experimental/Network Rigidbody 2D")]
|
||||
[HelpURL("https://mirror-networking.gitbook.io/docs/components/network-rigidbody")]
|
||||
public class NetworkRigidbody2D : NetworkBehaviour
|
||||
{
|
||||
[Header("Settings")]
|
||||
[SerializeField] internal Rigidbody2D target = null;
|
||||
|
||||
[Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")]
|
||||
public bool clientAuthority = false;
|
||||
|
||||
[Header("Velocity")]
|
||||
[Tooltip("Syncs Velocity every SyncInterval")]
|
||||
[SerializeField] bool syncVelocity = true;
|
||||
|
||||
[Tooltip("Set velocity to 0 each frame (only works if syncVelocity is false")]
|
||||
[SerializeField] bool clearVelocity = false;
|
||||
|
||||
[Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")]
|
||||
[SerializeField] float velocitySensitivity = 0.1f;
|
||||
|
||||
[Header("Angular Velocity")]
|
||||
[Tooltip("Syncs AngularVelocity every SyncInterval")]
|
||||
[SerializeField] bool syncAngularVelocity = true;
|
||||
|
||||
[Tooltip("Set angularVelocity to 0 each frame (only works if syncAngularVelocity is false")]
|
||||
[SerializeField] bool clearAngularVelocity = false;
|
||||
|
||||
[Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")]
|
||||
[SerializeField] float angularVelocitySensitivity = 0.1f;
|
||||
|
||||
/// <summary>
|
||||
/// Values sent on client with authority after they are sent to the server
|
||||
/// </summary>
|
||||
readonly ClientSyncState previousValue = new ClientSyncState();
|
||||
|
||||
protected override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
Reset();
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
if (target == null)
|
||||
target = GetComponent<Rigidbody2D>();
|
||||
|
||||
syncDirection = SyncDirection.ClientToServer;
|
||||
}
|
||||
|
||||
#region Sync vars
|
||||
|
||||
[SyncVar(hook = nameof(OnVelocityChanged))]
|
||||
Vector2 velocity;
|
||||
|
||||
[SyncVar(hook = nameof(OnAngularVelocityChanged))]
|
||||
float angularVelocity;
|
||||
|
||||
[SyncVar(hook = nameof(OnIsKinematicChanged))]
|
||||
bool isKinematic;
|
||||
|
||||
[SyncVar(hook = nameof(OnGravityScaleChanged))]
|
||||
float gravityScale;
|
||||
|
||||
[SyncVar(hook = nameof(OnuDragChanged))]
|
||||
float drag;
|
||||
|
||||
[SyncVar(hook = nameof(OnAngularDragChanged))]
|
||||
float angularDrag;
|
||||
|
||||
/// <summary>
|
||||
/// Ignore value if is host or client with Authority
|
||||
/// </summary>
|
||||
bool IgnoreSync => isServer || ClientWithAuthority;
|
||||
|
||||
bool ClientWithAuthority => clientAuthority && isOwned;
|
||||
|
||||
void OnVelocityChanged(Vector2 _, Vector2 newValue)
|
||||
{
|
||||
if (IgnoreSync)
|
||||
return;
|
||||
|
||||
target.linearVelocity = newValue;
|
||||
}
|
||||
|
||||
void OnAngularVelocityChanged(float _, float newValue)
|
||||
{
|
||||
if (IgnoreSync)
|
||||
return;
|
||||
|
||||
target.angularVelocity = newValue;
|
||||
}
|
||||
|
||||
void OnIsKinematicChanged(bool _, bool newValue)
|
||||
{
|
||||
if (IgnoreSync)
|
||||
return;
|
||||
|
||||
target.isKinematic = newValue;
|
||||
}
|
||||
|
||||
void OnGravityScaleChanged(float _, float newValue)
|
||||
{
|
||||
if (IgnoreSync)
|
||||
return;
|
||||
|
||||
target.gravityScale = newValue;
|
||||
}
|
||||
|
||||
void OnuDragChanged(float _, float newValue)
|
||||
{
|
||||
if (IgnoreSync)
|
||||
return;
|
||||
|
||||
target.linearDamping = newValue;
|
||||
}
|
||||
|
||||
void OnAngularDragChanged(float _, float newValue)
|
||||
{
|
||||
if (IgnoreSync)
|
||||
return;
|
||||
|
||||
target.angularDamping = newValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
if (isServer)
|
||||
SyncToClients();
|
||||
else if (ClientWithAuthority)
|
||||
SendToServer();
|
||||
}
|
||||
|
||||
internal void FixedUpdate()
|
||||
{
|
||||
if (clearAngularVelocity && !syncAngularVelocity)
|
||||
target.angularVelocity = 0f;
|
||||
|
||||
if (clearVelocity && !syncVelocity)
|
||||
target.linearVelocity = Vector2.zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates sync var values on server so that they sync to the client
|
||||
/// </summary>
|
||||
[Server]
|
||||
void SyncToClients()
|
||||
{
|
||||
// only update if they have changed more than Sensitivity
|
||||
|
||||
Vector2 currentVelocity = syncVelocity ? target.linearVelocity : default;
|
||||
float currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default;
|
||||
|
||||
bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity);
|
||||
bool angularVelocityChanged = syncAngularVelocity && ((previousValue.angularVelocity - currentAngularVelocity) > angularVelocitySensitivity);
|
||||
|
||||
if (velocityChanged)
|
||||
{
|
||||
velocity = currentVelocity;
|
||||
previousValue.velocity = currentVelocity;
|
||||
}
|
||||
|
||||
if (angularVelocityChanged)
|
||||
{
|
||||
angularVelocity = currentAngularVelocity;
|
||||
previousValue.angularVelocity = currentAngularVelocity;
|
||||
}
|
||||
|
||||
// other rigidbody settings
|
||||
isKinematic = target.isKinematic;
|
||||
gravityScale = target.gravityScale;
|
||||
drag = target.linearDamping;
|
||||
angularDrag = target.angularDamping;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses Command to send values to server
|
||||
/// </summary>
|
||||
[Client]
|
||||
void SendToServer()
|
||||
{
|
||||
if (!isOwned)
|
||||
{
|
||||
Debug.LogWarning("SendToServer called without authority");
|
||||
return;
|
||||
}
|
||||
|
||||
SendVelocity();
|
||||
SendRigidBodySettings();
|
||||
}
|
||||
|
||||
[Client]
|
||||
void SendVelocity()
|
||||
{
|
||||
float now = Time.time;
|
||||
if (now < previousValue.nextSyncTime)
|
||||
return;
|
||||
|
||||
Vector2 currentVelocity = syncVelocity ? target.linearVelocity : default;
|
||||
float currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default;
|
||||
|
||||
bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity);
|
||||
bool angularVelocityChanged = syncAngularVelocity && previousValue.angularVelocity != currentAngularVelocity;//((previousValue.angularVelocity - currentAngularVelocity).sqrMagnitude > angularVelocitySensitivity * angularVelocitySensitivity);
|
||||
|
||||
// if angularVelocity has changed it is likely that velocity has also changed so just sync both values
|
||||
// however if only velocity has changed just send velocity
|
||||
if (angularVelocityChanged)
|
||||
{
|
||||
CmdSendVelocityAndAngular(currentVelocity, currentAngularVelocity);
|
||||
previousValue.velocity = currentVelocity;
|
||||
previousValue.angularVelocity = currentAngularVelocity;
|
||||
}
|
||||
else if (velocityChanged)
|
||||
{
|
||||
CmdSendVelocity(currentVelocity);
|
||||
previousValue.velocity = currentVelocity;
|
||||
}
|
||||
|
||||
// only update syncTime if either has changed
|
||||
if (angularVelocityChanged || velocityChanged)
|
||||
previousValue.nextSyncTime = now + syncInterval;
|
||||
}
|
||||
|
||||
[Client]
|
||||
void SendRigidBodySettings()
|
||||
{
|
||||
// These shouldn't change often so it is ok to send in their own Command
|
||||
if (previousValue.isKinematic != target.isKinematic)
|
||||
{
|
||||
CmdSendIsKinematic(target.isKinematic);
|
||||
previousValue.isKinematic = target.isKinematic;
|
||||
}
|
||||
if (previousValue.gravityScale != target.gravityScale)
|
||||
{
|
||||
CmdChangeGravityScale(target.gravityScale);
|
||||
previousValue.gravityScale = target.gravityScale;
|
||||
}
|
||||
if (previousValue.drag != target.linearDamping)
|
||||
{
|
||||
CmdSendDrag(target.linearDamping);
|
||||
previousValue.drag = target.linearDamping;
|
||||
}
|
||||
if (previousValue.angularDrag != target.angularDamping)
|
||||
{
|
||||
CmdSendAngularDrag(target.angularDamping);
|
||||
previousValue.angularDrag = target.angularDamping;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when only Velocity has changed on the client
|
||||
/// </summary>
|
||||
[Command]
|
||||
void CmdSendVelocity(Vector2 velocity)
|
||||
{
|
||||
// Ignore messages from client if not in client authority mode
|
||||
if (!clientAuthority)
|
||||
return;
|
||||
|
||||
this.velocity = velocity;
|
||||
target.linearVelocity = velocity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when angularVelocity has changed on the client
|
||||
/// </summary>
|
||||
[Command]
|
||||
void CmdSendVelocityAndAngular(Vector2 velocity, float angularVelocity)
|
||||
{
|
||||
// Ignore messages from client if not in client authority mode
|
||||
if (!clientAuthority)
|
||||
return;
|
||||
|
||||
if (syncVelocity)
|
||||
{
|
||||
this.velocity = velocity;
|
||||
target.linearVelocity = velocity;
|
||||
}
|
||||
this.angularVelocity = angularVelocity;
|
||||
target.angularVelocity = angularVelocity;
|
||||
}
|
||||
|
||||
[Command]
|
||||
void CmdSendIsKinematic(bool isKinematic)
|
||||
{
|
||||
// Ignore messages from client if not in client authority mode
|
||||
if (!clientAuthority)
|
||||
return;
|
||||
|
||||
this.isKinematic = isKinematic;
|
||||
target.isKinematic = isKinematic;
|
||||
}
|
||||
|
||||
[Command]
|
||||
void CmdChangeGravityScale(float gravityScale)
|
||||
{
|
||||
// Ignore messages from client if not in client authority mode
|
||||
if (!clientAuthority)
|
||||
return;
|
||||
|
||||
this.gravityScale = gravityScale;
|
||||
target.gravityScale = gravityScale;
|
||||
}
|
||||
|
||||
[Command]
|
||||
void CmdSendDrag(float drag)
|
||||
{
|
||||
// Ignore messages from client if not in client authority mode
|
||||
if (!clientAuthority)
|
||||
return;
|
||||
|
||||
this.drag = drag;
|
||||
target.linearDamping = drag;
|
||||
}
|
||||
|
||||
[Command]
|
||||
void CmdSendAngularDrag(float angularDrag)
|
||||
{
|
||||
// Ignore messages from client if not in client authority mode
|
||||
if (!clientAuthority)
|
||||
return;
|
||||
|
||||
this.angularDrag = angularDrag;
|
||||
target.angularDamping = angularDrag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// holds previously synced values
|
||||
/// </summary>
|
||||
public class ClientSyncState
|
||||
{
|
||||
/// <summary>
|
||||
/// Next sync time that velocity will be synced, based on syncInterval.
|
||||
/// </summary>
|
||||
public float nextSyncTime;
|
||||
public Vector2 velocity;
|
||||
public float angularVelocity;
|
||||
public bool isKinematic;
|
||||
public float gravityScale;
|
||||
public float drag;
|
||||
public float angularDrag;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user