using System; using UnityEngine; using UnityEngine.Networking; using Cyber.Networking.Clientside; namespace Cyber.Entities { /// /// A syncable component that all characters have. Controls the character's subsystems. /// public class Character : SyncBase { /// /// How fast the player should move in Unity's spatial units per second. /// public float MovementSpeed = 5.0f; /// /// The character controller, used to move the character. Handles collisions. /// public CharacterController CharacterController; /// /// The head transform for looking around. /// public Transform Head; private Vector3 MovementDirection = new Vector3(); private Vector3 ServerPosition = new Vector3(); private bool ServerPositionShouldLerpSync = false; /// /// Moves the character in the given direction. /// /// Movement direction. public void Move(Vector3 Direction) { if (!Direction.Equals(MovementDirection)) { MovementDirection = Direction.normalized; } } /// /// Stops the player from moving. /// public void Stop() { if (Moving()) { MovementDirection = new Vector3(); } } /// /// Sets the character's rotation. /// /// Rotation in euler angles. public void SetRotation(Vector3 EulerAngles) { Vector3 HeadRot = Head.localEulerAngles; HeadRot.x = EulerAngles.x; HeadRot.z = EulerAngles.z; Head.localEulerAngles = HeadRot; Vector3 BodyRot = transform.localEulerAngles; BodyRot.y = EulerAngles.y; transform.localEulerAngles = BodyRot; } /// /// Whether the player is moving or not. /// public bool Moving() { return MovementDirection.sqrMagnitude != 0; } /// /// The character's rotation. Intended to be given as an input to /// . /// /// The rotation. public Vector3 GetRotation() { return new Vector3(Head.localEulerAngles.x, transform.localEulerAngles.y, Head.localEulerAngles.z); } /// /// Gets the Sync Handletype for Character, which doesn't require hash differences and syncs every tick. /// /// public override SyncHandletype GetSyncHandletype() { return new SyncHandletype(false, 1); } /// /// Deserializes the character. /// /// public override void Deserialize(NetworkReader reader) { ServerPosition = reader.ReadVector3(); Vector3 ServerMovementDirection = reader.ReadVector3(); Vector3 ServerRotation = reader.ReadVector3(); float Drift = (ServerPosition - transform.position).magnitude; // Update position if this is the local player if (Drift > MovementSpeed * 0.5f && Client.GetConnectedPlayer().Character.Equals(this)) { transform.position = ServerPosition; MovementDirection = ServerMovementDirection; } // Update position more often (with lerping) if this is not the local player if (Drift < 0.1) { ServerPositionShouldLerpSync = false; } else if (!Client.GetConnectedPlayer().Character.Equals(this)) { ServerPositionShouldLerpSync = true; } } /// /// Serializes the character. /// /// public override void Serialize(NetworkWriter writer) { writer.Write(transform.position); writer.Write(MovementDirection); writer.Write(GetRotation()); } private void Update() { if (ServerPositionShouldLerpSync) { transform.position = Vector3.Lerp(transform.position, ServerPosition, 10f * Time.deltaTime); } } private void FixedUpdate() { CharacterController.Move(MovementDirection * MovementSpeed * Time.fixedDeltaTime); } } }