NetworkRigidbody2D.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. using UnityEngine;
  2. namespace Mirror.Experimental
  3. {
  4. [AddComponentMenu("Network/ Experimental/Network Rigidbody 2D")]
  5. [HelpURL("https://mirror-networking.gitbook.io/docs/components/network-rigidbody")]
  6. public class NetworkRigidbody2D : NetworkBehaviour
  7. {
  8. [Header("Settings")]
  9. [SerializeField] internal Rigidbody2D target = null;
  10. [Tooltip("Set to true if moves come from owner client, set to false if moves always come from server")]
  11. public bool clientAuthority = false;
  12. [Header("Velocity")]
  13. [Tooltip("Syncs Velocity every SyncInterval")]
  14. [SerializeField] bool syncVelocity = true;
  15. [Tooltip("Set velocity to 0 each frame (only works if syncVelocity is false")]
  16. [SerializeField] bool clearVelocity = false;
  17. [Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")]
  18. [SerializeField] float velocitySensitivity = 0.1f;
  19. [Header("Angular Velocity")]
  20. [Tooltip("Syncs AngularVelocity every SyncInterval")]
  21. [SerializeField] bool syncAngularVelocity = true;
  22. [Tooltip("Set angularVelocity to 0 each frame (only works if syncAngularVelocity is false")]
  23. [SerializeField] bool clearAngularVelocity = false;
  24. [Tooltip("Only Syncs Value if distance between previous and current is great than sensitivity")]
  25. [SerializeField] float angularVelocitySensitivity = 0.1f;
  26. /// <summary>
  27. /// Values sent on client with authority after they are sent to the server
  28. /// </summary>
  29. readonly ClientSyncState previousValue = new ClientSyncState();
  30. protected override void OnValidate()
  31. {
  32. base.OnValidate();
  33. if (target == null)
  34. target = GetComponent<Rigidbody2D>();
  35. }
  36. #region Sync vars
  37. [SyncVar(hook = nameof(OnVelocityChanged))]
  38. Vector2 velocity;
  39. [SyncVar(hook = nameof(OnAngularVelocityChanged))]
  40. float angularVelocity;
  41. [SyncVar(hook = nameof(OnIsKinematicChanged))]
  42. bool isKinematic;
  43. [SyncVar(hook = nameof(OnGravityScaleChanged))]
  44. float gravityScale;
  45. [SyncVar(hook = nameof(OnuDragChanged))]
  46. float drag;
  47. [SyncVar(hook = nameof(OnAngularDragChanged))]
  48. float angularDrag;
  49. /// <summary>
  50. /// Ignore value if is host or client with Authority
  51. /// </summary>
  52. bool IgnoreSync => isServer || ClientWithAuthority;
  53. bool ClientWithAuthority => clientAuthority && isOwned;
  54. void OnVelocityChanged(Vector2 _, Vector2 newValue)
  55. {
  56. if (IgnoreSync)
  57. return;
  58. target.velocity = newValue;
  59. }
  60. void OnAngularVelocityChanged(float _, float newValue)
  61. {
  62. if (IgnoreSync)
  63. return;
  64. target.angularVelocity = newValue;
  65. }
  66. void OnIsKinematicChanged(bool _, bool newValue)
  67. {
  68. if (IgnoreSync)
  69. return;
  70. target.isKinematic = newValue;
  71. }
  72. void OnGravityScaleChanged(float _, float newValue)
  73. {
  74. if (IgnoreSync)
  75. return;
  76. target.gravityScale = newValue;
  77. }
  78. void OnuDragChanged(float _, float newValue)
  79. {
  80. if (IgnoreSync)
  81. return;
  82. target.drag = newValue;
  83. }
  84. void OnAngularDragChanged(float _, float newValue)
  85. {
  86. if (IgnoreSync)
  87. return;
  88. target.angularDrag = newValue;
  89. }
  90. #endregion
  91. internal void Update()
  92. {
  93. if (isServer)
  94. SyncToClients();
  95. else if (ClientWithAuthority)
  96. SendToServer();
  97. }
  98. internal void FixedUpdate()
  99. {
  100. if (clearAngularVelocity && !syncAngularVelocity)
  101. target.angularVelocity = 0f;
  102. if (clearVelocity && !syncVelocity)
  103. target.velocity = Vector2.zero;
  104. }
  105. /// <summary>
  106. /// Updates sync var values on server so that they sync to the client
  107. /// </summary>
  108. [Server]
  109. void SyncToClients()
  110. {
  111. // only update if they have changed more than Sensitivity
  112. Vector2 currentVelocity = syncVelocity ? target.velocity : default;
  113. float currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default;
  114. bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity);
  115. bool angularVelocityChanged = syncAngularVelocity && ((previousValue.angularVelocity - currentAngularVelocity) > angularVelocitySensitivity);
  116. if (velocityChanged)
  117. {
  118. velocity = currentVelocity;
  119. previousValue.velocity = currentVelocity;
  120. }
  121. if (angularVelocityChanged)
  122. {
  123. angularVelocity = currentAngularVelocity;
  124. previousValue.angularVelocity = currentAngularVelocity;
  125. }
  126. // other rigidbody settings
  127. isKinematic = target.isKinematic;
  128. gravityScale = target.gravityScale;
  129. drag = target.drag;
  130. angularDrag = target.angularDrag;
  131. }
  132. /// <summary>
  133. /// Uses Command to send values to server
  134. /// </summary>
  135. [Client]
  136. void SendToServer()
  137. {
  138. if (!isOwned)
  139. {
  140. Debug.LogWarning("SendToServer called without authority");
  141. return;
  142. }
  143. SendVelocity();
  144. SendRigidBodySettings();
  145. }
  146. [Client]
  147. void SendVelocity()
  148. {
  149. float now = Time.time;
  150. if (now < previousValue.nextSyncTime)
  151. return;
  152. Vector2 currentVelocity = syncVelocity ? target.velocity : default;
  153. float currentAngularVelocity = syncAngularVelocity ? target.angularVelocity : default;
  154. bool velocityChanged = syncVelocity && ((previousValue.velocity - currentVelocity).sqrMagnitude > velocitySensitivity * velocitySensitivity);
  155. bool angularVelocityChanged = syncAngularVelocity && previousValue.angularVelocity != currentAngularVelocity;//((previousValue.angularVelocity - currentAngularVelocity).sqrMagnitude > angularVelocitySensitivity * angularVelocitySensitivity);
  156. // if angularVelocity has changed it is likely that velocity has also changed so just sync both values
  157. // however if only velocity has changed just send velocity
  158. if (angularVelocityChanged)
  159. {
  160. CmdSendVelocityAndAngular(currentVelocity, currentAngularVelocity);
  161. previousValue.velocity = currentVelocity;
  162. previousValue.angularVelocity = currentAngularVelocity;
  163. }
  164. else if (velocityChanged)
  165. {
  166. CmdSendVelocity(currentVelocity);
  167. previousValue.velocity = currentVelocity;
  168. }
  169. // only update syncTime if either has changed
  170. if (angularVelocityChanged || velocityChanged)
  171. previousValue.nextSyncTime = now + syncInterval;
  172. }
  173. [Client]
  174. void SendRigidBodySettings()
  175. {
  176. // These shouldn't change often so it is ok to send in their own Command
  177. if (previousValue.isKinematic != target.isKinematic)
  178. {
  179. CmdSendIsKinematic(target.isKinematic);
  180. previousValue.isKinematic = target.isKinematic;
  181. }
  182. if (previousValue.gravityScale != target.gravityScale)
  183. {
  184. CmdChangeGravityScale(target.gravityScale);
  185. previousValue.gravityScale = target.gravityScale;
  186. }
  187. if (previousValue.drag != target.drag)
  188. {
  189. CmdSendDrag(target.drag);
  190. previousValue.drag = target.drag;
  191. }
  192. if (previousValue.angularDrag != target.angularDrag)
  193. {
  194. CmdSendAngularDrag(target.angularDrag);
  195. previousValue.angularDrag = target.angularDrag;
  196. }
  197. }
  198. /// <summary>
  199. /// Called when only Velocity has changed on the client
  200. /// </summary>
  201. [Command]
  202. void CmdSendVelocity(Vector2 velocity)
  203. {
  204. // Ignore messages from client if not in client authority mode
  205. if (!clientAuthority)
  206. return;
  207. this.velocity = velocity;
  208. target.velocity = velocity;
  209. }
  210. /// <summary>
  211. /// Called when angularVelocity has changed on the client
  212. /// </summary>
  213. [Command]
  214. void CmdSendVelocityAndAngular(Vector2 velocity, float angularVelocity)
  215. {
  216. // Ignore messages from client if not in client authority mode
  217. if (!clientAuthority)
  218. return;
  219. if (syncVelocity)
  220. {
  221. this.velocity = velocity;
  222. target.velocity = velocity;
  223. }
  224. this.angularVelocity = angularVelocity;
  225. target.angularVelocity = angularVelocity;
  226. }
  227. [Command]
  228. void CmdSendIsKinematic(bool isKinematic)
  229. {
  230. // Ignore messages from client if not in client authority mode
  231. if (!clientAuthority)
  232. return;
  233. this.isKinematic = isKinematic;
  234. target.isKinematic = isKinematic;
  235. }
  236. [Command]
  237. void CmdChangeGravityScale(float gravityScale)
  238. {
  239. // Ignore messages from client if not in client authority mode
  240. if (!clientAuthority)
  241. return;
  242. this.gravityScale = gravityScale;
  243. target.gravityScale = gravityScale;
  244. }
  245. [Command]
  246. void CmdSendDrag(float drag)
  247. {
  248. // Ignore messages from client if not in client authority mode
  249. if (!clientAuthority)
  250. return;
  251. this.drag = drag;
  252. target.drag = drag;
  253. }
  254. [Command]
  255. void CmdSendAngularDrag(float angularDrag)
  256. {
  257. // Ignore messages from client if not in client authority mode
  258. if (!clientAuthority)
  259. return;
  260. this.angularDrag = angularDrag;
  261. target.angularDrag = angularDrag;
  262. }
  263. /// <summary>
  264. /// holds previously synced values
  265. /// </summary>
  266. public class ClientSyncState
  267. {
  268. /// <summary>
  269. /// Next sync time that velocity will be synced, based on syncInterval.
  270. /// </summary>
  271. public float nextSyncTime;
  272. public Vector2 velocity;
  273. public float angularVelocity;
  274. public bool isKinematic;
  275. public float gravityScale;
  276. public float drag;
  277. public float angularDrag;
  278. }
  279. }
  280. }