Some mods may be broken due to the recent Alloyed Collective update.
Decompiled source of StageStutterFix v1.0.0
plugins/StageStutterFix.dll
Decompiled a day 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(); } } } }