using System; using Obvious.Soap; using SoapCustomVariable; using UnityEngine; public class FishController : MonoBehaviourExtended, IBatchFixedUpdate { private static readonly int MoveSpeedHash = Animator.StringToHash("Move"); public FishFSMReference fishState; public UpdateManager.UpdateMode UpdateMode = UpdateManager.UpdateMode.Always; public float stamina = 1f; public Vector3? followPosition; [SerializeField] private float mass = 10f; [SerializeField] private FloatVariable fightMoveSpeed; [SerializeField] private FSMVariable playerFSM; [SerializeField] public GameObjectVariable currentFightFishObject; [SerializeField] private GameObjectVariable playerGameObject; [SerializeField] private ScriptableEventNoParam onGearDamaged; [SerializeField] private ScriptableEventFishData onFishCatch; [SerializeField] private ScriptableEventFishData onFishRelease; [SerializeField] private ScriptableEventFishData onFishCollect; [SerializeField] private Lure connectedLure; [SerializeField] private FishingSetController connectedFishingSet; private FishModelBindings _FishModelBindings; private FishZoneObject _fishZoneObject; private Vector3 _currentDirection; private Vector3 _lastPosition; [OwnComponent(0)] private FishAI _AI; private ConfigurableJoint joint; [OwnComponent(0)] private WaterBody waterBody; [OwnComponent(0)] private Rigidbody rbody; private Animator _animator; private bool _isFightMode; private FishData fishData; private GameObject model; private Vector3 _startPosition; private Vector3 _moveDirection; private float lastTimeChangeRotation; private float length; private Vector3 _anchor; private bool _isThrown; private float lastTimeInWaterExit; private float _stateTimer; private float lastTimeTensionDirChange; private int directionOfFight; private float lineReeledAmount; public float Mass => mass; public Vector3 Velocity => rbody.linearVelocity; public FishData FishData => fishData; public Transform JawAnchor => _FishModelBindings.Jaw; public bool inWater => waterBody.InWater; public float moveSpeed { get; private set; } public bool isFightMode => _isFightMode; private bool IsConnectedToJoint => joint != null; private float rngRotateTime => Time.time + UnityEngine.Random.Range(1f, 2.5f); private event Action onPostInitialization = delegate { }; public void Initialize(FishData fishData, FishZoneObject fishZone, float mass) { this.fishData = fishData; this.fishData.Weight = mass; _fishZoneObject = fishZone; this.mass = mass; length = fishData.LWR.Evaluate(mass); float num = length * 1.73f; model = UnityEngine.Object.Instantiate(fishData.GetModel(), base.transform); _FishModelBindings = model.GetComponent(); model.transform.localScale = new Vector3(num, num, num); base.gameObject.name = fishData.name + " " + mass + "kg"; model.transform.localPosition = Vector3.zero; _FishModelBindings.TailSetEnable(setEnable: false); _AI.length = length; _AI.anchor = JawAnchor; _AI.fishData = fishData; rbody = GetComponent(); joint = GetComponentInChildren(); rbody.mass = mass; this.onPostInitialization(); } public void Reinitialize(FishData fishData, float mass) { if (model == null) { throw new InvalidOperationException("Fish was not initialized before. Call Initialize() first."); } if (fishState.Value != FishState.idle && fishState.Value != FishState.patrol) { throw new InvalidOperationException($"It is not safe to reinitialize a fish in state {fishState.Value}"); } this.fishData = fishData; this.fishData.Weight = mass; this.mass = mass; length = fishData.LWR.Evaluate(mass); float num = length * 1.73f; if (model != null) { UnityEngine.Object.Destroy(model.gameObject); model = null; _FishModelBindings = null; } model = UnityEngine.Object.Instantiate(fishData.GetModel(), base.transform); _FishModelBindings = model.GetComponent(); model.transform.localScale = new Vector3(num, num, num); base.gameObject.name = fishData.name + " " + mass + "kg"; model.transform.localPosition = Vector3.zero; _FishModelBindings.TailSetEnable(setEnable: false); _AI.length = length; _AI.anchor = JawAnchor; _AI.fishData = fishData; rbody = GetComponent(); joint = GetComponentInChildren(); rbody.mass = mass; } private new void Awake() { base.Awake(); WaterBody obj = waterBody; obj.OnWaterChangeState = (Action)Delegate.Combine(obj.OnWaterChangeState, new Action(OnWaterEnterExit)); fishState.OnValueChanged += FishStateOnOnValueChanged; _startPosition = base.transform.position; onPostInitialization += delegate { _AI.SetRandomizedMoveToTargetPosition(_startPosition); }; } private void Start() { OnWaterEnterExit(waterBody.InWater); } public void BatchFixedUpdate() { } private void FixedUpdate() { StateHandler(); } public void BatchUpdate() { } private void OnEnable() { UpdateManager.RegisterSlicedFixedUpdate(this); currentFightFishObject.OnValueChanged += CurrentFightFishObject_OnValueChanged; } private void OnDisable() { UpdateManager.DeregisterSlicedFixedUpdate(this); currentFightFishObject.OnValueChanged -= CurrentFightFishObject_OnValueChanged; } private void FishStateOnOnValueChanged(FishState state) { if (fishState.PreviousValue == FishState.catched) { rbody.detectCollisions = true; } switch (state) { case FishState.catched: rbody.automaticInertiaTensor = false; rbody.detectCollisions = false; rbody.linearVelocity = Vector3.zero; rbody.angularVelocity = Vector3.zero; break; case FishState.idle: _stateTimer = Time.time + UnityEngine.Random.Range(1f, 3f); break; case FishState.patrol: _AI.SetRandomizedMoveToTargetPosition(_startPosition); break; } } private void StateHandler() { switch (fishState.Value) { case FishState.idle: if (_stateTimer < Time.time) { fishState.Value = FishState.patrol; } break; case FishState.patrol: { float magnitude = rbody.linearVelocity.magnitude; _FishModelBindings.Animator.SetFloat(MoveSpeedHash, magnitude); if ((bool)_AI.lure) { _AI.SeekUpdateHandler(3f); if (_AI.isTargetReached) { _AI.lure.transform.position = JawAnchor.position; AttachLure(_AI.lure.RBody); fishState.Value = FishState.eat; break; } _AI.SetMovePosition(_AI.lure.transform.position); if (_AI.lure.IsFishConnected || !_AI.lure.isInWater) { _AI.SetLure(null); _AI.SetRandomizedMoveToTargetPosition(_startPosition); } break; } if (followPosition.HasValue) { float num2 = Vector3.Distance(base.transform.position, followPosition.Value); float multiply2 = Mathf.Lerp(1f, 4f, Mathf.Clamp01(num2 / 10f)); _AI.SeekUpdateHandler(multiply2); _AI.SetMovePosition(followPosition.Value); break; } _AI.SeekUpdateHandler(); if (_AI.isTargetReached) { if (UnityEngine.Random.Range(0f, 1f) > 0.35f) { fishState.Value = FishState.idle; } else { _AI.SetRandomizedMoveToTargetPosition(_startPosition); } } if (!waterBody.InWater) { _AI.SetRandomizedMoveToTargetPosition(_startPosition); } break; } case FishState.eat: { float magnitude = rbody.linearVelocity.magnitude; if (!connectedFishingSet) { break; } float num = 1f - connectedFishingSet.Tension / mass; _FishModelBindings.Animator.SetFloat(MoveSpeedHash, magnitude); if (inWater) { if (num < 0.9f) { fishState.Value = FishState.fight; break; } _AI.LureEatUpdateHandler((stamina > 0f) ? 3f : 0f); } else { _AI.SetMoveToTargetPosition(Vector3.down * 10f); } if (_AI.isTargetReached) { _AI.SetRandomizedMoveToTargetPosition(_startPosition); } rbody.useGravity = !inWater; UpdateMoveSpeed(); break; } case FishState.fight: { float magnitude = rbody.linearVelocity.magnitude; if (!connectedFishingSet) { break; } float num = connectedFishingSet.Tension / mass; _FishModelBindings.Animator.SetFloat(MoveSpeedHash, magnitude); Vector3 position = connectedFishingSet.transform.position; position.y = base.transform.position.y - 1f; Vector3 normalized = (base.transform.position - position).normalized; if (inWater) { if (num > 0.85f * stamina) { Vector3 vector = normalized; if (directionOfFight == -1) { vector = Quaternion.AngleAxis(-95f, Vector3.up) * normalized; directionOfFight = 1; } else if (directionOfFight == 1) { vector = Quaternion.AngleAxis(95f, Vector3.up) * normalized; directionOfFight = -1; } _AI.SetMoveToTargetPosition(base.transform.position + vector * 10f); } if (Time.time > lastTimeTensionDirChange) { Vector3 vector2 = normalized; bool flag = UnityEngine.Random.Range(0f, 100f) < 30f; if (num > 0.25f * stamina || flag) { if (directionOfFight == -1) { vector2 = Quaternion.AngleAxis(-95f, Vector3.up) * normalized; directionOfFight = 1; } else if (directionOfFight == 1) { vector2 = Quaternion.AngleAxis(95f, Vector3.up) * normalized; directionOfFight = -1; } else { bool flag2 = UnityEngine.Random.Range(0f, 1f) < 0.5f; vector2 = Quaternion.AngleAxis(flag2 ? (-95f) : 95f, Vector3.up) * normalized; directionOfFight = ((!flag2) ? 1 : (-1)); } } else { directionOfFight = 0; } _AI.SetMoveToTargetPosition(base.transform.position + vector2 * 10f); lastTimeTensionDirChange = Time.time + UnityEngine.Random.Range(2f, 3f); Debug.Log(">>>>>>>>>>Change dir to: " + directionOfFight); } stamina -= Time.deltaTime * num * 0.01f; float multiply = 6f; if (lineReeledAmount < 0f && stamina <= 0f) { multiply = 0f; } _AI.FightUpdateHandler(multiply); } else if (lastTimeInWaterExit < Time.time) { lastTimeInWaterExit = Time.time + 1f; lastTimeTensionDirChange = Time.time + UnityEngine.Random.Range(1f, 2f); Vector3 moveToTargetPosition = normalized; moveToTargetPosition.y = -2f; _AI.SetMoveToTargetPosition(moveToTargetPosition); } _FishModelBindings.Animator.SetBool("Jump", num > 0.75f); stamina = Mathf.Clamp(stamina, 0f, 1f); rbody.useGravity = !inWater; UpdateMoveSpeed(); break; } case FishState.catched: rbody.detectCollisions = false; rbody.automaticInertiaTensor = true; _FishModelBindings.Animator.SetFloat(MoveSpeedHash, (stamina > 0f) ? 0.1f : 0f); if (_isThrown && inWater) { fishState.Value = FishState.idle; _isThrown = false; } break; case FishState.seek: case FishState.followTarget: case FishState.chase: break; } } private void UpdateMoveSpeed() { Vector3 position = base.transform.position; moveSpeed = Vector3.Distance(_lastPosition, position); _lastPosition = position; } private Vector3 RandomPointInCone(Vector3 forward, float angle) { float minInclusive = Mathf.Cos(angle * (MathF.PI / 180f)); float f = UnityEngine.Random.Range(0f, MathF.PI * 2f); float num = UnityEngine.Random.Range(minInclusive, 1f); float num2 = Mathf.Sqrt(1f - num * num); Vector3 vector = new Vector3(num2 * Mathf.Cos(f), num2 * Mathf.Sin(f), num); return Quaternion.FromToRotation(Vector3.forward, forward.normalized) * vector; } public void AttachToFishingSet(FishingSetController fishingSetController) { connectedFishingSet = fishingSetController; connectedFishingSet.OnLineReeled += ConnectedFishingSetOnOnLineReeled; } private void ConnectedFishingSetOnOnLineReeled(float obj) { lineReeledAmount = obj; } public void AttachLure(Rigidbody lureRb) { if (!(currentFightFishObject.Value != null)) { currentFightFishObject.Value = base.gameObject; base.transform.parent = null; attach(); } void attach() { connectedLure = lureRb.GetComponent(); connectedLure.ConnectFish(this); _anchor = model.transform.localPosition + JawAnchor.localPosition * model.transform.localScale.x; playerFSM.Value = State.fight; _FishModelBindings.TailSetEnable(setEnable: true); _isFightMode = true; joint.anchor = _anchor; joint.connectedBody = lureRb; ConfigurableJoint configurableJoint = joint; ConfigurableJoint configurableJoint2 = joint; ConfigurableJointMotion configurableJointMotion = (joint.zMotion = ConfigurableJointMotion.Locked); ConfigurableJointMotion xMotion = (configurableJoint2.yMotion = configurableJointMotion); configurableJoint.xMotion = xMotion; } } public void SetJoint(Rigidbody rb) { joint.connectedBody = rb; } public void Catch() { _FishModelBindings.Animator.SetBool("Jump", value: false); SFXGameManagement.PlaySound("gather splash", base.transform); Debug.Log("Catched Fish" + fishData.name + " " + mass + "kg"); fishState.Value = FishState.catched; } public void CollectFish() { _isFightMode = false; rbody.automaticCenterOfMass = false; rbody.centerOfMass = -JawAnchor.localPosition; rbody.detectCollisions = false; } public void Throw(Vector3 force) { DisconnectFromAttachment(); _AI.ResetBehaviour(); _isThrown = true; rbody.linearVelocity = force; rbody.detectCollisions = true; rbody.automaticCenterOfMass = true; currentFightFishObject.Value = null; } public void FishDestroy() { OnFishCollect_OnRaised(fishData); } private void DisconnectFromAttachment() { connectedFishingSet.OnLineReeled -= ConnectedFishingSetOnOnLineReeled; connectedFishingSet = null; currentFightFishObject.Value = null; joint.connectedBody = null; ConfigurableJoint configurableJoint = joint; ConfigurableJoint configurableJoint2 = joint; ConfigurableJointMotion configurableJointMotion = (joint.zMotion = ConfigurableJointMotion.Free); ConfigurableJointMotion xMotion = (configurableJoint2.yMotion = configurableJointMotion); configurableJoint.xMotion = xMotion; connectedLure.ConnectFish(null); connectedLure = null; rbody.linearVelocity = Vector3.zero; stamina = 1f; _FishModelBindings.TailSetEnable(setEnable: false); _isFightMode = false; } private void OnFishCollect_OnRaised(FishData obj) { if (!(obj != fishData)) { if (currentFightFishObject.Value == base.gameObject) { currentFightFishObject.Value = null; } DisconnectFromAttachment(); UnityEngine.Object.Destroy(base.gameObject); } } private void CurrentFightFishObject_OnValueChanged(GameObject obj) { _ = base.gameObject == obj; } private void OnWaterEnterExit(bool inWater) { if (inWater) { rbody.useGravity = false; rbody.linearDamping = 3f; rbody.angularDamping = 1f; } else { rbody.useGravity = true; lastTimeChangeRotation = 0f; rbody.linearDamping = 1.5f; rbody.angularDamping = 2f; } } }