using GameKit.Dependencies.Utilities; using System.Runtime.CompilerServices; using UnityEngine; namespace FishNet.Object.Prediction { /// /// Data to be used to configure smoothing for an owned predicted object. /// internal struct MoveRates { public float Position; public float Rotation; public float Scale; public MoveRates(float value) { Position = value; Rotation = value; Scale = value; } public MoveRates(float position, float rotation) { Position = position; Rotation = rotation; Scale = MoveRatesCls.INSTANT_VALUE; } public MoveRates(float position, float rotation, float scale) { Position = position; Rotation = rotation; Scale = scale; } /// /// True if a positional move rate is set. /// public bool PositionSet => (Position != MoveRatesCls.UNSET_VALUE); /// /// True if rotation move rate is set. /// public bool RotationSet => (Rotation != MoveRatesCls.UNSET_VALUE); /// /// True if a scale move rate is set. /// public bool ScaleSet => (Scale != MoveRatesCls.UNSET_VALUE); /// /// True if any move rate is set. /// public bool AnySet => (PositionSet || RotationSet || ScaleSet); /// /// True if position move rate should be instant. /// public bool InstantPosition => (Position == MoveRatesCls.INSTANT_VALUE); /// /// True if rotation move rate should be instant. /// public bool InstantRotation => (Rotation == MoveRatesCls.INSTANT_VALUE); /// /// True if scale move rate should be instant. /// public bool InstantScale => (Scale == MoveRatesCls.INSTANT_VALUE); /// /// Sets all rates to instant. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetInstantRates() { Update(MoveRatesCls.INSTANT_VALUE); } /// /// Sets all rates to the same value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Update(float value) { Update(value, value, value); } /// /// Sets rates for each property. /// public void Update(float position, float rotation, float scale) { Position = position; Rotation = rotation; Scale = scale; } /// /// Returns a new MoveRates based on previous values, and a transforms current position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static MoveRates GetWorldMoveRates(Transform from, Transform to, float duration, float teleportThreshold) { return GetMoveRates(from.position, to.position, from.rotation, to.rotation, from.localScale, to.localScale, duration, teleportThreshold); } /// /// Returns a new MoveRates based on previous values, and a transforms current position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static MoveRates GetLocalMoveRates(Transform from, Transform to, float duration, float teleportThreshold) { return GetMoveRates(from.localPosition, to.localPosition, from.localRotation, to.localRotation, from.localScale, to.localScale, duration, teleportThreshold); } /// /// Returns a new MoveRates based on previous values, and a transforms current position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static MoveRates GetWorldMoveRates(TransformProperties prevValues, Transform t, float duration, float teleportThreshold) { return GetMoveRates(prevValues.Position, t.position, prevValues.Rotation, t.rotation, prevValues.LocalScale, t.localScale, duration, teleportThreshold); } /// /// Returns a new MoveRates based on previous values, and a transforms current position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static MoveRates GetLocalMoveRates(TransformProperties prevValues, Transform t, float duration, float teleportThreshold) { return GetMoveRates(prevValues.Position, t.localPosition, prevValues.Rotation, t.localRotation, prevValues.LocalScale, t.localScale, duration, teleportThreshold); } /// /// Returns a new MoveRates based on previous values, and a transforms current position. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static MoveRates GetMoveRates(Vector3 fromPosition, Vector3 toPosition, Quaternion fromRotation, Quaternion toRotation, Vector3 fromScale, Vector3 toScale, float duration, float teleportThreshold) { float rate; float distance; /* Position. */ rate = toPosition.GetRate(fromPosition, duration, out distance); //Basic teleport check. if (teleportThreshold != MoveRatesCls.UNSET_VALUE && distance > teleportThreshold) { return new MoveRates(MoveRatesCls.INSTANT_VALUE); } //Smoothing. else { float positionRate = rate.SetIfUnderTolerance(0.0001f, MoveRatesCls.INSTANT_VALUE); rate = toRotation.GetRate(fromRotation, duration, out _); float rotationRate = rate.SetIfUnderTolerance(0.2f, MoveRatesCls.INSTANT_VALUE); rate = toScale.GetRate(fromScale, duration, out _); float scaleRate = rate.SetIfUnderTolerance(0.0001f, MoveRatesCls.INSTANT_VALUE); return new MoveRates(positionRate, rotationRate, scaleRate); } } /// /// Gets a move rate for two Vector3s. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMoveRate(Vector3 fromPosition, Vector3 toPosition, float duration, float teleportThreshold) { float rate; float distance; /* Position. */ rate = toPosition.GetRate(fromPosition, duration, out distance); //Basic teleport check. if (teleportThreshold != MoveRatesCls.UNSET_VALUE && distance > teleportThreshold) { return MoveRatesCls.INSTANT_VALUE; } //Smoothing. else { float positionRate = rate.SetIfUnderTolerance(0.0001f, MoveRatesCls.INSTANT_VALUE); return positionRate; } } /// /// Gets a move rate for two Quaternions. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetMoveRate(Quaternion fromRotation, Quaternion toRotation, float duration) { float rate = toRotation.GetRate(fromRotation, duration, out _); float rotationRate = rate.SetIfUnderTolerance(0.2f, MoveRatesCls.INSTANT_VALUE); return rotationRate; } /// /// Moves transform to target values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MoveLocalToTarget(Transform movingTransform, TransformProperties goalProperties, float delta) { //No rates are set. if (!AnySet) return; MoveRatesCls.MoveLocalToTarget(movingTransform, goalProperties.Position, Position, goalProperties.Rotation, Rotation, goalProperties.LocalScale, Scale, delta); } /// /// Moves transform to target values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MoveWorldToTarget(Transform movingTransform, TransformProperties goalProperties, float delta) { //No rates are set. if (!AnySet) return; MoveRatesCls.MoveWorldToTarget(movingTransform, goalProperties.Position, Position, goalProperties.Rotation, Rotation, goalProperties.LocalScale, Scale, delta); } } /// /// Data to be used to configure smoothing for an owned predicted object. /// internal class MoveRatesCls : IResettable { public float Position; public float Rotation; public float Scale; public MoveRatesCls(float value) { Position = value; Rotation = value; Scale = value; } public MoveRatesCls(float position, float rotation) { Position = position; Rotation = rotation; Scale = INSTANT_VALUE; } public MoveRatesCls(float position, float rotation, float scale) { Position = position; Rotation = rotation; Scale = scale; } /// /// True if a positional move rate is set. /// public bool PositionSet => (Position != UNSET_VALUE); /// /// True if rotation move rate is set. /// public bool RotationSet => (Rotation != UNSET_VALUE); /// /// True if a scale move rate is set. /// public bool ScaleSet => (Scale != UNSET_VALUE); /// /// True if any move rate is set. /// public bool AnySet => (PositionSet || RotationSet || ScaleSet); /// /// True if position move rate should be instant. /// public bool InstantPosition => (Position == INSTANT_VALUE); /// /// True if rotation move rate should be instant. /// public bool InstantRotation => (Rotation == INSTANT_VALUE); /// /// True if scale move rate should be instant. /// public bool InstantScale => (Scale == INSTANT_VALUE); public MoveRatesCls() { Update(UNSET_VALUE, UNSET_VALUE, UNSET_VALUE); } /// /// Sets all rates to instant. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SetInstantRates() { Update(INSTANT_VALUE); } /// /// Sets all rates to the same value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Update(float value) { Update(value, value, value); } /// /// Updaes values. /// public void Update(float position, float rotation, float scale) { Position = position; Rotation = rotation; Scale = scale; } /// /// Updaes values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Update(MoveRatesCls mr) { Update(mr.Position, mr.Rotation, mr.Scale); } public void ResetState() { Position = UNSET_VALUE; Rotation = UNSET_VALUE; Scale = UNSET_VALUE; } public void InitializeState() { } /// /// Value used when data is not set. /// public const float UNSET_VALUE = float.NegativeInfinity; /// /// Value used when move rate should be instant. /// public const float INSTANT_VALUE = float.PositiveInfinity; /// /// Moves transform to target values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MoveLocalToTarget(Transform movingTransform, TransformPropertiesCls goalProperties, float delta) { //No rates are set. if (!AnySet) return; MoveRatesCls.MoveLocalToTarget(movingTransform, goalProperties.Position, Position, goalProperties.Rotation, Rotation, goalProperties.LocalScale, Scale, delta); } /// /// Moves transform to target values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MoveLocalToTarget(Transform movingTransform, Vector3 posGoal, float posRate, Quaternion rotGoal, float rotRate, Vector3 scaleGoal, float scaleRate, float delta) { Transform t = movingTransform; float rate; rate = posRate; if (rate == MoveRatesCls.INSTANT_VALUE) t.localPosition = posGoal; else t.localPosition = Vector3.MoveTowards(t.localPosition, posGoal, rate * delta); rate = rotRate; if (rate == MoveRatesCls.INSTANT_VALUE) t.localRotation = rotGoal; else t.localRotation = Quaternion.RotateTowards(t.localRotation, rotGoal, rate * delta); rate = scaleRate; if (rate == MoveRatesCls.INSTANT_VALUE) t.localScale = scaleGoal; else t.localScale = Vector3.MoveTowards(t.localScale, scaleGoal, rate * delta); } /// /// Moves transform to target values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MoveWorldToTarget(Transform movingTransform, Vector3 posGoal, float posRate, Quaternion rotGoal, float rotRate, Vector3 scaleGoal, float scaleRate, float delta) { Transform t = movingTransform; float rate; rate = posRate; if (rate == MoveRatesCls.INSTANT_VALUE) t.position = posGoal; else if (rate == MoveRatesCls.UNSET_VALUE) { } else t.position = Vector3.MoveTowards(t.position, posGoal, rate * delta); rate = rotRate; if (rate == MoveRatesCls.INSTANT_VALUE) t.rotation = rotGoal; else if (rate == MoveRatesCls.UNSET_VALUE) { } else t.rotation = Quaternion.RotateTowards(t.rotation, rotGoal, rate * delta); rate = scaleRate; if (rate == MoveRatesCls.INSTANT_VALUE) t.localScale = scaleGoal; else if (rate == MoveRatesCls.UNSET_VALUE) { } else t.localScale = Vector3.MoveTowards(t.localScale, scaleGoal, rate * delta); } } }