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 BepInEx.Configuration;
using HarmonyLib;
using Mirror;
using UnityEngine;
using UnityEngine.InputSystem;
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", "Enhanced TimeStep Stabilizer", "1.2.0")]
public class TimeStepStabilizer : BaseUnityPlugin
{
public GameMaster gameMaster;
public GeneralManager generalManager;
public MultiplayerRoomManager roomManager;
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;
private bool showMenu = false;
private InputAction toggleMenuAction;
private ConfigEntry<int> configSendRate;
private ConfigEntry<int> configFPSHistorySize;
private ConfigEntry<float> configMinFPSThreshold;
private ConfigEntry<float> configAdjustmentStep;
private ConfigEntry<float> configMaxFixedDeltaTime;
public static TimeStepStabilizer Instance { get; private set; }
public int SendRate { get; private set; } = 60;
public int FPSHistorySize { get; private set; } = 10;
public float MinFPSThreshold { get; private set; } = 29f;
public float AdjustmentStep { get; private set; } = 0.001f;
public float MaxFixedDeltaTime { get; private set; } = 0.015f;
private void Awake()
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Expected O, but got Unknown
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Expected O, but got Unknown
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Expected O, but got Unknown
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Expected O, but got Unknown
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Expected O, but got Unknown
//IL_0170: Unknown result type (might be due to invalid IL or missing references)
//IL_017a: Expected O, but got Unknown
((Object)Chainloader.ManagerObject).hideFlags = (HideFlags)61;
Instance = this;
Harmony.CreateAndPatchAll(typeof(TimeStepStabilizer), (string)null);
SceneManager.sceneLoaded += OnSceneLoaded;
configSendRate = ((BaseUnityPlugin)this).Config.Bind<int>("Network", "SendRate", 60, new ConfigDescription("Network send rate (ticks per second)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 60), Array.Empty<object>()));
configFPSHistorySize = ((BaseUnityPlugin)this).Config.Bind<int>("Stabilization", "FPSHistorySize", 10, new ConfigDescription("Number of FPS samples to average", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 30), Array.Empty<object>()));
configMinFPSThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("Stabilization", "MinFPSThreshold", 29f, new ConfigDescription("FPS threshold for stabilization activation", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 60f), Array.Empty<object>()));
configAdjustmentStep = ((BaseUnityPlugin)this).Config.Bind<float>("Stabilization", "AdjustmentStep", 0.001f, new ConfigDescription("FixedDeltaTime adjustment step size", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.001f, 0.1f), Array.Empty<object>()));
configMaxFixedDeltaTime = ((BaseUnityPlugin)this).Config.Bind<float>("Stabilization", "MaxFixedDeltaTime", 0.015f, new ConfigDescription("Maximum allowed FixedDeltaTime value", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.1f), Array.Empty<object>()));
LoadConfig();
toggleMenuAction = new InputAction("ToggleMenu", (InputActionType)1, "<Keyboard>/f8", (string)null, (string)null, (string)null);
toggleMenuAction.performed += delegate
{
showMenu = !showMenu;
};
toggleMenuAction.Enable();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Enhanced TimeStep Stabilizer initialized");
}
private void OnDestroy()
{
toggleMenuAction.Disable();
SceneManager.sceneLoaded -= OnSceneLoaded;
}
private void LoadConfig()
{
SendRate = configSendRate.Value;
FPSHistorySize = configFPSHistorySize.Value;
MinFPSThreshold = configMinFPSThreshold.Value;
AdjustmentStep = configAdjustmentStep.Value;
MaxFixedDeltaTime = configMaxFixedDeltaTime.Value;
ApplyNetworkSettings();
}
private void SaveConfig()
{
configSendRate.Value = SendRate;
configFPSHistorySize.Value = FPSHistorySize;
configMinFPSThreshold.Value = MinFPSThreshold;
configAdjustmentStep.Value = AdjustmentStep;
configMaxFixedDeltaTime.Value = MaxFixedDeltaTime;
((BaseUnityPlugin)this).Config.Save();
ApplyNetworkSettings();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Configuration saved");
}
private void ApplyNetworkSettings()
{
roomManager = Object.FindObjectOfType<MultiplayerRoomManager>(true);
if ((Object)(object)roomManager != (Object)null)
{
((NetworkManager)roomManager).sendRate = SendRate;
}
else
{
Debug.LogError((object)"MultiplayerRoomManager NOT FOUND");
}
}
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>();
roomManager = Object.FindObjectOfType<MultiplayerRoomManager>(true);
if ((Object)(object)gameMaster == (Object)null || (Object)(object)generalManager == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)("GameMaster, RoomManager or GeneralManager not found." + ((Object)gameMaster).name + ((Object)generalManager).name + ((Object)roomManager).name));
yield break;
}
LoadConfig();
fpsField = typeof(GeneralManager).GetField("fps", BindingFlags.Instance | BindingFlags.NonPublic);
setTimeScaleMethod = typeof(GameMaster).GetMethod("SetTimeScale", BindingFlags.Instance | BindingFlags.NonPublic);
currentGameSpeedField = typeof(GameMaster).GetField("currentGameSpeed", BindingFlags.Instance | BindingFlags.NonPublic);
if (currentGameSpeedField != null)
{
baseFixedDeltaTime = Time.fixedDeltaTime;
baseTimeScale = (float)currentGameSpeedField.GetValue(gameMaster);
((BaseUnityPlugin)this).Logger.LogInfo((object)$"Base TimeScale: {baseTimeScale:F2}");
}
for (int i = 0; i < FPSHistorySize; i++)
{
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)
{
continue;
}
int currentFps = (int)fpsField.GetValue(generalManager);
fpsHistory.Add(currentFps);
while (fpsHistory.Count > FPSHistorySize)
{
fpsHistory.RemoveAt(0);
}
float avgFps = fpsHistory.Average();
Time.fixedDeltaTime = baseFixedDeltaTime;
if (avgFps < MinFPSThreshold && baseFixedDeltaTime < MaxFixedDeltaTime)
{
float adjustment = AdjustmentStep * (MinFPSThreshold / avgFps);
float newFixedDeltaTime2 = baseFixedDeltaTime + adjustment;
if (newFixedDeltaTime2 > MaxFixedDeltaTime)
{
newFixedDeltaTime2 = MaxFixedDeltaTime;
}
newFixedDeltaTime2 = (float)Math.Round(newFixedDeltaTime2, 5);
((BaseUnityPlugin)this).Logger.LogInfo((object)$"Low FPS ({avgFps:F2} < {MinFPSThreshold}), adjusting FixedDeltaTime to: {newFixedDeltaTime2:F5}");
baseFixedDeltaTime = newFixedDeltaTime2;
fpsHistory.Add(50f);
fpsHistory.RemoveAt(0);
}
((BaseUnityPlugin)this).Logger.LogInfo((object)$"Current FixedDeltaTime: {Time.fixedDeltaTime:F5}");
}
}
private void OnGUI()
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_0198: Unknown result type (might be due to invalid IL or missing references)
//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
//IL_0218: Unknown result type (might be due to invalid IL or missing references)
//IL_024d: Unknown result type (might be due to invalid IL or missing references)
//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
//IL_031a: Unknown result type (might be due to invalid IL or missing references)
//IL_0349: Unknown result type (might be due to invalid IL or missing references)
//IL_037e: Unknown result type (might be due to invalid IL or missing references)
//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
if (showMenu)
{
int num = 430;
GUI.Box(new Rect(10f, (float)num, 400f, 430f), "TimeStep Stabilizer ModMenu");
num += 30;
GUI.Label(new Rect(20f, (float)num, 360f, 20f), "Network Send Rate: " + SendRate);
SendRate = (int)GUI.HorizontalSlider(new Rect(20f, (float)(num + 20), 360f, 20f), (float)SendRate, 1f, 60f);
num += 50;
GUI.Label(new Rect(20f, (float)num, 360f, 20f), $"FPS History Size: {FPSHistorySize}");
FPSHistorySize = (int)GUI.HorizontalSlider(new Rect(20f, (float)(num + 20), 360f, 20f), (float)FPSHistorySize, 5f, 30f);
num += 50;
GUI.Label(new Rect(20f, (float)num, 360f, 20f), $"Min FPS Threshold: {MinFPSThreshold:F1} ... increase for more FPS");
MinFPSThreshold = GUI.HorizontalSlider(new Rect(20f, (float)(num + 20), 360f, 20f), MinFPSThreshold, 15f, 60f);
num += 50;
GUI.Label(new Rect(20f, (float)num, 360f, 20f), $"Adjustment Step: {AdjustmentStep:F4}");
AdjustmentStep = GUI.HorizontalSlider(new Rect(20f, (float)(num + 20), 360f, 20f), AdjustmentStep, 0.0001f, 0.01f);
AdjustmentStep = (float)Math.Round(AdjustmentStep, 4);
num += 50;
GUI.Label(new Rect(20f, (float)num, 360f, 20f), $"Max FixedDeltaTime: {MaxFixedDeltaTime:F4}");
MaxFixedDeltaTime = GUI.HorizontalSlider(new Rect(20f, (float)(num + 20), 360f, 20f), MaxFixedDeltaTime, 0.01f, 0.05f);
MaxFixedDeltaTime = (float)Math.Round(MaxFixedDeltaTime, 4);
num += 50;
float num2 = (fpsHistory.Any() ? fpsHistory.Average() : 0f);
GUI.Label(new Rect(20f, (float)num, 360f, 20f), "Current FPS: " + ((fpsField != null && (Object)(object)generalManager != (Object)null) ? fpsField.GetValue(generalManager).ToString() : "N/A"));
GUI.Label(new Rect(20f, (float)(num + 20), 360f, 20f), $"Average FPS: {num2:F1}");
GUI.Label(new Rect(20f, (float)(num + 40), 360f, 20f), $"FixedDeltaTime: {Time.fixedDeltaTime:F5}");
num += 70;
if (GUI.Button(new Rect(20f, (float)num, 170f, 30f), "Apply Settings"))
{
SaveConfig();
}
if (GUI.Button(new Rect(200f, (float)num, 170f, 30f), "Reset to Default"))
{
SendRate = 60;
FPSHistorySize = 10;
MinFPSThreshold = 29f;
AdjustmentStep = 0.001f;
MaxFixedDeltaTime = 0.015f;
SaveConfig();
}
}
}
}