Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of SCH1BugFix v1.1.4
sch1bugfix.dll
Decompiled a day agousing 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"); } } }