using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Managers;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ValheimOptimizer")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ValheimOptimizer")]
[assembly: AssemblyTitle("ValheimOptimizer")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ValheimOptimizer
{
[BepInPlugin("com.yourname.valheimoptimizer", "Valheim Optimizer", "1.9.6")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class ValheimOptimizer : BaseUnityPlugin
{
[CompilerGenerated]
private sealed class <DelayedZoneReflection>d__63 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public ValheimOptimizer <>4__this;
private float <t>5__1;
private Type <zsType>5__2;
private object <zsInst>5__3;
private Type <pType>5__4;
private Type <cType>5__5;
private Type <zType>5__6;
private Type <znsType>5__7;
private object <znsInst>5__8;
private MethodInfo <destroyM>5__9;
private Exception <ex>5__10;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <DelayedZoneReflection>d__63(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<zsType>5__2 = null;
<zsInst>5__3 = null;
<pType>5__4 = null;
<cType>5__5 = null;
<zType>5__6 = null;
<znsType>5__7 = null;
<znsInst>5__8 = null;
<destroyM>5__9 = null;
<ex>5__10 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
//IL_03ef: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<t>5__1 = 0f;
break;
case 1:
<>1__state = -1;
<t>5__1 += 0.5f;
<zsType>5__2 = null;
<zsInst>5__3 = null;
break;
}
if (<t>5__1 < 10f)
{
<zsType>5__2 = AccessTools.TypeByName("ZoneSystem");
<zsInst>5__3 = <zsType>5__2?.GetField("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
if (<zsInst>5__3 != null)
{
try
{
<>4__this._spawnZoneDel = (Action<int, int>)Delegate.CreateDelegate(typeof(Action<int, int>), <zsInst>5__3, <zsType>5__2.GetMethod("SpawnZone", new Type[2]
{
typeof(int),
typeof(int)
}));
<>4__this._zoneCellSize = (float)<zsType>5__2.GetField("m_cellSize", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(<zsInst>5__3);
<pType>5__4 = AccessTools.TypeByName("Player");
<>4__this._playerField = <pType>5__4.GetField("m_localPlayer", BindingFlags.Static | BindingFlags.NonPublic);
<>4__this._transformProp = <pType>5__4.GetProperty("transform", BindingFlags.Instance | BindingFlags.Public);
<>4__this._characterField = <pType>5__4.GetField("m_character", BindingFlags.Instance | BindingFlags.NonPublic);
<cType>5__5 = AccessTools.TypeByName("Character");
<>4__this._velocityField = <cType>5__5.GetField("m_velocity", BindingFlags.Instance | BindingFlags.NonPublic);
<>4__this._getAllChars = (Func<IEnumerable>)Delegate.CreateDelegate(typeof(Func<IEnumerable>), <cType>5__5.GetMethod("GetAllCharacters", BindingFlags.Static | BindingFlags.Public));
<>4__this._isAlive = (Func<object, bool>)Delegate.CreateDelegate(typeof(Func<object, bool>), <cType>5__5.GetMethod("IsAlive", BindingFlags.Instance | BindingFlags.Public));
<>4__this._isBoss = (Func<object, bool>)Delegate.CreateDelegate(typeof(Func<object, bool>), <cType>5__5.GetMethod("IsBoss", BindingFlags.Instance | BindingFlags.Public));
<>4__this._isPlayer = (Func<object, bool>)Delegate.CreateDelegate(typeof(Func<object, bool>), <cType>5__5.GetMethod("IsPlayer", BindingFlags.Instance | BindingFlags.Public));
<zType>5__6 = AccessTools.TypeByName("ZNet");
<>4__this._getZNetInstance = (Func<object>)Delegate.CreateDelegate(typeof(Func<object>), <zType>5__6.GetProperty("instance", BindingFlags.Static | BindingFlags.Public).GetGetMethod());
<>4__this._isServer = (Func<object, bool>)Delegate.CreateDelegate(typeof(Func<object, bool>), <zType>5__6.GetProperty("IsServer", BindingFlags.Instance | BindingFlags.Public).GetGetMethod());
<znsType>5__7 = AccessTools.TypeByName("ZNetScene");
<>4__this._getZNetSceneInstance = (Func<object>)Delegate.CreateDelegate(typeof(Func<object>), <znsType>5__7.GetProperty("instance", BindingFlags.Static | BindingFlags.Public).GetGetMethod());
<znsInst>5__8 = <>4__this._getZNetSceneInstance();
<destroyM>5__9 = <znsType>5__7.GetMethod("Destroy", new Type[1] { typeof(GameObject) });
<>4__this._znetSceneDestroy = (Action<GameObject>)Delegate.CreateDelegate(typeof(Action<GameObject>), <znsInst>5__8, <destroyM>5__9);
<>4__this._zoneReflectionDone = true;
((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"[VO] Reflection complete");
return false;
}
catch (Exception ex)
{
<ex>5__10 = ex;
((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)$"[VO] Reflection error: {<ex>5__10}");
return false;
}
}
<>2__current = (object)new WaitForSeconds(0.5f);
<>1__state = 1;
return true;
}
((BaseUnityPlugin)<>4__this).Logger.LogWarning((object)"[VO] Zone reflection timed out; prefetch disabled");
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <MasterLoop>d__62 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public ValheimOptimizer <>4__this;
private float <lastGC>5__1;
private float <lastLOD>5__2;
private bool <jitDone>5__3;
private float <now>5__4;
private float <ft>5__5;
private int <maxBatch>5__6;
private int <minBatch>5__7;
private int <batch>5__8;
private int <toSpawn>5__9;
private object <netInst>5__10;
private float <bias>5__11;
private float <target>5__12;
private string[] <>s__13;
private int <>s__14;
private string <sig>5__15;
private MethodInfo <mi>5__16;
private Queue<Vector2Int> <>s__17;
private bool <>s__18;
private int <i>5__19;
private Vector2Int <cell>5__20;
private object <plObj>5__21;
private Vector3 <plPos>5__22;
private int <removed>5__23;
private int <maxKill>5__24;
private int <perTick>5__25;
private IEnumerator <>s__26;
private object <chr>5__27;
private Vector3 <cpos>5__28;
private object <plObj>5__29;
private Vector3 <plPos>5__30;
private IEnumerator <>s__31;
private object <chr>5__32;
private Component <comp>5__33;
private float <dist>5__34;
private bool <show>5__35;
private Renderer[] <>s__36;
private int <>s__37;
private Renderer <rend>5__38;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <MasterLoop>d__62(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<netInst>5__10 = null;
<>s__13 = null;
<sig>5__15 = null;
<mi>5__16 = null;
<>s__17 = null;
<plObj>5__21 = null;
<>s__26 = null;
<chr>5__27 = null;
<plObj>5__29 = null;
<>s__31 = null;
<chr>5__32 = null;
<comp>5__33 = null;
<>s__36 = null;
<rend>5__38 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_047a: Unknown result type (might be due to invalid IL or missing references)
//IL_047f: Unknown result type (might be due to invalid IL or missing references)
//IL_0555: Unknown result type (might be due to invalid IL or missing references)
//IL_055a: Unknown result type (might be due to invalid IL or missing references)
//IL_055f: Unknown result type (might be due to invalid IL or missing references)
//IL_0797: Unknown result type (might be due to invalid IL or missing references)
//IL_079c: Unknown result type (might be due to invalid IL or missing references)
//IL_07a1: Unknown result type (might be due to invalid IL or missing references)
//IL_0667: Unknown result type (might be due to invalid IL or missing references)
//IL_066c: Unknown result type (might be due to invalid IL or missing references)
//IL_0671: Unknown result type (might be due to invalid IL or missing references)
//IL_0677: Unknown result type (might be due to invalid IL or missing references)
//IL_067d: Unknown result type (might be due to invalid IL or missing references)
//IL_0857: Unknown result type (might be due to invalid IL or missing references)
//IL_0867: Unknown result type (might be due to invalid IL or missing references)
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<lastGC>5__1 = Time.time;
<lastLOD>5__2 = Time.time;
<jitDone>5__3 = false;
<>4__this._avgFT = Time.unscaledDeltaTime;
goto IL_0071;
case 1:
<>1__state = -1;
goto IL_0071;
case 2:
{
<>1__state = -1;
<now>5__4 = Time.time;
if (<now>5__4 - <lastGC>5__1 >= <>4__this._cleanupInterval.Value && Time.unscaledDeltaTime < <>4__this._maxFrameTime.Value)
{
GC.Collect();
Resources.UnloadUnusedAssets();
<lastGC>5__1 = <now>5__4;
}
<ft>5__5 = Time.unscaledDeltaTime;
<>4__this._avgFT = <>4__this._lodAdjustStep.Value * <ft>5__5 + (1f - <>4__this._lodAdjustStep.Value) * <>4__this._avgFT;
if (<now>5__4 - <lastLOD>5__2 >= <>4__this._lodInterval.Value)
{
<bias>5__11 = QualitySettings.lodBias;
<target>5__12 = ((<>4__this._avgFT > <>4__this._lodUpperThresh.Value) ? <>4__this._lodBiasMin.Value : ((<>4__this._avgFT < <>4__this._lodLowerThresh.Value) ? <>4__this._lodBiasMax.Value : <bias>5__11));
QualitySettings.lodBias = Mathf.MoveTowards(<bias>5__11, <target>5__12, <>4__this._lodAdjustStep.Value * <ft>5__5);
if (<>4__this._avgFT > <>4__this._lodUpperThresh.Value)
{
QualitySettings.masterTextureLimit = Math.Min(<>4__this._texLimitMax.Value, QualitySettings.masterTextureLimit + 1);
}
else if (<>4__this._avgFT < <>4__this._lodLowerThresh.Value)
{
QualitySettings.masterTextureLimit = Math.Max(<>4__this._texLimitMin.Value, QualitySettings.masterTextureLimit - 1);
}
<lastLOD>5__2 = <now>5__4;
}
if (!<jitDone>5__3)
{
<>s__13 = new string[4] { "BaseAI:FixedUpdate", "ZoneSystem:SpawnZone", "Projectile:OnHit", "Projectile:LateUpdate" };
for (<>s__14 = 0; <>s__14 < <>s__13.Length; <>s__14++)
{
<sig>5__15 = <>s__13[<>s__14];
<mi>5__16 = AccessTools.Method(<sig>5__15, (Type[])null, (Type[])null);
if (<mi>5__16 != null)
{
RuntimeHelpers.PrepareMethod(<mi>5__16.MethodHandle);
}
<mi>5__16 = null;
<sig>5__15 = null;
}
<>s__13 = null;
<jitDone>5__3 = true;
}
<maxBatch>5__6 = <>4__this._zoneBatchSize.Value;
<minBatch>5__7 = <>4__this._minZoneBatchSize.Value;
<batch>5__8 = ((<>4__this._avgFT > <>4__this._lodUpperThresh.Value) ? <minBatch>5__7 : <maxBatch>5__6);
<>s__17 = <>4__this._zoneQ;
<>s__18 = false;
try
{
Monitor.Enter(<>s__17, ref <>s__18);
<toSpawn>5__9 = Math.Min(<>4__this._zoneQ.Count, <batch>5__8);
}
finally
{
if (<>s__18)
{
Monitor.Exit(<>s__17);
}
}
<>s__17 = null;
<i>5__19 = 0;
while (<i>5__19 < <toSpawn>5__9)
{
if (<>4__this._spawnZoneDel != null)
{
<cell>5__20 = <>4__this._zoneQ.Dequeue();
<>4__this._spawnZoneDel(((Vector2Int)(ref <cell>5__20)).x, ((Vector2Int)(ref <cell>5__20)).y);
}
<i>5__19++;
}
<netInst>5__10 = <>4__this._getZNetInstance();
if (<netInst>5__10 != null && <>4__this._isServer(<netInst>5__10))
{
<plObj>5__21 = <>4__this._playerField.GetValue(null);
if (<plObj>5__21 != null)
{
<plPos>5__22 = ((Transform)<>4__this._transformProp.GetValue(<plObj>5__21)).position;
<removed>5__23 = 0;
<maxKill>5__24 = <>4__this._mobDespawnsPerTick.Value;
<perTick>5__25 = ((<>4__this._avgFT > <>4__this._lodUpperThresh.Value) ? 1 : <maxKill>5__24);
<>s__26 = <>4__this._getAllChars().GetEnumerator();
try
{
while (<>s__26.MoveNext())
{
<chr>5__27 = <>s__26.Current;
if (<removed>5__23 >= <perTick>5__25)
{
break;
}
if (!<>4__this._isAlive(<chr>5__27) || <>4__this._isBoss(<chr>5__27) || <>4__this._isPlayer(<chr>5__27))
{
continue;
}
<cpos>5__28 = ((Transform)<>4__this._transformProp.GetValue(<chr>5__27)).position;
if (!(Vector3.Distance(<plPos>5__22, <cpos>5__28) <= <>4__this._mobDespawnDistance.Value))
{
Action<GameObject> znetSceneDestroy = <>4__this._znetSceneDestroy;
if (znetSceneDestroy != null)
{
object obj = <chr>5__27;
object obj2 = ((obj is Component) ? obj : null);
znetSceneDestroy((obj2 != null) ? ((Component)obj2).gameObject : null);
}
<removed>5__23++;
<chr>5__27 = null;
}
}
}
finally
{
if (<>s__26 is IDisposable disposable)
{
disposable.Dispose();
}
}
<>s__26 = null;
}
<plObj>5__21 = null;
}
if (<netInst>5__10 != null && !<>4__this._isServer(<netInst>5__10))
{
<plObj>5__29 = <>4__this._playerField.GetValue(null);
if (<plObj>5__29 != null)
{
<plPos>5__30 = ((Transform)<>4__this._transformProp.GetValue(<plObj>5__29)).position;
<>s__31 = <>4__this._getAllChars().GetEnumerator();
try
{
while (<>s__31.MoveNext())
{
<chr>5__32 = <>s__31.Current;
if (!<>4__this._isAlive(<chr>5__32) || <>4__this._isBoss(<chr>5__32) || <>4__this._isPlayer(<chr>5__32))
{
continue;
}
ref Component reference = ref <comp>5__33;
object obj3 = <chr>5__32;
reference = (Component)((obj3 is Component) ? obj3 : null);
if (!((Object)(object)<comp>5__33 == (Object)null))
{
<dist>5__34 = Vector3.Distance(<plPos>5__30, <comp>5__33.transform.position);
<show>5__35 = <dist>5__34 <= <>4__this._clientMobHideDistance.Value;
<>s__36 = <comp>5__33.GetComponentsInChildren<Renderer>(true);
for (<>s__37 = 0; <>s__37 < <>s__36.Length; <>s__37++)
{
<rend>5__38 = <>s__36[<>s__37];
<rend>5__38.enabled = <show>5__35;
<rend>5__38 = null;
}
<>s__36 = null;
<comp>5__33 = null;
<chr>5__32 = null;
}
}
}
finally
{
if (<>s__31 is IDisposable disposable2)
{
disposable2.Dispose();
}
}
<>s__31 = null;
}
<plObj>5__29 = null;
}
<netInst>5__10 = null;
break;
}
IL_0071:
if (!<>4__this._zoneReflectionDone)
{
<>2__current = null;
<>1__state = 1;
return true;
}
break;
}
<>2__current = null;
<>1__state = 2;
return true;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <PreloadRoutine>d__65 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public ValheimOptimizer <>4__this;
private bool <spawned>5__1;
private string[] <>s__2;
private int <>s__3;
private string <name>5__4;
private Shader <s>5__5;
private Material <m>5__6;
private Dictionary<string, GameObject>.Enumerator <>s__7;
private KeyValuePair<string, GameObject> <kv>5__8;
private Type <zsType>5__9;
private object <inst>5__10;
private MethodInfo <mSpawn>5__11;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <PreloadRoutine>d__65(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
int num = <>1__state;
if (num == -3 || num == 2)
{
try
{
}
finally
{
<>m__Finally1();
}
}
<>s__2 = null;
<name>5__4 = null;
<s>5__5 = null;
<m>5__6 = null;
<>s__7 = default(Dictionary<string, GameObject>.Enumerator);
<kv>5__8 = default(KeyValuePair<string, GameObject>);
<zsType>5__9 = null;
<inst>5__10 = null;
<mSpawn>5__11 = null;
<>1__state = -2;
}
private bool MoveNext()
{
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Expected O, but got Unknown
try
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>s__2 = new string[2] { "Standard", "Unlit/Texture" };
<>s__3 = 0;
goto IL_0183;
case 1:
<>1__state = -1;
<m>5__6 = null;
goto IL_0167;
case 2:
<>1__state = -3;
<kv>5__8.Value.SetActive(false);
<kv>5__8 = default(KeyValuePair<string, GameObject>);
goto IL_021e;
case 3:
<>1__state = -1;
goto IL_034f;
case 4:
{
<>1__state = -1;
return false;
}
IL_0183:
if (<>s__3 < <>s__2.Length)
{
<name>5__4 = <>s__2[<>s__3];
<s>5__5 = Shader.Find(<name>5__4);
if (<s>5__5 != null)
{
<m>5__6 = new Material(<s>5__5);
GL.PushMatrix();
GL.LoadOrtho();
<m>5__6.SetPass(0);
GL.Begin(7);
GL.Vertex3(0f, 0f, 0f);
GL.Vertex3(1f, 0f, 0f);
GL.Vertex3(1f, 1f, 0f);
GL.Vertex3(0f, 1f, 0f);
GL.End();
GL.PopMatrix();
Object.Destroy((Object)(object)<m>5__6);
<>2__current = null;
<>1__state = 1;
return true;
}
goto IL_0167;
}
<>s__2 = null;
<>s__7 = <>4__this._prefabPool.GetEnumerator();
<>1__state = -3;
goto IL_021e;
IL_021e:
if (<>s__7.MoveNext())
{
<kv>5__8 = <>s__7.Current;
<kv>5__8.Value.SetActive(true);
<>2__current = null;
<>1__state = 2;
return true;
}
<>m__Finally1();
<>s__7 = default(Dictionary<string, GameObject>.Enumerator);
<spawned>5__1 = false;
try
{
<zsType>5__9 = AccessTools.TypeByName("ZoneSystem");
<inst>5__10 = <zsType>5__9?.GetField("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
<mSpawn>5__11 = <zsType>5__9?.GetMethod("SpawnZone", new Type[2]
{
typeof(int),
typeof(int)
});
if (<inst>5__10 != null && <mSpawn>5__11 != null)
{
<mSpawn>5__11.Invoke(<inst>5__10, new object[2] { 0, 0 });
<spawned>5__1 = true;
}
<zsType>5__9 = null;
<inst>5__10 = null;
<mSpawn>5__11 = null;
}
catch
{
}
if (<spawned>5__1)
{
<>2__current = null;
<>1__state = 3;
return true;
}
goto IL_034f;
IL_034f:
GC.Collect();
<>2__current = Resources.UnloadUnusedAssets();
<>1__state = 4;
return true;
IL_0167:
<s>5__5 = null;
<name>5__4 = null;
<>s__3++;
goto IL_0183;
}
}
catch
{
//try-fault
((IDisposable)this).Dispose();
throw;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
private void <>m__Finally1()
{
<>1__state = -1;
((IDisposable)<>s__7).Dispose();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
private ConfigEntry<float> _cleanupInterval;
private ConfigEntry<float> _maxFrameTime;
private ConfigEntry<float> _lodBiasMin;
private ConfigEntry<float> _lodBiasMax;
private ConfigEntry<float> _lodAdjustStep;
private ConfigEntry<float> _lodUpperThresh;
private ConfigEntry<float> _lodLowerThresh;
private ConfigEntry<float> _lodInterval;
private ConfigEntry<int> _lodSamples;
private ConfigEntry<int> _texLimitMin;
private ConfigEntry<int> _texLimitMax;
private ConfigEntry<int> _texAdjustStep;
private ConfigEntry<float> _texInterval;
private ConfigEntry<float> _prefetchInterval;
private ConfigEntry<float> _prefetchSpeed;
private ConfigEntry<float> _prefetchDistance;
private ConfigEntry<int> _zoneBatchSize;
private ConfigEntry<int> _minZoneBatchSize;
private ConfigEntry<bool> _enableVSync;
private ConfigEntry<int> _targetFrameRate;
private ConfigEntry<float> _mobDespawnDistance;
private ConfigEntry<int> _mobDespawnsPerTick;
private ConfigEntry<float> _clientMobHideDistance;
private FileSystemWatcher _configWatcher;
private DateTime _lastReloadTime;
private const long RELOAD_DELAY = 10000000L;
private const string CONFIG_NAME = "com.yourname.valheimoptimizer.cfg";
private static readonly string[] HeavyPrefabs = new string[5] { "vfx_fireplace", "npc_troll", "piece_workbench", "Arrow_explosive", "Arrow_explosion" };
private readonly Dictionary<string, GameObject> _prefabPool = new Dictionary<string, GameObject>();
private Action<int, int> _spawnZoneDel;
private float _zoneCellSize;
private FieldInfo _playerField;
private PropertyInfo _transformProp;
private FieldInfo _characterField;
private FieldInfo _velocityField;
private bool _zoneReflectionDone;
private Func<IEnumerable> _getAllChars;
private Func<object, bool> _isAlive;
private Func<object, bool> _isBoss;
private Func<object, bool> _isPlayer;
private Func<object> _getZNetInstance;
private Func<object, bool> _isServer;
private Func<object> _getZNetSceneInstance;
private Action<GameObject> _znetSceneDestroy;
private Vector3 _latestPos;
private Vector3 _latestVel;
private readonly object _movLock = new object();
private readonly Queue<Vector2Int> _zoneQ = new Queue<Vector2Int>();
private Thread _zoneThread;
private bool _zoneThreadRunning;
private Harmony _harmony;
private float _avgFT;
private WaitForSeconds _wsMaster;
public static ValheimOptimizer Instance { get; private set; }
private void Awake()
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Expected O, but got Unknown
//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
//IL_03bf: Expected O, but got Unknown
Instance = this;
_harmony = new Harmony("com.yourname.valheimoptimizer");
((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
_cleanupInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "MemoryCleanupInterval", 60f, "Secs between GC sweeps");
_maxFrameTime = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "MaxFrameTime", 0.033f, "Skip GC if frame > this");
_enableVSync = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance", "EnableVSync", true, "Enable V‑Sync");
_targetFrameRate = ((BaseUnityPlugin)this).Config.Bind<int>("Performance", "TargetFrameRate", 60, "Hard FPS cap (0 = uncapped)");
_mobDespawnDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "MobDespawnDistance", 100f, "Distance to drip‑despawn mobs");
_mobDespawnsPerTick = ((BaseUnityPlugin)this).Config.Bind<int>("Performance", "MobDespawnsPerTick", 2, "Max mobs removed per tick");
_clientMobHideDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "ClientMobHideDistance", 150f, "Hide mobs beyond this distance on clients");
_lodBiasMin = ((BaseUnityPlugin)this).Config.Bind<float>("Graphics", "LODBiasMin", 0.5f, "Min LOD bias");
_lodBiasMax = ((BaseUnityPlugin)this).Config.Bind<float>("Graphics", "LODBiasMax", 2f, "Max LOD bias");
_lodAdjustStep = ((BaseUnityPlugin)this).Config.Bind<float>("Graphics", "LODBiasStep", 0.1f, "Adjust/sec");
_lodUpperThresh = ((BaseUnityPlugin)this).Config.Bind<float>("Graphics", "LODUpperFrameThreshold", 0.04f, "Above → drop");
_lodLowerThresh = ((BaseUnityPlugin)this).Config.Bind<float>("Graphics", "LODLowerFrameThreshold", 0.03f, "Below → raise");
_lodSamples = ((BaseUnityPlugin)this).Config.Bind<int>("Graphics", "LODNumSamples", 10, "Frames/window");
_lodInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Graphics", "LODUpdateInterval", 1f, "Secs between adj");
_texLimitMin = ((BaseUnityPlugin)this).Config.Bind<int>("Graphics", "TextureLimitMin", 0, "Best (0=full)");
_texLimitMax = ((BaseUnityPlugin)this).Config.Bind<int>("Graphics", "TextureLimitMax", 2, "Worst (2=¼)");
_texAdjustStep = ((BaseUnityPlugin)this).Config.Bind<int>("Graphics", "TextureLimitStep", 1, "Step size");
_texInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Graphics", "TextureChangeInterval", 30f, "Secs between changes");
_prefetchInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Travel", "ZonePrefetchInterval", 0.1f, "Secs per check");
_prefetchSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Travel", "ZonePrefetchSpeed", 10f, "Speed to prefetch");
_prefetchDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Travel", "ZonePrefetchDistance", 50f, "Meters ahead");
_zoneBatchSize = ((BaseUnityPlugin)this).Config.Bind<int>("Travel", "ZoneBatchSize", 8, "Zones/tick (max)");
_minZoneBatchSize = ((BaseUnityPlugin)this).Config.Bind<int>("Travel", "MinZoneBatchSize", 1, "Zones/tick under load");
((BaseUnityPlugin)this).Config.Save();
((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
SetupWatcher();
QualitySettings.vSyncCount = (_enableVSync.Value ? 1 : 0);
Application.targetFrameRate = ((_targetFrameRate.Value > 0) ? _targetFrameRate.Value : (-1));
_wsMaster = new WaitForSeconds(0.2f);
CachePrefabPool();
((MonoBehaviour)this).StartCoroutine(DelayedZoneReflection());
_zoneThreadRunning = true;
_zoneThread = new Thread(ZonePrefetchLoop)
{
IsBackground = true
};
_zoneThread.Start();
((MonoBehaviour)this).StartCoroutine(PreloadRoutine());
((MonoBehaviour)this).StartCoroutine(MasterLoop());
_harmony.PatchAll();
}
private void OnDestroy()
{
_configWatcher?.Dispose();
_zoneThreadRunning = false;
_zoneThread?.Join(500);
((BaseUnityPlugin)this).Config.Save();
}
private void SetupWatcher()
{
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, "com.yourname.valheimoptimizer.cfg")
{
NotifyFilter = (NotifyFilters.LastWrite | NotifyFilters.CreationTime)
};
fileSystemWatcher.Changed += OnConfigChanged;
fileSystemWatcher.Created += OnConfigChanged;
fileSystemWatcher.EnableRaisingEvents = true;
_configWatcher = fileSystemWatcher;
}
private void OnConfigChanged(object s, FileSystemEventArgs e)
{
if (DateTime.Now.Ticks - _lastReloadTime.Ticks >= 10000000)
{
try
{
((BaseUnityPlugin)this).Logger.LogDebug((object)"[VO] Reloading config");
((BaseUnityPlugin)this).Config.Reload();
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"[VO] Config reload failed: {arg}");
}
_lastReloadTime = DateTime.Now;
}
}
private void Update()
{
//IL_0048: 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_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
if (_zoneReflectionDone)
{
object obj = _playerField?.GetValue(null);
if (obj != null)
{
object value = _characterField.GetValue(obj);
_latestVel = (Vector3)_velocityField.GetValue(value);
_latestPos = ((Transform)_transformProp.GetValue(obj)).position;
}
}
}
[IteratorStateMachine(typeof(<MasterLoop>d__62))]
private IEnumerator MasterLoop()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <MasterLoop>d__62(0)
{
<>4__this = this
};
}
[IteratorStateMachine(typeof(<DelayedZoneReflection>d__63))]
private IEnumerator DelayedZoneReflection()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <DelayedZoneReflection>d__63(0)
{
<>4__this = this
};
}
private void ZonePrefetchLoop()
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: 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_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
try
{
while (_zoneThreadRunning)
{
Vector3 latestPos;
Vector3 latestVel;
lock (_movLock)
{
latestPos = _latestPos;
latestVel = _latestVel;
}
if (((Vector3)(ref latestVel)).magnitude >= _prefetchSpeed.Value)
{
Vector3 val = latestPos + ((Vector3)(ref latestVel)).normalized * _prefetchDistance.Value;
int num = Mathf.FloorToInt(val.x / _zoneCellSize);
int num2 = Mathf.FloorToInt(val.z / _zoneCellSize);
lock (_zoneQ)
{
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
_zoneQ.Enqueue(new Vector2Int(num + i, num2 + j));
}
}
}
}
Thread.Sleep((int)(_prefetchInterval.Value * 1000f));
}
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"[VO] Zone thread error: {arg}");
}
}
[IteratorStateMachine(typeof(<PreloadRoutine>d__65))]
private IEnumerator PreloadRoutine()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <PreloadRoutine>d__65(0)
{
<>4__this = this
};
}
private void CachePrefabPool()
{
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: 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)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
string[] heavyPrefabs = HeavyPrefabs;
foreach (string text in heavyPrefabs)
{
GameObject prefab = PrefabManager.Instance.GetPrefab(text);
if (!((Object)(object)prefab == (Object)null))
{
GameObject val = Object.Instantiate<GameObject>(prefab);
((Object)val).name = "Pool_" + text;
val.SetActive(false);
Object.DontDestroyOnLoad((Object)(object)val);
_prefabPool[text] = val;
Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
LODGroup val2 = val.AddComponent<LODGroup>();
val2.SetLODs((LOD[])(object)new LOD[2]
{
new LOD(0.5f, componentsInChildren),
new LOD(0f, (Renderer[])(object)new Renderer[0])
});
val2.RecalculateBounds();
}
}
}
}
}
namespace ValheimOptimizer.Patches
{
public static class ArrowReflectionPatches
{
[HarmonyPrefix]
[HarmonyPatch("Projectile:LateUpdate")]
public static void LateUpdatePrefix(object __instance)
{
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: 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_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
Component val = (Component)((__instance is Component) ? __instance : null);
if (!((Object)(object)val == (Object)null) && ((Object)val.gameObject).name.Contains("Arrow"))
{
Type type = __instance.GetType();
FieldInfo field = type.GetField("m_velocity", BindingFlags.Instance | BindingFlags.NonPublic);
Vector3 val2 = (Vector3)field.GetValue(__instance);
Vector3 position = val.transform.position;
Vector3 val3 = position - val2 * Time.deltaTime;
Vector3 val4 = position - val3;
RaycastHit val5 = default(RaycastHit);
if (!(((Vector3)(ref val4)).sqrMagnitude < 1E-06f) && Physics.Raycast(val3, val4, ref val5, ((Vector3)(ref val4)).magnitude, LayerMask.GetMask(new string[2] { "Default", "character" })))
{
MethodInfo method = type.GetMethod("OnHit", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
method.Invoke(__instance, new object[3]
{
((RaycastHit)(ref val5)).point,
((RaycastHit)(ref val5)).normal,
((RaycastHit)(ref val5)).collider
});
}
}
}
[HarmonyPostfix]
[HarmonyPatch("Projectile:Awake")]
public static void AwakePostfix(object __instance)
{
Component val = (Component)((__instance is Component) ? __instance : null);
CapsuleCollider val2 = default(CapsuleCollider);
if (!((Object)(object)val == (Object)null) && ((Object)val.gameObject).name.Contains("Arrow") && val.TryGetComponent<CapsuleCollider>(ref val2))
{
CapsuleCollider obj = val2;
obj.radius *= 1.2f;
CapsuleCollider obj2 = val2;
obj2.height *= 1.1f;
}
}
[HarmonyPostfix]
[HarmonyPatch("Projectile:OnHit")]
public static void OnHitPostfix(object __instance, object character, object hitData)
{
Type type = __instance.GetType();
FieldInfo field = type.GetField("m_nview", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
object value = field.GetValue(__instance);
MethodInfo method = value.GetType().GetMethod("InvokeRPC", new Type[2]
{
typeof(string),
typeof(object[])
});
method.Invoke(value, new object[5]
{
"Hit",
character.GetType().GetMethod("GetZDOID").Invoke(character, null),
hitData.GetType().GetField("m_damage", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(hitData),
hitData.GetType().GetField("m_point", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(hitData),
hitData.GetType().GetField("m_dir", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(hitData)
});
(AccessTools.TypeByName("EpicLoot.Magic.ExplosionHandler")?.GetMethod("TryExplode", BindingFlags.Static | BindingFlags.Public))?.Invoke(null, new object[3] { __instance, character, hitData });
}
}
}