201 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			201 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | namespace TPSBR | ||
|  | { | ||
|  | 	using System; | ||
|  | 	using UnityEngine; | ||
|  | 	using UnityEngine.Animations; | ||
|  | 	using UnityEngine.Playables; | ||
|  | 	using Fusion.Addons.KCC; | ||
|  | 	using Fusion.Addons.AnimationController; | ||
|  | 
 | ||
|  | 	using AnimationState = Fusion.Addons.AnimationController.AnimationState; | ||
|  | 
 | ||
|  | 	public sealed unsafe class TurnState : AnimationState | ||
|  | 	{ | ||
|  | 		// PUBLIC MEMBERS | ||
|  | 
 | ||
|  | 		public float BlendSpeed => _blendSpeed; | ||
|  | 		public float TurnSpeed  => _turnSpeed; | ||
|  | 
 | ||
|  | 		[NonSerialized][AnimationProperty(nameof(InterpolateAnimationTime))] | ||
|  | 		public float AnimationTime; | ||
|  | 		[NonSerialized][AnimationProperty(nameof(InterpolateRemainingTime))] | ||
|  | 		public float RemainingTime; | ||
|  | 		[NonSerialized] | ||
|  | 		public float InterpolatedAnimationTime; | ||
|  | 		[NonSerialized] | ||
|  | 		public float InterpolatedRemainingTime; | ||
|  | 
 | ||
|  | 		// PRIVATE MEMBERS | ||
|  | 
 | ||
|  | 		[SerializeField] | ||
|  | 		private ClipNode[] _nodes; | ||
|  | 		[SerializeField] | ||
|  | 		private float      _blendSpeed = 1.0f; | ||
|  | 		[SerializeField] | ||
|  | 		private float      _turnSpeed = 1.0f; | ||
|  | 		[SerializeField] | ||
|  | 		private float      _animationPower = 1.0f; | ||
|  | 		[SerializeField] | ||
|  | 		private float      _maxAnimationSpeed = 1.0f; | ||
|  | 
 | ||
|  | 		private KCC                    _kcc; | ||
|  | 		private Agent                  _agent; | ||
|  | 		private Weapons                _weapons; | ||
|  | 		private AnimationMixerPlayable _mixer; | ||
|  | 
 | ||
|  | 		// PUBLIC METHODS | ||
|  | 
 | ||
|  | 		public void Refresh(float angle) | ||
|  | 		{ | ||
|  | 			if (angle < 0.0f && RemainingTime <= 0.0f) | ||
|  | 			{ | ||
|  | 				RemainingTime = Mathf.Clamp(RemainingTime + angle * _turnSpeed, -_maxAnimationSpeed, 0.0f); | ||
|  | 			} | ||
|  | 			if (angle > 0.0f && RemainingTime >= 0.0f) | ||
|  | 			{ | ||
|  | 				RemainingTime = Mathf.Clamp(RemainingTime + angle * _turnSpeed, 0.0f, _maxAnimationSpeed); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// AnimationState INTERFACE | ||
|  | 
 | ||
|  | 		protected override void CreatePlayable() | ||
|  | 		{ | ||
|  | 			_mixer = AnimationMixerPlayable.Create(Controller.Graph, _nodes.Length); | ||
|  | 
 | ||
|  | 			for (int i = 0, count = _nodes.Length; i < count; ++i) | ||
|  | 			{ | ||
|  | 				ClipNode node = _nodes[i]; | ||
|  | 
 | ||
|  | 				node.CreatePlayable(Controller.Graph); | ||
|  | 
 | ||
|  | 				_mixer.ConnectInput(i, node.PlayableClip, 0); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			AddPlayable(_mixer, 0); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		protected override void OnInitialize() | ||
|  | 		{ | ||
|  | 			base.OnInitialize(); | ||
|  | 
 | ||
|  | 			_kcc     = Controller.GetComponentNoAlloc<KCC>(); | ||
|  | 			_agent   = Controller.GetComponentNoAlloc<Agent>(); | ||
|  | 			_weapons = Controller.GetComponentNoAlloc<Weapons>(); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		protected override void OnDespawned() | ||
|  | 		{ | ||
|  | 			if (_mixer.IsValid() == true) | ||
|  | 			{ | ||
|  | 				_mixer.Destroy(); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			for (int i = 0, count = _nodes.Length; i < count; ++i) | ||
|  | 			{ | ||
|  | 				_nodes[i].DestroyPlayable(); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  | 		protected override void OnFixedUpdate() | ||
|  | 		{ | ||
|  | 			int idleClipID = GetClipID(); | ||
|  | 			int turnClipID; | ||
|  | 
 | ||
|  | 			float remainingTime = Mathf.Abs(RemainingTime); | ||
|  | 
 | ||
|  | 			float remainingDeltaTime = Controller.DeltaTime * Mathf.Max(0.5f, remainingTime); | ||
|  | 			float animationDeltaTime = Controller.DeltaTime * remainingTime; | ||
|  | 
 | ||
|  | 			if (RemainingTime <= 0.0f) | ||
|  | 			{ | ||
|  | 				turnClipID = idleClipID + 1; | ||
|  | 				RemainingTime = Mathf.Clamp(RemainingTime + remainingDeltaTime * _blendSpeed, -_maxAnimationSpeed, 0.0f); | ||
|  | 			} | ||
|  | 			else | ||
|  | 			{ | ||
|  | 				turnClipID = idleClipID + 2; | ||
|  | 				RemainingTime = Mathf.Clamp(RemainingTime - remainingDeltaTime * _blendSpeed, 0.0f, _maxAnimationSpeed); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			for (int i = 0, count = _nodes.Length; i < count; ++i) | ||
|  | 			{ | ||
|  | 				_mixer.SetInputWeight(i, 0.0f); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			ClipNode idleNode = _nodes[idleClipID]; | ||
|  | 			ClipNode turnNode = _nodes[turnClipID]; | ||
|  | 
 | ||
|  | 			float animationTime = AnimationTime + animationDeltaTime * turnNode.Speed / turnNode.Length; | ||
|  | 			if (animationTime >= 1.0f) | ||
|  | 			{ | ||
|  | 				animationTime %= 1.0f; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			AnimationTime = animationTime; | ||
|  | 
 | ||
|  | 			_mixer.SetInputWeight(idleClipID, 1.0f - _animationPower); | ||
|  | 			_mixer.SetInputWeight(turnClipID, _animationPower); | ||
|  | 
 | ||
|  | 			idleNode.PlayableClip.SetTime(animationTime * idleNode.Length); | ||
|  | 			turnNode.PlayableClip.SetTime(animationTime * turnNode.Length); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		protected override void OnInterpolate() | ||
|  | 		{ | ||
|  | 			int idleClipID = GetClipID(); | ||
|  | 			int turnClipID = InterpolatedRemainingTime <= 0.0f ? (idleClipID + 1) : (idleClipID + 2); | ||
|  | 
 | ||
|  | 			for (int i = 0, count = _nodes.Length; i < count; ++i) | ||
|  | 			{ | ||
|  | 				_mixer.SetInputWeight(i, 0.0f); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			_mixer.SetInputWeight(idleClipID, 1.0f - _animationPower); | ||
|  | 			_mixer.SetInputWeight(turnClipID, _animationPower); | ||
|  | 
 | ||
|  | 			ClipNode idleNode = _nodes[idleClipID]; | ||
|  | 			idleNode.PlayableClip.SetTime(InterpolatedAnimationTime * idleNode.Length); | ||
|  | 
 | ||
|  | 			ClipNode turnNode = _nodes[turnClipID]; | ||
|  | 			turnNode.PlayableClip.SetTime(InterpolatedAnimationTime * turnNode.Length); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		protected override void OnDeactivate() | ||
|  | 		{ | ||
|  | 			RemainingTime = 0.0f; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		protected override void OnSetDefaults() | ||
|  | 		{ | ||
|  | 			AnimationTime = 0.0f; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// PRIVATE METHODS | ||
|  | 
 | ||
|  | 		private int GetClipID() | ||
|  | 		{ | ||
|  | 			int currentWeaponSlot = _weapons.CurrentWeaponSlot; | ||
|  | 			if (currentWeaponSlot > 2) | ||
|  | 			{ | ||
|  | 				currentWeaponSlot = 1; // For grenades we use pistol set | ||
|  | 			} | ||
|  | 
 | ||
|  | 			if (currentWeaponSlot < 0) | ||
|  | 				return 0; | ||
|  | 
 | ||
|  | 			return currentWeaponSlot * 3; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		private void InterpolateAnimationTime(AnimationInterpolationInfo interpolationInfo) | ||
|  | 		{ | ||
|  | 			InterpolatedAnimationTime = AnimationUtility.InterpolateTime(interpolationInfo.FromBuffer.ReinterpretState<float>(interpolationInfo.Offset), interpolationInfo.ToBuffer.ReinterpretState<float>(interpolationInfo.Offset), 1.0f, interpolationInfo.Alpha); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		private void InterpolateRemainingTime(AnimationInterpolationInfo interpolationInfo) | ||
|  | 		{ | ||
|  | 			InterpolatedRemainingTime = Mathf.LerpUnclamped(interpolationInfo.FromBuffer.ReinterpretState<float>(interpolationInfo.Offset), interpolationInfo.ToBuffer.ReinterpretState<float>(interpolationInfo.Offset), interpolationInfo.Alpha); | ||
|  | 		} | ||
|  | 	} | ||
|  | } |