r2mods/ilspy_dump/ror2_csproj/RoR2.Navigation/MapNode.cs

434 lines
13 KiB
C#

using System.Collections.Generic;
using System.Collections.ObjectModel;
using UnityEngine;
namespace RoR2.Navigation;
[ExecuteInEditMode]
public class MapNode : MonoBehaviour
{
public struct Link
{
public MapNode nodeB;
public float distanceScore;
public float minJumpHeight;
public int hullMask;
public int jumpHullMask;
public string gateName;
}
public class MoveProbe
{
public CharacterController testCharacterController;
private float testTimeStep = 1f / 15f;
public void Init()
{
GameObject gameObject = new GameObject();
gameObject.name = "NodeGraphProbe";
_ = gameObject.transform;
testCharacterController = gameObject.AddComponent<CharacterController>();
testCharacterController.stepOffset = 0.5f;
testCharacterController.slopeLimit = 60f;
}
public void SetHull(HullClassification hullClassification)
{
HullDef hullDef = HullDef.Find(hullClassification);
testCharacterController.radius = hullDef.radius;
testCharacterController.height = hullDef.height;
}
public void Destroy()
{
Object.DestroyImmediate(testCharacterController.gameObject);
}
private static float DistanceXZ(Vector3 a, Vector3 b)
{
a.y = 0f;
b.y = 0f;
return Vector3.Distance(a, b);
}
public static Vector3 GetGroundPosition(Vector3 footPosition, float height, float radius)
{
Vector3 vector = Vector3.up * (height * 0.5f - radius);
Vector3 vector2 = Vector3.up * (height * 0.5f);
Vector3 vector3 = footPosition + vector2;
float num = radius * 0.5f + 0.005f;
Vector3 vector4 = footPosition + Vector3.up * num;
Vector3 vector5 = vector3 + Vector3.up * num;
if (Physics.CapsuleCast(vector5 + vector, vector5 - vector, radius, Vector3.down, out var hitInfo, num * 2f + 0.005f, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
{
Vector3 vector6 = hitInfo.distance * Vector3.down;
return vector4 + vector6;
}
return footPosition;
}
public Vector3 GetGroundPosition(Vector3 footPosition)
{
return GetGroundPosition(footPosition, testCharacterController.height, testCharacterController.radius);
}
public bool CapsuleOverlapTest(Vector3 centerOfCapsule)
{
Vector3 vector = Vector3.up * (testCharacterController.height * 0.5f - testCharacterController.radius);
_ = Vector3.up * (testCharacterController.height * 0.5f);
return Physics.OverlapCapsule(centerOfCapsule + vector, centerOfCapsule - vector, testCharacterController.radius, (int)LayerIndex.world.mask | (int)LayerIndex.CommonMasks.characterBodiesOrDefault, QueryTriggerInteraction.Ignore).Length == 0;
}
public bool FlyTest(Vector3 startPos, Vector3 endPos, float flySpeed)
{
Vector3 vector = Vector3.up * (testCharacterController.height * 0.5f - testCharacterController.radius);
return !Physics.CapsuleCast(startPos + vector, startPos - vector, testCharacterController.radius, (endPos - startPos).normalized, (endPos - startPos).magnitude, LayerIndex.world.mask);
}
private void MoveCapsule(Vector3 displacement)
{
testCharacterController.Move(displacement);
}
private void SetCapsulePosition(Vector3 position)
{
testCharacterController.transform.position = position;
Physics.SyncTransforms();
}
public bool GroundTest(Vector3 startCenterOfCapsulePos, Vector3 endCenterOfCapsulePos, float hSpeed)
{
MoveCapsule(Vector3.zero);
Vector3 zero = Vector3.zero;
float num = DistanceXZ(startCenterOfCapsulePos, endCenterOfCapsulePos);
SetCapsulePosition(startCenterOfCapsulePos + Vector3.up);
int num2 = Mathf.CeilToInt(num * 1.5f / hSpeed / testTimeStep);
Vector3 vector = testCharacterController.transform.position;
for (int i = 0; i < num2; i++)
{
Vector3 vector2 = endCenterOfCapsulePos - testCharacterController.transform.position;
if (vector2.sqrMagnitude <= 0.25f)
{
return true;
}
Vector3 vector3 = vector2;
vector3.y = 0f;
vector3.Normalize();
zero.x = vector3.x * hSpeed;
zero.z = vector3.z * hSpeed;
zero += Physics.gravity * testTimeStep;
MoveCapsule(zero * testTimeStep);
Vector3 position = testCharacterController.transform.position;
if (position == vector)
{
return false;
}
vector = position;
}
return false;
}
public float JumpTest(Vector3 startCenterOfCapsulePos, Vector3 endCenterOfCapsulePos, float hSpeed)
{
float y = Trajectory.CalculateInitialYSpeed(Trajectory.CalculateGroundTravelTime(hSpeed, DistanceXZ(startCenterOfCapsulePos, endCenterOfCapsulePos)), endCenterOfCapsulePos.y - startCenterOfCapsulePos.y);
testCharacterController.Move(Vector3.zero);
Vector3 vector = endCenterOfCapsulePos - startCenterOfCapsulePos;
vector.y = 0f;
vector.Normalize();
vector *= hSpeed;
vector.y = y;
float num = DistanceXZ(startCenterOfCapsulePos, endCenterOfCapsulePos);
SetCapsulePosition(startCenterOfCapsulePos);
int num2 = Mathf.CeilToInt(num * 1.5f / hSpeed / testTimeStep);
float num3 = float.NegativeInfinity;
Vector3 vector2 = testCharacterController.transform.position;
for (int i = 0; i < num2; i++)
{
Vector3 vector3 = endCenterOfCapsulePos - testCharacterController.transform.position;
if (vector3.sqrMagnitude <= 4f)
{
return num3 - startCenterOfCapsulePos.y;
}
num3 = Mathf.Max(testCharacterController.transform.position.y, num3);
Vector3 vector4 = vector3;
vector4.y = 0f;
vector4.Normalize();
vector.x = vector4.x * hSpeed;
vector.z = vector4.z * hSpeed;
vector += Physics.gravity * testTimeStep;
testCharacterController.Move(vector * testTimeStep);
Vector3 position = testCharacterController.transform.position;
if (position == vector2)
{
return 0f;
}
vector2 = position;
}
return 0f;
}
}
private static List<MapNode> _instances = new List<MapNode>();
private static ReadOnlyCollection<MapNode> instancesReadOnly = _instances.AsReadOnly();
public static readonly float maxConnectionDistance = 15f;
public List<Link> links = new List<Link>();
[EnumMask(typeof(HullMask))]
public HullMask forbiddenHulls;
[EnumMask(typeof(NodeFlags))]
public NodeFlags flags;
[Tooltip("The name of the nodegraph gate associated with this node. If the named gate is closed this node will be treated as though it does not exist.")]
public string gateName = "";
public static ReadOnlyCollection<MapNode> instances => instancesReadOnly;
public void OnEnable()
{
_instances.Add(this);
}
public void OnDisable()
{
_instances.Remove(this);
}
private void AddLink(MapNode nodeB, float distanceScore, float minJumpHeight, HullClassification hullClassification)
{
int num = links.FindIndex((Link item) => item.nodeB == nodeB);
if (num == -1)
{
links.Add(new Link
{
nodeB = nodeB
});
num = links.Count - 1;
}
Link value = links[num];
value.distanceScore = Mathf.Max(value.distanceScore, distanceScore);
value.minJumpHeight = Mathf.Max(value.minJumpHeight, minJumpHeight);
value.hullMask |= 1 << (int)hullClassification;
if (minJumpHeight > 0f)
{
value.jumpHullMask |= 1 << (int)hullClassification;
}
if (string.IsNullOrEmpty(value.gateName))
{
value.gateName = nodeB.gateName;
}
links[num] = value;
}
private void BuildGroundLinks(ReadOnlyCollection<MapNode> nodes, MoveProbe moveProbe)
{
Vector3 position = base.transform.position;
for (int i = 0; i < nodes.Count; i++)
{
MapNode mapNode = nodes[i];
if (mapNode == this)
{
continue;
}
Vector3 position2 = mapNode.transform.position;
float num = maxConnectionDistance;
float num2 = num * num;
float sqrMagnitude = (position2 - position).sqrMagnitude;
if (!(sqrMagnitude < num2))
{
continue;
}
float distanceScore = Mathf.Sqrt(sqrMagnitude);
for (int j = 0; j < 3; j++)
{
moveProbe.SetHull((HullClassification)j);
if (((uint)forbiddenHulls & (uint)(1 << j)) != 0 || ((uint)mapNode.forbiddenHulls & (uint)(1 << j)) != 0)
{
continue;
}
Vector3 vector = Vector3.up * (moveProbe.testCharacterController.height * 0.5f);
Vector3 vector2 = Vector3.up * 0.01f;
Vector3 vector3 = moveProbe.GetGroundPosition(position) + vector2;
Vector3 vector4 = moveProbe.GetGroundPosition(position2) + vector2;
Vector3 vector5 = vector3 + vector;
Vector3 vector6 = vector4 + vector;
if (moveProbe.CapsuleOverlapTest(vector5) && moveProbe.CapsuleOverlapTest(vector6))
{
bool num3 = moveProbe.GroundTest(vector5, vector6, 6f);
float num4 = ((!num3) ? moveProbe.JumpTest(vector5, vector6, 7.5f) : 0f);
if (num3 || (num4 > 0f && num4 < 10f))
{
AddLink(mapNode, distanceScore, num4, (HullClassification)j);
}
}
}
}
}
private void BuildAirLinks(ReadOnlyCollection<MapNode> nodes, MoveProbe moveProbe)
{
Vector3 position = base.transform.position;
for (int i = 0; i < nodes.Count; i++)
{
MapNode mapNode = nodes[i];
if (mapNode == this)
{
continue;
}
Vector3 position2 = mapNode.transform.position;
float num = maxConnectionDistance * 2f;
float num2 = num * num;
float sqrMagnitude = (position2 - position).sqrMagnitude;
if (!(sqrMagnitude < num2))
{
continue;
}
float distanceScore = Mathf.Sqrt(sqrMagnitude);
for (int j = 0; j < 3; j++)
{
if (((uint)forbiddenHulls & (uint)(1 << j)) == 0 && ((uint)mapNode.forbiddenHulls & (uint)(1 << j)) == 0)
{
moveProbe.SetHull((HullClassification)j);
Vector3 vector = position;
Vector3 vector2 = position2;
if (moveProbe.CapsuleOverlapTest(vector) && moveProbe.CapsuleOverlapTest(vector2) && moveProbe.FlyTest(vector, vector2, 6f))
{
AddLink(mapNode, distanceScore, 0f, (HullClassification)j);
}
}
}
}
}
private void BuildRailLinks(ReadOnlyCollection<MapNode> nodes, MoveProbe moveProbe)
{
Vector3 position = base.transform.position;
for (int i = 0; i < nodes.Count; i++)
{
MapNode mapNode = nodes[i];
if (mapNode == this)
{
continue;
}
Vector3 position2 = mapNode.transform.position;
float num = maxConnectionDistance * 2f;
float num2 = num * num;
float sqrMagnitude = (position2 - position).sqrMagnitude;
if (!(sqrMagnitude < num2))
{
continue;
}
float distanceScore = Mathf.Sqrt(sqrMagnitude);
for (int j = 0; j < 3; j++)
{
HullDef hullDef = HullDef.Find((HullClassification)j);
if (((uint)forbiddenHulls & (uint)(1 << j)) != 0 || ((uint)mapNode.forbiddenHulls & (uint)(1 << j)) != 0)
{
continue;
}
moveProbe.SetHull((HullClassification)j);
Vector3 vector = position;
Vector3 vector2 = position2;
if (!(Vector3.Angle(Vector3.up, vector2 - vector) <= 50f))
{
vector.y += hullDef.height;
vector2.y += hullDef.height;
if (moveProbe.CapsuleOverlapTest(vector) && moveProbe.CapsuleOverlapTest(vector2) && moveProbe.FlyTest(vector, vector2, 6f))
{
AddLink(mapNode, distanceScore, 0f, (HullClassification)j);
}
}
}
}
}
public void BuildLinks(ReadOnlyCollection<MapNode> nodes, MapNodeGroup.GraphType graphType)
{
links.Clear();
Vector3 position = base.transform.position;
MoveProbe moveProbe = new MoveProbe();
moveProbe.Init();
switch (graphType)
{
case MapNodeGroup.GraphType.Ground:
BuildGroundLinks(nodes, moveProbe);
break;
case MapNodeGroup.GraphType.Air:
BuildAirLinks(nodes, moveProbe);
break;
case MapNodeGroup.GraphType.Rail:
BuildRailLinks(nodes, moveProbe);
break;
}
MapNodeLink[] components = GetComponents<MapNodeLink>();
foreach (MapNodeLink mapNodeLink in components)
{
if (!mapNodeLink.other)
{
continue;
}
Link link = default(Link);
link.nodeB = mapNodeLink.other;
link.distanceScore = Vector3.Distance(position, mapNodeLink.other.transform.position);
link.minJumpHeight = mapNodeLink.minJumpHeight;
link.gateName = mapNodeLink.gateName;
link.hullMask = -1;
Link link2 = link;
bool flag = false;
for (int j = 0; j < links.Count; j++)
{
if (links[j].nodeB == mapNodeLink.other)
{
links[j] = link2;
flag = true;
break;
}
}
if (!flag)
{
links.Add(link2);
}
}
moveProbe.Destroy();
}
public bool TestLineOfSight(MapNode other)
{
return !Physics.Linecast(base.transform.position + Vector3.up, other.transform.position + Vector3.up, LayerIndex.world.mask);
}
public bool TestNoCeiling()
{
return !Physics.Raycast(new Ray(base.transform.position, Vector3.up), float.PositiveInfinity, LayerIndex.world.mask, QueryTriggerInteraction.Ignore);
}
public bool TestTeleporterOK()
{
float num = 15f;
int num2 = 20;
float num3 = 7f;
float num4 = 3f;
float num5 = 360f / (float)num2;
for (int i = 0; i < num2; i++)
{
Vector3 vector = Quaternion.AngleAxis(num5 * (float)i, Vector3.up) * (Vector3.forward * num);
Vector3 origin = base.transform.position + vector + Vector3.up * num3;
if (!Physics.Raycast(new Ray(origin, Vector3.down), out var _, num4 + num3, LayerIndex.world.mask, QueryTriggerInteraction.Ignore))
{
return false;
}
}
Debug.DrawRay(base.transform.position, base.transform.up * 20f, Color.green, 15f);
return true;
}
}