using System; using System.Collections; using System.Collections.Generic; using System.Linq; using RootMotion.FinalIK; using UnityEngine; using UnityStandardAssets.Characters.FirstPerson; public class FullBodyAvatar : MonoBehaviour { public enum AnimatorLayers { Movement = 0, ThirdPersonView = 1, RightHand = 2, PullUp = 3, LeftHand = 4, HandsRotationFish = 5, HandsRotationFishVertical = 6, RightHandFingers = 7 } public enum FishOnRod { None = 0, Hook = 1 } public enum FingersRight { Idle = 0, OnRodLoose = 1, OnRodTight = 2 } public enum FingersLeft { Idle = 0, OnReelHandle = 1 } public enum ThrowMethod { Far = 0, Near = 1 } public enum ArmLeft { Idle = 0, IK = 1, CastNear = 2, Catch = 3, CatchChwytak = 4 } public enum TPPAnimation { Idle = 0, MiddleFishView = 1, BigFishView = 2, ThrowFar = 3, ThrowNear = 4, RodJam = 5, Take = 6, PutDown = 7 } [Serializable] public struct AvatarSetup { public Avatar avatar; public List renderers; public Transform armatureBoneNeck; public ArmIK leftArm_ArmIK; public ArmIK leftArm_HandIK; public ArmIK rightArm_ArmIK; public ArmIK rightArm_HandIK; public Transform cameraPoint; public Transform rHandRodJoiner; public Transform lHandLineJoiner; public Transform lHandLineJoinerFish; public Transform lHandChwytakJoiner; public Transform fishInArmsPoint; } [SerializeField] private Animator animator; [SerializeField] private AvatarSetup maleSetup; [SerializeField] private AvatarSetup femaleSetup; [SerializeField] [Tooltip("Adjusts the momentum of animator state transitions in the Movement layer; higher values result in faster changes, while lower values produce smoother movements")] private float animatorMovementMomentum = 0.1f; [SerializeField] [Tooltip("Controls the speed at which hands are attached or detached from IK targets")] private float IKWeightChangeSpeed = 2f; private static FullBodyAvatar existingPlayerAvatar; private static List existingRemotePlayerAvatars; private Dictionary originalLayerWeights; private Coroutine layerWeightsChangeCoroutine; private float forward; private float right; private float angular; private Quaternion lastRotation; private bool isJumping; private Transform leftArm_IKTarget; private Vector3 leftArm_IKTargetPos; private Quaternion leftArm_IKTargetRot; private float leftArm_Lerp; private bool leftArm_IKWithRotation; private bool leftArm_IKByHand; private Transform rightArm_IKTarget; private Vector3 rightArm_IKTargetPos; private Quaternion rightArm_IKTargetRot; private float rightArm_Lerp; private bool rightArm_IKWithRotation; private bool rightArm_IKByHand; private int RightIdle_Rod; private int FishingHandsUp; public Transform CameraPoint => CurrentAvatarSetup.cameraPoint; public Transform RodJoiner => CurrentAvatarSetup.rHandRodJoiner; public Transform LineJoiner => CurrentAvatarSetup.lHandLineJoiner; public Transform LineJoinerFish => CurrentAvatarSetup.lHandLineJoinerFish; public Transform ChwytakJoiner => CurrentAvatarSetup.lHandChwytakJoiner; public Transform FishInArms => CurrentAvatarSetup.fishInArmsPoint; public bool IsThrowInProgress { get { if (!animator.GetBool("RightHand_ReelUnlock") && !animator.GetBool("RightHand_ThrowFar")) { return animator.GetBool("RightHand_ThrowNear"); } return true; } } public bool IsRodFishing { get { int shortNameHash = animator.GetCurrentAnimatorStateInfo(2).shortNameHash; if (shortNameHash == RightIdle_Rod || shortNameHash == FishingHandsUp) { return animator.GetLayerWeight(6) > 0f; } return false; } } public bool IsJumping => isJumping; public bool TPPMovement { get; set; } public float AnimatorMovementMomentum { get { if (TPPMovement) { return animatorMovementMomentum * 3f; } return animatorMovementMomentum; } } public FingersRight CurrentFingersRightState { get; private set; } public FingersLeft CurrentFingersLeftState { get; private set; } public ArmLeft CurrentArmLeftState { get; private set; } public AvatarSetup CurrentAvatarSetup { get; private set; } public TPPAnimation CurrentTPPAnimation { get; private set; } public static FullBodyAvatar ExistingPlayerAvatar { get { return existingPlayerAvatar; } private set { existingPlayerAvatar = value; } } public static List ExistingRemotePlayerAvatars { get { if (existingRemotePlayerAvatars == null) { existingRemotePlayerAvatars = new List(); } existingRemotePlayerAvatars.RemoveAll((FullBodyAvatar element) => element == null); return existingRemotePlayerAvatars; } } public static FullBodyAvatar GetAvatar() { if (!ExistingPlayerAvatar) { ExistingPlayerAvatar = UnityEngine.Object.FindObjectsByType(FindObjectsInactive.Exclude, FindObjectsSortMode.InstanceID).FirstOrDefault((FullBodyAvatar element) => !ExistingRemotePlayerAvatars.Contains(element)); if (ExistingPlayerAvatar == null) { ExistingPlayerAvatar = UnityEngine.Object.Instantiate(Resources.Load("FullBodyAvatar")).GetComponent(); } ExistingPlayerAvatar.animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; } return ExistingPlayerAvatar; } public static FullBodyAvatar GetAvatarRemote() { GameObject gameObject = UnityEngine.Object.Instantiate(Resources.Load("FullBodyAvatar")); ExistingRemotePlayerAvatars.Add(gameObject.GetComponent()); ExistingRemotePlayerAvatars.Last().animator.cullingMode = AnimatorCullingMode.CullUpdateTransforms; return ExistingRemotePlayerAvatars.Last(); } public void SetGender(bool male = true) { DisableSetup(maleSetup); DisableSetup(femaleSetup); CurrentAvatarSetup = (male ? maleSetup : femaleSetup); EnableSetup(CurrentAvatarSetup); Vector3 zero = Vector3.zero; if (!male) { zero.x = 3f; } animator.transform.localEulerAngles = zero; static void DisableSetup(AvatarSetup avatarSetup) { avatarSetup.renderers.ForEach(delegate(Renderer element) { element.enabled = false; }); avatarSetup.leftArm_ArmIK.gameObject.SetActive(value: false); avatarSetup.rightArm_ArmIK.gameObject.SetActive(value: false); } void EnableSetup(AvatarSetup avatarSetup) { avatarSetup.renderers.ForEach(delegate(Renderer element) { element.enabled = true; }); avatarSetup.leftArm_ArmIK.gameObject.SetActive(value: true); avatarSetup.rightArm_ArmIK.gameObject.SetActive(value: true); animator.avatar = avatarSetup.avatar; } } public void ShowHead(bool toggle = true) { if (toggle) { CurrentAvatarSetup.armatureBoneNeck.localScale = Vector3.one; } else { CurrentAvatarSetup.armatureBoneNeck.localScale = new Vector3(1f, 0f, 0f); } } public void MovementAnimation(FirstPersonController firstPersonController, Vector3 baselineVelocity) { MovementAnimation(firstPersonController.transform.forward, firstPersonController.transform.right, firstPersonController.m_CharacterController.velocity, baselineVelocity, firstPersonController.m_WalkSpeed, firstPersonController.m_RunSpeed); } public void MovementAnimation(Vector3 orientationForward, Vector3 orientationRight, Vector3 velocity, Vector3 baselineVelocity, float walkSpeed, float runSpeed) { velocity.y = 0f; baselineVelocity.y = 0f; velocity -= baselineVelocity; float num = Vector3.Dot(velocity, orientationForward); float num2 = Vector3.Dot(velocity, orientationRight); num /= walkSpeed; num2 /= walkSpeed; forward = Mathf.Lerp(forward, num, AnimatorMovementMomentum); right = Mathf.Lerp(right, num2, AnimatorMovementMomentum); forward = Mathf.Clamp(forward, -1f, 1.3f); right = Mathf.Clamp(right, -1f, 1f); if (float.IsNaN(forward)) { forward = 0f; } if (float.IsNaN(right)) { right = 0f; } animator.SetFloat("Movement_PlayerWalk", (Mathf.Abs(forward) < 0.01f) ? 0f : forward); animator.SetFloat("Movement_PlayerStrafe", (Mathf.Abs(right) < 0.01f) ? 0f : right); Quaternion rotation = base.transform.rotation; (Quaternion.Inverse(lastRotation) * rotation).ToAngleAxis(out var angle, out var axis); angle = ((angle > 180f) ? (angle - 360f) : angle); if (axis.y < 0f) { angle = 0f - angle; } if (Time.deltaTime > 0f) { angular = Mathf.Lerp(angular, angle / Time.deltaTime, AnimatorMovementMomentum); } lastRotation = rotation; animator.SetFloat("Movement_PlayerRotate", angular); bool num3 = velocity.magnitude > walkSpeed; float num4 = 1f; num4 = (num3 ? Mathf.Lerp(1.2f, 1.8f, velocity.magnitude / runSpeed) : ((!(velocity.magnitude > 0.001f)) ? 1f : Mathf.Lerp(0.7f, 1.2f, velocity.magnitude / runSpeed))); if ((double)num4 < 0.1) { num4 = 0f; } animator.SetFloat("Movement_MultiplierVelocity", num4); float num5 = Mathf.Clamp01(Mathf.Abs(angular) / 90f); if ((double)num5 < 0.1) { num5 = 0f; } animator.SetFloat("Movement_MultiplierAngular", num5); } public void HandsIdle() { if (CurrentTPPAnimation == TPPAnimation.Idle) { RodPullUp(0f); RodAngle(); RightArmIK(); LeftArmIK(); SetFingersRight(FingersRight.Idle); SetFingersLeft(FingersLeft.Idle); SetFishOnRod(FishOnRod.None); ReelLockUnlockReset(); ThrowReset(); LeftArmControl(ArmLeft.Idle); } } public void SetFishOnRod(FishOnRod fishOnRod) { switch (fishOnRod) { case FishOnRod.None: animator.SetBool("RightHand_isCatch", value: false); animator.SetBool("RightHand_isFish", value: false); break; case FishOnRod.Hook: animator.SetBool("RightHand_isCatch", value: false); animator.SetBool("RightHand_isFish", value: true); break; } } public void ShowRod(bool bySlot = true) { if (bySlot) { animator.SetTrigger("RightHand_ShowRodBySlot"); } else { animator.SetTrigger("RightHand_GetRod"); } } public void HideRod(bool bySlot = true) { if (bySlot) { animator.SetTrigger("RightHand_HideRodToSlot"); } else { animator.SetTrigger("RightHand_DropRod"); } } public void SetFingersRight(FingersRight fingers) { CurrentFingersRightState = fingers; switch (fingers) { case FingersRight.Idle: animator.SetBool("RightHandFingers_OnRod", value: false); animator.SetBool("RightHandFingers_OnRodPowered", value: false); break; case FingersRight.OnRodLoose: animator.SetBool("RightHandFingers_OnRod", value: true); animator.SetBool("RightHandFingers_OnRodPowered", value: false); break; case FingersRight.OnRodTight: animator.SetBool("RightHandFingers_OnRod", value: true); animator.SetBool("RightHandFingers_OnRodPowered", value: true); break; } } public void SetFingersLeft(FingersLeft fingers) { CurrentFingersLeftState = fingers; switch (fingers) { case FingersLeft.Idle: animator.SetBool("LeftHand_OnReel", value: false); break; case FingersLeft.OnReelHandle: animator.SetBool("LeftHand_OnReel", value: true); break; } } public void RodPullUp(float amount, float weight = 0f) { float layerWeight = animator.GetLayerWeight(3); if (layerWeight != weight) { animator.SetLayerWeight(3, Mathf.MoveTowards(layerWeight, weight, Time.deltaTime * 4f)); } float min = 0.02f; amount = Mathf.Clamp(amount, min, 1f); animator.Play("PullUpRodFishing", 3, amount); } public void RodAngle(float amountHorizontal = 0f, float amountVertical = 0f, float weightHorizontal = 0f, float weightVertical = 0f) { float layerWeight = animator.GetLayerWeight(5); float layerWeight2 = animator.GetLayerWeight(6); if (layerWeight != weightHorizontal || layerWeight2 != weightVertical) { animator.SetLayerWeight(5, Mathf.MoveTowards(layerWeight, weightHorizontal, Time.deltaTime * 4f)); animator.SetLayerWeight(6, Mathf.MoveTowards(layerWeight2, weightVertical, Time.deltaTime * 4f)); } amountHorizontal = Mathf.Clamp(amountHorizontal, -1f, 1f); amountVertical = Mathf.Clamp(amountVertical, -1f, 1f); float num = 0.02f; if (Mathf.Abs(amountVertical) < num) { amountVertical = ((!(amountVertical >= 0f)) ? (0f - num) : num); } if (amountHorizontal > 0f) { animator.Play("FishingHandsRightRot", 5, amountHorizontal); } else { animator.Play("FishingHandsLeftRot", 5, 0f - amountHorizontal); } if (amountVertical > 0f) { animator.Play("FishingHandsUpRot", 6, amountVertical); } else { animator.Play("FishingHandsDownRot", 6, 0f - amountVertical); } } public void ReelLockUnlockReset() { animator.SetBool("RightHand_ReelLock", value: false); animator.SetBool("RightHand_ReelUnlock", value: false); } public void ThrowReset() { animator.SetBool("RightHand_ThrowFar", value: false); animator.SetBool("RightHand_ThrowNear", value: false); } public void Throw(ThrowMethod throwMethod) { ReelLockUnlockReset(); ThrowReset(); switch (throwMethod) { case ThrowMethod.Far: animator.SetBool("RightHand_ReelUnlock", value: true); animator.SetBool("RightHand_ThrowFar", value: true); break; case ThrowMethod.Near: animator.SetBool("RightHand_ThrowNear", value: true); break; } } public void ReelControl(bool reelUnlock = false, bool reelLock = false) { animator.SetBool("RightHand_ReelUnlock", reelUnlock); animator.SetBool("RightHand_ReelLock", reelLock); } public void LeftArmControl(ArmLeft armLeft, Transform ikTarget = null) { LeftArmIK(); switch (armLeft) { case ArmLeft.Idle: animator.SetBool("LeftHand_PreCast", value: false); animator.SetBool("LeftHand_GrabLineFish", value: false); animator.SetBool("LeftHand_isFishChwytak", value: false); break; case ArmLeft.IK: animator.SetBool("LeftHand_PreCast", value: false); animator.SetBool("LeftHand_GrabLineFish", value: false); animator.SetBool("LeftHand_isFishChwytak", value: false); if (ikTarget != null) { LeftArmIK(ikTarget); } break; case ArmLeft.CastNear: animator.SetBool("LeftHand_PreCast", value: true); animator.SetBool("LeftHand_GrabLineFish", value: false); animator.SetBool("LeftHand_isFishChwytak", value: false); break; case ArmLeft.Catch: animator.SetBool("LeftHand_PreCast", value: false); animator.SetBool("LeftHand_GrabLineFish", value: true); animator.SetBool("LeftHand_isFishChwytak", value: false); break; case ArmLeft.CatchChwytak: animator.SetBool("LeftHand_PreCast", value: false); animator.SetBool("LeftHand_GrabLineFish", value: false); animator.SetBool("LeftHand_isFishChwytak", value: true); break; } CurrentArmLeftState = armLeft; } public void LeftArmIK(Transform ikTarget = null, bool withRotation = false, bool byHand = false) { leftArm_IKTarget = ikTarget; leftArm_Lerp = 0f; leftArm_IKWithRotation = withRotation; leftArm_IKByHand = byHand; } public void RightArmIK(Transform ikTarget = null, bool withRotation = false, bool byHand = false) { rightArm_IKTarget = ikTarget; rightArm_Lerp = 0f; rightArm_IKWithRotation = withRotation; rightArm_IKByHand = byHand; } public void Jump() { if (!isJumping) { isJumping = true; animator.SetBool("Movement_Jump", value: true); } } public void Land() { if (isJumping) { isJumping = false; animator.SetBool("Movement_Jump", value: false); } } public void PlayTPPAnimation(TPPAnimation animation) { animator.SetBool("Movement_MFV", value: false); animator.SetBool("Movement_BFV", value: false); animator.SetBool("ThirdPersonView_ThrowFar", value: false); animator.SetBool("ThirdPersonView_ThrowNear", value: false); animator.SetBool("ThirdPersonView_ThrowRodJam", value: false); animator.SetBool("ThirdPersonView_Take", value: false); animator.SetBool("ThirdPersonView_PutDown", value: false); CurrentTPPAnimation = animation; switch (animation) { case TPPAnimation.Idle: RestoreOriginalLayerWeights(); break; case TPPAnimation.MiddleFishView: animator.SetBool("Movement_MFV", value: true); CullAllLayers(new List { AnimatorLayers.Movement }); break; case TPPAnimation.BigFishView: animator.SetBool("Movement_BFV", value: true); CullAllLayers(new List { AnimatorLayers.Movement }); break; case TPPAnimation.ThrowFar: animator.SetBool("ThirdPersonView_ThrowFar", value: true); CullAllLayers(new List { AnimatorLayers.Movement, AnimatorLayers.ThirdPersonView, AnimatorLayers.RightHandFingers }); break; case TPPAnimation.ThrowNear: animator.SetBool("ThirdPersonView_ThrowNear", value: true); CullAllLayers(new List { AnimatorLayers.Movement, AnimatorLayers.ThirdPersonView, AnimatorLayers.RightHandFingers }); break; case TPPAnimation.RodJam: animator.SetBool("ThirdPersonView_ThrowRodJam", value: true); CullAllLayers(new List { AnimatorLayers.Movement, AnimatorLayers.ThirdPersonView, AnimatorLayers.RightHandFingers }); break; case TPPAnimation.Take: animator.SetBool("ThirdPersonView_Take", value: true); CullAllLayers(new List { AnimatorLayers.Movement, AnimatorLayers.ThirdPersonView }); break; case TPPAnimation.PutDown: animator.SetBool("ThirdPersonView_PutDown", value: true); CullAllLayers(new List { AnimatorLayers.Movement, AnimatorLayers.ThirdPersonView }); break; } } public void LookAtFishInHand() { Vector3 eulerAngles = CurrentAvatarSetup.cameraPoint.eulerAngles; eulerAngles.x = 20f; CurrentAvatarSetup.cameraPoint.eulerAngles = eulerAngles; } public Transform GetBoneTransform(HumanBodyBones humanBodyBones) { return animator.GetBoneTransform(humanBodyBones); } private void Start() { originalLayerWeights = new Dictionary(); foreach (AnimatorLayers value in Enum.GetValues(typeof(AnimatorLayers))) { originalLayerWeights[value] = animator.GetLayerWeight((int)value); } lastRotation = base.transform.rotation; RightIdle_Rod = Animator.StringToHash("RightIdle_Rod"); FishingHandsUp = Animator.StringToHash("FishingHandsUp"); } private void Update() { SmoothIKUpdate(); } private void SmoothIKUpdate() { if (CurrentAvatarSetup.leftArm_ArmIK == null) { return; } ArmIK armIK; ArmIK armIK2; if (leftArm_IKByHand) { armIK = CurrentAvatarSetup.leftArm_HandIK; armIK2 = CurrentAvatarSetup.leftArm_ArmIK; } else { armIK = CurrentAvatarSetup.leftArm_ArmIK; armIK2 = CurrentAvatarSetup.leftArm_HandIK; } armIK.gameObject.SetActive(value: true); armIK2.gameObject.SetActive(value: false); armIK2.solver.IKPositionWeight = 0f; armIK2.solver.IKRotationWeight = 0f; if (leftArm_IKTarget != null) { leftArm_Lerp = Mathf.MoveTowards(leftArm_Lerp, 1f, Time.deltaTime * IKWeightChangeSpeed); leftArm_IKTargetPos = Vector3.Lerp(armIK.solver.IKPosition, leftArm_IKTarget.position, leftArm_Lerp); leftArm_IKTargetRot = Quaternion.Lerp(armIK.solver.IKRotation, leftArm_IKTarget.rotation, leftArm_Lerp); armIK.solver.IKPosition = leftArm_IKTargetPos; armIK.solver.IKPositionWeight = Mathf.MoveTowards(armIK.solver.IKPositionWeight, 1f, Time.deltaTime * IKWeightChangeSpeed); if (leftArm_IKWithRotation) { armIK.solver.IKRotation = leftArm_IKTargetRot; armIK.solver.IKRotationWeight = Mathf.MoveTowards(armIK.solver.IKRotationWeight, 1f, Time.deltaTime * IKWeightChangeSpeed); } else { armIK.solver.IKRotationWeight = Mathf.MoveTowards(armIK.solver.IKRotationWeight, 0f, Time.deltaTime * IKWeightChangeSpeed); } } else { armIK.solver.IKPositionWeight = Mathf.MoveTowards(armIK.solver.IKPositionWeight, 0f, Time.deltaTime * IKWeightChangeSpeed); armIK.solver.IKRotationWeight = Mathf.MoveTowards(armIK.solver.IKRotationWeight, 0f, Time.deltaTime * IKWeightChangeSpeed); } if (rightArm_IKByHand) { armIK = CurrentAvatarSetup.rightArm_HandIK; armIK2 = CurrentAvatarSetup.rightArm_ArmIK; } else { armIK = CurrentAvatarSetup.rightArm_ArmIK; armIK2 = CurrentAvatarSetup.rightArm_HandIK; } armIK.gameObject.SetActive(value: true); armIK2.gameObject.SetActive(value: false); armIK2.solver.IKPositionWeight = 0f; armIK2.solver.IKRotationWeight = 0f; if (rightArm_IKTarget != null) { rightArm_Lerp = Mathf.MoveTowards(rightArm_Lerp, 1f, Time.deltaTime * IKWeightChangeSpeed); rightArm_IKTargetPos = Vector3.Lerp(armIK.solver.IKPosition, rightArm_IKTarget.position, rightArm_Lerp); rightArm_IKTargetRot = Quaternion.Lerp(armIK.solver.IKRotation, rightArm_IKTarget.rotation, rightArm_Lerp); armIK.solver.IKPosition = rightArm_IKTargetPos; armIK.solver.IKPositionWeight = Mathf.MoveTowards(armIK.solver.IKPositionWeight, 1f, Time.deltaTime * IKWeightChangeSpeed); if (rightArm_IKWithRotation) { armIK.solver.IKRotation = rightArm_IKTargetRot; armIK.solver.IKRotationWeight = Mathf.MoveTowards(armIK.solver.IKRotationWeight, 1f, Time.deltaTime * IKWeightChangeSpeed); } else { armIK.solver.IKRotationWeight = Mathf.MoveTowards(armIK.solver.IKRotationWeight, 0f, Time.deltaTime * IKWeightChangeSpeed); } } else { armIK.solver.IKPositionWeight = Mathf.MoveTowards(armIK.solver.IKPositionWeight, 0f, Time.deltaTime * IKWeightChangeSpeed); armIK.solver.IKRotationWeight = Mathf.MoveTowards(armIK.solver.IKRotationWeight, 0f, Time.deltaTime * IKWeightChangeSpeed); } } private void CullAllLayers(List except = null) { Dictionary dictionary = new Dictionary(); foreach (AnimatorLayers value in Enum.GetValues(typeof(AnimatorLayers))) { dictionary[value] = ((except != null && except.Contains(value)) ? 1f : 0f); } if (layerWeightsChangeCoroutine != null) { StopCoroutine(layerWeightsChangeCoroutine); } layerWeightsChangeCoroutine = StartCoroutine(LayerWeightsChangeCoroutine(dictionary)); } private void RestoreOriginalLayerWeights() { if (layerWeightsChangeCoroutine != null) { StopCoroutine(layerWeightsChangeCoroutine); } layerWeightsChangeCoroutine = StartCoroutine(LayerWeightsChangeCoroutine(originalLayerWeights)); } private IEnumerator LayerWeightsChangeCoroutine(Dictionary targetWeights) { Dictionary initialWeights = new Dictionary(); foreach (AnimatorLayers key in targetWeights.Keys) { initialWeights[key] = animator.GetLayerWeight((int)key); } float duration = 1f; float time = 0f; while (time < duration) { time += Time.deltaTime; float t = time / duration; foreach (AnimatorLayers key2 in targetWeights.Keys) { float weight = Mathf.Lerp(initialWeights[key2], targetWeights[key2], t); animator.SetLayerWeight((int)key2, weight); } yield return null; } foreach (AnimatorLayers key3 in targetWeights.Keys) { animator.SetLayerWeight((int)key3, targetWeights[key3]); } } }