123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- using UnityEngine;
- namespace Mirror.Experimental
- {
- [AddComponentMenu("Network/Experimental/NetworkRigidbody")]
- [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-rigidbody")]
- public class NetworkRigidbody : NetworkBehaviour
- {
- [Header("Settings")]
- [SerializeField] internal Rigidbody 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();
- void OnValidate()
- {
- if (target == null)
- {
- target = GetComponent<Rigidbody>();
- }
- }
- #region Sync vars
- [SyncVar(hook = nameof(OnVelocityChanged))]
- Vector3 velocity;
- [SyncVar(hook = nameof(OnAngularVelocityChanged))]
- Vector3 angularVelocity;
- [SyncVar(hook = nameof(OnIsKinematicChanged))]
- bool isKinematic;
- [SyncVar(hook = nameof(OnUseGravityChanged))]
- bool useGravity;
- [SyncVar(hook = nameof(OnuDragChanged))]
- float drag;
- [SyncVar(hook = nameof(OnAngularDragChanged))]
- float angularDrag;
- /// <summary>
- /// Ignore value if is host or client with Authority
- /// </summary>
- /// <returns></returns>
- bool IgnoreSync => isServer || ClientWithAuthority;
- bool ClientWithAuthority => clientAuthority && hasAuthority;
- void OnVelocityChanged(Vector3 _, Vector3 newValue)
- {
- if (IgnoreSync)
- return;
- target.velocity = newValue;
- }
- void OnAngularVelocityChanged(Vector3 _, Vector3 newValue)
- {
- if (IgnoreSync)
- return;
- target.angularVelocity = newValue;
- }
- void OnIsKinematicChanged(bool _, bool newValue)
- {
- if (IgnoreSync)
- return;
- target.isKinematic = newValue;
- }
- void OnUseGravityChanged(bool _, bool newValue)
- {
- if (IgnoreSync)
- return;
- target.useGravity = newValue;
- }
- void OnuDragChanged(float _, float newValue)
- {
- if (IgnoreSync)
- return;
- target.drag = newValue;
- }
- void OnAngularDragChanged(float _, float newValue)
- {
- if (IgnoreSync)
- return;
- target.angularDrag = newValue;
- }
- #endregion
- internal void Update()
- {
- if (isServer)
- {
- SyncToClients();
- }
- else if (ClientWithAuthority)
- {
- SendToServer();
- }
- }
- internal void FixedUpdate()
- {
- if (clearAngularVelocity && !syncAngularVelocity)
- {
- target.angularVelocity = Vector3.zero;
- }
- if (clearVelocity && !syncVelocity)
- {
- target.velocity = Vector3.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
- Vector3 currentVelocity = syncVelocity ? target.velocity : default;
- Vector3 currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default;
- bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity);
- bool angularVelocityChanged = syncAngularVelocity && ((previousValue.angularVelocity - currentAngularVelocity).sqrMagnitude > angularVelocitySensitivity * angularVelocitySensitivity);
- if (velocityChanged)
- {
- velocity = currentVelocity;
- previousValue.velocity = currentVelocity;
- }
- if (angularVelocityChanged)
- {
- angularVelocity = currentAngularVelocity;
- previousValue.angularVelocity = currentAngularVelocity;
- }
- // other rigidbody settings
- isKinematic = target.isKinematic;
- useGravity = target.useGravity;
- drag = target.drag;
- angularDrag = target.angularDrag;
- }
- /// <summary>
- /// Uses Command to send values to server
- /// </summary>
- [Client]
- void SendToServer()
- {
- if (!hasAuthority)
- {
- Debug.LogWarning("SendToServer called without authority");
- return;
- }
- SendVelocity();
- SendRigidBodySettings();
- }
- [Client]
- void SendVelocity()
- {
- float now = Time.time;
- if (now < previousValue.nextSyncTime)
- return;
- Vector3 currentVelocity = syncVelocity ? target.velocity : default;
- Vector3 currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default;
- bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity);
- bool angularVelocityChanged = syncAngularVelocity && ((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.useGravity != target.useGravity)
- {
- CmdSendUseGravity(target.useGravity);
- previousValue.useGravity = target.useGravity;
- }
- if (previousValue.drag != target.drag)
- {
- CmdSendDrag(target.drag);
- previousValue.drag = target.drag;
- }
- if (previousValue.angularDrag != target.angularDrag)
- {
- CmdSendAngularDrag(target.angularDrag);
- previousValue.angularDrag = target.angularDrag;
- }
- }
- /// <summary>
- /// Called when only Velocity has changed on the client
- /// </summary>
- [Command]
- void CmdSendVelocity(Vector3 velocity)
- {
- // Ignore messages from client if not in client authority mode
- if (!clientAuthority)
- return;
- this.velocity = velocity;
- target.velocity = velocity;
- }
- /// <summary>
- /// Called when angularVelocity has changed on the client
- /// </summary>
- [Command]
- void CmdSendVelocityAndAngular(Vector3 velocity, Vector3 angularVelocity)
- {
- // Ignore messages from client if not in client authority mode
- if (!clientAuthority)
- return;
- if (syncVelocity)
- {
- this.velocity = velocity;
- target.velocity = 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 CmdSendUseGravity(bool useGravity)
- {
- // Ignore messages from client if not in client authority mode
- if (!clientAuthority)
- return;
- this.useGravity = useGravity;
- target.useGravity = useGravity;
- }
- [Command]
- void CmdSendDrag(float drag)
- {
- // Ignore messages from client if not in client authority mode
- if (!clientAuthority)
- return;
- this.drag = drag;
- target.drag = drag;
- }
- [Command]
- void CmdSendAngularDrag(float angularDrag)
- {
- // Ignore messages from client if not in client authority mode
- if (!clientAuthority)
- return;
- this.angularDrag = angularDrag;
- target.angularDrag = 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 Vector3 velocity;
- public Vector3 angularVelocity;
- public bool isKinematic;
- public bool useGravity;
- public float drag;
- public float angularDrag;
- }
- }
- }
|