title: Unity: Rotation sync over network on dedicated server
body: <p>This was probably asked a dozen of times, but I can't seem to find the answer anywhere.</p>
  
  <p>I have a dedicated server for a space game written in C# console application. The problems that I'm facing is the synchronisation of GameObject rotations. I'm suspecting the issue being related to gimbal lock, but I am not sure.</p>
  
  <p>Here I have my player movement/rotation controller:</p>
  
  <pre><code>public class PlayerMovement : MonoBehaviour {
      [SerializeField] float maxSpeed = 40f;
      [SerializeField] float shipRotationSpeed = 60f;
  
      Transform characterTransform;
  
      void Awake()
      {
          characterTransform = transform;
      }
  
      void Update()
      {
          Turn();
          Thrust();
      }
  
      float Speed() {
          return maxSpeed;
      }
  
      void Turn() {
          float rotX = shipRotationSpeed * Time.deltaTime * CrossPlatformInputManager.GetAxis("Vertical");
          float rotY = shipRotationSpeed * Time.deltaTime * CrossPlatformInputManager.GetAxis("Horizontal");
  
          characterTransform.Rotate(-rotX, rotY, 0);
      }
  
      void Thrust() {
          if (CrossPlatformInputManager.GetAxis("Move") &gt; 0) {
              characterTransform.position += shipTransform.forward * Speed() * Time.deltaTime * CrossPlatformInputManager.GetAxis("Move");
          }
      }
  }
  </code></pre>
  
  <p>This script is applied to my character object which is a ship. Note that the character object has a child object which is the ship itself and has fixed rotation and position that do not change. When character has moved/rotated I send the following to the server: position(x, y, z) and rotation(x, y, z, w).</p>
  
  <p>Now here is the actual script that receives network packet information and updates the other players in game:</p>
  
  <pre><code>public class CharacterObject : MonoBehaviour {
      [SerializeField] GameObject shipModel;
  
      public int guid;
      public int characterId;
      public string name;
      public int shipId;
  
      Vector3 realPosition;
      Quaternion realRotation;
  
      public void Awake() {
      }
  
      public int Guid { get { return guid; } }
      public int CharacterId { get { return characterId; } }
  
      void Start () {
          realPosition = transform.position;
          realRotation = transform.rotation;
      }
  
      void Update () {
          // Do nothing
      }
  
      internal void LoadCharacter(SNCharacterUpdatePacket cuPacket) {
          guid = cuPacket.CharacterGuid;
          characterId = cuPacket.CharacterId;
          name = cuPacket.CharacterName;
          shipId = cuPacket.ShipId;
          realPosition = new Vector3(cuPacket.ShipPosX, cuPacket.ShipPosY, cuPacket.ShipPosZ);
          realRotation = new Quaternion(cuPacket.ShipRotX, cuPacket.ShipRotY, cuPacket.ShipRotZ, cuPacket.ShipRotW);
          UpdateTransform();
  
          Instantiate(Resources.Load("Ships/Ship1/Ship1"), shipModel.transform);
      }
  
      internal void UpdateCharacter(SNCharacterUpdatePacket cuPacket) {
          realPosition = new Vector3(cuPacket.ShipPosX, cuPacket.ShipPosY, cuPacket.ShipPosZ);
          realRotation = new Quaternion(cuPacket.ShipRotX, cuPacket.ShipRotY, cuPacket.ShipRotZ, cuPacket.ShipRotW);
          UpdateTransform();
      }
  
      void UpdateTransform() {
          transform.position = Vector3.Lerp(transform.position, realPosition, 0.1f);
          transform.rotation = Quaternion.Lerp(transform.rotation, realRotation, 0.5f);
      }
  }
  </code></pre>
  
  <p>Do you see anything wrong with the code ?</p>
  
  <p>My experience with 2 players in game is the following:
  When I start the game with two players they spawn at the same location (0,0,0) and same rotation (0,0,0).
  Lets say that The other player is rotating continuously around the X-axis only. What I am experiencing is: </p>
  
  <ol>
  <li>First 90 deg. of rotation it renders fine.</li>
  <li>Next 180 deg. of rotation the object stays in place</li>
  <li>The last 90 deg. of rotation renders fine</li>
  </ol>
  
  <p>In the first version I did not send the 'w' value of Quaternion, but then added it in the second version and it did not help. Note that there is no restrictions in rotation and users can rotate endlessly in all directions.
  Btw the positioning works fine.</p>
  
  <p>I might not understand Quaternions fully, but I thought that they had a purpose in avoiding the gimbal lock issue.</p>
  
  <p>Any help would be appreciated.</p>