using System; using System.Collections; using Obvious.Soap; using ShiningGames.UFS2; using UFS2.ScriptableObjects; using UltimateWater; using UnityEngine; using Voxus.Random; namespace UFS2.Gameplay { public class FishSpawner : MonoBehaviour { [Range(0f, 100f)] public int InstantiateCount = 1; public int FishPoolMaxSize = 100; [SerializeField] private LevelFishData LevelFishData; [SerializeField] private Vector3Variable player_CurrentPosition; [SerializeField] private FloatVariable lineTension; public bool IsTriggerCollider; public GameObject ObjectPool; private float lastSpawnTime; private const float spawnCooldown = 1f; public static event Action OnSpawnFish; public static event Action OnDespawnFish; public static event Action OnStartFishesSpawned; private void OnEnable() { FishEntity.OnPostSpitOutBait += FishEntity_OnPostSpitOutBait; FishEntity.OnOldFishKill += FishEntity_OnPostSpitOutBait; MultiplayerFishSpawner.OnNetworkedFishSpawn += MultiplayerFishSpawner_OnNetworkedFishSpawn; MultiplayerFishSpawner.OnNetworkedFishDelete += MultiplayerFishSpawner_OnNetworkedFishDelete; MultiplayerFishSpawner.OnFishDeleteAfterInteraction += MultiplayerFishSpawner_OnFishDeleteAfterInteraction; } private void OnDisable() { FishEntity.OnPostSpitOutBait -= FishEntity_OnPostSpitOutBait; FishEntity.OnOldFishKill -= FishEntity_OnPostSpitOutBait; MultiplayerFishSpawner.OnNetworkedFishSpawn -= MultiplayerFishSpawner_OnNetworkedFishSpawn; MultiplayerFishSpawner.OnNetworkedFishDelete -= MultiplayerFishSpawner_OnNetworkedFishDelete; MultiplayerFishSpawner.OnFishDeleteAfterInteraction -= MultiplayerFishSpawner_OnFishDeleteAfterInteraction; } private void FishEntity_OnPostSpitOutBait(FishEntity fish) { if (!MultiplayerFishSpawner.IsSlave) { InstantiateNewFish(1); } } private void MultiplayerFishSpawner_OnNetworkedFishSpawn(MultiplayerFishSpawner.NetworkedFish networkedFish) { if (MultiplayerFishSpawner.IsSlave) { networkedFish.fishEntity = InstantiateNewFish(networkedFish.fishID, networkedFish.fishWeight, networkedFish.position, networkedFish.targetAreaID); } } private void MultiplayerFishSpawner_OnNetworkedFishDelete(MultiplayerFishSpawner.NetworkedFish networkedFish) { if (MultiplayerFishSpawner.IsSlave) { FishEntity fishEntity = networkedFish.fishEntity; if (fishEntity != null) { FishSpawner.OnDespawnFish?.Invoke(fishEntity); fishEntity.gameObject.Destroy(); } } } private void MultiplayerFishSpawner_OnFishDeleteAfterInteraction() { if (!MultiplayerFishSpawner.IsSlave) { InstantiateNewFish(1); } } private void Start() { int count = ((!MultiplayerFishSpawner.IsSlave) ? LevelFishData.StartCount : 0); InstantiateNewFish(count); StartCoroutine(WaitForStartFishGenerated(count)); } private void Update() { InstantiateExtraFish(); } private IEnumerator WaitForStartFishGenerated(int count) { OnSpawnFish += FishSpawner_OnSpawnFish; while (count > 0) { yield return null; } FishSpawner.OnStartFishesSpawned?.Invoke(); OnSpawnFish -= FishSpawner_OnSpawnFish; void FishSpawner_OnSpawnFish(FishEntity obj, int levelFishDataIndex) { count--; } } public static void Despawn(FishEntity fish) { FishSpawner.OnDespawnFish?.Invoke(fish); } public void KillFishes() { FishEntity[] componentsInChildren = ObjectPool.GetComponentsInChildren(); foreach (FishEntity fishEntity in componentsInChildren) { FishSpawner.OnDespawnFish?.Invoke(fishEntity); fishEntity.gameObject.Destroy(); } } public void InstantiateExtraFish() { if (MultiplayerFishSpawner.IsMaster) { int count = Singleton.Instance.CullTransforms.Count; int count2 = Singleton.Instance.AllFishes.Count; int num = LevelFishData.StartCount; if (count >= 7) { num = 70; } if (count >= 14) { num = 120; } if (count2 < num && Time.time - lastSpawnTime >= 1f) { lastSpawnTime = Time.time; InstantiateNewFish(1); } } } public FishEntity InstantiateNewFish(int fishIndex, float weight, Vector3 position, int targetAreaID) { if (fishIndex < 0 || fishIndex >= LevelFishData.FishesSetting.Count) { Debug.LogError("Invalid fish index specified for spawning."); return null; } LevelFishData.FishDataHelper fishDataHelper = LevelFishData.FishesSetting[fishIndex]; GameObject original = fishDataHelper.FishData.LoadFishResource(weight); GameObject gameObject = new GameObject("FishObject " + fishDataHelper.FishData.Name + " " + weight); GameObject gameObject2 = UnityEngine.Object.Instantiate(original, gameObject.transform); gameObject2.transform.localPosition = Vector3.zero; gameObject2.transform.localRotation = Quaternion.identity; Transform jointAnchor = gameObject2.GetComponent().jointAnchor; Transform transform = gameObject2.GetComponentInChildren().transform; if (transform.TryGetComponent(out var component)) { UnityEngine.Object.Destroy(component); } Collider[] componentsInChildren = gameObject2.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].isTrigger = true; } UnityEngine.Object.Destroy(gameObject2.GetComponent()); UnityEngine.Object.Destroy(gameObject2.GetComponent()); UnityEngine.Object.Destroy(gameObject2.GetComponentInChildren()); Rigidbody[] componentsInChildren2 = gameObject2.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren2.Length; i++) { UnityEngine.Object.Destroy(componentsInChildren2[i]); } FishTargetArea fishTargetArea = FishTargetBaker.Instance.Areas[targetAreaID]; LocalAvoidance localAvoidance = gameObject.AddComponent(); localAvoidance.TailRag = transform; localAvoidance.Target = fishTargetArea.GetRandomTarget(fishDataHelper.FishData.BehaviourType).Transform; FishEntity fishEntity = gameObject.AddComponent(); FishPhysics fishPhysics = gameObject.AddComponent(); gameObject.AddComponent().collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic; gameObject.AddComponent(); gameObject2.GetComponent().cullingMode = AnimatorCullingMode.CullCompletely; fishPhysics.ImportData(fishDataHelper.FishData, weight); fishEntity.InitializeData(fishDataHelper.FishData, weight); fishEntity.Player_CurrentPosition = player_CurrentPosition; fishEntity.CurrentArea = fishTargetArea; fishEntity.transform.position = position; fishEntity.transform.parent = ObjectPool.transform; fishEntity.JointAnchor = jointAnchor; FishSpawner.OnSpawnFish?.Invoke(fishEntity, fishIndex); return fishEntity; } public GameObject InstantiateFishDummy(int fishIndex, float weight, Vector3 position) { if (fishIndex < 0 || fishIndex >= LevelFishData.FishesSetting.Count) { Debug.LogError("Invalid fish index specified for spawning."); return null; } LevelFishData.FishDataHelper fishDataHelper = LevelFishData.FishesSetting[fishIndex]; GameObject original = fishDataHelper.FishData.LoadFishResource(weight); GameObject gameObject = new GameObject("FishObject " + fishDataHelper.FishData.Name + " " + weight); gameObject.transform.position = position; GameObject gameObject2 = UnityEngine.Object.Instantiate(original, gameObject.transform); gameObject2.transform.localPosition = Vector3.zero; gameObject2.transform.localRotation = Quaternion.identity; _ = gameObject2.GetComponent().jointAnchor; if (gameObject2.GetComponentInChildren().transform.TryGetComponent(out var component)) { UnityEngine.Object.Destroy(component); } Collider[] componentsInChildren = gameObject2.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { UnityEngine.Object.Destroy(componentsInChildren[i]); } UnityEngine.Object.Destroy(gameObject2.GetComponent()); UnityEngine.Object.Destroy(gameObject2.GetComponent()); UnityEngine.Object.Destroy(gameObject2.GetComponentInChildren()); Rigidbody[] componentsInChildren2 = gameObject2.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren2.Length; i++) { UnityEngine.Object.Destroy(componentsInChildren2[i]); } gameObject2.GetComponent().cullingMode = AnimatorCullingMode.CullCompletely; gameObject2.transform.localScale = fishDataHelper.FishData.GetFishScale(weight); return gameObject; } public void InstantiateNewFish(int count) { StartCoroutine(Spawn()); IEnumerator Spawn() { yield return null; RandomGaussian randomGenerator = new RandomGaussian(0.2f, 0.4f); randomGenerator.SetSeed(UnityEngine.Random.value); for (int i = 0; i < count; i++) { LevelFishData.FishDataHelper randomFishDataToSpawn = LevelFishData.GetRandomFishDataToSpawn(); int arg = LevelFishData.FishesSetting.IndexOf(randomFishDataToSpawn); Vector2 weight = randomFishDataToSpawn.Weight; float t = Mathf.Clamp01(randomGenerator.Get()); float weight2 = Mathf.Lerp(weight.x, weight.y, t); GameObject original = randomFishDataToSpawn.FishData.LoadFishResource(weight2); GameObject gameObject = new GameObject("FishObject " + randomFishDataToSpawn.FishData.Name + " " + weight2); GameObject gameObject2 = UnityEngine.Object.Instantiate(original, gameObject.transform); gameObject2.transform.localPosition = Vector3.zero; gameObject2.transform.localRotation = Quaternion.identity; Transform jointAnchor = gameObject2.GetComponent().jointAnchor; Transform transform = gameObject2.GetComponentInChildren().transform; if (transform.TryGetComponent(out var component)) { UnityEngine.Object.Destroy(component); } Collider[] componentsInChildren = gameObject2.GetComponentsInChildren(); for (int j = 0; j < componentsInChildren.Length; j++) { componentsInChildren[j].isTrigger = true; } UnityEngine.Object.Destroy(gameObject2.GetComponent()); UnityEngine.Object.Destroy(gameObject2.GetComponent()); UnityEngine.Object.Destroy(gameObject2.GetComponentInChildren()); Rigidbody[] componentsInChildren2 = gameObject2.GetComponentsInChildren(); for (int j = 0; j < componentsInChildren2.Length; j++) { UnityEngine.Object.Destroy(componentsInChildren2[j]); } LocalAvoidance localAvoidance = gameObject.AddComponent(); localAvoidance.TailRag = transform; FishEntity fishEntity = gameObject.AddComponent(); FishPhysics fishPhysics = gameObject.AddComponent(); gameObject.AddComponent().collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic; gameObject.AddComponent(); Animator component2 = gameObject2.GetComponent(); FishTarget startFishTarget = GetStartFishTarget(randomFishDataToSpawn.FishData.FishDeepType); localAvoidance.Target = startFishTarget.Transform; component2.cullingMode = AnimatorCullingMode.CullCompletely; fishPhysics.ImportData(randomFishDataToSpawn.FishData, weight2); fishEntity.InitializeData(randomFishDataToSpawn.FishData, weight2); fishEntity.Player_CurrentPosition = player_CurrentPosition; fishEntity.CurrentArea = startFishTarget.Area; fishEntity.transform.position = startFishTarget.Transform.position; fishEntity.transform.parent = ObjectPool.transform; fishEntity.JointAnchor = jointAnchor; FishSpawner.OnSpawnFish?.Invoke(fishEntity, arg); yield return null; } } } private FishTarget GetStartFishTarget(FishDeepType deepType) { FishTarget fishTarget = null; fishTarget = deepType switch { FishDeepType.Overall => FishTargetBaker.GetRandomOverallTarget(), FishDeepType.Bottom => FishTargetBaker.GetRandomBottomTarget(), FishDeepType.Surface => FishTargetBaker.GetRandomSurfaceTarget(), _ => FishTargetBaker.GetRandomOverallTarget(), }; if (fishTarget == null) { fishTarget = FishTargetBaker.GetRandomOverallTarget(); } if (fishTarget == null) { fishTarget = FishTargetBaker.GetRandomBottomTarget(); } if (fishTarget == null) { fishTarget = FishTargetBaker.GetRandomSurfaceTarget(); } return fishTarget; } } }