Decompiled source of NavMeshFix v0.0.1

NavMeshFix.dll

Decompiled 4 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.AI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Autodesk.Fbx")]
[assembly: IgnoresAccessChecksTo("Discord.Sdk")]
[assembly: IgnoresAccessChecksTo("Domain_Reload")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("FbxBuildTestAssets")]
[assembly: IgnoresAccessChecksTo("Klattersynth")]
[assembly: IgnoresAccessChecksTo("Photon3Unity3D")]
[assembly: IgnoresAccessChecksTo("PhotonChat")]
[assembly: IgnoresAccessChecksTo("PhotonRealtime")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking.Utilities")]
[assembly: IgnoresAccessChecksTo("PhotonVoice.API")]
[assembly: IgnoresAccessChecksTo("PhotonVoice")]
[assembly: IgnoresAccessChecksTo("PhotonVoice.PUN")]
[assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime")]
[assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime.Public")]
[assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Attributes")]
[assembly: IgnoresAccessChecksTo("Sirenix.Serialization.Config")]
[assembly: IgnoresAccessChecksTo("Sirenix.Serialization")]
[assembly: IgnoresAccessChecksTo("Sirenix.Utilities")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.Formats.Fbx.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.MemoryProfiler")]
[assembly: IgnoresAccessChecksTo("Unity.Postprocessing.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Splines")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Antlr3.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Core")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Flow")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.State")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: IgnoresAccessChecksTo("websocket-sharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("NavMeshFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.0.1.0")]
[assembly: AssemblyInformationalVersion("0.0.1+9a884721e2c99fb1e78a501ede3505e4dcb993b4")]
[assembly: AssemblyProduct("NavMeshFix")]
[assembly: AssemblyTitle("NavMeshFix")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 NavMeshFix
{
	[BepInPlugin("MARCROCK22.NavMeshFix", "NavMeshFix", "0.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static ConfigEntry<float> RepairRadius;

		internal static ConfigEntry<bool> Enabled;

		private readonly Harmony _harmony = new Harmony("MARCROCK22.NavMeshFix");

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable automatic NavMesh repair for broken levels");
			RepairRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "RepairRadius", 5f, "Max distance to search for a valid NavMesh position when repairing LevelPoints");
			_harmony.PatchAll(typeof(NavMeshRepairPatch));
			_harmony.PatchAll(typeof(MapBacktrackStartPatch));
			((BaseUnityPlugin)this).Logger.LogInfo((object)"NavMeshFix v1.2.0 loaded");
		}
	}
	[HarmonyPatch(typeof(LevelGenerator))]
	internal static class NavMeshRepairPatch
	{
		[CompilerGenerated]
		private sealed class <RepairConnectionsDelayed>d__4 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <RepairConnectionsDelayed>d__4(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(1f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					if (_repairApplied)
					{
						return false;
					}
					_repairApplied = true;
					List<LevelPoint> levelPathPoints = LevelGenerator.Instance.LevelPathPoints;
					string name = ((Object)RunManager.instance.levelCurrent).name;
					int num = RepairConnections(levelPathPoints);
					int num2 = RepairRooms(levelPathPoints);
					if (num > 0 || num2 > 0)
					{
						Plugin.Log.LogWarning((object)$"[NavMeshFix] Level '{name}': repaired {num} connections, {num2} rooms");
					}
					return false;
				}
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static bool _repairQueued;

		private static bool _repairApplied;

		[HarmonyPatch("NavMeshSetupRPC")]
		[HarmonyPostfix]
		private static void NavMeshSetupPostfix(LevelGenerator __instance)
		{
			if (Plugin.Enabled.Value)
			{
				_repairQueued = false;
				_repairApplied = false;
				RepairPositions();
				RepairExtractionPoints();
			}
		}

		[HarmonyPatch("GenerateDone")]
		[HarmonyPostfix]
		private static void GenerateDonePostfix(LevelGenerator __instance)
		{
			if (Plugin.Enabled.Value && !_repairQueued)
			{
				_repairQueued = true;
				((MonoBehaviour)__instance).StartCoroutine(RepairConnectionsDelayed());
			}
		}

		[IteratorStateMachine(typeof(<RepairConnectionsDelayed>d__4))]
		private static IEnumerator RepairConnectionsDelayed()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <RepairConnectionsDelayed>d__4(0);
		}

		private static void RepairPositions()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			float value = Plugin.RepairRadius.Value;
			LevelPoint[] array = Object.FindObjectsOfType<LevelPoint>();
			string name = ((Object)RunManager.instance.levelCurrent).name;
			int num = 0;
			LevelPoint[] array2 = array;
			NavMeshHit val2 = default(NavMeshHit);
			NavMeshHit val3 = default(NavMeshHit);
			foreach (LevelPoint val in array2)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Vector3 position = ((Component)val).transform.position;
				if (!NavMesh.SamplePosition(position, ref val2, 0.5f, -1))
				{
					if (NavMesh.SamplePosition(position, ref val3, value, -1))
					{
						Vector3 val4 = position;
						((Component)val).transform.position = ((NavMeshHit)(ref val3)).position;
						num++;
						Plugin.Log.LogWarning((object)$"[NavMeshFix] Moved '{((Object)val).name}': {val4} -> {((NavMeshHit)(ref val3)).position} (dist={Vector3.Distance(val4, ((NavMeshHit)(ref val3)).position):F2})");
					}
					else
					{
						Plugin.Log.LogError((object)$"[NavMeshFix] Could not repair '{((Object)val).name}' at {position} — no NavMesh within {value}m");
					}
				}
			}
			if (num > 0)
			{
				Plugin.Log.LogWarning((object)$"[NavMeshFix] Level '{name}': repaired {num}/{array.Length} positions");
			}
		}

		private static void RepairExtractionPoints()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: 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)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			float value = Plugin.RepairRadius.Value;
			ExtractionPoint[] array = Object.FindObjectsOfType<ExtractionPoint>();
			string name = ((Object)RunManager.instance.levelCurrent).name;
			int num = 0;
			ExtractionPoint[] array2 = array;
			NavMeshHit val2 = default(NavMeshHit);
			NavMeshHit val3 = default(NavMeshHit);
			foreach (ExtractionPoint val in array2)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Vector3 position = ((Component)val).transform.position;
				if (!NavMesh.SamplePosition(position, ref val2, 0.5f, -1))
				{
					if (NavMesh.SamplePosition(position, ref val3, value, -1))
					{
						Vector3 val4 = position;
						((Component)val).transform.position = ((NavMeshHit)(ref val3)).position;
						num++;
						Plugin.Log.LogWarning((object)$"[NavMeshFix] Moved ExtractionPoint '{((Object)val).name}': {val4} -> {((NavMeshHit)(ref val3)).position} (dist={Vector3.Distance(val4, ((NavMeshHit)(ref val3)).position):F2})");
					}
					else
					{
						Plugin.Log.LogError((object)$"[NavMeshFix] Could not repair ExtractionPoint '{((Object)val).name}' at {position} — no NavMesh within {value}m");
					}
				}
			}
			if (num > 0)
			{
				Plugin.Log.LogWarning((object)$"[NavMeshFix] Level '{name}': repaired {num}/{array.Length} ExtractionPoints");
			}
		}

		private static int RepairConnections(List<LevelPoint> allPoints)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: 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_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			foreach (LevelPoint allPoint in allPoints)
			{
				if ((Object)(object)allPoint == (Object)null || !allPoint.ModuleConnect || allPoint.ConnectedPoints.Any((LevelPoint c) => (Object)(object)c != (Object)null))
				{
					continue;
				}
				LevelPoint val = null;
				float num2 = 15f;
				foreach (LevelPoint allPoint2 in allPoints)
				{
					if ((Object)(object)allPoint2 == (Object)null || (Object)(object)allPoint2 == (Object)(object)allPoint || !allPoint2.ModuleConnect)
					{
						continue;
					}
					float num3 = Vector3.Distance(((Component)allPoint).transform.position, ((Component)allPoint2).transform.position);
					if (!(num3 >= num2) && !(Vector3.Dot(((Component)allPoint2).transform.forward, ((Component)allPoint).transform.forward) > -0.8f))
					{
						Vector3 val2 = ((Component)allPoint).transform.position - ((Component)allPoint2).transform.position;
						Vector3 normalized = ((Vector3)(ref val2)).normalized;
						if (!(Vector3.Dot(((Component)allPoint2).transform.forward, normalized) < 0.8f))
						{
							num2 = num3;
							val = allPoint2;
						}
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					if (!allPoint.ConnectedPoints.Contains(val))
					{
						allPoint.ConnectedPoints.Add(val);
					}
					if (!val.ConnectedPoints.Contains(allPoint))
					{
						val.ConnectedPoints.Add(allPoint);
					}
					num++;
					Plugin.Log.LogWarning((object)$"[NavMeshFix] Connected '{((Object)allPoint).name}' <-> '{((Object)val).name}' (dist={num2:F2})");
				}
			}
			foreach (LevelPoint allPoint3 in allPoints)
			{
				if ((Object)(object)allPoint3 == (Object)null)
				{
					continue;
				}
				LevelPoint[] array = allPoint3.ConnectedPoints.ToArray();
				foreach (LevelPoint val3 in array)
				{
					if (!((Object)(object)val3 == (Object)null) && !val3.ConnectedPoints.Contains(allPoint3))
					{
						val3.ConnectedPoints.Add(allPoint3);
						num++;
						Plugin.Log.LogWarning((object)("[NavMeshFix] Fixed one-way: '" + ((Object)val3).name + "' -> '" + ((Object)allPoint3).name + "'"));
					}
				}
			}
			return num;
		}

		private static int RepairRooms(List<LevelPoint> allPoints)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			foreach (LevelPoint allPoint in allPoints)
			{
				if ((Object)(object)allPoint == (Object)null || (Object)(object)allPoint.Room != (Object)null)
				{
					continue;
				}
				Collider[] array = Physics.OverlapSphere(((Component)allPoint).transform.position, 0.5f, LayerMask.GetMask(new string[1] { "RoomVolume" }), (QueryTriggerInteraction)2);
				for (int i = 0; i < array.Length; i++)
				{
					RoomVolume componentInParent = ((Component)array[i]).GetComponentInParent<RoomVolume>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						allPoint.Room = componentInParent;
						num++;
						Plugin.Log.LogWarning((object)("[NavMeshFix] Assigned Room to '" + ((Object)allPoint).name + "' -> '" + ((Object)componentInParent).name + "'"));
						break;
					}
				}
			}
			return num;
		}
	}
	internal class MapBacktrackMonitor : MonoBehaviour
	{
		private float _logTimer;

		private NavMeshPath _testPath;

		private void Start()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			_testPath = new NavMeshPath();
		}

		private void Update()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: 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_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value)
			{
				return;
			}
			_logTimer -= Time.deltaTime;
			if (_logTimer > 0f)
			{
				return;
			}
			_logTimer = 5f;
			if (!Object.op_Implicit((Object)(object)LevelGenerator.Instance) || !LevelGenerator.Instance.Generated || !Object.op_Implicit((Object)(object)Map.Instance) || !Map.Instance.Active || !Object.op_Implicit((Object)(object)PlayerController.instance))
			{
				return;
			}
			Vector3 lastNavmeshPosition = PlayerController.instance.playerAvatarScript.LastNavmeshPosition;
			Vector3 val = lastNavmeshPosition;
			if (RoundDirector.instance.allExtractionPointsCompleted)
			{
				if ((Object)(object)LevelGenerator.Instance.LevelPathTruck != (Object)null)
				{
					val = ((Component)LevelGenerator.Instance.LevelPathTruck).transform.position;
				}
			}
			else if ((Object)(object)RoundDirector.instance.extractionPointCurrent != (Object)null)
			{
				val = ((Component)RoundDirector.instance.extractionPointCurrent).transform.position;
			}
			if (!(Vector3.Distance(lastNavmeshPosition, val) < 1f))
			{
				NavMesh.CalculatePath(lastNavmeshPosition, val, -1, _testPath);
				if ((int)_testPath.status != 0)
				{
					NavMeshHit val2 = default(NavMeshHit);
					bool flag = NavMesh.SamplePosition(lastNavmeshPosition, ref val2, 0.5f, -1);
					bool flag2 = NavMesh.SamplePosition(val, ref val2, 0.5f, -1);
					Plugin.Log.LogWarning((object)($"[NavMeshFix][MapDiag] Path {_testPath.status} | corners={_testPath.corners.Length}" + $" | playerOnNav={flag} playerPos={lastNavmeshPosition}" + $" | targetOnNav={flag2} targetPos={val}" + " | level=" + ((Object)RunManager.instance.levelCurrent).name));
				}
			}
		}
	}
	[HarmonyPatch(typeof(MapBacktrack), "Start")]
	internal static class MapBacktrackStartPatch
	{
		private static void Postfix(MapBacktrack __instance)
		{
			if (Plugin.Enabled.Value && (Object)(object)((Component)__instance).GetComponent<MapBacktrackMonitor>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<MapBacktrackMonitor>();
				Plugin.Log.LogInfo((object)"[NavMeshFix] MapBacktrack diagnostics attached");
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}