Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of StageStutterFix v1.0.0
plugins/StageStutterFix.dll
Decompiled 5 months agousing 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(); } } } }