using System; using System.Collections; using System.Linq; using Photon.Pun; using RootMotion.FinalIK; using TMPro; using UFS2.Gameplay; using UnityEngine; public class MultiplayerAvatarControler : MonoBehaviourPun, IPunObservable { [Flags] public enum StateBits { Jumping = 1, MFV = 2, BFV = 4, IsMale = 8, FingersRightOnRod = 0x10, FingersLeftOnReel = 0x20, IsRodFishing = 0x40, TPP_OnThrowFar = 0x80, TPP_OnThrowNear = 0x100, TPP_OnRodJam = 0x200, TPP_OnRodTake = 0x400, TPP_OnRodPutDown = 0x800, OnBoat = 0x1000, UsingFlashlight = 0x2000 } [SerializeField] private Transform visual; [SerializeField] private TMP_Text text; [SerializeField] private Collider coll; [SerializeField] private Light flashlight; [SerializeField] private Vector3 positionOffset; [SerializeField] [Tooltip("Lower values increase smoothing and delay, higher values decrease smoothing and improve response time.")] private float handSmoothTimeIK; private FPlayer fPlayer; private FullBodyAvatar fullBodyAvatar; private Transform reelHandleRemote; private MultiplayerBoatEntity multiplayerBoatEntity; private Vector3 remoteVelocity; private Vector3 previousPosition; private float lastUpdateTime; private float jumpTimer = -1f; private Coroutine smoothChangeIKModeCoroutine; private Coroutine finishTPPAnimation; private Transform leftArm_Hand_Local; private Transform rightArm_Hand_Local; private Transform leftArm_Hand_Remote; private Transform rightArm_Hand_Remote; private bool isMaleCurrent; private bool isLeftHandOnReelHandle; private StateBits stateBits; private byte[] valueBits = new byte[36]; public static event Action OnUpdateRemote; public void Init(FPlayer fPlayer) { if (base.photonView.IsMine) { text.gameObject.SetActive(value: false); coll.gameObject.SetActive(value: false); flashlight.gameObject.SetActive(value: false); this.fPlayer = fPlayer; base.photonView.Owner.NickName = Singleton.Instance.GetCurrentPlayerData().PlayerName; PackStateBits(null, null, null, Singleton.Instance.GetCurrentPlayerData().PlayerSexIndex == 0); leftArm_Hand_Local = this.fPlayer.FullBodyAvatar.GetBoneTransform(HumanBodyBones.LeftHand); rightArm_Hand_Local = this.fPlayer.FullBodyAvatar.GetBoneTransform(HumanBodyBones.RightHand); } } private void UpdateLocal() { if (!(fPlayer == null)) { base.transform.SetPositionAndRotation(fPlayer.transform.position + positionOffset, fPlayer.transform.rotation); bool value = (bool)Singleton.Instance && (bool)Singleton.Instance.currentPlayerCharacter; bool activeSelf = fPlayer.flashLight.activeSelf; PackStateBits(fPlayer.FullBodyAvatar.IsJumping, fPlayer.FullBodyAvatar.CurrentTPPAnimation == FullBodyAvatar.TPPAnimation.MiddleFishView, fPlayer.FullBodyAvatar.CurrentTPPAnimation == FullBodyAvatar.TPPAnimation.BigFishView, null, fPlayer.currentRod != null, fPlayer.FullBodyAvatar.CurrentFingersLeftState != FullBodyAvatar.FingersLeft.Idle, fPlayer.FullBodyAvatar.IsRodFishing, null, null, null, null, null, value, activeSelf); PackValueBits(base.transform.InverseTransformPoint(leftArm_Hand_Local.position), base.transform.InverseTransformPoint(rightArm_Hand_Local.position), leftArm_Hand_Local.rotation, rightArm_Hand_Local.rotation, fPlayer.flashLight.transform.rotation); } } private void UpdateRemote() { UnpackStateBits(out var jumping, out var mfv, out var bfv, out var isMale, out var fingersRightOnRod, out var fingersLeftOnReel, out var isRodFishing, out var tppOnThrowFar, out var tppOnThrowNear, out var tppOnRodJam, out var tppOnRodTake, out var tppOnRodPutDown, out var onBoat, out var usingFlashlight); UnpackValueBits(out var leftArm_IKTargetPos, out var rightArm_IKTargetPos, out var leftArm_IKTargetRot, out var rightArm_IKTargetRot, out var flashlight_Rot); text.gameObject.SetActive(value: false); if (Camera.main != null) { text.transform.LookAt(Camera.main.transform); text.transform.rotation = Quaternion.Euler(0f, text.transform.rotation.eulerAngles.y, 0f); } if (fullBodyAvatar == null) { fullBodyAvatar = FullBodyAvatar.GetAvatarRemote(); fullBodyAvatar.SetGender(); fullBodyAvatar.TPPMovement = true; fullBodyAvatar.transform.SetParent(visual); fullBodyAvatar.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); isMaleCurrent = true; } if (isMale != isMaleCurrent) { isMaleCurrent = isMale; fullBodyAvatar.SetGender(isMaleCurrent); } if (jumpTimer >= 0f) { jumpTimer += Time.deltaTime; } if (jumping) { if (jumpTimer == -1f) { jumpTimer = 0f; fullBodyAvatar.Jump(); } } else if (jumpTimer >= 0.4f) { fullBodyAvatar.Land(); jumpTimer = -1f; } UpdateRemoteVelocity(); float walkSpeed = 2f; float runSpeed = 5f; Vector3 baselineVelocity = (multiplayerBoatEntity ? multiplayerBoatEntity.RemoteVelocity : Vector3.zero); fullBodyAvatar.MovementAnimation(base.transform.forward, base.transform.right, remoteVelocity, baselineVelocity, walkSpeed, runSpeed); fullBodyAvatar.SetFingersRight(fingersRightOnRod ? FullBodyAvatar.FingersRight.OnRodLoose : FullBodyAvatar.FingersRight.Idle); fullBodyAvatar.SetFingersLeft(fingersLeftOnReel ? FullBodyAvatar.FingersLeft.OnReelHandle : FullBodyAvatar.FingersLeft.Idle); if (!leftArm_Hand_Remote) { leftArm_Hand_Remote = new GameObject("leftArm_Hand_Remote").transform; rightArm_Hand_Remote = new GameObject("rightArm_Hand_Remote").transform; leftArm_Hand_Remote.SetParent(base.transform); rightArm_Hand_Remote.SetParent(base.transform); fullBodyAvatar.LeftArmIK(leftArm_Hand_Remote, withRotation: true, byHand: true); fullBodyAvatar.RightArmIK(rightArm_Hand_Remote, withRotation: true, byHand: true); isLeftHandOnReelHandle = false; } if (isRodFishing) { rightArm_IKTargetPos.x = Mathf.Clamp(rightArm_IKTargetPos.x, 0.1f, 0.4f); rightArm_IKTargetPos.y = Mathf.Clamp(rightArm_IKTargetPos.y, 1.2f, 1.5f); rightArm_IKTargetPos.z = Mathf.Clamp(rightArm_IKTargetPos.z, 0.4f, 0.6f); rightArm_IKTargetRot *= Quaternion.AngleAxis(30f, Vector3.right) * Quaternion.AngleAxis(15f, Vector3.up); } if (isRodFishing && !reelHandleRemote) { MultiplayerRodEntity multiplayerRodEntity = UnityEngine.Object.FindObjectsOfType().FirstOrDefault((MultiplayerRodEntity element) => element.GetComponentInParent()?.Owner.ActorNumber == base.photonView.Owner.ActorNumber); if (multiplayerRodEntity != null) { reelHandleRemote = multiplayerRodEntity.ReelHandleRemote; } } if (isRodFishing && (bool)reelHandleRemote) { if (!isLeftHandOnReelHandle) { isLeftHandOnReelHandle = true; if (smoothChangeIKModeCoroutine != null) { StopCoroutine(smoothChangeIKModeCoroutine); } smoothChangeIKModeCoroutine = StartCoroutine(SmoothChangeIKModeCoroutine()); } } else if (isLeftHandOnReelHandle) { isLeftHandOnReelHandle = false; if (smoothChangeIKModeCoroutine != null) { StopCoroutine(smoothChangeIKModeCoroutine); } smoothChangeIKModeCoroutine = StartCoroutine(SmoothChangeIKModeCoroutine()); } leftArm_Hand_Remote.localPosition = Vector3.Lerp(leftArm_Hand_Remote.localPosition, leftArm_IKTargetPos, Time.deltaTime * handSmoothTimeIK); rightArm_Hand_Remote.localPosition = Vector3.Lerp(rightArm_Hand_Remote.localPosition, rightArm_IKTargetPos, Time.deltaTime * handSmoothTimeIK); leftArm_Hand_Remote.rotation = Quaternion.Slerp(leftArm_Hand_Remote.rotation, leftArm_IKTargetRot, Time.deltaTime * handSmoothTimeIK); rightArm_Hand_Remote.rotation = Quaternion.Slerp(rightArm_Hand_Remote.rotation, rightArm_IKTargetRot, Time.deltaTime * handSmoothTimeIK); if (mfv) { if (fullBodyAvatar.CurrentTPPAnimation != FullBodyAvatar.TPPAnimation.MiddleFishView) { fullBodyAvatar.PlayTPPAnimation(FullBodyAvatar.TPPAnimation.MiddleFishView); } } else if (bfv) { if (fullBodyAvatar.CurrentTPPAnimation != FullBodyAvatar.TPPAnimation.BigFishView) { fullBodyAvatar.LeftArmIK(); fullBodyAvatar.RightArmIK(); fullBodyAvatar.PlayTPPAnimation(FullBodyAvatar.TPPAnimation.BigFishView); } } else if (tppOnThrowFar) { if (fullBodyAvatar.CurrentTPPAnimation != FullBodyAvatar.TPPAnimation.ThrowFar) { fullBodyAvatar.LeftArmIK(); fullBodyAvatar.RightArmIK(); fullBodyAvatar.PlayTPPAnimation(FullBodyAvatar.TPPAnimation.ThrowFar); } } else if (tppOnThrowNear) { if (fullBodyAvatar.CurrentTPPAnimation != FullBodyAvatar.TPPAnimation.ThrowNear) { fullBodyAvatar.LeftArmIK(); fullBodyAvatar.RightArmIK(); fullBodyAvatar.PlayTPPAnimation(FullBodyAvatar.TPPAnimation.ThrowNear); } } else if (tppOnRodJam) { if (fullBodyAvatar.CurrentTPPAnimation != FullBodyAvatar.TPPAnimation.RodJam) { fullBodyAvatar.LeftArmIK(); fullBodyAvatar.RightArmIK(); fullBodyAvatar.PlayTPPAnimation(FullBodyAvatar.TPPAnimation.RodJam); } } else if (tppOnRodTake) { if (fullBodyAvatar.CurrentTPPAnimation != FullBodyAvatar.TPPAnimation.Take) { fullBodyAvatar.LeftArmIK(); fullBodyAvatar.RightArmIK(); fullBodyAvatar.PlayTPPAnimation(FullBodyAvatar.TPPAnimation.Take); } } else if (tppOnRodPutDown) { if (fullBodyAvatar.CurrentTPPAnimation != FullBodyAvatar.TPPAnimation.PutDown) { fullBodyAvatar.LeftArmIK(); fullBodyAvatar.RightArmIK(); fullBodyAvatar.PlayTPPAnimation(FullBodyAvatar.TPPAnimation.PutDown); } } else if (fullBodyAvatar.CurrentTPPAnimation != FullBodyAvatar.TPPAnimation.Idle) { fullBodyAvatar.CurrentAvatarSetup.leftArm_HandIK.solver.IKPosition = leftArm_Hand_Remote.position; fullBodyAvatar.CurrentAvatarSetup.leftArm_HandIK.solver.IKRotation = leftArm_Hand_Remote.rotation; fullBodyAvatar.CurrentAvatarSetup.leftArm_HandIK.solver.IKPositionWeight = 0.8f; fullBodyAvatar.CurrentAvatarSetup.leftArm_HandIK.solver.IKRotationWeight = 0.8f; fullBodyAvatar.LeftArmIK(leftArm_Hand_Remote, withRotation: true, byHand: true); isLeftHandOnReelHandle = false; fullBodyAvatar.CurrentAvatarSetup.rightArm_HandIK.solver.IKPosition = rightArm_Hand_Remote.position; fullBodyAvatar.CurrentAvatarSetup.rightArm_HandIK.solver.IKRotation = rightArm_Hand_Remote.rotation; fullBodyAvatar.CurrentAvatarSetup.rightArm_HandIK.solver.IKPositionWeight = 0.8f; fullBodyAvatar.CurrentAvatarSetup.rightArm_HandIK.solver.IKRotationWeight = 0.8f; fullBodyAvatar.RightArmIK(rightArm_Hand_Remote, withRotation: true, byHand: true); fullBodyAvatar.PlayTPPAnimation(FullBodyAvatar.TPPAnimation.Idle); } coll.enabled = !onBoat; flashlight.gameObject.SetActive(usingFlashlight); if (usingFlashlight) { flashlight.transform.rotation = flashlight_Rot; } MultiplayerAvatarControler.OnUpdateRemote?.Invoke(this); } private void UpdateRemoteVelocity() { float num = Time.time - lastUpdateTime; if (num > 0f) { Vector3 position = base.transform.position; Vector3 b = (position - previousPosition) / num; remoteVelocity = Vector3.Lerp(remoteVelocity, b, Time.deltaTime * handSmoothTimeIK); previousPosition = position; lastUpdateTime = Time.time; } } private void PackStateBits(bool? jumping = null, bool? mfv = null, bool? bfv = null, bool? isMale = null, bool? fingersRightOnRod = null, bool? fingersLeftOnReel = null, bool? isRodFishing = null, bool? tppOnThrowFar = null, bool? tppOnThrowNear = null, bool? tppOnRodJam = null, bool? tppOnRodTake = null, bool? tppOnRodPutDown = null, bool? onBoat = null, bool? usingFlashlight = null) { UpdateBit(jumping, StateBits.Jumping); UpdateBit(mfv, StateBits.MFV); UpdateBit(bfv, StateBits.BFV); UpdateBit(isMale, StateBits.IsMale); UpdateBit(fingersRightOnRod, StateBits.FingersRightOnRod); UpdateBit(fingersLeftOnReel, StateBits.FingersLeftOnReel); UpdateBit(isRodFishing, StateBits.IsRodFishing); UpdateBit(tppOnThrowFar, StateBits.TPP_OnThrowFar); UpdateBit(tppOnThrowNear, StateBits.TPP_OnThrowNear); UpdateBit(tppOnRodJam, StateBits.TPP_OnRodJam); UpdateBit(tppOnRodTake, StateBits.TPP_OnRodTake); UpdateBit(tppOnRodPutDown, StateBits.TPP_OnRodPutDown); UpdateBit(onBoat, StateBits.OnBoat); UpdateBit(usingFlashlight, StateBits.UsingFlashlight); void UpdateBit(bool? value, StateBits bit) { if (value.HasValue) { if (value.Value) { stateBits |= bit; } else { stateBits &= ~bit; } } } } private void UnpackStateBits(out bool jumping, out bool mfv, out bool bfv, out bool isMale, out bool fingersRightOnRod, out bool fingersLeftOnReel, out bool isRodFishing, out bool tppOnThrowFar, out bool tppOnThrowNear, out bool tppOnRodJam, out bool tppOnRodTake, out bool tppOnRodPutDown, out bool onBoat, out bool usingFlashlight) { jumping = (stateBits & StateBits.Jumping) != 0; mfv = (stateBits & StateBits.MFV) != 0; bfv = (stateBits & StateBits.BFV) != 0; isMale = (stateBits & StateBits.IsMale) != 0; fingersRightOnRod = (stateBits & StateBits.FingersRightOnRod) != 0; fingersLeftOnReel = (stateBits & StateBits.FingersLeftOnReel) != 0; isRodFishing = (stateBits & StateBits.IsRodFishing) != 0; tppOnThrowFar = (stateBits & StateBits.TPP_OnThrowFar) != 0; tppOnThrowNear = (stateBits & StateBits.TPP_OnThrowNear) != 0; tppOnRodJam = (stateBits & StateBits.TPP_OnRodJam) != 0; tppOnRodTake = (stateBits & StateBits.TPP_OnRodTake) != 0; tppOnRodPutDown = (stateBits & StateBits.TPP_OnRodPutDown) != 0; onBoat = (stateBits & StateBits.OnBoat) != 0; usingFlashlight = (stateBits & StateBits.UsingFlashlight) != 0; } private void PackValueBits(Vector3 leftArm_IKTargetPos, Vector3 rightArm_IKTargetPos, Quaternion leftArm_IKTargetRot, Quaternion rightArm_IKTargetRot, Quaternion flashlight_Rot) { int index = 0; PackFloat(leftArm_IKTargetPos.x); PackFloat(leftArm_IKTargetPos.y); PackFloat(leftArm_IKTargetPos.z); PackFloat(rightArm_IKTargetPos.x); PackFloat(rightArm_IKTargetPos.y); PackFloat(rightArm_IKTargetPos.z); PackFloat(leftArm_IKTargetRot.x); PackFloat(leftArm_IKTargetRot.y); PackFloat(leftArm_IKTargetRot.z); PackFloat(leftArm_IKTargetRot.w); PackFloat(rightArm_IKTargetRot.x); PackFloat(rightArm_IKTargetRot.y); PackFloat(rightArm_IKTargetRot.z); PackFloat(rightArm_IKTargetRot.w); PackFloat(flashlight_Rot.x); PackFloat(flashlight_Rot.y); PackFloat(flashlight_Rot.z); PackFloat(flashlight_Rot.w); void PackFloat(float value) { byte[] bytes = BitConverter.GetBytes(Mathf.FloatToHalf(value)); Array.Copy(bytes, 0, valueBits, index, bytes.Length); index += 2; } } private void UnpackValueBits(out Vector3 leftArm_IKTargetPos, out Vector3 rightArm_IKTargetPos, out Quaternion leftArm_IKTargetRot, out Quaternion rightArm_IKTargetRot, out Quaternion flashlight_Rot) { int index = 0; leftArm_IKTargetPos.x = UnpackFloat(); leftArm_IKTargetPos.y = UnpackFloat(); leftArm_IKTargetPos.z = UnpackFloat(); rightArm_IKTargetPos.x = UnpackFloat(); rightArm_IKTargetPos.y = UnpackFloat(); rightArm_IKTargetPos.z = UnpackFloat(); leftArm_IKTargetRot.x = UnpackFloat(); leftArm_IKTargetRot.y = UnpackFloat(); leftArm_IKTargetRot.z = UnpackFloat(); leftArm_IKTargetRot.w = UnpackFloat(); rightArm_IKTargetRot.x = UnpackFloat(); rightArm_IKTargetRot.y = UnpackFloat(); rightArm_IKTargetRot.z = UnpackFloat(); rightArm_IKTargetRot.w = UnpackFloat(); flashlight_Rot.x = UnpackFloat(); flashlight_Rot.y = UnpackFloat(); flashlight_Rot.z = UnpackFloat(); flashlight_Rot.w = UnpackFloat(); float UnpackFloat() { float result = Mathf.HalfToFloat(BitConverter.ToUInt16(valueBits, index)); index += 2; return result; } } public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info) { if (stream.IsWriting) { stream.SendNext(stateBits); stream.SendNext(valueBits); } else { stateBits = (StateBits)stream.ReceiveNext(); valueBits = (byte[])stream.ReceiveNext(); } } private void FPlayer_OnThrowFar(FPlayer fp) { if (base.photonView.IsMine) { PackStateBits(null, null, null, null, null, null, null, true); if (finishTPPAnimation != null) { StopCoroutine(finishTPPAnimation); } finishTPPAnimation = StartCoroutine(FinishTPPAnimation(2.5f)); } } private void FPlayer_OnThrowNear(FPlayer fp) { if (base.photonView.IsMine) { PackStateBits(null, null, null, null, null, null, null, null, true); if (finishTPPAnimation != null) { StopCoroutine(finishTPPAnimation); } finishTPPAnimation = StartCoroutine(FinishTPPAnimation(1.5f)); } } private void FPlayer_OnRodJam(FPlayer fp) { if (base.photonView.IsMine) { PackStateBits(null, null, null, null, null, null, null, null, null, true); if (finishTPPAnimation != null) { StopCoroutine(finishTPPAnimation); } finishTPPAnimation = StartCoroutine(FinishTPPAnimation(2f)); } } private void RodSupport_OnRodTake(FRod fRod) { if (base.photonView.IsMine) { PackStateBits(null, null, null, null, null, null, null, null, null, null, true); if (finishTPPAnimation != null) { StopCoroutine(finishTPPAnimation); } finishTPPAnimation = StartCoroutine(FinishTPPAnimation(2f)); } } private void RodSupport_OnRodPutDown(FRod fRod) { if (base.photonView.IsMine) { PackStateBits(null, null, null, null, null, null, null, null, null, null, null, true); if (finishTPPAnimation != null) { StopCoroutine(finishTPPAnimation); } finishTPPAnimation = StartCoroutine(FinishTPPAnimation(2f)); } } private void MultiplayerBoatEntity_OnRemoteBoatSpawn(MultiplayerBoatEntity boat) { if (boat.photonView.OwnerActorNr == base.photonView.OwnerActorNr) { multiplayerBoatEntity = boat; } } private void MultiplayerBoatEntity_OnRemoteBoatDespawn(MultiplayerBoatEntity boat) { if (multiplayerBoatEntity == boat) { multiplayerBoatEntity = null; } } private void Update() { if (base.photonView.IsMine) { UpdateLocal(); } else { UpdateRemote(); } } private void Start() { if (!base.photonView.IsMine) { FishEntityManager.AddTransformCull(base.transform); } remoteVelocity = Vector3.zero; previousPosition = base.transform.position; lastUpdateTime = Time.time; } private void OnDestroy() { if (!base.photonView.IsMine) { FishEntityManager.RemoveTransformCull(base.transform); } } private void OnEnable() { FPlayer.OnThrowFar += FPlayer_OnThrowFar; FPlayer.OnThrowNear += FPlayer_OnThrowNear; FPlayer.OnRodJam += FPlayer_OnRodJam; RodSupport.OnRodTake += RodSupport_OnRodTake; RodSupport.OnRodPutDown += RodSupport_OnRodPutDown; BoatRodSupport.OnRodTake += RodSupport_OnRodTake; BoatRodSupport.OnRodPutDown += RodSupport_OnRodPutDown; MultiplayerBoatEntity.OnRemoteBoatSpawn += MultiplayerBoatEntity_OnRemoteBoatSpawn; MultiplayerBoatEntity.OnRemoteBoatDespawn += MultiplayerBoatEntity_OnRemoteBoatDespawn; } private void OnDisable() { FPlayer.OnThrowFar -= FPlayer_OnThrowFar; FPlayer.OnThrowNear -= FPlayer_OnThrowNear; FPlayer.OnRodJam -= FPlayer_OnRodJam; RodSupport.OnRodTake -= RodSupport_OnRodTake; RodSupport.OnRodPutDown -= RodSupport_OnRodPutDown; BoatRodSupport.OnRodTake -= RodSupport_OnRodTake; BoatRodSupport.OnRodPutDown -= RodSupport_OnRodPutDown; MultiplayerBoatEntity.OnRemoteBoatSpawn -= MultiplayerBoatEntity_OnRemoteBoatSpawn; MultiplayerBoatEntity.OnRemoteBoatDespawn -= MultiplayerBoatEntity_OnRemoteBoatDespawn; } private IEnumerator SmoothChangeIKModeCoroutine() { fullBodyAvatar.LeftArmIK(); IKSolverArm solver; IKSolverArm solver2; if (isLeftHandOnReelHandle) { solver = fullBodyAvatar.CurrentAvatarSetup.leftArm_ArmIK.solver; solver2 = fullBodyAvatar.CurrentAvatarSetup.leftArm_HandIK.solver; } else { solver = fullBodyAvatar.CurrentAvatarSetup.leftArm_HandIK.solver; solver2 = fullBodyAvatar.CurrentAvatarSetup.leftArm_ArmIK.solver; } solver.IKPosition = solver2.IKPosition; solver.IKRotation = solver2.IKRotation; if (isLeftHandOnReelHandle) { fullBodyAvatar.LeftArmIK(reelHandleRemote); } else { fullBodyAvatar.LeftArmIK(leftArm_Hand_Remote, withRotation: true, byHand: true); } yield break; } private IEnumerator FinishTPPAnimation(float duration) { yield return new WaitForSeconds(duration); PackStateBits(null, null, null, null, null, null, null, false, false, false, false, false); } }