using System;
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 HarmonyLib;
using UnityEngine;
using ValheimFPSOptimizer.CPU;
using ValheimFPSOptimizer.GPU;
using ValheimFPSOptimizer.Monitoring;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ValheimFPSOptimizer")]
[assembly: AssemblyDescription("Adaptive FPS & Frametime Optimizer for Valheim")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ValheimFPSOptimizer")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("BE52F8E6-343B-4FAF-85C3-7047DE1AB2E4")]
[assembly: AssemblyFileVersion("3.2.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("3.2.0.0")]
namespace ValheimFPSOptimizer.Monitoring
{
public class FrametimeMonitor
{
private readonly Queue<float> samples = new Queue<float>();
private const int MaxSamples = 120;
public float AvgMs { get; private set; }
public float OnePercentLowMs { get; private set; }
public void Update()
{
float item = Time.unscaledDeltaTime * 1000f;
samples.Enqueue(item);
if (samples.Count > 120)
{
samples.Dequeue();
}
if (samples.Count >= 30)
{
float[] array = samples.ToArray();
AvgMs = array.Average();
Array.Sort(array);
int value = Mathf.Max(1, array.Length / 100);
OnePercentLowMs = array[^value];
}
}
}
}
namespace ValheimFPSOptimizer.Harmony
{
[HarmonyPatch(typeof(Character), "CustomFixedUpdate")]
public static class Character_CustomFixedUpdate_Patch
{
private static bool Prefix(Character __instance)
{
if (__instance.IsPlayer())
{
return true;
}
return (Time.frameCount & 1) == 0;
}
}
}
namespace ValheimFPSOptimizer.GPU
{
public class GpuEfficiencyController
{
private int lastQueue = -1;
public void Apply(FrametimeMonitor ft)
{
int num = ((!(ft.OnePercentLowMs > ft.AvgMs * 1.4f)) ? 3 : 2);
if (num != lastQueue)
{
QualitySettings.maxQueuedFrames = num;
lastQueue = num;
}
QualitySettings.asyncUploadTimeSlice = 2;
QualitySettings.asyncUploadBufferSize = 64;
}
}
}
namespace ValheimFPSOptimizer.CPU
{
public class AdaptiveRendererOptimizer
{
private readonly List<Renderer> renderers = new List<Renderer>();
private int index;
private float nextTick;
private Vector3 lastCamPos;
private Quaternion lastCamRot;
private const int batchSize = 40;
public void Init()
{
renderers.AddRange(Object.FindObjectsByType<Renderer>((FindObjectsSortMode)0));
}
public void Tick(Camera cam, float interval)
{
//IL_001d: 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)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)cam == (Object)null || Time.unscaledTime < nextTick || (Vector3.Distance(((Component)cam).transform.position, lastCamPos) < 0.3f && Quaternion.Angle(((Component)cam).transform.rotation, lastCamRot) < 2f))
{
return;
}
lastCamPos = ((Component)cam).transform.position;
lastCamRot = ((Component)cam).transform.rotation;
nextTick = Time.unscaledTime + interval;
Plane[] array = GeometryUtility.CalculateFrustumPlanes(cam);
int num = 0;
while (num < 40 && index < renderers.Count)
{
Renderer val = renderers[index];
if (Object.op_Implicit((Object)(object)val))
{
bool flag = GeometryUtility.TestPlanesAABB(array, val.bounds);
if (val.enabled != flag)
{
val.enabled = flag;
}
}
num++;
index++;
}
if (index >= renderers.Count)
{
index = 0;
}
}
}
public class FrameBudgetGuard
{
private float lastTarget = -1f;
public void Apply(FrametimeMonitor ft)
{
float num = ((ft.OnePercentLowMs > 28f) ? 0.045f : ((!(ft.OnePercentLowMs > 22f)) ? 0.07f : 0.055f));
if (!Mathf.Approximately(lastTarget, num))
{
Time.maximumDeltaTime = num;
lastTarget = num;
}
}
}
}
namespace ValheimFPSOptimizer.Core
{
public static class HardwareDetector
{
public static HardwareClass Detect()
{
int processorCount = SystemInfo.processorCount;
int graphicsMemorySize = SystemInfo.graphicsMemorySize;
if (processorCount >= 8 && graphicsMemorySize >= 6000)
{
return HardwareClass.Strong;
}
if (processorCount >= 4 && graphicsMemorySize >= 3000)
{
return HardwareClass.Medium;
}
return HardwareClass.Weak;
}
}
[BepInPlugin("dev.fpsoptimizer.valheim", "Valheim FPS Optimizer", "3.2.1")]
public class PerformanceOptimizer : BaseUnityPlugin
{
private FrametimeMonitor frametime;
private FrameBudgetGuard budget;
private AdaptiveRendererOptimizer rendererOpt;
private GpuEfficiencyController gpuOpt;
private Camera cam;
private HardwareClass hw;
private void Awake()
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
hw = HardwareDetector.Detect();
cam = Camera.main;
frametime = new FrametimeMonitor();
budget = new FrameBudgetGuard();
rendererOpt = new AdaptiveRendererOptimizer();
gpuOpt = new GpuEfficiencyController();
rendererOpt.Init();
new Harmony("dev.fpsoptimizer.valheim").PatchAll();
Physics.autoSyncTransforms = false;
Application.targetFrameRate = 60;
QualitySettings.vSyncCount = 0;
}
private void Update()
{
frametime.Update();
float interval = ((hw == HardwareClass.Strong) ? 0.35f : ((hw == HardwareClass.Medium) ? 0.3f : 0.25f));
rendererOpt.Tick(cam, interval);
budget.Apply(frametime);
gpuOpt.Apply(frametime);
}
}
public enum HardwareClass
{
Weak,
Medium,
Strong
}
}