Files
BarotraumaModServer/LocalMods/Enhanced Loading/CSharp/Client/LoadOptimizer.cs

366 lines
16 KiBLFS
C#
Executable File

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 <number> (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);
}
}
}
}