Decompiled source of ExitLineFromEnteredDoor v1.0.1

ExitLineFromEnteredDoor.dll

Decompiled an hour ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ExitLineFromEnteredDoor
{
	internal class ExitLineController : MonoBehaviour
	{
		private sealed class DotLine
		{
			public GameObject Container;

			public readonly List<Transform> Dots = new List<Transform>();

			public NavMeshPath Path;

			public bool HasPath;

			public float RecomputeIn;

			public Vector3 LastDestination;

			public Vector3[] Corners;

			public float[] CumLen;

			public float TotalLen;

			public readonly List<float> BaseArcs = new List<float>();

			public float OverflowArc;

			public float Phase;

			public bool IsFireExit;

			public int AppliedColorKind = -1;
		}

		private static readonly FieldInfo PingScanField = AccessTools.Field(typeof(HUDManager), "playerPingingScan");

		private static readonly FieldInfo IsScreenOnField = AccessTools.Field(typeof(ManualCameraRenderer), "isScreenOn");

		private const int MaxDotsPerLine = 400;

		private readonly List<DotLine> _lines = new List<DotLine>();

		private readonly List<EntranceTeleport> _insideDoors = new List<EntranceTeleport>();

		private readonly List<Vector3> _destinations = new List<Vector3>();

		private readonly List<bool> _destinationIsFireExit = new List<bool>();

		private bool _wasInside;

		private bool _wasVisible;

		private float _lastPing;

		private float _pulseTimer;

		private float _lastScanTime = -9999f;

		private MineshaftElevatorController _elevator;

		private bool _searchedElevator;

		private int _worldLayer;

		private bool _worldLayerResolved;

		private float _doorRescanCooldown;

		private float _errorLogCooldown;

		private static Mesh _dotMesh;

		private static Material _dotMatMain;

		private static Material _dotMatFire;

		private static readonly List<float> ArcScratch = new List<float>();

		private Color _mainColor = new Color(0.38f, 1f, 0.44f, 1f);

		private Color _fireColor = new Color(1f, 0.3f, 0.3f, 1f);

		private string _parsedMainText;

		private string _parsedFireText;

		private int _dotBudget;

		private bool _loggedArcFallback;

		private bool _snapshotDirty;

		private void Update()
		{
			try
			{
				UpdateInternal();
			}
			catch (Exception ex)
			{
				if (Time.unscaledTime >= _errorLogCooldown)
				{
					_errorLogCooldown = Time.unscaledTime + 10f;
					ExitLinePlugin.Log.LogWarning((object)("ExitLineController error: " + ex));
				}
				HideAll();
			}
		}

		private void UpdateInternal()
		{
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_03da: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			GameNetworkManager instance = GameNetworkManager.Instance;
			PlayerControllerB val = (((Object)(object)instance != (Object)null) ? instance.localPlayerController : null);
			StartOfRound instance2 = StartOfRound.Instance;
			if ((Object)(object)val == (Object)null || (Object)(object)instance2 == (Object)null)
			{
				HideAll();
				return;
			}
			DetectScan();
			bool isInsideFactory = val.isInsideFactory;
			if (!isInsideFactory)
			{
				ExitLinePlugin.LastEnteredEntranceId = -1;
			}
			if (isInsideFactory && !_wasInside)
			{
				OnEnteredInterior();
			}
			_wasInside = isInsideFactory;
			_doorRescanCooldown -= Time.deltaTime;
			if (!IsLineVisible(val, instance2, isInsideFactory))
			{
				_wasVisible = false;
				HideAll();
				return;
			}
			if (!_wasVisible)
			{
				_snapshotDirty = true;
				for (int i = 0; i < _lines.Count; i++)
				{
					_lines[i].RecomputeIn = 0f;
				}
			}
			_wasVisible = true;
			if (!EnsureDotAssets())
			{
				HideAll();
				return;
			}
			EnsureWorldLayer(val);
			bool value = ExitLinePlugin.OnlyShowAfterScan.Value;
			if (!value || _snapshotDirty)
			{
				_destinations.Clear();
				_destinationIsFireExit.Clear();
				ResolveDestinations(val);
				if (value && _destinations.Count > 0)
				{
					for (int j = 0; j < _lines.Count; j++)
					{
						_lines[j].HasPath = false;
						_lines[j].RecomputeIn = 0f;
					}
					_snapshotDirty = false;
				}
			}
			if (_destinations.Count == 0)
			{
				HideAll();
				return;
			}
			EnsurePool(_destinations.Count);
			_dotBudget = 80;
			float deltaTime = Time.deltaTime;
			bool num = _pulseTimer > 0f && ExitLinePlugin.PulseOnScan.Value;
			_pulseTimer = Mathf.Max(0f, _pulseTimer - deltaTime);
			float num2 = (num ? (_pulseTimer / Mathf.Max(0.5f, ExitLinePlugin.PulseDuration.Value)) : 0f);
			float num3 = ExitLinePlugin.FlowSpeed.Value * Mathf.Pow(num2, 1.5f);
			float value2 = ExitLinePlugin.BreatheStrength.Value;
			float num4 = Mathf.Max(0.25f, ExitLinePlugin.BreathePeriod.Value);
			float num5 = 1f + value2 * 0.5f * Mathf.Sin(Time.time * 2f * (float)Math.PI / num4);
			num5 += ExitLinePlugin.PulseBrightness.Value * num2;
			if (ExitLinePlugin.OnlyShowAfterScan.Value)
			{
				float num6 = ExitLinePlugin.ShowDurationAfterScan.Value - (Time.time - _lastScanTime);
				num5 *= Mathf.Clamp01(num6 / 1.2f);
			}
			ApplyBrightness(num5);
			Vector3 position = ((Component)val).transform.position;
			for (int k = 0; k < _lines.Count; k++)
			{
				DotLine dotLine = _lines[k];
				if (k >= _destinations.Count)
				{
					dotLine.RecomputeIn = 0f;
					SetLineActive(dotLine, on: false);
					continue;
				}
				dotLine.IsFireExit = k < _destinationIsFireExit.Count && _destinationIsFireExit[k];
				ApplyLineMaterial(dotLine);
				if (value)
				{
					if (!dotLine.HasPath)
					{
						dotLine.RecomputeIn -= deltaTime;
						if (dotLine.RecomputeIn <= 0f)
						{
							ComputePath(dotLine, position, _destinations[k]);
						}
					}
				}
				else
				{
					dotLine.RecomputeIn -= deltaTime;
					if (dotLine.RecomputeIn <= 0f)
					{
						goto IL_03d7;
					}
					if (dotLine.HasPath)
					{
						Vector3 val2 = _destinations[k] - dotLine.LastDestination;
						if (((Vector3)(ref val2)).sqrMagnitude > 1f)
						{
							goto IL_03d7;
						}
					}
				}
				goto IL_03ee;
				IL_03d7:
				ComputePath(dotLine, position, _destinations[k]);
				goto IL_03ee;
				IL_03ee:
				if (!dotLine.HasPath)
				{
					SetLineActive(dotLine, on: false);
					continue;
				}
				if (num3 > 0f)
				{
					dotLine.Phase = Mathf.Repeat(dotLine.Phase + deltaTime * num3, 1f);
					RepositionDots(dotLine);
				}
				else if (dotLine.Dots.Count < dotLine.BaseArcs.Count + 1)
				{
					RepositionDots(dotLine);
				}
				SetLineActive(dotLine, on: true);
			}
			BillboardDots(val);
		}

		private void BillboardDots(PlayerControllerB localPlayer)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			Camera gameplayCamera = localPlayer.gameplayCamera;
			if ((Object)(object)gameplayCamera == (Object)null)
			{
				return;
			}
			Quaternion rotation = ((Component)gameplayCamera).transform.rotation;
			for (int i = 0; i < _lines.Count; i++)
			{
				DotLine dotLine = _lines[i];
				if ((Object)(object)dotLine.Container == (Object)null || !dotLine.Container.activeSelf)
				{
					continue;
				}
				List<Transform> dots = dotLine.Dots;
				for (int j = 0; j < dots.Count; j++)
				{
					Transform val = dots[j];
					if (((Component)val).gameObject.activeSelf)
					{
						val.rotation = rotation;
					}
				}
			}
		}

		private bool IsLineVisible(PlayerControllerB localPlayer, StartOfRound sor, bool inside)
		{
			if (!ExitLinePlugin.Enabled.Value)
			{
				return false;
			}
			if (!inside || localPlayer.isPlayerDead || !localPlayer.isPlayerControlled)
			{
				return false;
			}
			if (sor.inShipPhase)
			{
				return false;
			}
			if (ExitLinePlugin.RequirePlayerInShip.Value && !AnyPlayerInShip(sor))
			{
				return false;
			}
			if (ExitLinePlugin.RequireShipCameraOnYou.Value && !ShipCameraOnLocal(sor, localPlayer))
			{
				return false;
			}
			if (ExitLinePlugin.OnlyShowAfterScan.Value && Time.time - _lastScanTime > ExitLinePlugin.ShowDurationAfterScan.Value)
			{
				return false;
			}
			return true;
		}

		private static bool AnyPlayerInShip(StartOfRound sor)
		{
			PlayerControllerB[] allPlayerScripts = sor.allPlayerScripts;
			if (allPlayerScripts == null)
			{
				return false;
			}
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if ((Object)(object)val != (Object)null && val.isPlayerControlled && !val.isPlayerDead && val.isInHangarShipRoom)
				{
					return true;
				}
			}
			return false;
		}

		private static bool ShipCameraOnLocal(StartOfRound sor, PlayerControllerB localPlayer)
		{
			ManualCameraRenderer mapScreen = sor.mapScreen;
			if ((Object)(object)mapScreen == (Object)null || (Object)(object)mapScreen.targetedPlayer != (Object)(object)localPlayer)
			{
				return false;
			}
			if (IsScreenOnField != null && !(bool)IsScreenOnField.GetValue(mapScreen))
			{
				return false;
			}
			return true;
		}

		private void DetectScan()
		{
			HUDManager instance = HUDManager.Instance;
			if (!((Object)(object)instance == (Object)null) && !(PingScanField == null))
			{
				float num = (float)PingScanField.GetValue(instance);
				if (num > 0f && _lastPing <= 0f)
				{
					_lastScanTime = Time.time;
					_pulseTimer = ExitLinePlugin.PulseDuration.Value;
					_snapshotDirty = true;
				}
				_lastPing = num;
			}
		}

		private void OnEnteredInterior()
		{
			RescanDoors();
			_elevator = null;
			_searchedElevator = false;
			foreach (DotLine line in _lines)
			{
				line.HasPath = false;
				line.RecomputeIn = 0f;
			}
		}

		private void RescanDoors()
		{
			_insideDoors.Clear();
			EntranceTeleport[] array = Object.FindObjectsOfType<EntranceTeleport>();
			foreach (EntranceTeleport val in array)
			{
				if ((Object)(object)val != (Object)null && !val.isEntranceToBuilding)
				{
					_insideDoors.Add(val);
				}
			}
			_doorRescanCooldown = 5f;
		}

		private void ResolveDestinations(PlayerControllerB localPlayer)
		{
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			bool flag = _insideDoors.Count == 0;
			for (int num = _insideDoors.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)_insideDoors[num] == (Object)null)
				{
					_insideDoors.RemoveAt(num);
					flag = true;
				}
			}
			if (flag && _doorRescanCooldown <= 0f)
			{
				RescanDoors();
			}
			if (_insideDoors.Count == 0)
			{
				return;
			}
			RoundManager instance = RoundManager.Instance;
			if ((Object)(object)instance != (Object)null && instance.currentDungeonType == 4)
			{
				if (!_searchedElevator || (Object)(object)_elevator == (Object)null)
				{
					_elevator = Object.FindObjectOfType<MineshaftElevatorController>();
					_searchedElevator = true;
				}
				if ((Object)(object)_elevator != (Object)null && (Object)(object)_elevator.elevatorTopPoint != (Object)null && (Object)(object)_elevator.elevatorBottomPoint != (Object)null && _elevator.elevatorTopPoint.position.y - ((Component)localPlayer).transform.position.y > 10f)
				{
					EntranceTeleport val = ResolveModeDoor(_elevator.elevatorTopPoint.position);
					AddDestination(_elevator.elevatorBottomPoint.position, (Object)(object)val != (Object)null && IsFireExitDoor(val));
					return;
				}
			}
			if (ExitLinePlugin.Mode.Value == DoorMode.AllDoors)
			{
				for (int i = 0; i < _insideDoors.Count; i++)
				{
					AddDoorDestination(_insideDoors[i]);
				}
				return;
			}
			EntranceTeleport val2 = ResolveModeDoor(((Component)localPlayer).transform.position);
			if ((Object)(object)val2 != (Object)null)
			{
				AddDoorDestination(val2);
			}
		}

		private EntranceTeleport ResolveModeDoor(Vector3 from)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (ExitLinePlugin.Mode.Value == DoorMode.EnteredDoor)
			{
				int lastEnteredEntranceId = ExitLinePlugin.LastEnteredEntranceId;
				if (lastEnteredEntranceId >= 0)
				{
					for (int i = 0; i < _insideDoors.Count; i++)
					{
						if ((Object)(object)_insideDoors[i] != (Object)null && _insideDoors[i].entranceId == lastEnteredEntranceId)
						{
							return _insideDoors[i];
						}
					}
				}
			}
			return ClosestDoorTo(from);
		}

		private EntranceTeleport ClosestDoorTo(Vector3 from)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			EntranceTeleport result = null;
			float num = float.MaxValue;
			for (int i = 0; i < _insideDoors.Count; i++)
			{
				EntranceTeleport val = _insideDoors[i];
				if (!((Object)(object)val == (Object)null))
				{
					Vector3 val2 = DoorPosition(val) - from;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
						result = val;
					}
				}
			}
			return result;
		}

		private void AddDoorDestination(EntranceTeleport door)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			AddDestination(DoorPosition(door), IsFireExitDoor(door));
		}

		private void AddDestination(Vector3 pos, bool isFireExit)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			_destinations.Add(pos);
			_destinationIsFireExit.Add(isFireExit);
		}

		private static bool IsFireExitDoor(EntranceTeleport door)
		{
			return door.entranceId != 0;
		}

		private static Vector3 DoorPosition(EntranceTeleport door)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)door.entrancePoint != (Object)null))
			{
				return ((Component)door).transform.position;
			}
			return door.entrancePoint.position;
		}

		private void ComputePath(DotLine line, Vector3 start, Vector3 destination)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			line.HasPath = false;
			line.RecomputeIn = 1f;
			Vector3 val = start;
			NavMeshHit val2 = default(NavMeshHit);
			if (NavMesh.SamplePosition(start, ref val2, 4f, -1))
			{
				val = ((NavMeshHit)(ref val2)).position;
			}
			Vector3 val3 = destination;
			if (NavMesh.SamplePosition(destination, ref val2, 4f, -1))
			{
				val3 = ((NavMeshHit)(ref val2)).position;
			}
			if (!NavMesh.CalculatePath(val, val3, -1, line.Path))
			{
				return;
			}
			Vector3[] corners = line.Path.corners;
			if (corners.Length >= 2)
			{
				float value = ExitLinePlugin.LineHeight.Value;
				int num = corners.Length;
				line.Corners = (Vector3[])(object)new Vector3[num];
				line.CumLen = new float[num];
				float num2 = 0f;
				line.Corners[0] = corners[0] + Vector3.up * value;
				line.CumLen[0] = 0f;
				for (int i = 1; i < num; i++)
				{
					line.Corners[i] = corners[i] + Vector3.up * value;
					num2 += Vector3.Distance(line.Corners[i - 1], line.Corners[i]);
					line.CumLen[i] = num2;
				}
				line.TotalLen = num2;
				if (!(num2 < 0.5f))
				{
					GenerateBaseArcs(line);
					RepositionDots(line);
					line.HasPath = true;
					line.LastDestination = destination;
					line.RecomputeIn = ((num > 50) ? 2f : ((num < 36) ? 0.4f : 1f));
				}
			}
		}

		private void GenerateBaseArcs(DotLine line)
		{
			float value = ExitLinePlugin.DotSpacingNear.Value;
			float far = Mathf.Max(value, ExitLinePlugin.DotSpacingFar.Value);
			float value2 = ExitLinePlugin.DotSpacingFarDistance.Value;
			float num = 1f;
			for (int i = 0; i < 4; i++)
			{
				float num2 = FillArcs(line.BaseArcs, line.TotalLen, value, far, value2, num, 400);
				if (num2 >= line.TotalLen)
				{
					line.OverflowArc = num2;
					return;
				}
				num *= 1.6f;
			}
			float num3 = FillArcs(ArcScratch, line.TotalLen, value, far, value2, num, 1600);
			if (num3 < line.TotalLen)
			{
				ArcScratch.Clear();
				float num4 = line.TotalLen / 400f;
				for (int j = 0; j < 400; j++)
				{
					ArcScratch.Add(0.3f + (float)j * num4);
				}
				num3 = 0.3f + 400f * num4;
			}
			line.BaseArcs.Clear();
			if (ArcScratch.Count <= 400)
			{
				line.BaseArcs.AddRange(ArcScratch);
			}
			else
			{
				for (int k = 0; k < 400; k++)
				{
					line.BaseArcs.Add(ArcScratch[Mathf.RoundToInt((float)(k * (ArcScratch.Count - 1)) / 399f)]);
				}
			}
			line.OverflowArc = num3;
			if (!_loggedArcFallback)
			{
				_loggedArcFallback = true;
				ExitLinePlugin.Log.LogInfo((object)("Very long path (" + line.TotalLen.ToString("F0") + "m) - dot trail thinned to stay under the dot cap."));
			}
		}

		private static float FillArcs(List<float> arcs, float totalLen, float near, float far, float farDist, float scale, int cap)
		{
			arcs.Clear();
			float num;
			for (num = 0.3f; num < totalLen; num += Mathf.Lerp(near, far, Mathf.Clamp01(num / farDist)) * scale)
			{
				if (arcs.Count >= cap)
				{
					break;
				}
				arcs.Add(num);
			}
			return num;
		}

		private void RepositionDots(DotLine line)
		{
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			int num = line.BaseArcs.Count + 1;
			while (line.Dots.Count < num && _dotBudget > 0)
			{
				line.Dots.Add(CreateDot(line.Container.transform, LineMaterial(line)));
				_dotBudget--;
			}
			float value = ExitLinePlugin.DotSize.Value;
			Vector3 localScale = default(Vector3);
			((Vector3)(ref localScale))..ctor(value, value, value);
			int segCursor = line.CumLen.Length - 1;
			for (int i = 0; i < line.Dots.Count; i++)
			{
				Transform val = line.Dots[i];
				if (i >= num)
				{
					if (((Component)val).gameObject.activeSelf)
					{
						((Component)val).gameObject.SetActive(false);
					}
					continue;
				}
				float num2 = ((i < line.BaseArcs.Count) ? line.BaseArcs[i] : line.OverflowArc);
				float num3 = ((i == 0) ? 0f : line.BaseArcs[i - 1]);
				float num4 = num2 - line.Phase * (num2 - num3);
				if (num4 < 0.05f || num4 > line.TotalLen - 0.05f)
				{
					if (((Component)val).gameObject.activeSelf)
					{
						((Component)val).gameObject.SetActive(false);
					}
					continue;
				}
				val.position = SampleAlongPath(line, line.TotalLen - num4, ref segCursor);
				val.localScale = localScale;
				if (!((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(true);
				}
			}
		}

		private static Vector3 SampleAlongPath(DotLine line, float arcFromStart, ref int segCursor)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			float[] cumLen = line.CumLen;
			if (arcFromStart >= line.TotalLen)
			{
				return line.Corners[cumLen.Length - 1];
			}
			if (segCursor < 1)
			{
				segCursor = 1;
			}
			while (segCursor > 1 && arcFromStart <= cumLen[segCursor - 1])
			{
				segCursor--;
			}
			float num = cumLen[segCursor] - cumLen[segCursor - 1];
			float num2 = ((num > 0.0001f) ? ((arcFromStart - cumLen[segCursor - 1]) / num) : 0f);
			return Vector3.Lerp(line.Corners[segCursor - 1], line.Corners[segCursor], Mathf.Clamp01(num2));
		}

		private bool EnsureDotAssets()
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_dotMesh == (Object)null)
			{
				GameObject obj = GameObject.CreatePrimitive((PrimitiveType)5);
				obj.SetActive(false);
				_dotMesh = obj.GetComponent<MeshFilter>().sharedMesh;
				Object.Destroy((Object)(object)obj);
			}
			if ((Object)(object)_dotMatMain == (Object)null || (Object)(object)_dotMatFire == (Object)null)
			{
				Shader val = Shader.Find("HDRP/Unlit");
				if ((Object)(object)val == (Object)null)
				{
					val = Shader.Find("Sprites/Default");
				}
				if ((Object)(object)val == (Object)null)
				{
					ExitLinePlugin.Log.LogWarning((object)"No usable shader found for the exit dots.");
					return false;
				}
				if ((Object)(object)_dotMatMain == (Object)null)
				{
					_dotMatMain = MakeDotMaterial(val);
				}
				if ((Object)(object)_dotMatFire == (Object)null)
				{
					_dotMatFire = MakeDotMaterial(val);
				}
			}
			_mainColor = ParseColor(ExitLinePlugin.DotColorMainEntrance.Value, ref _parsedMainText, _mainColor, "DotColorMainEntrance");
			_fireColor = ParseColor(ExitLinePlugin.DotColorFireExit.Value, ref _parsedFireText, _fireColor, "DotColorFireExit");
			return true;
		}

		private static Material MakeDotMaterial(Shader shader)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			Material val = new Material(shader);
			if (val.HasProperty("_DoubleSidedEnable"))
			{
				val.SetFloat("_DoubleSidedEnable", 1f);
				val.EnableKeyword("_DOUBLESIDED_ON");
			}
			if (val.HasProperty("_CullMode"))
			{
				val.SetFloat("_CullMode", 0f);
			}
			return val;
		}

		private static Color ParseColor(string text, ref string cached, Color current, string settingName)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (text == cached)
			{
				return current;
			}
			cached = text;
			Color result = default(Color);
			if (ColorUtility.TryParseHtmlString(text.StartsWith("#") ? text : ("#" + text), ref result))
			{
				return result;
			}
			ExitLinePlugin.Log.LogWarning((object)("Could not parse " + settingName + " '" + text + "', keeping previous color."));
			return current;
		}

		private void ApplyBrightness(float brightness)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			ApplyColor(_dotMatMain, _mainColor, brightness);
			ApplyColor(_dotMatFire, _fireColor, brightness);
		}

		private static void ApplyColor(Material mat, Color baseColor, float brightness)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			((Color)(ref val))..ctor(baseColor.r * brightness, baseColor.g * brightness, baseColor.b * brightness, baseColor.a);
			if (mat.HasProperty("_UnlitColor"))
			{
				mat.SetColor("_UnlitColor", val);
			}
			else
			{
				mat.color = val;
			}
		}

		private Transform CreateDot(Transform parent, Material mat)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Dot")
			{
				layer = _worldLayer
			};
			val.transform.SetParent(parent, false);
			val.AddComponent<MeshFilter>().sharedMesh = _dotMesh;
			MeshRenderer obj = val.AddComponent<MeshRenderer>();
			((Renderer)obj).sharedMaterial = mat;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
			val.SetActive(false);
			return val.transform;
		}

		private static Material LineMaterial(DotLine line)
		{
			if (!line.IsFireExit)
			{
				return _dotMatMain;
			}
			return _dotMatFire;
		}

		private void ApplyLineMaterial(DotLine line)
		{
			int num = (line.IsFireExit ? 1 : 0);
			if (line.AppliedColorKind == num)
			{
				return;
			}
			line.AppliedColorKind = num;
			Material sharedMaterial = LineMaterial(line);
			for (int i = 0; i < line.Dots.Count; i++)
			{
				Transform val = line.Dots[i];
				if (!((Object)(object)val == (Object)null))
				{
					MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
					if ((Object)(object)component != (Object)null)
					{
						((Renderer)component).sharedMaterial = sharedMaterial;
					}
				}
			}
		}

		private void EnsureWorldLayer(PlayerControllerB localPlayer)
		{
			if (_worldLayerResolved)
			{
				return;
			}
			Camera gameplayCamera = localPlayer.gameplayCamera;
			if ((Object)(object)gameplayCamera == (Object)null)
			{
				return;
			}
			int cullingMask = gameplayCamera.cullingMask;
			if ((cullingMask & 1) != 0)
			{
				_worldLayer = 0;
			}
			else
			{
				for (int i = 0; i < 32; i++)
				{
					if ((cullingMask & (1 << i)) != 0 && i != 5)
					{
						_worldLayer = i;
						break;
					}
				}
			}
			_worldLayerResolved = true;
			foreach (DotLine line in _lines)
			{
				if ((Object)(object)line.Container != (Object)null)
				{
					line.Container.layer = _worldLayer;
				}
				foreach (Transform dot in line.Dots)
				{
					if ((Object)(object)dot != (Object)null)
					{
						((Component)dot).gameObject.layer = _worldLayer;
					}
				}
			}
		}

		private void EnsurePool(int needed)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			while (_lines.Count < needed)
			{
				GameObject val = new GameObject("ExitLineFromEnteredDoor_Dots");
				val.transform.SetParent(((Component)this).transform, false);
				val.layer = _worldLayer;
				val.SetActive(false);
				_lines.Add(new DotLine
				{
					Container = val,
					Path = new NavMeshPath()
				});
			}
		}

		private static void SetLineActive(DotLine line, bool on)
		{
			if ((Object)(object)line.Container != (Object)null && line.Container.activeSelf != on)
			{
				line.Container.SetActive(on);
			}
		}

		private void HideAll()
		{
			for (int i = 0; i < _lines.Count; i++)
			{
				SetLineActive(_lines[i], on: false);
			}
		}
	}
	public enum DoorMode
	{
		EnteredDoor,
		ClosestDoor,
		AllDoors
	}
	[BepInPlugin("Haaylo.ExitLineFromEnteredDoor", "ExitLineFromEnteredDoor", "1.0.1")]
	public class ExitLinePlugin : BaseUnityPlugin
	{
		public const string Guid = "Haaylo.ExitLineFromEnteredDoor";

		public const string Name = "ExitLineFromEnteredDoor";

		public const string Version = "1.0.1";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<DoorMode> Mode;

		internal static ConfigEntry<bool> RequirePlayerInShip;

		internal static ConfigEntry<bool> RequireShipCameraOnYou;

		internal static ConfigEntry<float> LineHeight;

		internal static ConfigEntry<float> DotSize;

		internal static ConfigEntry<string> DotColorMainEntrance;

		internal static ConfigEntry<string> DotColorFireExit;

		internal static ConfigEntry<float> DotSpacingNear;

		internal static ConfigEntry<float> DotSpacingFar;

		internal static ConfigEntry<float> DotSpacingFarDistance;

		internal static ConfigEntry<float> BreathePeriod;

		internal static ConfigEntry<float> BreatheStrength;

		internal static ConfigEntry<bool> PulseOnScan;

		internal static ConfigEntry<float> PulseDuration;

		internal static ConfigEntry<float> FlowSpeed;

		internal static ConfigEntry<float> PulseBrightness;

		internal static ConfigEntry<bool> OnlyShowAfterScan;

		internal static ConfigEntry<float> ShowDurationAfterScan;

		internal static int LastEnteredEntranceId = -1;

		private void Awake()
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Expected O, but got Unknown
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Expected O, but got Unknown
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Expected O, but got Unknown
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Expected O, but got Unknown
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Expected O, but got Unknown
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Expected O, but got Unknown
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Expected O, but got Unknown
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_0313: Expected O, but got Unknown
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Expected O, but got Unknown
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ad: Expected O, but got Unknown
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Expected O, but got Unknown
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for the exit line.");
			Mode = ((BaseUnityPlugin)this).Config.Bind<DoorMode>("General", "DoorMode", DoorMode.EnteredDoor, "Which exit the line leads to. EnteredDoor = the door you came in through (falls back to closest if unknown, e.g. after a teleport). ClosestDoor = nearest exit by distance. AllDoors = one line per exit.");
			RequirePlayerInShip = ((BaseUnityPlugin)this).Config.Bind<bool>("Conditions", "RequirePlayerInShip", false, "Only show the line while at least one living player is inside the ship.");
			RequireShipCameraOnYou = ((BaseUnityPlugin)this).Config.Bind<bool>("Conditions", "RequireShipCameraOnYou", false, "Only show the line while the ship's map screen is on and its radar is targeting you.");
			LineHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "LineHeight", 0.1f, new ConfigDescription("How high above the floor the dots sit, in meters. 0.1 hugs the ground.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			DotSize = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DotSize", 0.04f, new ConfigDescription("Diameter of each dot, in meters. Keep it tiny for a subtle pixel-like trail.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.005f, 0.5f), Array.Empty<object>()));
			DotColorMainEntrance = ((BaseUnityPlugin)this).Config.Bind<string>("Visuals", "DotColorMainEntrance", "62FF71", "Dot color when the trail leads to the main entrance, as an RGB hex value (radar green by default).");
			DotColorFireExit = ((BaseUnityPlugin)this).Config.Bind<string>("Visuals", "DotColorFireExit", "FF4D4D", "Dot color when the trail leads to a fire exit, as an RGB hex value (red by default), so you can tell at a glance which way out you're being pointed.");
			DotSpacingNear = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DotSpacingNear", 0.4f, new ConfigDescription("Distance between dots right next to the exit door, in meters (dense end).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			DotSpacingFar = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DotSpacingFar", 2f, new ConfigDescription("Distance between dots far away from the exit door, in meters (sparse end). The trail getting denser tells you which way the door is.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			DotSpacingFarDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "DotSpacingFarDistance", 40f, new ConfigDescription("How many meters from the door the spacing reaches its sparsest.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 200f), Array.Empty<object>()));
			BreathePeriod = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "BreathePeriod", 2.5f, new ConfigDescription("Seconds per breathing cycle.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), Array.Empty<object>()));
			BreatheStrength = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "BreatheStrength", 0.35f, new ConfigDescription("How strongly the dots breathe (brightness swing). 0 disables breathing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			PulseOnScan = ((BaseUnityPlugin)this).Config.Bind<bool>("Scan", "PulseOnScan", true, "Make the dots flow toward the exit right after a scan, slowing back down to a static trail.");
			PulseDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Scan", "PulseDuration", 3f, new ConfigDescription("How long the scan flow takes to settle back to static, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), Array.Empty<object>()));
			FlowSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Scan", "FlowSpeed", 4f, new ConfigDescription("How fast dots travel toward the exit at the peak of the scan flow (dots per second).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>()));
			PulseBrightness = ((BaseUnityPlugin)this).Config.Bind<float>("Scan", "PulseBrightness", 1f, new ConfigDescription("Extra brightness at the start of the scan flow.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			OnlyShowAfterScan = ((BaseUnityPlugin)this).Config.Bind<bool>("Scan", "OnlyShowAfterScan", true, "Hide the trail by default and only reveal it for a few seconds after each scan. The trail is a snapshot: it runs from where you scanned to the door and stays put. Turning this off keeps an always-on trail that follows you instead.");
			ShowDurationAfterScan = ((BaseUnityPlugin)this).Config.Bind<float>("Scan", "ShowDurationAfterScan", 5f, new ConfigDescription("How long the trail stays visible after a scan when OnlyShowAfterScan is on (fades out at the end).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>()));
			new Harmony("Haaylo.ExitLineFromEnteredDoor").PatchAll(typeof(EntranceTeleportPatch));
			GameObject val = new GameObject("ExitLineFromEnteredDoorController");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<ExitLineController>();
			Log.LogInfo((object)"ExitLineFromEnteredDoor 1.0.1 loaded.");
		}
	}
	[HarmonyPatch(typeof(EntranceTeleport), "TeleportPlayer")]
	internal static class EntranceTeleportPatch
	{
		private static void Postfix(EntranceTeleport __instance)
		{
			try
			{
				if (!((Object)(object)__instance.exitScript == (Object)null))
				{
					ExitLinePlugin.LastEnteredEntranceId = (__instance.isEntranceToBuilding ? __instance.entranceId : (-1));
				}
			}
			catch
			{
			}
		}
	}
}