OMRViewModelAimAlignment.cs
using Sandbox;
using System;

/// <summary>
/// Attachment-aware ADS correction applied from OneMoreRoundWeapon.PlaceViewModel.
///
/// IMPORTANT: this class never samples a world-space bone after the viewmodel root has
/// been moved. OneMoreRoundWeapon supplies a root-relative lens pose captured before
/// BaseCombatWeapon.PlaceViewModel. That makes centering independent of the previous
/// frame's root transform and avoids the A/B oscillation that was visible while strafing.
/// </summary>
[Title( "OMR Viewmodel Aim Alignment" )]
public sealed class OMRViewModelAimAlignment : Component
{
	[Property, Group( "Diagnostics" )]
	public bool LogCorrection { get; set; } = false;

	public float CurrentBlend { get; private set; }
	public Vector3 CurrentCorrection { get; private set; }
	public bool HasCapturedEyeRelief { get; private set; }
	public bool EyeReliefGuardActive { get; private set; }
	public float CapturedEyeReliefDepth { get; private set; }
	public float CurrentEyeReliefDepth { get; private set; }
	private float _nextLogAt;

	public void ApplyAlignment(
		OneMoreRoundWeapon weapon,
		CameraComponent camera,
		in CameraView view,
		in OMRViewModelBoneAnchor.RootRelativePose alignmentPose
	)
	{
		CurrentBlend = 0f;
		CurrentCorrection = Vector3.Zero;
		EyeReliefGuardActive = false;

		if (
			weapon is null ||
			!weapon.IsValid ||
			camera is null ||
			!camera.IsValid ||
			Scene is null ||
			Scene.Camera != camera ||
			weapon.ViewModel != GameObject
		)
		{
			ResetEyeReliefCapture();
			return;
		}

		OMROpticProfile profile = weapon.ActiveOpticProfile;
		if (
			profile is null ||
			!profile.IsValid ||
			!profile.EnableViewModelAimAlignment
		)
		{
			ResetEyeReliefCapture();
			return;
		}

		if ( !profile.ProtectViewModelEyeRelief && HasCapturedEyeRelief )
		{
			ResetEyeReliefCapture();
		}

		float blend = ResolveBlend( weapon.AimFraction, profile );
		CurrentBlend = blend;

		float alignmentStart = MathX.Clamp(
			profile.ViewModelAimAlignmentStart,
			0f,
			1f
		);

		if ( weapon.AimFraction <= alignmentStart + 0.0001f )
		{
			ResetEyeReliefCapture();
		}

		if ( blend <= 0.0001f )
			return;

		// BaseCombatWeapon has already pinned the root to this frame's final CameraView.
		// Rebuild the current optical-center position from the CURRENT root plus the
		// root-relative animated pose captured before the root moved.
		Vector3 predictedAnchorWorld = GameObject.WorldTransform.PointToWorld(
			alignmentPose.Position
		);

		Rotation cameraRotation = view.Rotation;
		Vector3 cameraPosition = view.Position;
		Vector3 cameraToAnchor = predictedAnchorWorld - cameraPosition;

		float currentRight = Vector3.Dot(
			cameraToAnchor,
			cameraRotation.Right
		);

		float currentUp = Vector3.Dot(
			cameraToAnchor,
			cameraRotation.Up
		);

		float currentForward = Vector3.Dot(
			cameraToAnchor,
			cameraRotation.Forward
		);

		CurrentEyeReliefDepth = currentForward;

		float depthCorrection = profile.ViewModelAimDepthOffset;

		if ( profile.ProtectViewModelEyeRelief )
		{
			float captureThreshold = MathX.Clamp(
				profile.ViewModelEyeReliefCaptureThreshold,
				0f,
				1f
			);

			if (
				!HasCapturedEyeRelief &&
				weapon.AimFraction >= captureThreshold
			)
			{
				HasCapturedEyeRelief = true;
				CapturedEyeReliefDepth = currentForward;
			}

			if ( HasCapturedEyeRelief )
			{
				float tolerance = MathF.Max(
					profile.ViewModelEyeReliefTolerance,
					0f
				);

				float minimumDepth =
					CapturedEyeReliefDepth - tolerance;

				if ( currentForward < minimumDepth )
				{
					depthCorrection += minimumDepth - currentForward;
					EyeReliefGuardActive = true;
				}
			}
		}

		Vector2 target = profile.ViewModelAimScreenOffset;

		Vector3 fullCorrection =
			cameraRotation.Right * (target.x - currentRight) +
			cameraRotation.Up * (target.y - currentUp) +
			cameraRotation.Forward * depthCorrection;

		Vector3 applied = fullCorrection * blend;

		// Always rebuild from the canonical camera baseline. Never += the previous
		// root transform, and never measure against a helper that we just moved.
		GameObject.WorldPosition = cameraPosition + applied;
		GameObject.WorldRotation = cameraRotation;

		CurrentCorrection = applied;

		if ( LogCorrection && RealTime.Now >= _nextLogAt )
		{
			_nextLogAt = RealTime.Now + 0.5f;
			Log.Info(
				$"[OMR VM ALIGN] Weapon:{weapon.WeaponId} | " +
				$"Aim:{weapon.AimFraction:0.###} | Blend:{blend:0.###} | " +
				$"AnchorPlane:({currentRight:0.###},{currentUp:0.###}) | " +
				$"Depth:{currentForward:0.###} | EyeBase:{(HasCapturedEyeRelief ? CapturedEyeReliefDepth : -1f):0.###} | " +
				$"EyeGuard:{EyeReliefGuardActive} | Correction:{applied}"
			);
		}
	}

	private void ResetEyeReliefCapture()
	{
		HasCapturedEyeRelief = false;
		EyeReliefGuardActive = false;
		CapturedEyeReliefDepth = 0f;
	}

	private static float ResolveBlend(
		float aimFraction,
		OMROpticProfile profile
	)
	{
		float start = MathX.Clamp(
			profile.ViewModelAimAlignmentStart,
			0f,
			1f
		);

		float full = MathX.Clamp(
			profile.ViewModelAimAlignmentFull,
			start,
			1f
		);

		float t;

		if ( full <= start + 0.0001f )
		{
			t = aimFraction >= full ? 1f : 0f;
		}
		else
		{
			t = MathX.Clamp(
				(aimFraction - start) / (full - start),
				0f,
				1f
			);
		}

		return t * t * (3f - 2f * t);
	}
}