Decompiled source of SCH1BugFix v1.1.4

sch1bugfix.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using MelonLoader;
using Microsoft.CodeAnalysis;
using SCH1BugFix;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: MelonInfo(typeof(SCH1BugFixMod), "SCH1BugFix", "1.1.4", "Virtunerd", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: AssemblyFileVersion("1.1.4")]
[assembly: AssemblyInformationalVersion("1.1.4")]
[assembly: AssemblyVersion("1.1.4.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 SCH1BugFix
{
	public class SCH1BugFixMod : MelonMod
	{
		private const string AuthorName = "Virtunerd";

		private static readonly Type[] PatchTypes = new Type[16]
		{
			typeof(NpcOnDestroyPatch),
			typeof(EmployeeOnDestroyPatch),
			typeof(CustomerOnDestroyPatch),
			typeof(DealerOnDestroyPatch),
			typeof(WheelOnWeatherChangePatch),
			typeof(EnvironmentManagerUpdateWeatherEntitiesPatch),
			typeof(ConfigurationServiceNetworkerOnDestroyPatch),
			typeof(ContractUpdateTimingPatch),
			typeof(RectTransformLerpLocalScalePatch),
			typeof(NpcMovementFaceDirectionProcessMoveNextPatch),
			typeof(SetupCoroutineInvokeMoveNextPatch),
			typeof(NpcBehaviourUpdatePatch),
			typeof(CanvasGroupFaderFadeToPatch),
			typeof(VanillaLogSpamPatch),
			typeof(NpcMovementSetAgentEnabledGuardPatch),
			typeof(NpcMovementPauseMovementGuardPatch)
		};

		private static bool isIl2Cpp;

		private static bool backendKnown;

		private static readonly Dictionary<string, DateTime> LastSuppressedLogUtcByLocation = new Dictionary<string, DateTime>(StringComparer.Ordinal);

		private static readonly object SuppressedLogLock = new object();

		private static Harmony harmony;

		private const double SceneTransitionWindowSeconds = 8.0;

		private static DateTime sceneTransitionUntilUtc = DateTime.MinValue;

		private static readonly object SceneTransitionLock = new object();

		public override void OnInitializeMelon()
		{
			try
			{
				harmony = ((MelonBase)this).HarmonyInstance;
				try
				{
					isIl2Cpp = MelonUtils.IsGameIl2Cpp();
					backendKnown = true;
				}
				catch
				{
					backendKnown = false;
				}
				int value = ApplyPatchesSafely();
				string value2 = (isIl2Cpp ? "Il2Cpp" : "Mono");
				MelonLogger.Msg($"[SCH1BugFix] sch1bugfix v{((MelonBase)this).Info.Version} by {"Virtunerd"} initialized. Runtime: {value2}. Applied {value}/{PatchTypes.Length} patch classes.");
			}
			catch (Exception value3)
			{
				MelonLogger.Error($"[SCH1BugFix] Critical init failure: {value3}");
			}
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			OpenSceneTransitionWindow();
		}

		public override void OnSceneWasInitialized(int buildIndex, string sceneName)
		{
			OpenSceneTransitionWindow();
		}

		public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
		{
			OpenSceneTransitionWindow();
		}

		private static void OpenSceneTransitionWindow()
		{
			try
			{
				lock (SceneTransitionLock)
				{
					sceneTransitionUntilUtc = DateTime.UtcNow.AddSeconds(8.0);
				}
			}
			catch
			{
			}
		}

		private static bool IsInSceneTransitionWindow()
		{
			try
			{
				lock (SceneTransitionLock)
				{
					return DateTime.UtcNow < sceneTransitionUntilUtc;
				}
			}
			catch
			{
				return false;
			}
		}

		internal static Exception SuppressKnownNullRef(Exception exception, string location)
		{
			if (exception == null)
			{
				return null;
			}
			try
			{
				if (exception is NullReferenceException)
				{
					LogSuppressedOncePerWindow(location, "known game-side NRE");
					return null;
				}
				if ((exception.GetType().FullName ?? string.Empty).IndexOf("Il2CppException", StringComparison.OrdinalIgnoreCase) >= 0 && (exception.Message ?? string.Empty).IndexOf("NullReferenceException", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					LogSuppressedOncePerWindow(location, "wrapped game-side NRE");
					return null;
				}
			}
			catch
			{
			}
			return exception;
		}

		internal static Exception SuppressKnownGameCoroutineExitError(Exception exception)
		{
			if (exception == null)
			{
				return null;
			}
			try
			{
				string text = exception.ToString();
				if (text.IndexOf("NullReferenceException", StringComparison.OrdinalIgnoreCase) < 0)
				{
					return exception;
				}
				if (IsInSceneTransitionWindow())
				{
					LogSuppressedOncePerWindow("SetupCoroutine.* (scene transition window)", "generic game-side NRE during scene transition");
					return null;
				}
				if (text.IndexOf("FaceDirection_Process", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					LogSuppressedOncePerWindow("NPCMovement.FaceDirection_Process.MoveNext", "wrapped game-side NRE (SetupCoroutine fallback)");
					return null;
				}
				if (text.IndexOf("StartConversate", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					LogSuppressedOncePerWindow("NPCEvent_Conversate.StartConversate.MoveNext", "wrapped game-side NRE (SetupCoroutine fallback)");
					return null;
				}
				if (text.IndexOf("SetSeat", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					LogSuppressedOncePerWindow("AvatarAnimation.SetSeat.Lerp.MoveNext", "wrapped game-side NRE (SetupCoroutine fallback)");
					return null;
				}
				if (text.IndexOf("SaveRoutine", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("SaveManager", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					LogSuppressedOncePerWindow("Persistence.SaveManager.SaveRoutine.MoveNext", "wrapped game-side NRE (SetupCoroutine fallback)");
					return null;
				}
				if (text.IndexOf("StayInBuilding", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("PlayEnter", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					LogSuppressedOncePerWindow("NPCEvent_StayInBuilding.PlayEnter.Enter.MoveNext", "wrapped game-side NRE (SetupCoroutine fallback)");
					return null;
				}
				if (text.IndexOf("LerpEmotion", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("AvatarEmotionManager", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("SetFaceTexture", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					LogSuppressedOncePerWindow("AvatarEmotionManager.LerpEmotion.MoveNext", "wrapped game-side NRE (SetupCoroutine fallback)");
					return null;
				}
				if (text.IndexOf("QuestHUDUI", StringComparison.OrdinalIgnoreCase) >= 0 || (text.IndexOf("FadeOut", StringComparison.OrdinalIgnoreCase) >= 0 && text.IndexOf("Quest", StringComparison.OrdinalIgnoreCase) >= 0))
				{
					LogSuppressedOncePerWindow("QuestHUDUI.Complete.FadeOut.MoveNext", "wrapped game-side NRE (SetupCoroutine fallback)");
					return null;
				}
			}
			catch
			{
			}
			return exception;
		}

		private static int ApplyPatchesSafely()
		{
			int num = 0;
			if (harmony == null)
			{
				MelonLogger.Error("[SCH1BugFix] Harmony instance not available. No patches were applied.");
				return num;
			}
			for (int i = 0; i < PatchTypes.Length; i++)
			{
				Type type = PatchTypes[i];
				try
				{
					harmony.CreateClassProcessor(type).Patch();
					num++;
				}
				catch (Exception ex)
				{
					MelonLogger.Warning("[SCH1BugFix] Skipping patch " + type.Name + ": " + ex.Message);
				}
			}
			return num;
		}

		private static void LogSuppressedOncePerWindow(string location, string reason)
		{
			try
			{
				DateTime utcNow = DateTime.UtcNow;
				bool flag = false;
				lock (SuppressedLogLock)
				{
					if (!LastSuppressedLogUtcByLocation.TryGetValue(location, out var value) || (utcNow - value).TotalSeconds >= 5.0)
					{
						LastSuppressedLogUtcByLocation[location] = utcNow;
						flag = true;
					}
				}
				if (flag)
				{
					MelonLogger.Warning($"[SCH1BugFix] Suppressed {reason} in {location}.");
				}
			}
			catch
			{
			}
		}

		internal static string[] OrderByBackend(string[] typeNames)
		{
			if (!backendKnown || typeNames == null || typeNames.Length < 2)
			{
				return typeNames;
			}
			string[] array = new string[typeNames.Length];
			int num = 0;
			for (int i = 0; i < typeNames.Length; i++)
			{
				if (typeNames[i].StartsWith("Il2Cpp", StringComparison.Ordinal) == isIl2Cpp)
				{
					array[num++] = typeNames[i];
				}
			}
			for (int j = 0; j < typeNames.Length; j++)
			{
				if (typeNames[j].StartsWith("Il2Cpp", StringComparison.Ordinal) != isIl2Cpp)
				{
					array[num++] = typeNames[j];
				}
			}
			return array;
		}

		internal static MethodBase ResolveMethod(string[] typeNames, string methodName, int parameterCount)
		{
			try
			{
				typeNames = OrderByBackend(typeNames);
				for (int i = 0; i < typeNames.Length; i++)
				{
					Type type = AccessTools.TypeByName(typeNames[i]);
					if (!(type == null))
					{
						MethodBase methodBase = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == methodName && m.GetParameters().Length == parameterCount);
						if (methodBase != null)
						{
							return methodBase;
						}
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[SCH1BugFix] ResolveMethod error for " + methodName + ": " + ex.Message);
			}
			MelonLogger.Warning($"[SCH1BugFix] Target not found: {string.Join(" | ", typeNames)}::{methodName}/{parameterCount}");
			return null;
		}
	}
	[HarmonyPatch]
	internal static class NpcOnDestroyPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.NPCs.NPC", "Il2CppScheduleOne.NPCs.NPC" }, "OnDestroy", 0);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "NPC.OnDestroy");
		}
	}
	[HarmonyPatch]
	internal static class EmployeeOnDestroyPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.Employees.Employee", "Il2CppScheduleOne.Employees.Employee" }, "OnDestroy", 0);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "Employee.OnDestroy");
		}
	}
	[HarmonyPatch]
	internal static class CustomerOnDestroyPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.Economy.Customer", "Il2CppScheduleOne.Economy.Customer" }, "OnDestroy", 0);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "Customer.OnDestroy");
		}
	}
	[HarmonyPatch]
	internal static class DealerOnDestroyPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.Economy.Dealer", "Il2CppScheduleOne.Economy.Dealer" }, "OnDestroy", 0);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "Dealer.OnDestroy");
		}
	}
	[HarmonyPatch]
	internal static class WheelOnWeatherChangePatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.Vehicles.Wheel", "Il2CppScheduleOne.Vehicles.Wheel" }, "OnWeatherChange", 1);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "Wheel.OnWeatherChange");
		}
	}
	[HarmonyPatch]
	internal static class EnvironmentManagerUpdateWeatherEntitiesPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.Weather.EnvironmentManager", "Il2CppScheduleOne.Weather.EnvironmentManager" }, "UpdateWeatherEntities", 0);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "EnvironmentManager.UpdateWeatherEntities");
		}
	}
	[HarmonyPatch]
	internal static class ConfigurationServiceNetworkerOnDestroyPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.Configuration.ConfigurationServiceNetworker", "Il2CppScheduleOne.Configuration.ConfigurationServiceNetworker" }, "OnDestroy", 0);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "ConfigurationServiceNetworker.OnDestroy");
		}
	}
	[HarmonyPatch]
	internal static class ContractUpdateTimingPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.Quests.Contract", "Il2CppScheduleOne.Quests.Contract" }, "UpdateTiming", 0);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "Contract.UpdateTiming");
		}
	}
	[HarmonyPatch]
	internal static class RectTransformLerpLocalScalePatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.UI.RectTransformLerp", "Il2CppScheduleOne.UI.RectTransformLerp" }, "LerpLocalScale", 2);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "RectTransformLerp.LerpLocalScale");
		}
	}
	[HarmonyPatch]
	internal static class NpcMovementFaceDirectionProcessMoveNextPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = FindTarget();
			if (cachedTarget == null)
			{
				MelonLogger.Warning("[SCH1BugFix] NPCMovement FaceDirection iterator target not found. Skipping this optional patch.");
				return false;
			}
			return true;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		private static bool IsIteratorFor(string nestedTypeName, string methodName)
		{
			if (string.IsNullOrEmpty(nestedTypeName))
			{
				return false;
			}
			if (!nestedTypeName.StartsWith("<" + methodName + ">d__", StringComparison.Ordinal))
			{
				return nestedTypeName.StartsWith("_" + methodName + "_d__", StringComparison.Ordinal);
			}
			return true;
		}

		private static MethodBase FindTarget()
		{
			string[] array = SCH1BugFixMod.OrderByBackend(new string[2] { "ScheduleOne.NPCs.NPCMovement", "Il2CppScheduleOne.NPCs.NPCMovement" });
			try
			{
				for (int i = 0; i < array.Length; i++)
				{
					Type type = AccessTools.TypeByName(array[i]);
					if (type == null)
					{
						continue;
					}
					Type[] array2;
					try
					{
						array2 = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);
					}
					catch (ReflectionTypeLoadException ex)
					{
						array2 = ex.Types;
					}
					if (array2 == null)
					{
						continue;
					}
					foreach (Type type2 in array2)
					{
						if (!(type2 == null) && IsIteratorFor(type2.Name, "FaceDirection_Process"))
						{
							MethodInfo method = type2.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
							if (method != null)
							{
								return method;
							}
						}
					}
				}
			}
			catch (Exception ex2)
			{
				MelonLogger.Warning("[SCH1BugFix] FindTarget error: " + ex2.Message);
			}
			return null;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "NPCMovement.FaceDirection_Process.MoveNext");
		}
	}
	[HarmonyPatch]
	internal static class NpcBehaviourUpdatePatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.NPCs.Behaviour.NPCBehaviour", "Il2CppScheduleOne.NPCs.Behaviour.NPCBehaviour" }, "Update", 0);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "NPCBehaviour.Update");
		}
	}
	[HarmonyPatch]
	internal static class SetupCoroutineInvokeMoveNextPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			try
			{
				cachedTarget = AccessTools.Method("UnityEngine.SetupCoroutine:InvokeMoveNext", (Type[])null, (Type[])null);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[SCH1BugFix] SetupCoroutine target resolution error: " + ex.Message);
			}
			if (cachedTarget == null)
			{
				MelonLogger.Warning("[SCH1BugFix] SetupCoroutine.InvokeMoveNext not found. Skipping fallback patch.");
				return false;
			}
			return true;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownGameCoroutineExitError(__exception);
		}
	}
	internal static class NavMeshPauseGuard
	{
		private static MethodInfo isPausedGetter;

		private static MethodInfo isPausedSetter;

		private static MethodInfo agentGetter;

		private static FieldInfo agentField;

		private static MethodInfo isOnNavMeshGetter;

		private static bool resolved;

		private static readonly object[] FalseArg = new object[1] { false };

		private static DateTime lastReportUtc = DateTime.MinValue;

		private static long clearedTotal;

		private static readonly object CountLock = new object();

		internal static bool ResolveAccessors()
		{
			if (resolved)
			{
				return true;
			}
			try
			{
				Type type = null;
				string[] array = SCH1BugFixMod.OrderByBackend(new string[2] { "ScheduleOne.NPCs.NPCMovement", "Il2CppScheduleOne.NPCs.NPCMovement" });
				for (int i = 0; i < array.Length; i++)
				{
					if (!(type == null))
					{
						break;
					}
					type = AccessTools.TypeByName(array[i]);
				}
				if (type == null)
				{
					return false;
				}
				isPausedGetter = type.GetMethod("get_IsPaused", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				isPausedSetter = type.GetMethod("set_IsPaused", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				agentGetter = type.GetMethod("get_Agent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (agentGetter == null)
				{
					agentField = type.GetField("Agent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				Type type2 = AccessTools.TypeByName("UnityEngine.AI.NavMeshAgent");
				if (type2 != null)
				{
					isOnNavMeshGetter = type2.GetMethod("get_isOnNavMesh", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[SCH1BugFix] NavMesh guard accessor resolution failed: " + ex.Message);
				return false;
			}
			resolved = isPausedGetter != null && isPausedSetter != null && (agentGetter != null || agentField != null) && isOnNavMeshGetter != null;
			return resolved;
		}

		private static bool AgentCannotStop(object instance)
		{
			object obj = ((agentGetter != null) ? agentGetter.Invoke(instance, null) : agentField.GetValue(instance));
			if (obj == null)
			{
				return true;
			}
			if (isOnNavMeshGetter.Invoke(obj, null) is bool flag)
			{
				return !flag;
			}
			return false;
		}

		internal static void ClearPauseIfAgentCannotStop(object instance, string origin)
		{
			try
			{
				if (instance != null && resolved)
				{
					object obj = isPausedGetter.Invoke(instance, null);
					if (obj is bool && (bool)obj && AgentCannotStop(instance))
					{
						isPausedSetter.Invoke(instance, FalseArg);
						Report(origin);
					}
				}
			}
			catch
			{
			}
		}

		private static void Report(string origin)
		{
			try
			{
				DateTime utcNow = DateTime.UtcNow;
				long value;
				bool flag;
				lock (CountLock)
				{
					clearedTotal++;
					value = clearedTotal;
					flag = (utcNow - lastReportUtc).TotalSeconds >= 60.0;
					if (flag)
					{
						lastReportUtc = utcNow;
					}
				}
				if (flag)
				{
					MelonLogger.Msg($"[SCH1BugFix] Cleared off-NavMesh pause via {origin} ({value} so far).");
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch]
	internal static class NpcMovementSetAgentEnabledGuardPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.NPCs.NPCMovement", "Il2CppScheduleOne.NPCs.NPCMovement" }, "SetAgentEnabled", 1);
			if (cachedTarget == null)
			{
				return false;
			}
			if (!NavMeshPauseGuard.ResolveAccessors())
			{
				MelonLogger.Warning("[SCH1BugFix] NavMesh guard: accessors unavailable. Skipping this patch.");
				return false;
			}
			return true;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyPostfix]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static void Postfix(object __instance, bool __0)
		{
			if (!__0)
			{
				NavMeshPauseGuard.ClearPauseIfAgentCannotStop(__instance, "SetAgentEnabled(false)");
			}
		}
	}
	[HarmonyPatch]
	internal static class NpcMovementPauseMovementGuardPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.NPCs.NPCMovement", "Il2CppScheduleOne.NPCs.NPCMovement" }, "PauseMovement", 0);
			if (cachedTarget != null)
			{
				return NavMeshPauseGuard.ResolveAccessors();
			}
			return false;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyPostfix]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static void Postfix(object __instance)
		{
			NavMeshPauseGuard.ClearPauseIfAgentCannotStop(__instance, "PauseMovement()");
		}
	}
	[HarmonyPatch]
	internal static class VanillaLogSpamPatch
	{
		private static MethodBase cachedTarget;

		private static readonly string[] SuppressedPrefixes = new string[1] { "No affinity data found for product type" };

		private static long suppressedTotal;

		private static readonly object CountLock = new object();

		private static DateTime lastReportUtc = DateTime.MinValue;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[1] { "UnityEngine.Debug" }, "LogWarning", 1);
			if (cachedTarget == null)
			{
				MelonLogger.Warning("[SCH1BugFix] UnityEngine.Debug.LogWarning not found. Vanilla log-spam filter disabled.");
				return false;
			}
			return true;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyPrefix]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static bool Prefix(object __0)
		{
			try
			{
				if (__0 == null)
				{
					return true;
				}
				string text = __0.ToString();
				if (string.IsNullOrEmpty(text))
				{
					return true;
				}
				for (int i = 0; i < SuppressedPrefixes.Length; i++)
				{
					if (text.StartsWith(SuppressedPrefixes[i], StringComparison.Ordinal))
					{
						long value;
						lock (CountLock)
						{
							suppressedTotal++;
							value = suppressedTotal;
						}
						LogSuppressedThrottled($"vanilla log spam \"{SuppressedPrefixes[i]}...\" ({value} so far)");
						return false;
					}
				}
			}
			catch
			{
			}
			return true;
		}

		private static void LogSuppressedThrottled(string what)
		{
			try
			{
				DateTime utcNow = DateTime.UtcNow;
				bool flag;
				lock (CountLock)
				{
					flag = (utcNow - lastReportUtc).TotalSeconds >= 60.0;
					if (flag)
					{
						lastReportUtc = utcNow;
					}
				}
				if (flag)
				{
					MelonLogger.Msg("[SCH1BugFix] Suppressed " + what + ".");
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch]
	internal static class CanvasGroupFaderFadeToPatch
	{
		private static MethodBase cachedTarget;

		private static bool Prepare()
		{
			cachedTarget = SCH1BugFixMod.ResolveMethod(new string[2] { "ScheduleOne.UI.CanvasGroupFader", "Il2CppScheduleOne.UI.CanvasGroupFader" }, "FadeTo", 2);
			return cachedTarget != null;
		}

		private static MethodBase TargetMethod()
		{
			return cachedTarget;
		}

		[HarmonyFinalizer]
		[HarmonyWrapSafe]
		[HarmonyPriority(0)]
		private static Exception Finalizer(Exception __exception)
		{
			return SCH1BugFixMod.SuppressKnownNullRef(__exception, "CanvasGroupFader.FadeTo");
		}
	}
}