Decompiled source of TimeStepStabilizer v1.0.2

TimeStepStabilizer.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using HarmonyLib;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("TimeStepStabilizer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TimeStepStabilizer")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("bb671ece-09f3-4584-ad0c-c15b01188054")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("com.yourname.TimeStepStabilizer", "TimeStep Stabilizer", "1.0.0")]
public class TimeStepStabilizer : BaseUnityPlugin
{
	public GameMaster gameMaster;

	public GeneralManager generalManager;

	public List<float> fpsHistory = new List<float>();

	public FieldInfo fpsField;

	public MethodInfo setTimeScaleMethod;

	public FieldInfo currentGameSpeedField;

	public float baseTimeScale = 1f;

	public float baseFixedDeltaTime;

	private Coroutine adjustCoroutine;

	public static TimeStepStabilizer Instance { get; private set; }

	private void Awake()
	{
		((Object)Chainloader.ManagerObject).hideFlags = (HideFlags)61;
		Instance = this;
		Harmony.CreateAndPatchAll(typeof(TimeStepStabilizer), (string)null);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"AWAKE: Hooking into SceneManager.sceneLoaded");
		SceneManager.sceneLoaded += OnSceneLoaded;
	}

	private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)("SCENE LOADED: " + ((Scene)(ref scene)).name));
		fpsHistory.Clear();
		if (adjustCoroutine != null)
		{
			((MonoBehaviour)this).StopCoroutine(adjustCoroutine);
			adjustCoroutine = null;
		}
		((MonoBehaviour)this).StartCoroutine(DelayedSetup());
	}

	private IEnumerator DelayedSetup()
	{
		yield return (object)new WaitForSeconds(0.5f);
		gameMaster = Object.FindObjectOfType<GameMaster>();
		generalManager = Object.FindObjectOfType<GeneralManager>();
		if ((Object)(object)gameMaster == (Object)null || (Object)(object)generalManager == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"GameMaster or GeneralManager not found in the scene.");
			yield break;
		}
		fpsField = typeof(GeneralManager).GetField("fps", BindingFlags.Instance | BindingFlags.NonPublic);
		if (fpsField == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"Failed to obtain the fps field from GeneralManager.");
		}
		setTimeScaleMethod = typeof(GameMaster).GetMethod("SetTimeScale", BindingFlags.Instance | BindingFlags.NonPublic);
		if (setTimeScaleMethod == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"Failed to obtain the SetTimeScale method from GameMaster.");
		}
		currentGameSpeedField = typeof(GameMaster).GetField("currentGameSpeed", BindingFlags.Instance | BindingFlags.NonPublic);
		if (currentGameSpeedField == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"Failed to obtain currentGameSpeed from GameMaster.");
		}
		else
		{
			baseFixedDeltaTime = Time.fixedDeltaTime;
			baseTimeScale = (float)currentGameSpeedField.GetValue(gameMaster);
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Base TimeScale captured: {baseTimeScale:F2}");
		}
		fpsHistory.Add(30f);
		adjustCoroutine = ((MonoBehaviour)this).StartCoroutine(AdjustTimeScaleCoroutine());
	}

	private IEnumerator AdjustTimeScaleCoroutine()
	{
		while (true)
		{
			yield return (object)new WaitForSecondsRealtime(1f);
			if ((Object)(object)generalManager == (Object)null || (Object)(object)gameMaster == (Object)null || fpsField == null || setTimeScaleMethod == null)
			{
				continue;
			}
			int currentFps = (int)fpsField.GetValue(generalManager);
			fpsHistory.Add(currentFps);
			if (fpsHistory.Count > 10)
			{
				fpsHistory.RemoveAt(0);
			}
			float avgFps = fpsHistory.Average();
			Time.fixedDeltaTime = baseFixedDeltaTime;
			if (avgFps < 29f && baseFixedDeltaTime < 1f / 51f)
			{
				float adjustment = 0.005f * (30f / avgFps);
				float newFixedDeltaTime2 = baseFixedDeltaTime + adjustment;
				if (newFixedDeltaTime2 > 0.02f)
				{
					newFixedDeltaTime2 = 0.02f;
				}
				newFixedDeltaTime2 = (float)Math.Round(newFixedDeltaTime2, 3);
				((BaseUnityPlugin)this).Logger.LogInfo((object)$"Average FPS: {avgFps:F2} is below 30, setting fixedDeltaTime to: {newFixedDeltaTime2:F3} to relieve work from the CPU");
				baseFixedDeltaTime = newFixedDeltaTime2;
				fpsHistory.Add(50f);
				fpsHistory.RemoveAt(0);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"FixedDeltaTime is: {Time.fixedDeltaTime}");
		}
	}
}