491 lines
12 KiB
C#
491 lines
12 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Obvious.Soap;
|
|
using ShiningGames.UFS2;
|
|
using UFS2.ScriptableObjects;
|
|
using UnityEngine;
|
|
|
|
namespace UFS2.Gameplay
|
|
{
|
|
public class FishEntityManager : Singleton<FishEntityManager>
|
|
{
|
|
public class Fish
|
|
{
|
|
private FishData fishData;
|
|
|
|
private Transform lastTarget;
|
|
|
|
private Vector3 position;
|
|
|
|
private Vector3 eulerRotation;
|
|
|
|
private float weight;
|
|
|
|
private bool isCulled;
|
|
|
|
public static event Action<Fish> OnCull;
|
|
|
|
public static event Action<Fish> OnDraw;
|
|
|
|
public float DistanceTo(Vector3 position)
|
|
{
|
|
return Vector3.Distance(position, this.position);
|
|
}
|
|
|
|
public void Cull()
|
|
{
|
|
if (!isCulled)
|
|
{
|
|
isCulled = true;
|
|
Fish.OnCull?.Invoke(this);
|
|
}
|
|
}
|
|
|
|
public void Show()
|
|
{
|
|
if (isCulled)
|
|
{
|
|
isCulled = false;
|
|
Fish.OnDraw?.Invoke(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Tooltip("How many times check raycast on fish, use this for optimiziation fish scanners")]
|
|
[SerializeField]
|
|
private int _RayPerFrame = 5;
|
|
|
|
[SerializeField]
|
|
private List<FishEntity> _FisheshList;
|
|
|
|
[SerializeField]
|
|
private int _IterationPos;
|
|
|
|
[SerializeField]
|
|
private LevelFishData levelFishData;
|
|
|
|
[SerializeField]
|
|
private FloatVariable fishGrowInterval;
|
|
|
|
[SerializeField]
|
|
private Vector2IntVariable FishGrowRate;
|
|
|
|
private bool isUpdating = true;
|
|
|
|
private bool isInitializationLoading = true;
|
|
|
|
private List<Transform> cullTransforms = new List<Transform>();
|
|
|
|
private List<Transform> cullTransformsPending = new List<Transform>();
|
|
|
|
private static List<Transform> transformsCulledBeforeInitialize;
|
|
|
|
public List<FishEntity> AllFishes => _FisheshList;
|
|
|
|
public List<Transform> CullTransforms => cullTransforms;
|
|
|
|
private float DespawnCullDistance
|
|
{
|
|
get
|
|
{
|
|
if ((float)cullTransformsPending.Count != 0f)
|
|
{
|
|
return levelFishData.DrawDistance + 20f;
|
|
}
|
|
return levelFishData.CullDistance;
|
|
}
|
|
}
|
|
|
|
public static event Action<FishEntity, float> OnGrowFish;
|
|
|
|
public static event Action<FishEntity> OnFishReachMaxSize;
|
|
|
|
private void Start()
|
|
{
|
|
_FisheshList = UnityEngine.Object.FindObjectsOfType<FishEntity>().ToList();
|
|
if (transformsCulledBeforeInitialize == null)
|
|
{
|
|
return;
|
|
}
|
|
foreach (Transform item in transformsCulledBeforeInitialize)
|
|
{
|
|
AddTransformCull(item);
|
|
}
|
|
transformsCulledBeforeInitialize = null;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
FishSpawner.OnSpawnFish += AddFish;
|
|
FishSpawner.OnDespawnFish += RemoveFish;
|
|
FishSpawner.OnStartFishesSpawned += FishSpawner_OnStartFishesSpawned;
|
|
StartCoroutine(CullTransformsPendingCoroutine());
|
|
StartCoroutine(FarthestFishDespawnCoroutine());
|
|
StartCoroutine(FishAIRaycastingCoroutine());
|
|
StartCoroutine(FishGrowCoroutine());
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
FishSpawner.OnSpawnFish -= AddFish;
|
|
FishSpawner.OnDespawnFish -= RemoveFish;
|
|
FishSpawner.OnStartFishesSpawned -= FishSpawner_OnStartFishesSpawned;
|
|
StopAllCoroutines();
|
|
}
|
|
|
|
private void FishSpawner_OnStartFishesSpawned()
|
|
{
|
|
isInitializationLoading = false;
|
|
}
|
|
|
|
private IEnumerator SpawnFishInPointCoroutine(FishEntity entity)
|
|
{
|
|
int num = 0;
|
|
int abortCounter = 0;
|
|
int perFrameMax = 15;
|
|
int abortMax = 100;
|
|
float distanceToDraw = (isInitializationLoading ? 0f : levelFishData.DrawDistance);
|
|
Transform transform = GetCullTargetToCheck(preferPending: true);
|
|
isUpdating = false;
|
|
do
|
|
{
|
|
FishTarget fishTarget = FishTargetBaker.GetRandomTarget(entity.Data.BehaviourType, transform);
|
|
if (!FishTargetBaker.Instance.CheckIfFishCanBeSpawnedInArea(entity, fishTarget.Area))
|
|
{
|
|
fishTarget = null;
|
|
}
|
|
if (fishTarget != null)
|
|
{
|
|
int num2 = ((!(transform == null)) ? 1 : 0);
|
|
if (num2 > 0)
|
|
{
|
|
float num3 = Vector3.Distance(transform.position, fishTarget.Transform.position);
|
|
if (num3 > distanceToDraw && num3 < DespawnCullDistance)
|
|
{
|
|
num2--;
|
|
}
|
|
}
|
|
if (num2 <= 0)
|
|
{
|
|
entity.Draw(fishTarget);
|
|
if (isInitializationLoading)
|
|
{
|
|
yield return null;
|
|
}
|
|
else
|
|
{
|
|
yield return new WaitForSeconds(0.1f);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
num++;
|
|
abortCounter++;
|
|
if (num > perFrameMax)
|
|
{
|
|
yield return null;
|
|
transform = GetCullTargetToCheck(preferPending: false);
|
|
num = 0;
|
|
}
|
|
}
|
|
while (abortCounter <= abortMax);
|
|
isUpdating = true;
|
|
Transform GetCullTargetToCheck(bool preferPending)
|
|
{
|
|
Transform result = null;
|
|
if (preferPending && cullTransformsPending.Count > 0)
|
|
{
|
|
result = cullTransformsPending[UnityEngine.Random.Range(0, cullTransformsPending.Count)];
|
|
}
|
|
else if (cullTransforms.Count > 0)
|
|
{
|
|
result = cullTransforms[UnityEngine.Random.Range(0, cullTransforms.Count)];
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
private IEnumerator CullTransformsPendingCoroutine()
|
|
{
|
|
int nearFishCountMin = 5;
|
|
float NearFishDistance = levelFishData.DrawDistance + 10f;
|
|
int targetIndex = 0;
|
|
while (true)
|
|
{
|
|
ValidateTransformsList();
|
|
if (cullTransforms != null && cullTransforms.Count > 0)
|
|
{
|
|
if (targetIndex >= cullTransforms.Count)
|
|
{
|
|
targetIndex = 0;
|
|
}
|
|
Transform transform = cullTransforms[targetIndex];
|
|
targetIndex++;
|
|
int num = 0;
|
|
if (_FisheshList != null && _FisheshList.Count > 0)
|
|
{
|
|
foreach (FishEntity fishesh in _FisheshList)
|
|
{
|
|
if (Vector3.Distance(transform.position, fishesh.transform.position) < NearFishDistance)
|
|
{
|
|
num++;
|
|
if (num >= nearFishCountMin)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (num >= nearFishCountMin)
|
|
{
|
|
if (cullTransformsPending.Contains(transform))
|
|
{
|
|
cullTransformsPending.Remove(transform);
|
|
}
|
|
}
|
|
else if (!cullTransformsPending.Contains(transform))
|
|
{
|
|
cullTransformsPending.Add(transform);
|
|
}
|
|
}
|
|
yield return new WaitForSeconds(3f);
|
|
}
|
|
}
|
|
|
|
private IEnumerator FarthestFishDespawnCoroutine()
|
|
{
|
|
while (true)
|
|
{
|
|
if (!MultiplayerFishSpawner.IsSlave && cullTransformsPending.Count > 0)
|
|
{
|
|
FishEntity fishEntity = null;
|
|
float num = 0f;
|
|
foreach (FishEntity fishesh in _FisheshList)
|
|
{
|
|
if (!(fishesh != null) || !(FishEntity.CurrentFishInFight != fishesh) || fishesh.CurrentFishState == FishState.Atack || MultiplayerFishSpawner.CheckFishInteractionWithPlayer(fishesh) || fishesh.IsCulled)
|
|
{
|
|
continue;
|
|
}
|
|
float num2 = float.MaxValue;
|
|
foreach (Transform cullTransform in cullTransforms)
|
|
{
|
|
float num3 = Vector3.Distance(fishesh.transform.position, cullTransform.position);
|
|
if (num3 < num2)
|
|
{
|
|
num2 = num3;
|
|
}
|
|
}
|
|
if (num2 > num)
|
|
{
|
|
num = num2;
|
|
fishEntity = fishesh;
|
|
}
|
|
}
|
|
if (fishEntity != null)
|
|
{
|
|
fishEntity.Cull();
|
|
}
|
|
}
|
|
yield return new WaitForSeconds(6f);
|
|
}
|
|
}
|
|
|
|
private IEnumerator FishAIRaycastingCoroutine()
|
|
{
|
|
int currentIndex = 0;
|
|
while (true)
|
|
{
|
|
int num = 0;
|
|
while (num < _RayPerFrame && _FisheshList.Count > 0)
|
|
{
|
|
if (currentIndex >= _FisheshList.Count)
|
|
{
|
|
currentIndex = 0;
|
|
}
|
|
FishEntity fishEntity = _FisheshList[currentIndex];
|
|
currentIndex++;
|
|
num++;
|
|
if (fishEntity != null && FishEntity.CurrentFishInFight != fishEntity && !fishEntity.IsCulled)
|
|
{
|
|
fishEntity.EnableAIRaycasting();
|
|
}
|
|
}
|
|
yield return null;
|
|
}
|
|
}
|
|
|
|
private IEnumerator FishGrowCoroutine()
|
|
{
|
|
int currentIndex = 0;
|
|
while (true)
|
|
{
|
|
if (!MultiplayerFishSpawner.IsSlave && fishGrowInterval != null && FishGrowRate != null && _FisheshList != null && _FisheshList.Count > 0)
|
|
{
|
|
if (currentIndex >= _FisheshList.Count)
|
|
{
|
|
currentIndex = 0;
|
|
}
|
|
FishEntity fish = _FisheshList[currentIndex];
|
|
currentIndex++;
|
|
if (fish != null && FishEntity.CurrentFishInFight != fish && fish.CurrentFishState != FishState.Atack && !MultiplayerFishSpawner.CheckFishInteractionWithPlayer(fish) && !fish.IsCulled && !FishIsNerbyTarget(fish))
|
|
{
|
|
float y = levelFishData.FishesSetting.First((LevelFishData.FishDataHelper element) => element.FishData == fish.Data).Weight.y;
|
|
float num = y * ((float)UnityEngine.Random.Range(FishGrowRate.Value.x, FishGrowRate.Value.y) * 0.01f);
|
|
float num2 = fish.Weight + num;
|
|
if (num2 > y)
|
|
{
|
|
FishEntityManager.OnFishReachMaxSize?.Invoke(fish);
|
|
}
|
|
else
|
|
{
|
|
FishEntityManager.OnGrowFish?.Invoke(fish, num2);
|
|
}
|
|
}
|
|
yield return new WaitForSeconds(fishGrowInterval.Value / (float)_FisheshList.Count);
|
|
}
|
|
else
|
|
{
|
|
yield return new WaitForSeconds(1f);
|
|
}
|
|
}
|
|
bool FishIsNerbyTarget(FishEntity fishEntity)
|
|
{
|
|
bool result = false;
|
|
foreach (Transform cullTransform in cullTransforms)
|
|
{
|
|
if (Vector3.Distance(fishEntity.transform.position, cullTransform.position) <= 10f)
|
|
{
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
private void CullUpdater()
|
|
{
|
|
if (MultiplayerFishSpawner.IsSlave)
|
|
{
|
|
return;
|
|
}
|
|
for (int i = 0; i < _RayPerFrame; i++)
|
|
{
|
|
if (_FisheshList == null)
|
|
{
|
|
break;
|
|
}
|
|
if (_FisheshList.Count <= 0)
|
|
{
|
|
break;
|
|
}
|
|
if (_IterationPos >= _FisheshList.Count)
|
|
{
|
|
_IterationPos = 0;
|
|
}
|
|
FishEntity fishEntity = _FisheshList[_IterationPos];
|
|
_IterationPos++;
|
|
if (!(fishEntity != null) || !(FishEntity.CurrentFishInFight != fishEntity) || fishEntity.CurrentFishState == FishState.Atack || MultiplayerFishSpawner.CheckFishInteractionWithPlayer(fishEntity))
|
|
{
|
|
continue;
|
|
}
|
|
int num = cullTransforms.Count;
|
|
foreach (Transform cullTransform in cullTransforms)
|
|
{
|
|
bool flag = Vector3.Distance(cullTransform.position, fishEntity.transform.position) > DespawnCullDistance;
|
|
if (!fishEntity.IsCulled && flag)
|
|
{
|
|
num--;
|
|
}
|
|
}
|
|
if (fishEntity.IsCulled)
|
|
{
|
|
StartCoroutine(SpawnFishInPointCoroutine(fishEntity));
|
|
break;
|
|
}
|
|
if (num <= 0)
|
|
{
|
|
fishEntity.Cull();
|
|
StartCoroutine(SpawnFishInPointCoroutine(fishEntity));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RemoveCull()
|
|
{
|
|
if (!MultiplayerFishSpawner.IsSlave || _FisheshList == null || _FisheshList.Count <= 0)
|
|
{
|
|
return;
|
|
}
|
|
foreach (FishEntity fishesh in _FisheshList)
|
|
{
|
|
if (fishesh != null && fishesh.IsCulled)
|
|
{
|
|
fishesh.Draw();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
ValidateTransformsList();
|
|
if (!MultiplayerFishSpawner.IsSlave)
|
|
{
|
|
if (isUpdating)
|
|
{
|
|
CullUpdater();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RemoveCull();
|
|
}
|
|
}
|
|
|
|
public static void AddTransformCull(Transform t)
|
|
{
|
|
if (Singleton<FishEntityManager>.Instance == null)
|
|
{
|
|
if (transformsCulledBeforeInitialize == null)
|
|
{
|
|
transformsCulledBeforeInitialize = new List<Transform>();
|
|
}
|
|
transformsCulledBeforeInitialize.Add(t);
|
|
}
|
|
else
|
|
{
|
|
Singleton<FishEntityManager>.Instance.cullTransforms.Add(t);
|
|
Singleton<FishEntityManager>.Instance.cullTransformsPending.Add(t);
|
|
}
|
|
}
|
|
|
|
public static void RemoveTransformCull(Transform t)
|
|
{
|
|
if ((bool)Singleton<FishEntityManager>.Instance)
|
|
{
|
|
Singleton<FishEntityManager>.Instance.cullTransforms.Remove(t);
|
|
Singleton<FishEntityManager>.Instance.cullTransformsPending.Remove(t);
|
|
}
|
|
}
|
|
|
|
private void ValidateTransformsList()
|
|
{
|
|
cullTransforms.RemoveAll((Transform element) => element == null);
|
|
cullTransformsPending.RemoveAll((Transform element) => element == null);
|
|
}
|
|
|
|
private void AddFish(FishEntity fish, int levelFishDataIndex)
|
|
{
|
|
_FisheshList.Add(fish);
|
|
}
|
|
|
|
private void RemoveFish(FishEntity fish)
|
|
{
|
|
_FisheshList.Remove(fish);
|
|
}
|
|
}
|
|
}
|