using System; using UnityEngine; using UnityEngine.Networking; using Cyber.Networking.Clientside; using Cyber.Items; namespace Cyber.Entities.SyncBases { /// /// 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 interaction distance of this player. /// public float InteractionDistance = 2.0f; /// /// The character controller, used to move the character. Handles collisions. /// public CharacterController CharacterController; /// /// The inventory of this player. /// public Inventory Inventory; /// /// The head transform for looking around. /// public Transform Head; /// /// The head bone for rotation. /// public Transform HeadBone; private Vector3 MovementDirection = new Vector3(); private Vector3 ServerPosition = new Vector3(); private bool ServerPositionShouldLerpSync = false; private Vector3 ServerRotation = new Vector3(); private bool ServerRotationShouldLerpSync = 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 HeadBoneRot = HeadBone.localEulerAngles; HeadBoneRot.z = EulerAngles.x; HeadBone.localEulerAngles = HeadBoneRot; Vector3 BodyRot = transform.localEulerAngles; BodyRot.y = EulerAngles.y; transform.localEulerAngles = BodyRot; } /// /// Sets the position of this character. /// /// Position. public void SetPosition(Vector3 Position) { transform.position = Position; } /// /// Whether the player is moving or not. /// public bool Moving() { return MovementDirection.sqrMagnitude != 0; } /// /// Returns the current movement direction; /// /// The Movement Direction Vector3 public Vector3 GetMovementDirection() { return MovementDirection; } /// /// 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); } /// /// Returns the position of this character. /// /// The position. public Vector3 GetPosition() { return transform.position; } /// /// 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(); ServerRotation = reader.ReadVector3(); float Drift = (ServerPosition - GetPosition()).magnitude; // Update position if this is the local player Character LocalCharacter = Client.GetConnectedPlayer().Character; if (Drift > MovementSpeed * 0.5f && LocalCharacter.Equals(this)) { SetPosition(ServerPosition); MovementDirection = ServerMovementDirection; } // Update position and rotation more often (with lerping) // if this is not the local player ServerRotationShouldLerpSync = !LocalCharacter.Equals(this); ServerPositionShouldLerpSync = !LocalCharacter.Equals(this) && Drift > 0.1; } /// /// Serializes the character. /// /// public override void Serialize(NetworkWriter writer) { writer.Write(GetPosition()); writer.Write(MovementDirection); writer.Write(GetRotation()); } private void Update() { if (ServerPositionShouldLerpSync) { SetPosition(Vector3.Lerp(GetPosition(), ServerPosition, 10f * Time.deltaTime)); } if (ServerRotationShouldLerpSync) { Quaternion ServerRot = Quaternion.Euler(ServerRotation); Quaternion LocalRot = Quaternion.Euler(GetRotation()); Vector3 NewRot = Quaternion.Lerp(LocalRot, ServerRot, 10f * Time.deltaTime).eulerAngles; SetRotation(NewRot); } } private void FixedUpdate() { CharacterController.Move(MovementDirection * MovementSpeed * Time.fixedDeltaTime); } } }