r2mods/ilspy_dump/ror2_csproj/RoR2/BullseyeSearch.cs

299 lines
7.1 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace RoR2;
public class BullseyeSearch
{
private struct CandidateInfo
{
public HurtBox hurtBox;
public Vector3 position;
public float dot;
public float distanceSqr;
}
public enum SortMode
{
None,
Distance,
Angle,
DistanceAndAngle
}
private delegate CandidateInfo Selector(HurtBox hurtBox);
public CharacterBody viewer;
public Vector3 searchOrigin;
public Vector3 searchDirection;
private float minThetaDot = -1f;
private float maxThetaDot = 1f;
public float minDistanceFilter;
public float maxDistanceFilter = float.PositiveInfinity;
public TeamMask teamMaskFilter = TeamMask.allButNeutral;
public bool filterByLoS = true;
public bool filterByDistinctEntity;
public QueryTriggerInteraction queryTriggerInteraction;
public SortMode sortMode = SortMode.Distance;
private List<CandidateInfo> candidatesEnumerable;
private HashSet<int> DistinctEntityHash = new HashSet<int>();
public float minAngleFilter
{
set
{
maxThetaDot = Mathf.Cos(Mathf.Clamp(value, 0f, 180f) * (MathF.PI / 180f));
}
}
public float maxAngleFilter
{
set
{
minThetaDot = Mathf.Cos(Mathf.Clamp(value, 0f, 180f) * (MathF.PI / 180f));
}
}
private bool filterByDistance
{
get
{
if (!(minDistanceFilter > 0f) && !(maxDistanceFilter < float.PositiveInfinity))
{
if ((bool)viewer)
{
return viewer.visionDistance < float.PositiveInfinity;
}
return false;
}
return true;
}
}
private bool filterByAngle
{
get
{
if (!(minThetaDot > -1f))
{
return maxThetaDot < 1f;
}
return true;
}
}
private Func<HurtBox, CandidateInfo> GetSelector()
{
bool getDot = filterByAngle;
bool getDistanceSqr = filterByDistance;
getDistanceSqr |= sortMode == SortMode.Distance || sortMode == SortMode.DistanceAndAngle;
getDot |= sortMode == SortMode.Angle || sortMode == SortMode.DistanceAndAngle;
bool getDifference = getDot || getDistanceSqr;
bool getPosition = getDot || getDistanceSqr || filterByLoS;
return delegate(HurtBox hurtBox)
{
CandidateInfo candidateInfo = default(CandidateInfo);
candidateInfo.hurtBox = hurtBox;
CandidateInfo result = candidateInfo;
if (getPosition)
{
result.position = hurtBox.transform.position;
}
Vector3 vector = default(Vector3);
if (getDifference)
{
vector = result.position - searchOrigin;
}
if (getDot)
{
result.dot = Vector3.Dot(searchDirection, vector.normalized);
}
if (getDistanceSqr)
{
result.distanceSqr = vector.sqrMagnitude;
}
return result;
};
}
public void RefreshCandidates()
{
Func<HurtBox, CandidateInfo> selector = GetSelector();
int count = HurtBox.readOnlyBullseyesList.Count;
List<CandidateInfo> list = (candidatesEnumerable = new List<CandidateInfo>(count));
bool flag = filterByAngle;
bool flag2 = filterByDistance;
float minDistanceSqr = 0f;
float maxDistanceSqr = 0f;
if (flag2)
{
float num = maxDistanceFilter;
if ((bool)viewer)
{
num = Mathf.Min(num, viewer.visionDistance);
}
minDistanceSqr = minDistanceFilter * minDistanceFilter;
maxDistanceSqr = num * num;
}
for (int i = 0; i < count; i++)
{
HurtBox hurtBox = HurtBox.readOnlyBullseyesList[i];
int item = 0;
if (filterByDistinctEntity)
{
item = hurtBox.healthComponent.GetInstanceID();
if (DistinctEntityHash.Contains(item))
{
continue;
}
}
if (!teamMaskFilter.HasTeam(hurtBox.teamIndex))
{
continue;
}
CandidateInfo candidateInfo2 = selector(hurtBox);
if ((!flag || DotOkay(candidateInfo2)) && (!flag2 || DistanceOkay(candidateInfo2)))
{
if (filterByDistinctEntity)
{
DistinctEntityHash.Add(item);
}
list.Add(candidateInfo2);
}
}
Func<CandidateInfo, float> sorter = GetSorter();
if (sorter != null)
{
Comparison<CandidateInfo> comparison = (CandidateInfo x, CandidateInfo y) => sorter(x).CompareTo(sorter(y));
list.Sort(comparison);
}
if (filterByDistinctEntity)
{
DistinctEntityHash.Clear();
}
bool DistanceOkay(CandidateInfo candidateInfo)
{
if (candidateInfo.distanceSqr >= minDistanceSqr)
{
return candidateInfo.distanceSqr <= maxDistanceSqr;
}
return false;
}
bool DotOkay(CandidateInfo candidateInfo)
{
if (minThetaDot <= candidateInfo.dot)
{
return candidateInfo.dot <= maxThetaDot;
}
return false;
}
}
private Func<CandidateInfo, float> GetSorter()
{
return sortMode switch
{
SortMode.Distance => (CandidateInfo candidateInfo) => candidateInfo.distanceSqr,
SortMode.Angle => (CandidateInfo candidateInfo) => 0f - candidateInfo.dot,
SortMode.DistanceAndAngle => (CandidateInfo candidateInfo) => (0f - candidateInfo.dot) * candidateInfo.distanceSqr,
_ => null,
};
}
public void FilterCandidatesByHealthFraction(float minHealthFraction = 0f, float maxHealthFraction = 1f)
{
if (minHealthFraction > 0f)
{
if (maxHealthFraction < 1f)
{
candidatesEnumerable.RemoveAll(delegate(CandidateInfo v)
{
float combinedHealthFraction = v.hurtBox.healthComponent.combinedHealthFraction;
return combinedHealthFraction < minHealthFraction || maxHealthFraction < combinedHealthFraction;
});
}
else
{
candidatesEnumerable.RemoveAll((CandidateInfo v) => v.hurtBox.healthComponent.combinedHealthFraction < minHealthFraction);
}
}
else if (maxHealthFraction < 1f)
{
candidatesEnumerable.RemoveAll((CandidateInfo v) => v.hurtBox.healthComponent.combinedHealthFraction > maxHealthFraction);
}
}
public void FilterOutGameObject(GameObject gameObject)
{
candidatesEnumerable.RemoveAll((CandidateInfo v) => v.hurtBox.healthComponent.gameObject == gameObject);
}
public IEnumerable<HurtBox> GetResults()
{
_ = candidatesEnumerable;
if (filterByLoS)
{
candidatesEnumerable.RemoveAll((CandidateInfo candidateInfo) => !CheckLoS(candidateInfo.position));
}
if ((bool)viewer)
{
candidatesEnumerable.RemoveAll((CandidateInfo candidateInfo) => !CheckVisible(candidateInfo.hurtBox.healthComponent.gameObject));
}
int count = candidatesEnumerable.Count;
HurtBox[] array = new HurtBox[count];
for (int i = 0; i < count; i++)
{
array[i] = candidatesEnumerable[i].hurtBox;
}
return array;
}
public bool CheckLoS(Vector3 targetPosition)
{
Vector3 direction = targetPosition - searchOrigin;
RaycastHit hitInfo;
return !Physics.Raycast(searchOrigin, direction, out hitInfo, direction.magnitude, LayerIndex.world.mask, queryTriggerInteraction);
}
public bool CheckVisible(GameObject gameObject)
{
CharacterBody component = gameObject.GetComponent<CharacterBody>();
if ((bool)component)
{
return component.GetVisibilityLevel(viewer) >= VisibilityLevel.Revealed;
}
return true;
}
public void Reset()
{
viewer = null;
searchOrigin = Vector3.zero;
searchDirection = Vector3.zero;
minThetaDot = -1f;
minDistanceFilter = 0f;
maxDistanceFilter = float.PositiveInfinity;
teamMaskFilter = TeamMask.allButNeutral;
filterByLoS = true;
queryTriggerInteraction = QueryTriggerInteraction.UseGlobal;
sortMode = SortMode.Distance;
}
}