Decompiled source of StageStutterFix v1.0.0

plugins/StageStutterFix.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HG.Reflection;
using Microsoft.CodeAnalysis;
using MonoMod.RuntimeDetour;
using RoR2;
using RoR2.Networking;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceLocations;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("StageStutterFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+f5231a32897f5294c51f5bfe080b8b9985b4f2ca")]
[assembly: AssemblyProduct("StageStutterFix")]
[assembly: AssemblyTitle("StageStutterFix")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
[module: UnverifiableCode]
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 StageStutterFix
{
	public static class BetterPreloadPatch
	{
		private class NewScenePreloadData
		{
			public string sceneName;

			public bool preserveInMenuScenes;

			public AsyncOperationHandle<IList<IResourceLocation>> locationsHandle;

			public List<AsyncOperationHandle<Object>> assetHandles;

			public Coroutine preloadAssetsCoroutine;

			public void ReleaseLocations()
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				if (locationsHandle.IsValid())
				{
					Addressables.Release<IList<IResourceLocation>>(locationsHandle);
				}
			}

			public void ReleaseAssets()
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: 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)
				if (assetHandles == null)
				{
					return;
				}
				foreach (AsyncOperationHandle<Object> assetHandle in assetHandles)
				{
					if (assetHandle.IsValid())
					{
						Addressables.Release<Object>(assetHandle);
					}
				}
				assetHandles = null;
			}
		}

		[CompilerGenerated]
		private sealed class <DoScenePreloadCoroutine>d__7 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public NewScenePreloadData scenePreloadData;

			private IList<IResourceLocation> <preloadLocations>5__2;

			private Stopwatch <frameStopwatch>5__3;

			private int <i>5__4;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DoScenePreloadCoroutine>d__7(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<preloadLocations>5__2 = null;
				<frameStopwatch>5__3 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_009c: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					<frameStopwatch>5__3.Restart();
					goto IL_0080;
				}
				<>1__state = -1;
				<preloadLocations>5__2 = scenePreloadData.locationsHandle.WaitForCompletion();
				<frameStopwatch>5__3 = new Stopwatch();
				<frameStopwatch>5__3.Start();
				<i>5__4 = 0;
				goto IL_00b6;
				IL_0080:
				scenePreloadData.assetHandles.Add(Addressables.LoadAssetAsync<Object>(<preloadLocations>5__2[<i>5__4]));
				<i>5__4++;
				goto IL_00b6;
				IL_00b6:
				if (<i>5__4 < <preloadLocations>5__2.Count)
				{
					if (<frameStopwatch>5__3.ElapsedMilliseconds >= StageStutterFixPlugin.PreloadBudgetPerFrame)
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					goto IL_0080;
				}
				scenePreloadData.ReleaseLocations();
				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();
			}
		}

		[CompilerGenerated]
		private sealed class <WaitBeforeUnloadingScenePreloads>d__9 : 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 <WaitBeforeUnloadingScenePreloads>d__9(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Expected O, but got Unknown
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Invalid comparison between Unknown and I4
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					unloadingScenePreloads = true;
					<>2__current = (object)new WaitForSeconds(NetworkPreloadManager.delayBeforeReleasingScenePreloads);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					SceneDef sceneDefForCurrentScene = SceneCatalog.GetSceneDefForCurrentScene();
					bool flag = (Object)(object)sceneDefForCurrentScene == (Object)null || (int)sceneDefForCurrentScene.sceneType <= 0;
					for (int num = allScenePreloadData.Count - 1; num >= 0; num--)
					{
						NewScenePreloadData newScenePreloadData = allScenePreloadData[num];
						if (!flag || !newScenePreloadData.preserveInMenuScenes)
						{
							newScenePreloadData.ReleaseAssets();
							newScenePreloadData.ReleaseLocations();
							if (newScenePreloadData.preloadAssetsCoroutine != null)
							{
								CoroutineManager.StopCoroutine(newScenePreloadData.preloadAssetsCoroutine);
							}
							allScenePreloadData.RemoveAt(num);
						}
					}
					unloadingScenePreloads = false;
					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 readonly List<NewScenePreloadData> allScenePreloadData = new List<NewScenePreloadData>();

		private static bool unloadingScenePreloads;

		private static MonoBehaviour CoroutineManager => (MonoBehaviour)(object)StageStutterFixPlugin.Instance;

		public static void Init()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			StageStutterFixPlugin.Logger.LogMessage((object)$"Using better scene preloading with a frame budget of {StageStutterFixPlugin.PreloadBudgetPerFrame}ms");
			new Hook((MethodBase)typeof(NetworkPreloadManager).GetMethod("StartNewScenePreload", new Type[2]
			{
				typeof(string),
				typeof(bool)
			}), (Delegate)new Action<string, bool>(StartBetterScenePreload));
			SceneManager.activeSceneChanged += OnActiveSceneChanged;
		}

		private static void StartBetterScenePreload(string sceneCachedName, bool preserveSceneInMenus)
		{
			//IL_0046: 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)
			if (!allScenePreloadData.Exists((NewScenePreloadData x) => x.sceneName == sceneCachedName))
			{
				NewScenePreloadData newScenePreloadData = new NewScenePreloadData
				{
					sceneName = sceneCachedName,
					preserveInMenuScenes = preserveSceneInMenus,
					locationsHandle = Addressables.LoadResourceLocationsAsync((object)sceneCachedName, (Type)null),
					assetHandles = new List<AsyncOperationHandle<Object>>()
				};
				allScenePreloadData.Add(newScenePreloadData);
				newScenePreloadData.preloadAssetsCoroutine = CoroutineManager.StartCoroutine(DoScenePreloadCoroutine(newScenePreloadData));
			}
		}

		[IteratorStateMachine(typeof(<DoScenePreloadCoroutine>d__7))]
		private static IEnumerator DoScenePreloadCoroutine(NewScenePreloadData scenePreloadData)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DoScenePreloadCoroutine>d__7(0)
			{
				scenePreloadData = scenePreloadData
			};
		}

		private static void OnActiveSceneChanged(Scene oldScene, Scene newScene)
		{
			if (!unloadingScenePreloads && allScenePreloadData.Count > 0)
			{
				CoroutineManager.StartCoroutine(WaitBeforeUnloadingScenePreloads());
			}
		}

		[IteratorStateMachine(typeof(<WaitBeforeUnloadingScenePreloads>d__9))]
		private static IEnumerator WaitBeforeUnloadingScenePreloads()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WaitBeforeUnloadingScenePreloads>d__9(0);
		}
	}
	public static class NoPreloadPatch
	{
		public static void Init()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			StageStutterFixPlugin.Logger.LogMessage((object)"Disabling scene preloading");
			new Hook((MethodBase)typeof(NetworkPreloadManager).GetMethod("StartNewScenePreload", new Type[2]
			{
				typeof(string),
				typeof(bool)
			}), (Delegate)new Action<string, bool>(DoNothing));
			static void DoNothing(string sceneCachedName, bool preserveSceneInMenus)
			{
			}
		}
	}
	[BepInPlugin("groovesalad.StageStutterFix", "StageStutterFix", "1.0.0")]
	public class StageStutterFixPlugin : BaseUnityPlugin
	{
		public const string GUID = "groovesalad.StageStutterFix";

		public const string NAME = "StageStutterFix";

		public const string VERSION = "1.0.0";

		public static StageStutterFixPlugin Instance { get; private set; }

		public static ManualLogSource Logger { get; private set; }

		public static long PreloadBudgetPerFrame { get; private set; }

		private void Awake()
		{
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			PreloadBudgetPerFrame = ((BaseUnityPlugin)this).Config.Bind<long>("Stage Stutter Fix", "Max preload time per frame", 1L, "The ideal maximum time per frame (in milliseconds) to spend preloading the next stage. A value of zero or less will disable stage preloading").Value;
			if (PreloadBudgetPerFrame > 0)
			{
				BetterPreloadPatch.Init();
			}
			else
			{
				NoPreloadPatch.Init();
			}
		}
	}
}