using System; using System.Reflection; using System.Collections.Generic; using System.Linq; using Barotrauma; using Microsoft.Xna.Framework; using HarmonyLib; namespace FastLoadMod { // ------------------------------------------------------------------- // COMMUNITY REQUESTED FEATURE // ------------------------------------------------------------------- public class LoadOptimizer : IAssemblyPlugin { private static void PreventCrashing() { bool isCrashing = false; if (isCrashing) return; // This prevents 100% of ALL crashes thanks to the innovative minds over on the Barotrauma discord server. // In other words, yucky you. This is obviously a joke, but god forbid I wrap everything in try-catch. } private static Harmony harmony; private static int originalFrameLimit; private static bool originalVSync; private static bool originalFixedTimeStep; private static TimeSpan originalSleepTime; // STATE FLAGS private static bool isOptimized = false; private static bool isBenchmarking = false; private static bool hasLoggedState = false; public static bool VerboseLogging = false; public static bool BenchmarkMode = false; // STATS VARIABLES private static DateTime loadStartTime; private static int loadFrameCount; private static double maxFrameTimeRecorded = 0f; private static DateTime lastProfileLog = DateTime.MinValue; private static DateTime optimizationExpiryTime = DateTime.MinValue; public void Initialize() { harmony = new Harmony("com.fastload.mod"); try { var updateMethod = typeof(GameMain).GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(GameTime) }, null); if (updateMethod != null) { harmony.Patch(updateMethod, new HarmonyMethod(AccessTools.Method(typeof(LoadOptimizer), "CheckLoadingState"))); } var consoleMethod = typeof(DebugConsole).GetMethod("ExecuteCommand", BindingFlags.Static | BindingFlags.Public); if (consoleMethod != null) { harmony.Patch(consoleMethod, new HarmonyMethod(AccessTools.Method(typeof(LoadOptimizer), "InterceptConsoleCommand"))); } var forceTurboProbe = new HarmonyMethod(AccessTools.Method(typeof(LoadOptimizer), "ProbeLoadSession")); int hookCount = 0; foreach (MethodInfo method in typeof(Level).GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)) { if (method.Name == "Generate") { harmony.Patch(method, forceTurboProbe); hookCount++; } } foreach (MethodInfo method in typeof(Submarine).GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)) { if (method.Name == "Load") { harmony.Patch(method, forceTurboProbe); hookCount++; } } Type saveUtilType = Type.GetType("Barotrauma.SaveUtil, Barotrauma"); if (saveUtilType != null) { foreach (MethodInfo method in saveUtilType.GetMethods(BindingFlags.Public | BindingFlags.Static)) { if (method.Name == "LoadGame") { harmony.Patch(method, forceTurboProbe); hookCount++; } } } foreach (MethodInfo method in typeof(GameSession).GetMethods(BindingFlags.Public | BindingFlags.Instance)) { if (method.Name == "StartRound") { harmony.Patch(method, forceTurboProbe); hookCount++; } } foreach (MethodInfo method in typeof(Screen).GetMethods(BindingFlags.Public | BindingFlags.Instance)) { if (method.Name == "Select") { harmony.Patch(method, forceTurboProbe); hookCount++; } } Type campaignType = Type.GetType("Barotrauma.CampaignMode, Barotrauma"); if (campaignType != null) { foreach (MethodInfo method in campaignType.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { if (method.Name == "LoadNewLevel") { harmony.Patch(method, forceTurboProbe); hookCount++; } } } Type gameServerType = Type.GetType("Barotrauma.Networking.GameServer, Barotrauma"); if (gameServerType != null) { foreach (MethodInfo method in gameServerType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)) { if (method.Name == "StartGameCore") { harmony.Patch(method, forceTurboProbe); hookCount++; } } } DebugConsole.NewMessage($"[EnLo] Optimizer Ready. Hooked {hookCount} telemetry triggers.", Color.Green); // Console Command Stubs DebugConsole.Commands.Add(new DebugConsole.Command("fastload_verbose", "Toggle logs", (string[] args) => { })); DebugConsole.Commands.Add(new DebugConsole.Command("fastload_benchmark", "Toggle comparison simulation of the mod. Limits fps to 60 during loads", (string[] args) => { })); DebugConsole.Commands.Add(new DebugConsole.Command( "fastload_setfps", "Changes max FPS. Usage: fastload_setfps [number]", (string[] args) => { }, () => new string[][] { new string[] { "60", "120", "144", "240", "0" } } )); } catch (Exception ex) { DebugConsole.NewMessage($"[EnLo] Init Error: {ex.Message}", Color.Orange); } } public void OnLoadCompleted() { } public void PreInitPatching() { } public void Dispose() { if (isOptimized) RestoreFramerate(); if (harmony != null) Harmony.UnpatchID("com.fastload.mod"); harmony = null; } public static bool InterceptConsoleCommand(string inputtedCommands) { if (string.IsNullOrWhiteSpace(inputtedCommands)) return true; string[] parts = inputtedCommands.Trim().Split(' '); string cleanCmd = parts[0]; if (cleanCmd.Equals("fastload_verbose", StringComparison.OrdinalIgnoreCase)) { VerboseLogging = !VerboseLogging; DebugConsole.NewMessage($"[EnLo] Logging: {VerboseLogging}", Color.Cyan); return false; } if (cleanCmd.Equals("fastload_benchmark", StringComparison.OrdinalIgnoreCase)) { BenchmarkMode = !BenchmarkMode; string status = BenchmarkMode ? "ENABLED (Next load forced to 60 FPS)" : "DISABLED (Unlimited FPS)"; DebugConsole.NewMessage($"[EnLo] Benchmark: {status}", Color.Yellow); return false; } if (cleanCmd.Equals("fastload_setfps", StringComparison.OrdinalIgnoreCase)) { // No arguments provided? Print current FPS if (parts.Length == 1) { int currentLimit = GameSettings.CurrentConfig.Graphics.FrameLimit; DebugConsole.NewMessage($"[EnLo] Current FPS cap is {currentLimit}.", Color.Cyan); return false; } // Argument provided but it's not a valid number? Show usage if (!int.TryParse(parts[1], out int newLimit)) { DebugConsole.NewMessage("[EnLo] Usage: fastload_setfps (e.g., fastload_setfps 144)", Color.Yellow); return false; } // Valid number provided? Apply and save GameSettings.SetCurrentConfig(GameSettings.CurrentConfig with { Graphics = GameSettings.CurrentConfig.Graphics with { FrameLimit = newLimit } }); GameSettings.SaveCurrentConfig(); originalFrameLimit = newLimit; DebugConsole.NewMessage($"[EnLo] Success! Max FPS set to {newLimit} and saved to config_player.xml.", Color.Lime); return false; } return true; } public static void ProbeLoadSession(MethodBase __originalMethod) { if (VerboseLogging && __originalMethod != null) { DebugConsole.NewMessage($"[EnLo Probe] Event Fired: {__originalMethod.DeclaringType.Name}.{__originalMethod.Name}", Color.Magenta); } StartLoadSession(__originalMethod?.Name ?? "Unknown"); } public static void StartLoadSession(string triggerName) { if (!isOptimized) { loadStartTime = DateTime.UtcNow; loadFrameCount = 0; maxFrameTimeRecorded = 0f; hasLoggedState = false; } float timerSeconds = 4.0f; if (triggerName == "Select") { timerSeconds = 2.0f; } else if (triggerName == "StartRound" || triggerName == "StartGameCore" || triggerName == "LoadGame") { timerSeconds = 8.0f; } else if (triggerName == "Generate" || triggerName == "Load") { timerSeconds = 6.0f; } optimizationExpiryTime = DateTime.UtcNow.AddSeconds(timerSeconds); isBenchmarking = BenchmarkMode; } public static void CheckLoadingState(GameMain __instance, GameTime gameTime) { bool isVisualLoading = __instance.LoadingScreenOpen; if (isVisualLoading) { if (optimizationExpiryTime < DateTime.UtcNow.AddSeconds(1.0)) optimizationExpiryTime = DateTime.UtcNow.AddSeconds(1.0); } if (gameTime != null && (isOptimized || isBenchmarking)) { double frameMs = gameTime.ElapsedGameTime.TotalMilliseconds; if (frameMs > maxFrameTimeRecorded) maxFrameTimeRecorded = frameMs; loadFrameCount++; if (!isBenchmarking) { if (frameMs > 33.0) { if (optimizationExpiryTime < DateTime.UtcNow.AddSeconds(1.5)) optimizationExpiryTime = DateTime.UtcNow.AddSeconds(1.5); } } } if (DateTime.UtcNow < optimizationExpiryTime) { if (isBenchmarking) { var settings = GameSettings.CurrentConfig.Graphics; if (settings.FrameLimit != 60 || settings.VSync != true) { originalFrameLimit = settings.FrameLimit; originalVSync = settings.VSync; originalFixedTimeStep = GameMain.Instance.IsFixedTimeStep; settings.FrameLimit = 60; settings.VSync = true; GameMain.GraphicsDeviceManager.SynchronizeWithVerticalRetrace = true; GameMain.Instance.IsFixedTimeStep = true; GameMain.GraphicsDeviceManager.ApplyChanges(); isOptimized = true; } } else { if (!isOptimized) UncapFramerate(); } } else { // Timer fully ran out if (isOptimized) RestoreFramerate(); } if (VerboseLogging && (isOptimized || isBenchmarking)) { if (!hasLoggedState) { DebugConsole.NewMessage(">>> [EnLo] LOAD STARTED >>>", Color.Cyan); hasLoggedState = true; } if ((DateTime.UtcNow - lastProfileLog).TotalMilliseconds > 500) { double currentFPS = (gameTime != null && gameTime.ElapsedGameTime.TotalMilliseconds > 0) ? (1000.0 / gameTime.ElapsedGameTime.TotalMilliseconds) : 0; DebugConsole.NewMessage($"[EnLo Monitor] FPS: {currentFPS:F0} | FrameTime: {gameTime?.ElapsedGameTime.TotalMilliseconds:F1}ms", Color.Gray); lastProfileLog = DateTime.UtcNow; } } else if (!isOptimized && hasLoggedState) { hasLoggedState = false; } } public static void UncapFramerate() { try { var graphicsSettings = GameSettings.CurrentConfig.Graphics; originalFrameLimit = graphicsSettings.FrameLimit; originalVSync = graphicsSettings.VSync; originalFixedTimeStep = GameMain.Instance.IsFixedTimeStep; // Save the user's normal background sleep time and disable it originalSleepTime = GameMain.Instance.InactiveSleepTime; GameMain.Instance.InactiveSleepTime = TimeSpan.Zero; GameMain.Instance.IsFixedTimeStep = false; GameMain.GraphicsDeviceManager.SynchronizeWithVerticalRetrace = false; GameMain.GraphicsDeviceManager.ApplyChanges(); isOptimized = true; } catch (Exception ex) { if (VerboseLogging) DebugConsole.NewMessage($"[EnLo] Warning: Failed to Uncap: {ex.Message}", Color.Yellow); } } public static void RestoreFramerate() { try { GameMain.Instance.IsFixedTimeStep = originalFixedTimeStep; GameMain.GraphicsDeviceManager.SynchronizeWithVerticalRetrace = originalVSync; // Restores vanilla game config after load GameMain.Instance.InactiveSleepTime = originalSleepTime; GameMain.GraphicsDeviceManager.ApplyChanges(); isOptimized = false; isBenchmarking = false; if (VerboseLogging) { double durationMs = (DateTime.UtcNow - loadStartTime).TotalMilliseconds; double avgFps = durationMs > 0 ? (loadFrameCount / (durationMs / 1000.0)) : 0; string mode = BenchmarkMode ? "BENCHMARK" : "TURBO"; DebugConsole.NewMessage($"<<< [EnLo] {mode} FINISHED <<<", Color.Cyan); DebugConsole.NewMessage($" Duration: {durationMs:F0}ms", Color.Cyan); DebugConsole.NewMessage($" Avg FPS: {avgFps:F0}", Color.Cyan); Color statColor = (maxFrameTimeRecorded > 1000) ? Color.Red : Color.Green; DebugConsole.NewMessage($" Longest Stutter (MaxFrameTime): {maxFrameTimeRecorded:F0}ms", statColor); } } catch (Exception ex) { if (VerboseLogging) DebugConsole.NewMessage($"[EnLo] Warning: Failed to Restore: {ex.Message}", Color.Yellow); } } } }