Code/CameraUtilities.cs
using Sandbox;
using System;

namespace EZCameraShake
{
    public class CameraUtilities
    {
		/// <summary>
		/// Smoothes a Vector3 that represents euler angles.
		/// </summary>
		/// <param name="current">The current Vector3 value.</param>
		/// <param name="target">The target Vector3 value.</param>
		/// <param name="velocity">A refernce Vector3 used internally.</param>
		/// <param name="smoothTime">The time to smooth, in seconds.</param>
		/// <returns>The smoothed Vector3 value.</returns>
		public static Vector3 SmoothDampEuler( Vector3 current, Vector3 target, ref Vector3 velocity, float smoothTime, float deltaTime )
		{
			float velocityX = velocity.x;
			float velocityY = velocity.y;
			float velocityZ = velocity.z;

			float x = MathExtensions.SmoothDampAngle( current.x, target.x, ref velocityX, smoothTime, deltaTime );
			float y = MathExtensions.SmoothDampAngle( current.y, target.y, ref velocityY, smoothTime, deltaTime );
			float z = MathExtensions.SmoothDampAngle( current.z, target.z, ref velocityZ, smoothTime, deltaTime );

			velocity = new Vector3( velocityX, velocityY, velocityZ );

			return new Vector3( x, y, z );
		}


		/// <summary>
		/// Multiplies each element in Vector3 v by the corresponding element of w.
		/// </summary>
		public static Vector3 MultiplyVectors(Vector3 v, Vector3 w)
        {
            v.x *= w.x;
            v.y *= w.y;
            v.z *= w.z;

            return v;
        }
    }
}

public static class MathExtensions
{
	public static float SmoothDampAngle( float current, float target, ref float currentVelocity, float smoothTime, float deltaTime, float maxSpeed = float.PositiveInfinity )
	{
		// Ensure smoothTime is never too small
		smoothTime = Math.Max( 0.0001f, smoothTime );

		// Calculate the difference between the current and target angles
		float deltaAngle = MathfDeltaAngle( current, target );

		// Calculate the desired target position by adding deltaAngle to the current angle
		target = current + deltaAngle;

		// SmoothDamp logic for interpolating between angles
		float result = SmoothDamp( current, target, ref currentVelocity, smoothTime, deltaTime, maxSpeed );

		return result;
	}

	// SmoothDamp function: interpolates between two values using velocity and smooth time
	public static float SmoothDamp( float current, float target, ref float currentVelocity, float smoothTime, float deltaTime, float maxSpeed = float.PositiveInfinity )
	{
		// Similar to Mathf.SmoothDamp logic in Unity
		float num = 2f / smoothTime;
		float num2 = num * deltaTime;
		float num3 = 1f / (1f + num2 + 0.48f * num2 * num2 + 0.235f * num2 * num2 * num2);
		float num4 = current - target;
		float num5 = target;
		float maxDelta = maxSpeed * smoothTime;
		num4 = Clamp( num4, -maxDelta, maxDelta );
		target = current - num4;
		float num7 = (currentVelocity + num * num4) * deltaTime;
		currentVelocity = (currentVelocity - num * num7) * num3;
		float num8 = target + (num4 + num7) * num3;

		// Prevent overshooting
		if ( num5 - current > 0f == num8 > num5 )
		{
			num8 = num5;
			currentVelocity = (num8 - num5) / deltaTime;
		}
		return num8;
	}

	// Function to calculate the shortest difference between two angles, handling wrap-around
	public static float MathfDeltaAngle( float current, float target )
	{
		float delta = target - current;
		while ( delta < -180f ) delta += 360f;
		while ( delta > 180f ) delta -= 360f;
		return delta;
	}

	// Clamp function to restrict values between min and max
	public static float Clamp( float value, float min, float max )
	{
		if ( value < min ) return min;
		if ( value > max ) return max;
		return value;
	}
}