Decompiled source of PeakScrollFix v1.1.0

PeakScrollFix.dll

Decompiled a month ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Peak;
using Portningsbolaget.Platforms;
using UnityEngine;
using Zorro.Core;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PeakScrollFix
{
	[BepInPlugin("com.dsh.peakscrollfix", "PEAK Guidebook Scroll Fix", "1.1.0")]
	public class PeakScrollFixPlugin : BaseUnityPlugin
	{
		internal static ConfigEntry<bool> EnableGuard;

		internal static ConfigEntry<bool> Verbose;

		private void Awake()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Expected O, but got Unknown
			EnableGuard = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableGuard", true, "Keep the game's AchievementManager singleton (and its guidebook page data) alive while playing. Recommended on.");
			Verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "Log every page-validation fallback and every direct page recording.");
			GameObject val = new GameObject("PeakScrollFix_Guard");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<AchievementManagerGuard>();
			Harmony val2 = new Harmony("com.dsh.peakscrollfix");
			int num = 0;
			MethodInfo methodInfo = AccessTools.Method(typeof(Guidebook), "GuidebookPageValid", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				val2.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Patches), "GuidebookPageValidPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				num++;
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(AchievementManager), "TriggerSeenGuidebookPage", (Type[])null, (Type[])null);
			if (methodInfo2 != null)
			{
				val2.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(Patches), "TriggerSeenGuidebookPagePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				num++;
			}
			MethodInfo methodInfo3 = AccessTools.Method(typeof(GuidebookPageCollection), "TryPickPageToSpawn", (Type[])null, (Type[])null);
			if (methodInfo3 != null)
			{
				val2.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "TryPickPageToSpawnPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				num++;
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[PeakScrollFix] v1.1.0 loaded. Guard active, {num}/3 concrete patches applied (no generic patching).");
		}
	}
	internal static class ScrollFixCore
	{
		private const string TotalPagesReadStat = "TotalPagesRead";

		internal static void Log(string message)
		{
			if (PeakScrollFixPlugin.Verbose != null && PeakScrollFixPlugin.Verbose.Value)
			{
				Debug.Log((object)("[PeakScrollFix] " + message));
			}
		}

		internal static bool TryReadSeenPages(out int seen)
		{
			seen = 0;
			IPlatform platform = PlatformManager.Platform;
			if (platform == null || !platform.Initialized)
			{
				return false;
			}
			return platform.GetStat("TotalPagesRead", ref seen);
		}

		internal static bool TryHeal(AchievementManager manager)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)manager == (Object)null || manager.guidebookData != null)
			{
				return (Object)(object)manager != (Object)null;
			}
			if (!TryReadSeenPages(out var seen))
			{
				return false;
			}
			manager.guidebookData = new GuidebookData();
			manager.guidebookData.seenGuidebookPages = (GUIDEBOOKPAGEFLAGS)seen;
			Log($"healed guidebookData from TotalPagesRead={seen}");
			UnlockBookwormIfEarned(seen);
			return true;
		}

		internal static void RecordPageDirectly(GUIDEBOOKPAGEFLAGS flag, string reason)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected I4, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if ((int)flag == 0)
			{
				return;
			}
			IPlatform platform = PlatformManager.Platform;
			if (platform != null && platform.Initialized)
			{
				int num = default(int);
				if (!platform.GetStat("TotalPagesRead", ref num))
				{
					num = 0;
				}
				int num2 = num | flag;
				if (num2 != num)
				{
					platform.SetStat("TotalPagesRead", num2);
					platform.StoreStats();
				}
				UnlockBookwormIfEarned(num2);
				Debug.Log((object)$"[PeakScrollFix] recorded page {flag} directly ({reason}); TotalPagesRead {num} -> {num2}");
			}
		}

		private static void UnlockBookwormIfEarned(int seenFlags)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if ((seenFlags & 0x80) == 0)
			{
				return;
			}
			IPlatform platform = PlatformManager.Platform;
			if (platform == null || !platform.Initialized)
			{
				return;
			}
			try
			{
				platform.UnlockAchievement(((object)(ACHIEVEMENTTYPE)31/*cast due to .constrained prefix*/).ToString());
			}
			catch
			{
			}
		}

		internal static int CountFlags(int seenFlags)
		{
			int num = 0;
			for (int num2 = 1; num2 <= 262144; num2 <<= 1)
			{
				if ((seenFlags & num2) != 0)
				{
					num++;
				}
			}
			return num;
		}
	}
	public class AchievementManagerGuard : MonoBehaviour
	{
		private static AchievementManager s_fallback;

		private void Update()
		{
			if (PeakScrollFixPlugin.EnableGuard != null && !PeakScrollFixPlugin.EnableGuard.Value)
			{
				return;
			}
			AchievementManager instance = Singleton<AchievementManager>.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				if (instance.guidebookData == null)
				{
					ScrollFixCore.TryHeal(instance);
				}
			}
			else if (Time.frameCount % 5 == 0 && !((Object)(object)GameHandler.Instance == (Object)null) && GameHandler.IsInGameplayScene)
			{
				Ensure();
			}
		}

		private static void Ensure()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			if ((Object)(object)s_fallback != (Object)null)
			{
				ScrollFixCore.TryHeal(s_fallback);
				return;
			}
			AchievementManager val = Object.FindAnyObjectByType<AchievementManager>();
			if ((Object)(object)val != (Object)null)
			{
				ScrollFixCore.TryHeal(val);
				s_fallback = val;
				return;
			}
			GameObject val2 = new GameObject("PeakScrollFix_AchievementManager");
			Object.DontDestroyOnLoad((Object)(object)val2);
			AchievementManager val3 = val2.AddComponent<AchievementManager>();
			if ((Object)(object)val3 == (Object)null)
			{
				Object.Destroy((Object)(object)val2);
				AchievementManager val4 = Object.FindAnyObjectByType<AchievementManager>();
				if ((Object)(object)val4 != (Object)null)
				{
					ScrollFixCore.TryHeal(val4);
					s_fallback = val4;
				}
			}
			else
			{
				ScrollFixCore.TryHeal(val3);
				val3.InitRunBasedValues();
				s_fallback = val3;
				Debug.Log((object)"[PeakScrollFix] AchievementManager singleton was missing; created a persistent replacement so guidebook scrolls keep working.");
			}
		}
	}
	internal static class Patches
	{
		internal static bool GuidebookPageValidPrefix(Guidebook __instance, Vector3 position, ref bool __result)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			AchievementManager instance = Singleton<AchievementManager>.Instance;
			if ((Object)(object)instance != (Object)null)
			{
				if (instance.guidebookData != null)
				{
					return true;
				}
				if (ScrollFixCore.TryHeal(instance))
				{
					return true;
				}
			}
			__result = ValidateWithoutManager(__instance, position);
			return false;
		}

		private static bool ValidateWithoutManager(Guidebook page, Vector3 position)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)page == (Object)null || !page.isSinglePage)
			{
				return false;
			}
			if (!ScrollFixCore.TryReadSeenPages(out var seen))
			{
				return false;
			}
			GUIDEBOOKPAGEFLAGS val = (GUIDEBOOKPAGEFLAGS)seen;
			if ((int)page.requiredSeenPagesToSpawn != 0)
			{
				foreach (GUIDEBOOKPAGEFLAGS value in Enum.GetValues(typeof(GUIDEBOOKPAGEFLAGS)))
				{
					if ((int)value != 0 && ((Enum)page.requiredSeenPagesToSpawn).HasFlag((Enum)(object)value) && !((Enum)val).HasFlag((Enum)(object)value))
					{
						return false;
					}
				}
			}
			if (page.requiredSeenPagesCountToSpawn > 0 && ScrollFixCore.CountFlags(seen) < page.requiredSeenPagesCountToSpawn)
			{
				return false;
			}
			if (page.minimumSegment > 0 && Object.op_Implicit((Object)(object)Singleton<MapHandler>.Instance) && Campfire.GetClosestCampfireNextSegment(position) < page.minimumSegment)
			{
				return false;
			}
			if (page.requireBiomeType && Campfire.GetClosestCampfireNextBiome(position) != page.requiredBiome)
			{
				return false;
			}
			if (page.minSpawnHeight > 0f && position.y < page.minSpawnHeight)
			{
				return false;
			}
			Debug.Log((object)$"[PeakScrollFix] Page{((Object)((Component)page).gameObject).name} validated without AchievementManager (seen={val}); scroll will still produce a page.");
			return true;
		}

		internal static bool TriggerSeenGuidebookPagePrefix(AchievementManager __instance, GUIDEBOOKPAGEFLAGS flag)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null)
			{
				ScrollFixCore.RecordPageDirectly(flag, "no AchievementManager instance");
				return false;
			}
			if (__instance.guidebookData == null && !ScrollFixCore.TryHeal(__instance))
			{
				ScrollFixCore.RecordPageDirectly(flag, "guidebookData unavailable");
				return false;
			}
			return true;
		}

		internal static void TryPickPageToSpawnPostfix(bool __result, ref GameObject result)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!__result || (Object)(object)result == (Object)null)
			{
				return;
			}
			AchievementManager instance = Singleton<AchievementManager>.Instance;
			if (!((Object)(object)instance != (Object)null) || instance.guidebookData == null)
			{
				Guidebook component = result.GetComponent<Guidebook>();
				if (!((Object)(object)component == (Object)null))
				{
					ScrollFixCore.RecordPageDirectly(component.pageFlag, "manager unavailable at pick time");
				}
			}
		}
	}
}