Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of AutoLodBias v1.0.0
plugins\AutoLodBias\AutoLodBias.dll
Decompiled a day agousing System; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("AutoLodBias")] [assembly: AssemblyDescription("Adaptive Valheim LOD bias controller")] [assembly: AssemblyCompany("LEGIOmods")] [assembly: AssemblyProduct("AutoLodBias")] [assembly: AssemblyCopyright("Copyright 2026 LEGIOmods")] [assembly: ComVisible(false)] [assembly: Guid("3605278b-2b13-42e3-903a-e49e21e598fa")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI for code, documentation, and package preparation.")] [assembly: AssemblyMetadata("AI_Model_Vendor", "OpenAI")] [assembly: AssemblyMetadata("AI_Agent", "OpenAI Codex")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 AutoLodBias { [BepInPlugin("domen.valheim.autolodbias", "AutoLodBias", "1.0.0")] public sealed class AutoLodBiasPlugin : BaseUnityPlugin { public const string PluginGuid = "domen.valheim.autolodbias"; public const string PluginName = "AutoLodBias"; public const string PluginVersion = "1.0.0"; private ModConfig _config; private FpsLodController _controller; private PortalState _portal; private OverlayRenderer _overlay; private Harmony _harmony; internal static AutoLodBiasPlugin Instance { get; private set; } private void Awake() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown Instance = this; _config = new ModConfig(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); _controller = new FpsLodController(_config, ((BaseUnityPlugin)this).Logger); _portal = new PortalState(_config, _controller, ((BaseUnityPlugin)this).Logger); _overlay = new OverlayRenderer(_config); _controller.SetLod(_config.DefaultLodBias.Value, "startup"); _harmony = new Harmony("domen.valheim.autolodbias"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"AutoLodBias 1.0.0 loaded."); } private void Update() { HandleHotkeys(); if (_config.Enabled.Value) { float unscaledDeltaTime = Time.unscaledDeltaTime; if (_portal.Active) { _portal.Tick(); } else if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null)) { _controller.Tick(unscaledDeltaTime); } } } private void OnGUI() { _overlay.Draw(_controller.SmoothedFps, _config.Enabled.Value, _portal.Phase); } private void HandleHotkeys() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) bool flag = Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); bool num = !_config.RequireAlt.Value || flag; if (num && Input.GetKeyDown(_config.ToggleOverlayKey.Value)) { _config.ShowOverlay.Value = !_config.ShowOverlay.Value; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Overlay " + (_config.ShowOverlay.Value ? "enabled." : "disabled."))); } if (num && Input.GetKeyDown(_config.ToggleModKey.Value)) { _config.Enabled.Value = !_config.Enabled.Value; _portal.Cancel(); _controller.Reset(); _controller.SetLod(_config.DefaultLodBias.Value, _config.Enabled.Value ? "mod enabled" : "mod disabled"); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Automatic control " + (_config.Enabled.Value ? "enabled." : "disabled."))); } } internal void BeginPortal() { if (_config.Enabled.Value) { _portal.Begin(); } } private void OnDestroy() { _portal?.Cancel(); if (_config != null && _controller != null) { _controller.SetLod(_config.DefaultLodBias.Value, "unload"); } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } Instance = null; } } internal sealed class ModConfig { internal readonly ConfigEntry<bool> Enabled; internal readonly ConfigEntry<float> DefaultLodBias; internal readonly ConfigEntry<float> MinimumLodBias; internal readonly ConfigEntry<float> MaximumLodBias; internal readonly ConfigEntry<float> LodStep; internal readonly ConfigEntry<int> TargetFps; internal readonly ConfigEntry<float> LowDuration; internal readonly ConfigEntry<float> HighDuration; internal readonly ConfigEntry<float> SevereDuration; internal readonly ConfigEntry<float> CriticalDuration; internal readonly ConfigEntry<float> DownAdjustmentCooldown; internal readonly ConfigEntry<float> UpAdjustmentCooldown; internal readonly ConfigEntry<float> PostEmergencyIncreaseLock; internal readonly ConfigEntry<float> FastSmoothingSeconds; internal readonly ConfigEntry<float> SlowSmoothingSeconds; internal readonly ConfigEntry<float> PortalLodBias; internal readonly ConfigEntry<float> PortalLowDuration; internal readonly ConfigEntry<float> PortalRecoveryLodBias; internal readonly ConfigEntry<float> PositionJumpThreshold; internal readonly ConfigEntry<float> PostArrivalLowDuration; internal readonly ConfigEntry<float> PortalTimeout; internal readonly ConfigEntry<float> RecoveryTimeout; internal readonly ConfigEntry<bool> ShowOverlay; internal readonly ConfigEntry<bool> ShowTargetFps; internal readonly ConfigEntry<bool> ShowClock; internal readonly ConfigEntry<bool> Use24HourClock; internal readonly ConfigEntry<bool> RequireAlt; internal readonly ConfigEntry<int> PositionX; internal readonly ConfigEntry<int> PositionY; internal readonly ConfigEntry<int> FontSize; internal readonly ConfigEntry<float> RefreshInterval; internal readonly ConfigEntry<KeyCode> ToggleOverlayKey; internal readonly ConfigEntry<KeyCode> ToggleModKey; internal int ActiveTargetFps { get; private set; } internal int ActiveLowerThreshold { get; private set; } internal int ActiveUpperThreshold { get; private set; } internal int ActiveSevereThreshold { get; private set; } internal int ActiveCriticalThreshold { get; private set; } internal ModConfig(ConfigFile config, ManualLogSource log) { Enabled = config.Bind<bool>("General", "Enabled", true, "Enable automatic LOD control."); DefaultLodBias = config.Bind<float>("General", "DefaultLodBias", 3f, "LOD bias used at startup and while disabled."); MinimumLodBias = config.Bind<float>("General", "MinimumLodBias", 1f, "Minimum permitted LOD bias."); MaximumLodBias = config.Bind<float>("General", "MaximumLodBias", 100f, "Maximum permitted LOD bias."); LodStep = config.Bind<float>("General", "LodStep", 1f, "Legacy setting retained for configuration compatibility."); TargetFps = config.Bind<int>("FPS", "TargetFPS", 0, "0 selects a profile from the display refresh rate; a positive value selects a manual target."); FastSmoothingSeconds = config.Bind<float>("FPS", "FastSmoothingSeconds", 0.15f, "Smoothing time used for downward adjustments."); SlowSmoothingSeconds = config.Bind<float>("FPS", "SlowSmoothingSeconds", 1f, "Smoothing time used for upward adjustments."); LowDuration = config.Bind<float>("FPS", "LowDuration", 0.25f, "Time the fast FPS average must remain below the lower threshold."); HighDuration = config.Bind<float>("FPS", "HighDuration", 1f, "Time the slow FPS average must remain above the upper threshold."); SevereDuration = config.Bind<float>("FPS", "SevereDuration", 0.25f, "Time below the severe profile threshold before switching to LOD 3."); CriticalDuration = config.Bind<float>("FPS", "CriticalDuration", 0.25f, "Time below the critical profile threshold before switching to LOD 1."); DownAdjustmentCooldown = config.Bind<float>("FPS", "DownAdjustmentCooldown", 0.25f, "Cooldown after a normal downward adjustment."); UpAdjustmentCooldown = config.Bind<float>("FPS", "UpAdjustmentCooldown", 1f, "Cooldown after an upward adjustment."); PostEmergencyIncreaseLock = config.Bind<float>("FPS", "PostEmergencyIncreaseLock", 1f, "Time an increase remains blocked after a safety reduction."); PortalLodBias = config.Bind<float>("Portal", "PortalLodBias", 1f, "LOD bias during portal travel."); PortalLowDuration = config.Bind<float>("Portal", "PortalLowDuration", 2f, "Legacy setting retained for configuration compatibility."); PortalRecoveryLodBias = config.Bind<float>("Portal", "PortalRecoveryLodBias", 3f, "LOD bias after portal arrival."); PositionJumpThreshold = config.Bind<float>("Portal", "PositionJumpThreshold", 50f, "Minimum horizontal position jump that counts as portal arrival."); PostArrivalLowDuration = config.Bind<float>("Portal", "PostArrivalLowDuration", 0.75f, "Time to keep the low LOD bias after a detected position jump."); PortalTimeout = config.Bind<float>("Portal", "PortalTimeout", 8f, "Maximum time to wait for a position jump."); RecoveryTimeout = config.Bind<float>("Portal", "RecoveryTimeout", 3f, "Hard timeout after a detected arrival."); ShowOverlay = config.Bind<bool>("Overlay", "ShowOverlay", true, "Show FPS and LOD overlay."); ShowTargetFps = config.Bind<bool>("Overlay", "ShowTargetFPS", true, "Show the active FPS profile next to the measured FPS."); PositionX = config.Bind<int>("Overlay", "PositionX", 15, "Overlay X position."); PositionY = config.Bind<int>("Overlay", "PositionY", 15, "Overlay Y position."); FontSize = config.Bind<int>("Overlay", "FontSize", 16, "Overlay font size."); RefreshInterval = config.Bind<float>("Overlay", "RefreshInterval", 0.25f, "Overlay refresh interval."); ShowClock = config.Bind<bool>("Clock", "ShowClock", true, "Show the local real-world time in the overlay."); Use24HourClock = config.Bind<bool>("Clock", "Use24HourClock", true, "Use 24-hour time instead of 12-hour time."); ToggleOverlayKey = config.Bind<KeyCode>("Hotkeys", "ToggleOverlayKey", (KeyCode)282, "Overlay toggle key."); ToggleModKey = config.Bind<KeyCode>("Hotkeys", "ToggleModKey", (KeyCode)283, "Automatic control toggle key."); RequireAlt = config.Bind<bool>("Hotkeys", "RequireAlt", true, "Require left or right Alt."); Validate(config, log); SelectRuntimeProfile(log); } private void Validate(ConfigFile config, ManualLogSource log) { bool flag = false; flag |= SetIfDifferent(MinimumLodBias, 1f); flag |= SetIfDifferent(MaximumLodBias, 100f); flag |= SetIfDifferent(LodStep, 1f); if (TargetFps.Value < 0) { TargetFps.Value = 0; flag = true; } flag |= EnsurePositive(FastSmoothingSeconds, 0.15f); flag |= EnsurePositive(SlowSmoothingSeconds, 1f); flag |= EnsureNonNegative(LowDuration, 0.25f); flag |= EnsureNonNegative(HighDuration, 1f); flag |= EnsureNonNegative(SevereDuration, 0.25f); flag |= EnsureNonNegative(CriticalDuration, 0.25f); flag |= EnsureNonNegative(DownAdjustmentCooldown, 0.25f); flag |= EnsureNonNegative(UpAdjustmentCooldown, 1f); if (flag | EnsureNonNegative(PostEmergencyIncreaseLock, 1f)) { config.Save(); log.LogWarning((object)"Invalid configuration values were corrected and saved."); } } private void SelectRuntimeProfile(ManualLogSource log) { float refreshRate; bool flag = TryGetDisplayRefreshRate(out refreshRate); bool flag2 = TargetFps.Value == 0; int target; if (flag2) { if (flag) { target = ((refreshRate <= 75f) ? 60 : ((!(refreshRate < 120f)) ? 120 : 90)); } else { target = 60; log.LogWarning((object)"Display refresh rate could not be detected; using the 60 FPS profile."); } } else { target = TargetFps.Value; } ApplyProfile(target, log); string text = (flag ? (refreshRate.ToString("0.##", CultureInfo.InvariantCulture) + " Hz") : "unknown"); log.LogInfo((object)("Display: " + text + " | Mode: " + (flag2 ? "Auto" : "Manual") + " | Selected target: " + ActiveTargetFps + " FPS")); } private void ApplyProfile(int target, ManualLogSource log) { ActiveTargetFps = target; switch (target) { case 30: SetThresholds(25, 29, 20, 15); return; case 60: SetThresholds(50, 57, 40, 30); return; case 90: SetThresholds(80, 100, 60, 40); return; case 120: SetThresholds(105, 125, 80, 55); return; } int num = Mathf.RoundToInt((float)target * 0.85f); int num2 = Mathf.RoundToInt((float)target * 0.97f); int num3 = Mathf.RoundToInt((float)target * 0.67f); int num4 = Mathf.RoundToInt((float)target * 0.5f); bool num5 = num4 >= num3 || num3 >= num || num >= num2; num4 = Mathf.Max(1, num4); num3 = Mathf.Max(num4 + 1, num3); num = Mathf.Max(num3 + 1, num); num2 = Mathf.Max(num + 1, num2); SetThresholds(num, num2, num3, num4); if (num5) { log.LogWarning((object)"Calculated FPS thresholds were corrected to preserve their required order."); } } private void SetThresholds(int lower, int upper, int severe, int critical) { ActiveLowerThreshold = lower; ActiveUpperThreshold = upper; ActiveSevereThreshold = severe; ActiveCriticalThreshold = critical; } private static bool TryGetDisplayRefreshRate(out float refreshRate) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) Resolution currentResolution = Screen.currentResolution; if (((Resolution)(ref currentResolution)).refreshRateRatio.denominator == 0) { refreshRate = 0f; return false; } refreshRate = (float)((Resolution)(ref currentResolution)).refreshRateRatio.numerator / (float)((Resolution)(ref currentResolution)).refreshRateRatio.denominator; if (!float.IsNaN(refreshRate) && !float.IsInfinity(refreshRate) && refreshRate >= 30f) { return refreshRate <= 500f; } return false; } private static bool SetIfDifferent(ConfigEntry<float> entry, float value) { if (Mathf.Abs(entry.Value - value) < 0.001f) { return false; } entry.Value = value; return true; } private static bool EnsurePositive(ConfigEntry<float> entry, float fallback) { if (!float.IsNaN(entry.Value) && !float.IsInfinity(entry.Value) && entry.Value > 0f) { return false; } entry.Value = fallback; return true; } private static bool EnsureNonNegative(ConfigEntry<float> entry, float fallback) { if (!float.IsNaN(entry.Value) && !float.IsInfinity(entry.Value) && entry.Value >= 0f) { return false; } entry.Value = fallback; return true; } } internal sealed class FpsLodController { private static readonly float[] LodStages = new float[16] { 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f, 10f, 15f, 20f, 25f, 50f, 75f, 100f }; private readonly ModConfig _config; private readonly ManualLogSource _log; private float _fastFps; private float _slowFps; private float _lowTime; private float _highTime; private float _criticalTime; private float _severeTime; private float _downCooldown; private float _upCooldown; private float _increaseBlock; private bool _hasSample; private bool _criticalLatched; private bool _severeLatched; internal float SmoothedFps => _slowFps; internal FpsLodController(ModConfig config, ManualLogSource log) { _config = config; _log = log; } internal void Reset() { _fastFps = (_slowFps = 0f); _downCooldown = (_upCooldown = (_increaseBlock = 0f)); _hasSample = false; _criticalLatched = (_severeLatched = false); ResetTimers(); } internal void SetLod(float requested, string reason) { SetStage(NearestStage(requested), reason); } internal void Tick(float dt) { if (dt <= 0f) { return; } UpdateAverages(dt); UpdateCooldowns(dt); UpdateTimers(dt); float lodBias = QualitySettings.lodBias; if (_criticalTime >= _config.CriticalDuration.Value && !_criticalLatched) { _criticalLatched = true; _increaseBlock = _config.PostEmergencyIncreaseLock.Value; _lowTime = (_highTime = 0f); if (lodBias > 1f) { SetStage(1f, "critical FPS"); return; } } if (_severeTime >= _config.SevereDuration.Value && !_severeLatched) { _severeLatched = true; _increaseBlock = _config.PostEmergencyIncreaseLock.Value; _lowTime = (_highTime = 0f); if (lodBias > 3f) { SetStage(3f, "severe FPS"); return; } } if (_lowTime >= _config.LowDuration.Value && _downCooldown <= 0f) { SetStage(PreviousStage(lodBias), "low FPS"); _downCooldown = _config.DownAdjustmentCooldown.Value; ResetTimers(); } else if (_highTime >= _config.HighDuration.Value && _upCooldown <= 0f && _increaseBlock <= 0f) { SetStage(NextUpStage(lodBias), "high FPS"); _upCooldown = _config.UpAdjustmentCooldown.Value; ResetTimers(); } } private void UpdateAverages(float dt) { float num = 1f / dt; if (!_hasSample) { _fastFps = (_slowFps = num); _hasSample = true; return; } float num2 = 1f - Mathf.Exp((0f - dt) / _config.FastSmoothingSeconds.Value); float num3 = 1f - Mathf.Exp((0f - dt) / _config.SlowSmoothingSeconds.Value); _fastFps = Mathf.Lerp(_fastFps, num, num2); _slowFps = Mathf.Lerp(_slowFps, num, num3); } private void UpdateCooldowns(float dt) { _downCooldown = Mathf.Max(0f, _downCooldown - dt); _upCooldown = Mathf.Max(0f, _upCooldown - dt); _increaseBlock = Mathf.Max(0f, _increaseBlock - dt); } private void UpdateTimers(float dt) { _lowTime = ((_fastFps < (float)_config.ActiveLowerThreshold) ? (_lowTime + dt) : 0f); if (_fastFps < (float)_config.ActiveCriticalThreshold) { _criticalTime += dt; } else { _criticalTime = 0f; _criticalLatched = false; } if (_fastFps < (float)_config.ActiveSevereThreshold) { _severeTime += dt; } else { _severeTime = 0f; _severeLatched = false; } if (_upCooldown > 0f || _increaseBlock > 0f) { _highTime = 0f; } else { _highTime = ((_slowFps > (float)_config.ActiveUpperThreshold) ? (_highTime + dt) : 0f); } } private void SetStage(float stage, string reason) { float num = NearestStage(stage); if (!(Mathf.Abs(QualitySettings.lodBias - num) < 0.001f)) { QualitySettings.lodBias = num; _log.LogInfo((object)("LOD changed to " + num.ToString("0") + " (" + reason + ").")); } } private static float PreviousStage(float current) { for (int num = LodStages.Length - 1; num >= 0; num--) { if (LodStages[num] < current - 0.001f) { return LodStages[num]; } } return LodStages[0]; } private static float NextUpStage(float current) { if (!IsValidStage(current)) { for (int i = 0; i < LodStages.Length; i++) { if (LodStages[i] > current + 0.001f) { return LodStages[i]; } } return LodStages[LodStages.Length - 1]; } if (current < 10f) { float num = Mathf.Min(10f, current + 2f); for (int num2 = LodStages.Length - 1; num2 >= 0; num2--) { if (LodStages[num2] <= num + 0.001f) { return LodStages[num2]; } } } for (int j = 0; j < LodStages.Length; j++) { if (LodStages[j] > current + 0.001f) { return LodStages[j]; } } return LodStages[LodStages.Length - 1]; } private static bool IsValidStage(float value) { for (int i = 0; i < LodStages.Length; i++) { if (Mathf.Abs(value - LodStages[i]) < 0.001f) { return true; } } return false; } private static float NearestStage(float value) { float num = LodStages[0]; float num2 = Mathf.Abs(value - num); for (int i = 1; i < LodStages.Length; i++) { float num3 = Mathf.Abs(value - LodStages[i]); if (num3 < num2) { num = LodStages[i]; num2 = num3; } } return num; } private void ResetTimers() { _lowTime = (_highTime = (_criticalTime = (_severeTime = 0f))); } } internal enum PortalPhase { Inactive, WaitingForPositionJump, PostArrivalRecovery } internal sealed class PortalState { private const float MinimumDetectionDelay = 0.1f; private readonly ModConfig _config; private readonly FpsLodController _controller; private readonly ManualLogSource _log; private Vector3 _startPosition; private float _portalStartedAt; private float _arrivalAt; internal PortalPhase Phase { get; private set; } internal bool Active => Phase != PortalPhase.Inactive; internal PortalState(ModConfig config, FpsLodController controller, ManualLogSource log) { _config = config; _controller = controller; _log = log; } internal void Begin() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Active && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)((Component)localPlayer).gameObject == (Object)null)) { Cancel(); _startPosition = ((Component)localPlayer).transform.position; _portalStartedAt = Time.unscaledTime; Phase = PortalPhase.WaitingForPositionJump; _controller.SetLod(_config.PortalLodBias.Value, "portal started"); _log.LogInfo((object)"Portal start detected."); } } internal void Tick() { if (!Active) { return; } float unscaledTime = Time.unscaledTime; if (Phase == PortalPhase.WaitingForPositionJump) { DetectPositionJump(unscaledTime); if (Phase == PortalPhase.WaitingForPositionJump && unscaledTime - _portalStartedAt >= Mathf.Max(0.1f, _config.PortalTimeout.Value)) { Finish("Portal timeout.", warning: true); } return; } float num = unscaledTime - _arrivalAt; if (num >= Mathf.Max(0f, _config.RecoveryTimeout.Value)) { Finish("Recovery timeout.", warning: true); } else if (num >= Mathf.Max(0f, _config.PostArrivalLowDuration.Value)) { Finish("Portal recovery completed.", warning: false); } } internal void Cancel() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) Phase = PortalPhase.Inactive; _portalStartedAt = 0f; _arrivalAt = 0f; _startPosition = Vector3.zero; } private void DetectPositionJump(float now) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (now - _portalStartedAt < 0.1f) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)((Component)localPlayer).gameObject == (Object)null)) { Vector3 position = ((Component)localPlayer).transform.position; float num = position.x - _startPosition.x; float num2 = position.z - _startPosition.z; float num3 = Mathf.Sqrt(num * num + num2 * num2); if (!(num3 <= Mathf.Max(1f, _config.PositionJumpThreshold.Value))) { Phase = PortalPhase.PostArrivalRecovery; _arrivalAt = now; _log.LogInfo((object)("Portal position jump detected: " + num3.ToString("0.0") + " m.")); } } } private void Finish(string message, bool warning) { _controller.SetLod(_config.PortalRecoveryLodBias.Value, message); Cancel(); _controller.Reset(); if (warning) { _log.LogWarning((object)message); } else { _log.LogInfo((object)message); } } } internal sealed class OverlayRenderer { private static readonly CultureInfo German = CultureInfo.GetCultureInfo("de-DE"); private readonly ModConfig _config; private GUIStyle _style; private GUIStyle _shadow; private string _text = string.Empty; private float _nextRefresh; internal OverlayRenderer(ModConfig config) { _config = config; } internal void Draw(float fps, bool enabled, PortalPhase portalPhase) { //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) if (_config.ShowOverlay.Value) { if (Time.unscaledTime >= _nextRefresh) { _nextRefresh = Time.unscaledTime + Mathf.Max(0.05f, _config.RefreshInterval.Value); float lodBias = QualitySettings.lodBias; string text = ((Mathf.Abs(lodBias - Mathf.Round(lodBias)) < 0.001f) ? lodBias.ToString("0", German) : lodBias.ToString("0.0", German)); string text2 = (_config.ShowClock.Value ? (" | " + DateTime.Now.ToString(_config.Use24HourClock.Value ? "HH:mm" : "h:mm tt", CultureInfo.CurrentCulture)) : string.Empty); _text = Mathf.RoundToInt(fps) + " FPS" + (_config.ShowTargetFps.Value ? (" | " + _config.ActiveTargetFps + " mode") : string.Empty) + " | LOD: " + text + text2 + portalPhase switch { PortalPhase.PostArrivalRecovery => " | Laden", PortalPhase.WaitingForPositionJump => " | Portal", _ => enabled ? string.Empty : " | Auto: Aus", }; } EnsureStyles(); Rect val = default(Rect); ((Rect)(ref val))..ctor((float)_config.PositionX.Value, (float)_config.PositionY.Value, 650f, 30f); GUI.Label(new Rect(((Rect)(ref val)).x + 1f, ((Rect)(ref val)).y + 1f, ((Rect)(ref val)).width, ((Rect)(ref val)).height), _text, _shadow); GUI.Label(val, _text, _style); } } private void EnsureStyles() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown int num = Mathf.Clamp(_config.FontSize.Value, 8, 48); if (_style == null || _style.fontSize != num) { GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = num }; val.normal.textColor = Color.white; _style = val; GUIStyle val2 = new GUIStyle(_style); val2.normal.textColor = new Color(0f, 0f, 0f, 0.85f); _shadow = val2; } } } [HarmonyPatch(typeof(TeleportWorld), "Teleport")] internal static class TeleportWorldTeleportPatch { private static void Prefix(Player player) { if ((Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer) { AutoLodBiasPlugin.Instance?.BeginPortal(); } } } }