Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of NavMeshFix v0.0.1
NavMeshFix.dll
Decompiled 4 hours agousing 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) { } } }