Decompiled source of GK2 Faster Doors v0.1.0

GK2FasterDoors.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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Cysharp.Threading.Tasks;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Scripting;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace GK2FasterDoors;

[BepInPlugin("gk2.fasterdoors", "GK2 Faster Doors", "0.1.0")]
public class Plugin : BaseUnityPlugin
{
	public const string Guid = "gk2.fasterdoors";

	public const string Version = "0.1.0";

	internal static ManualLogSource Log;

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<bool> Verbose;

	internal static ConfigEntry<int> EveryDoors;

	internal static ConfigEntry<int> GrowthMb;

	private static int _doorsSkipped;

	private static long _baseManaged;

	private static long _baseNative;

	private static bool _haveBase;

	private static float _measureAt = -1f;

	private static int _gcAtDoor;

	private static readonly Dictionary<string, int> Stripped = new Dictionary<string, int>();

	private static bool _counting;

	private void Awake()
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Expected O, but got Unknown
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Expected O, but got Unknown
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Expected O, but got Unknown
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Expected O, but got Unknown
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Expected O, but got Unknown
		//IL_018e: Expected O, but got Unknown
		//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e4: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Skip the game's memory clean-up on most doors and teleports (it runs in full when due, see below).");
		EveryDoors = ((BaseUnityPlugin)this).Config.Bind<int>("General", "FullCleanupEveryDoors", 10, new ConfigDescription("Run the full clean-up at least on every Nth door. 1 = every door, as in the unmodded game.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
		GrowthMb = ((BaseUnityPlugin)this).Config.Bind<int>("General", "FullCleanupAfterGrowthMB", 300, new ConfigDescription("Also run the full clean-up on the next door once the game's memory has grown by this many MB since the last one.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(50, 4000), Array.Empty<object>()));
		Verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Verbose", false, "Log every door's decision and what the full clean-up removed.");
		try
		{
			Harmony val = new Harmony("gk2.fasterdoors");
			MethodInfo methodInfo = AccessTools.Method(typeof(MainGame), "HiddenOptimization", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Log.LogError((object)"MainGame.HiddenOptimization not found - the mod does nothing");
				return;
			}
			HarmonyMethod val2 = new HarmonyMethod(typeof(Plugin), "OptPre", (Type[])null);
			val2.priority = 800;
			val.Patch((MethodBase)methodInfo, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(MainGame).Assembly.GetType("EditorOnlyComponentStripper"), "StripAll", (Type[])null, (Type[])null);
			if (methodInfo2 != null)
			{
				val.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(Plugin), "StripPre", (Type[])null), new HarmonyMethod(typeof(Plugin), "StripPost", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo3 = AccessTools.Method(typeof(MainGame).Assembly.GetType("EditorOnlyComponentStripper"), "DestroyEditorOnlyComponent", (Type[])null, (Type[])null);
			if (methodInfo3 != null)
			{
				val.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(Plugin), "DestroyPre", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Patching failed, the mod does nothing: " + ex));
			return;
		}
		Log.LogInfo((object)("GK2 Faster Doors 0.1.0 loaded (full clean-up every " + EveryDoors.Value + " doors or after +" + GrowthMb.Value + " MB; incremental GC " + ((!IncrementalGc()) ? "off" : "on") + ")"));
	}

	private static bool IncrementalGc()
	{
		try
		{
			return GarbageCollector.isIncremental;
		}
		catch
		{
			return false;
		}
	}

	private void OnDestroy()
	{
		try
		{
			Harmony.UnpatchID("gk2.fasterdoors");
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Unpatch: " + ex.Message));
		}
	}

	private void Update()
	{
		if (_measureAt >= 0f && Time.unscaledTime >= _measureAt)
		{
			_measureAt = -1f;
			_baseManaged = GC.GetTotalMemory(forceFullCollection: false);
			_baseNative = Native();
			_haveBase = true;
			if (Verbose.Value)
			{
				Log.LogInfo((object)("base after full clean-up: managed " + Mb(_baseManaged) + " MB, native " + Mb(_baseNative) + " MB"));
			}
		}
	}

	private static long Native()
	{
		try
		{
			return Profiler.GetTotalAllocatedMemoryLong();
		}
		catch
		{
			return 0L;
		}
	}

	private static long Mb(long bytes)
	{
		return bytes / 1048576;
	}

	private static bool FromTeleport()
	{
		try
		{
			StackFrame[] frames = new StackTrace(fNeedFileInfo: false).GetFrames();
			if (frames == null)
			{
				return false;
			}
			StackFrame[] array = frames;
			foreach (StackFrame stackFrame in array)
			{
				Type type = stackFrame.GetMethod()?.DeclaringType;
				while (type != null)
				{
					if (type == typeof(PlayerController))
					{
						return true;
					}
					type = type.DeclaringType;
				}
			}
		}
		catch
		{
		}
		return false;
	}

	private static bool OptPre(ref UniTask __result)
	{
		//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!Enabled.Value)
			{
				FullRun("off");
				return true;
			}
			if (!FromTeleport())
			{
				FullRun("scene load");
				return true;
			}
			string text = null;
			long totalMemory = GC.GetTotalMemory(forceFullCollection: false);
			long num = Native();
			long num2 = ((!_haveBase) ? 0 : (Math.Max(0L, totalMemory - _baseManaged) + Math.Max(0L, num - _baseNative)));
			if (!_haveBase)
			{
				text = "first door";
			}
			else if (_doorsSkipped + 1 >= EveryDoors.Value)
			{
				text = "door " + (_doorsSkipped + 1) + " of " + EveryDoors.Value;
			}
			else if (num2 >= (long)GrowthMb.Value * 1024L * 1024)
			{
				text = "memory +" + Mb(num2) + " MB";
			}
			if (text != null)
			{
				FullRun(text);
				return true;
			}
			_doorsSkipped++;
			if (Verbose.Value)
			{
				Log.LogInfo((object)("door: clean-up skipped (" + _doorsSkipped + " since the last one, memory +" + Mb(num2) + " MB, managed " + Mb(totalMemory) + " MB, native " + Mb(num) + " MB, GCs since last door " + (GC.CollectionCount(0) - _gcAtDoor) + ")"));
			}
			_gcAtDoor = GC.CollectionCount(0);
			__result = default(UniTask);
			return false;
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Deciding failed, running the game's clean-up: " + ex.Message));
			return true;
		}
	}

	private static void FullRun(string why)
	{
		_doorsSkipped = 0;
		_measureAt = Time.unscaledTime + 3f;
		_gcAtDoor = GC.CollectionCount(0);
		if (Verbose.Value)
		{
			Log.LogInfo((object)("full clean-up (" + why + "): managed " + Mb(GC.GetTotalMemory(forceFullCollection: false)) + " MB, native " + Mb(Native()) + " MB"));
		}
	}

	private static void StripPre()
	{
		_counting = Verbose.Value;
		Stripped.Clear();
	}

	private static void StripPost()
	{
		if (_counting)
		{
			_counting = false;
			Log.LogInfo((object)((Stripped.Count != 0) ? ("editor-only components removed: " + string.Join(", ", from p in Stripped
				orderby p.Value descending
				select p.Key + " " + p.Value)) : "editor-only components removed: none"));
		}
	}

	private static void DestroyPre(Component __0)
	{
		if (_counting && !((Object)(object)__0 == (Object)null))
		{
			string name = ((object)__0).GetType().Name;
			Stripped.TryGetValue(name, out var value);
			Stripped[name] = value + 1;
		}
	}
}