r2mods/ilspy_dump/ror2_csproj/RoR2.Projectile/ProjectileSphereTargetFinde...

164 lines
4.1 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.Serialization;
namespace RoR2.Projectile;
[RequireComponent(typeof(ProjectileTargetComponent))]
[RequireComponent(typeof(TeamFilter))]
public class ProjectileSphereTargetFinder : MonoBehaviour
{
[Tooltip("How far ahead the projectile should look to find a target.")]
public float lookRange;
[Tooltip("How long before searching for a target.")]
public float targetSearchInterval = 0.5f;
[Tooltip("Will not search for new targets once it has one.")]
public bool onlySearchIfNoTarget;
[Tooltip("Allows the target to be lost if it's outside the acceptable range.")]
public bool allowTargetLoss;
[Tooltip("If set, targets can only be found when there is a free line of sight.")]
public bool testLoS;
[Tooltip("Whether or not airborne characters should be ignored.")]
public bool ignoreAir;
[Tooltip("The difference in altitude at which a result will be ignored.")]
[FormerlySerializedAs("altitudeTolerance")]
public float flierAltitudeTolerance = float.PositiveInfinity;
public UnityEvent onNewTargetFound;
public UnityEvent onTargetLost;
private new Transform transform;
private TeamFilter teamFilter;
private ProjectileTargetComponent targetComponent;
private float searchTimer;
private SphereSearch sphereSearch;
private bool hasTarget;
private bool hadTargetLastUpdate;
private HurtBox lastFoundHurtBox;
private Transform lastFoundTransform;
private static readonly List<HurtBox> foundHurtBoxes = new List<HurtBox>();
private void Start()
{
if (!NetworkServer.active)
{
base.enabled = false;
return;
}
transform = base.transform;
teamFilter = GetComponent<TeamFilter>();
targetComponent = GetComponent<ProjectileTargetComponent>();
sphereSearch = new SphereSearch();
searchTimer = 0f;
}
private void FixedUpdate()
{
searchTimer -= Time.fixedDeltaTime;
if (!(searchTimer <= 0f))
{
return;
}
searchTimer += targetSearchInterval;
if (allowTargetLoss && (object)targetComponent.target != null && (object)lastFoundTransform == targetComponent.target && !PassesFilters(lastFoundHurtBox))
{
SetTarget(null);
}
if (!onlySearchIfNoTarget || targetComponent.target == null)
{
SearchForTarget();
}
hasTarget = targetComponent.target != null;
if (hadTargetLastUpdate != hasTarget)
{
if (hasTarget)
{
onNewTargetFound?.Invoke();
}
else
{
onTargetLost?.Invoke();
}
}
hadTargetLastUpdate = hasTarget;
}
private bool PassesFilters(HurtBox result)
{
CharacterBody body = result.healthComponent.body;
if (!body || (ignoreAir && body.isFlying))
{
return false;
}
if (body.isFlying && !float.IsInfinity(flierAltitudeTolerance) && flierAltitudeTolerance < Mathf.Abs(result.transform.position.y - transform.position.y))
{
return false;
}
return true;
}
private void SearchForTarget()
{
sphereSearch.origin = transform.position;
sphereSearch.radius = lookRange;
sphereSearch.mask = LayerIndex.entityPrecise.mask;
sphereSearch.queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
sphereSearch.RefreshCandidates();
sphereSearch.FilterCandidatesByHurtBoxTeam(TeamMask.GetEnemyTeams(teamFilter.teamIndex));
sphereSearch.OrderCandidatesByDistance();
sphereSearch.FilterCandidatesByDistinctHurtBoxEntities();
sphereSearch.GetHurtBoxes(foundHurtBoxes);
HurtBox target = null;
if (foundHurtBoxes.Count > 0)
{
int i = 0;
for (int count = foundHurtBoxes.Count; i < count; i++)
{
if (PassesFilters(foundHurtBoxes[i]))
{
target = foundHurtBoxes[i];
break;
}
}
foundHurtBoxes.Clear();
}
SetTarget(target);
}
private void SetTarget(HurtBox hurtBox)
{
lastFoundHurtBox = hurtBox;
lastFoundTransform = hurtBox?.transform;
targetComponent.target = lastFoundTransform;
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.yellow;
Vector3 position = base.transform.position;
Gizmos.DrawWireSphere(position, lookRange);
if (!float.IsInfinity(flierAltitudeTolerance))
{
Gizmos.DrawWireCube(position, new Vector3(lookRange * 2f, flierAltitudeTolerance * 2f, lookRange * 2f));
}
}
}