Decompiled source of SosigOptimizer v1.0.3

SosigOptimizer.dll

Decompiled 15 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")]
[assembly: AssemblyCompany("SosigOptimizer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SosigOptimizer")]
[assembly: AssemblyTitle("SosigOptimizer")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace SosigOptimizer;

public class GibMarker : MonoBehaviour
{
	public static readonly List<GibMarker> All = new List<GibMarker>();

	private void Awake()
	{
		All.Add(this);
	}

	private void OnDestroy()
	{
		All.Remove(this);
	}
}
public class SosigLODController : MonoBehaviour
{
	internal Sosig _sosig;

	internal bool _lodActive;

	private float _nextTickTime;

	private float _avoidanceTimer;

	private bool _avoidanceOff;

	private int[] _origSolverIter;

	private int[] _origSolverVelIter;

	private bool[] _origProjection;

	private RigidbodyInterpolation[] _origInterp;

	private float[] _origSleepThreshold;

	private ObstacleAvoidanceType _origAvoidance;

	private ShadowCastingMode[] _origShadows;

	private static readonly FieldInfo _navTickField = typeof(Sosig).GetField("m_navAgentUpdateTick", BindingFlags.Instance | BindingFlags.NonPublic);

	private static readonly bool _navTickFieldFound = (object)typeof(Sosig).GetField("m_navAgentUpdateTick", BindingFlags.Instance | BindingFlags.NonPublic) != null;

	public static readonly List<SosigLODController> AllControllers = new List<SosigLODController>();

	private void Start()
	{
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Expected I4, but got Unknown
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Expected I4, but got Unknown
		_sosig = ((Component)this).GetComponent<Sosig>();
		int count = _sosig.Links.Count;
		_origSolverIter = new int[count];
		_origSolverVelIter = new int[count];
		_origProjection = new bool[count];
		_origInterp = (RigidbodyInterpolation[])(object)new RigidbodyInterpolation[count];
		_origSleepThreshold = new float[count];
		for (int i = 0; i < count; i++)
		{
			SosigLink val = _sosig.Links[i];
			if (!((Object)(object)val == (Object)null))
			{
				if ((Object)(object)val.R != (Object)null)
				{
					_origSolverIter[i] = val.R.solverIterations;
					_origSolverVelIter[i] = val.R.solverVelocityIterations;
					_origInterp[i] = (RigidbodyInterpolation)(int)val.R.interpolation;
					_origSleepThreshold[i] = val.R.sleepThreshold;
				}
				if ((Object)(object)val.J != (Object)null)
				{
					_origProjection[i] = val.J.enableProjection;
				}
			}
		}
		if ((Object)(object)_sosig.Agent != (Object)null)
		{
			_origAvoidance = _sosig.Agent.obstacleAvoidanceType;
		}
		if (_sosig.Renderers != null)
		{
			_origShadows = (ShadowCastingMode[])(object)new ShadowCastingMode[_sosig.Renderers.Length];
			for (int j = 0; j < _sosig.Renderers.Length; j++)
			{
				if ((Object)(object)_sosig.Renderers[j] != (Object)null)
				{
					_origShadows[j] = (ShadowCastingMode)(int)_sosig.Renderers[j].shadowCastingMode;
				}
			}
		}
		_nextTickTime = Time.time + Random.Range(0f, SosigOptimizerPlugin.CfgLODInterval.Value);
		AllControllers.Add(this);
	}

	private void Update()
	{
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		if (Time.time >= _nextTickTime)
		{
			_nextTickTime = Time.time + SosigOptimizerPlugin.CfgLODInterval.Value;
			if (SosigOptimizerPlugin.CfgLODEnabled.Value)
			{
				Tick();
			}
			else if (_lodActive)
			{
				RestoreLOD();
			}
		}
		if (_lodActive && _avoidanceTimer > 0f && SosigOptimizerPlugin.CfgLODPulseAvoidance.Value && (Object)(object)_sosig?.Agent != (Object)null)
		{
			_avoidanceTimer -= Time.deltaTime;
			if (_avoidanceTimer <= 0f)
			{
				_avoidanceOff = !_avoidanceOff;
				_sosig.Agent.obstacleAvoidanceType = (ObstacleAvoidanceType)((!_avoidanceOff) ? ((int)_origAvoidance) : 0);
				_avoidanceTimer = (_avoidanceOff ? SosigOptimizerPlugin.CfgLODAvoidanceOffSecs.Value : SosigOptimizerPlugin.CfgLODAvoidanceOnSecs.Value);
			}
		}
	}

	private bool IsObservedByCamera()
	{
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: 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_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Camera val = null;
			Camera[] allCameras = Camera.allCameras;
			foreach (Camera val2 in allCameras)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				if (val2.stereoEnabled)
				{
					if ((Object)(object)val == (Object)null)
					{
						val = val2;
					}
				}
				else if ((Object)(object)val2.targetTexture != (Object)null)
				{
					Bounds val3 = (Bounds)((_sosig.Renderers != null && _sosig.Renderers.Length != 0 && (Object)(object)_sosig.Renderers[0] != (Object)null) ? _sosig.Renderers[0].bounds : new Bounds(((Component)this).transform.position, Vector3.one * 2f));
					if (GeometryUtility.TestPlanesAABB(GeometryUtility.CalculateFrustumPlanes(val2), val3))
					{
						return true;
					}
				}
			}
			if ((Object)(object)val != (Object)null && SosigOptimizerPlugin.IsScopeActive())
			{
				Vector3 val4 = ((Component)_sosig).transform.position - ((Component)val).transform.position;
				Vector3 normalized = ((Vector3)(ref val4)).normalized;
				if (Vector3.Angle(((Component)val).transform.forward, normalized) < 15f)
				{
					return true;
				}
			}
			return false;
		}
		catch
		{
			return false;
		}
	}

	private void Tick()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Invalid comparison between Unknown and I4
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		if ((int)_sosig.BodyState == 3)
		{
			if (_lodActive)
			{
				RestoreLOD();
			}
		}
		else
		{
			if ((Object)(object)GM.CurrentPlayerBody == (Object)null)
			{
				return;
			}
			if (IsObservedByCamera())
			{
				if (_lodActive)
				{
					SosigOptimizerPlugin.Log.LogInfo((object)("[SosigLOD] RESTORE (observed) " + ((Object)_sosig).name));
					RestoreLOD();
				}
				return;
			}
			float num = Vector3.Distance(((Component)this).transform.position, ((Component)GM.CurrentPlayerBody).transform.position);
			if (!_lodActive && num > SosigOptimizerPlugin.CfgLODFarDist.Value)
			{
				SosigOptimizerPlugin.Log.LogInfo((object)$"[SosigLOD] LOD ON  {((Object)_sosig).name} @ {num:F0}m");
				ApplyLOD();
			}
			else if (_lodActive && num < SosigOptimizerPlugin.CfgLODNearDist.Value)
			{
				SosigOptimizerPlugin.Log.LogInfo((object)$"[SosigLOD] LOD OFF {((Object)_sosig).name} @ {num:F0}m");
				RestoreLOD();
			}
			else if (_lodActive)
			{
				BumpNavTick();
				ClearSleepThresholdIfH3MP();
			}
		}
	}

	private void ApplyLOD()
	{
		int solverIterations = Mathf.Max(1, SosigOptimizerPlugin.CfgLODSolverIter.Value);
		for (int i = 0; i < _sosig.Links.Count; i++)
		{
			SosigLink val = _sosig.Links[i];
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			if ((Object)(object)val.R != (Object)null)
			{
				if (SosigOptimizerPlugin.CfgLODReducePhysics.Value)
				{
					val.R.solverIterations = solverIterations;
					val.R.solverVelocityIterations = 1;
				}
				if (SosigOptimizerPlugin.CfgLODReduceInterp.Value)
				{
					val.R.interpolation = (RigidbodyInterpolation)0;
				}
				if (SosigOptimizerPlugin.CfgLODRaiseSleepThreshold.Value && !SosigOptimizerPlugin.IsH3MPSessionActive())
				{
					val.R.sleepThreshold = SosigOptimizerPlugin.CfgLODSleepThreshold.Value;
				}
			}
			if ((Object)(object)val.J != (Object)null && SosigOptimizerPlugin.CfgLODReducePhysics.Value)
			{
				val.J.enableProjection = false;
			}
		}
		if (SosigOptimizerPlugin.CfgLODPulseAvoidance.Value && (Object)(object)_sosig.Agent != (Object)null)
		{
			_sosig.Agent.obstacleAvoidanceType = (ObstacleAvoidanceType)0;
			_avoidanceOff = true;
			_avoidanceTimer = SosigOptimizerPlugin.CfgLODAvoidanceOffSecs.Value;
		}
		BumpNavTick();
		if (SosigOptimizerPlugin.CfgLODHideShadows.Value && _sosig.Renderers != null)
		{
			Renderer[] renderers = _sosig.Renderers;
			foreach (Renderer val2 in renderers)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					val2.shadowCastingMode = (ShadowCastingMode)0;
				}
			}
		}
		_lodActive = true;
	}

	private void RestoreLOD()
	{
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		_avoidanceTimer = 0f;
		for (int i = 0; i < _sosig.Links.Count; i++)
		{
			SosigLink val = _sosig.Links[i];
			if (!((Object)(object)val == (Object)null))
			{
				if ((Object)(object)val.R != (Object)null && i < _origSolverIter.Length)
				{
					val.R.solverIterations = _origSolverIter[i];
					val.R.solverVelocityIterations = _origSolverVelIter[i];
					val.R.interpolation = _origInterp[i];
					val.R.sleepThreshold = _origSleepThreshold[i];
					val.R.WakeUp();
				}
				if ((Object)(object)val.J != (Object)null && i < _origProjection.Length)
				{
					val.J.enableProjection = _origProjection[i];
				}
			}
		}
		if ((Object)(object)_sosig.Agent != (Object)null)
		{
			_sosig.Agent.obstacleAvoidanceType = _origAvoidance;
		}
		if (_sosig.Renderers != null && _origShadows != null)
		{
			for (int j = 0; j < _sosig.Renderers.Length; j++)
			{
				if ((Object)(object)_sosig.Renderers[j] != (Object)null && j < _origShadows.Length)
				{
					_sosig.Renderers[j].shadowCastingMode = _origShadows[j];
				}
			}
		}
		_lodActive = false;
	}

	private void BumpNavTick()
	{
		if (SosigOptimizerPlugin.CfgLODReduceNavTick.Value && _navTickFieldFound)
		{
			_navTickField.SetValue(_sosig, SosigOptimizerPlugin.CfgLODNavTickSecs.Value);
		}
	}

	private void ClearSleepThresholdIfH3MP()
	{
		if (!SosigOptimizerPlugin.CfgLODRaiseSleepThreshold.Value || !SosigOptimizerPlugin.IsH3MPSessionActive())
		{
			return;
		}
		for (int i = 0; i < _sosig.Links.Count && i < _origSleepThreshold.Length; i++)
		{
			SosigLink val = _sosig.Links[i];
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val.R == (Object)null) && val.R.sleepThreshold != _origSleepThreshold[i])
			{
				val.R.sleepThreshold = _origSleepThreshold[i];
				val.R.WakeUp();
			}
		}
	}

	private void OnDestroy()
	{
		if (_lodActive && (Object)(object)_sosig != (Object)null)
		{
			RestoreLOD();
		}
		AllControllers.Remove(this);
	}
}
[BepInPlugin("h3vr.invent60.sosigoptimizer", "SosigOptimizer", "1.0.3")]
public class SosigOptimizerPlugin : BaseUnityPlugin
{
	[CompilerGenerated]
	private sealed class <AttachRadar>d__40 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public SosigOptimizerPlugin <>4__this;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <AttachRadar>d__40(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			int num = <>1__state;
			SosigOptimizerPlugin sosigOptimizerPlugin = <>4__this;
			switch (num)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				((Component)sosigOptimizerPlugin).gameObject.AddComponent<SosigRadar>();
				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 <DestroyLinkAfterDelay>d__39 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public float delay;

		public SosigLink link;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <DestroyLinkAfterDelay>d__39(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(delay);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				if ((Object)(object)link == (Object)null)
				{
					return false;
				}
				if ((Object)(object)link.O != (Object)null && ((FVRInteractiveObject)link.O).IsHeld)
				{
					return false;
				}
				Object.Destroy((Object)(object)((Component)link).gameObject);
				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 <EnforceGibCapNextFrame>d__38 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <EnforceGibCapNextFrame>d__38(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
			{
				<>1__state = -1;
				_gibCapPending = false;
				int value = CfgGibMax.Value;
				if (value <= 0)
				{
					return false;
				}
				GibMarker[] array = GibMarker.All.ToArray();
				if (array.Length <= value)
				{
					return false;
				}
				int num = array.Length - value;
				for (int i = 0; i < num; i++)
				{
					int num2 = Random.Range(i, array.Length);
					GibMarker gibMarker = array[i];
					array[i] = array[num2];
					array[num2] = gibMarker;
				}
				for (int j = 0; j < num; j++)
				{
					GibMarker gibMarker2 = array[j];
					if (!((Object)(object)gibMarker2 == (Object)null) && !((Object)(object)((Component)gibMarker2).GetComponentInParent<FVRViveHand>() != (Object)null) && !((Object)(object)((Component)gibMarker2).GetComponentInParent<FVRPlayerBody>() != (Object)null) && !((Object)(object)((Component)gibMarker2).GetComponentInParent<FVRPlayerHitbox>() != (Object)null))
					{
						FVRInteractiveObject componentInParent = ((Component)gibMarker2).GetComponentInParent<FVRInteractiveObject>();
						if (!((Object)(object)componentInParent != (Object)null) || !((Object)(object)componentInParent.m_hand != (Object)null))
						{
							Object.Destroy((Object)(object)((Component)gibMarker2).gameObject);
						}
					}
				}
				Log.LogInfo((object)("[SosigOptimizer] Gib cap: removed " + num + " of " + array.Length + "."));
				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();
		}
	}

	internal static ManualLogSource Log;

	internal static SosigOptimizerPlugin Instance;

	internal static ConfigEntry<bool> CfgLODEnabled;

	internal static ConfigEntry<float> CfgLODInterval;

	internal static ConfigEntry<float> CfgLODNearDist;

	internal static ConfigEntry<float> CfgLODFarDist;

	internal static ConfigEntry<bool> CfgLODReducePhysics;

	internal static ConfigEntry<int> CfgLODSolverIter;

	internal static ConfigEntry<bool> CfgLODReduceInterp;

	internal static ConfigEntry<bool> CfgLODRaiseSleepThreshold;

	internal static ConfigEntry<float> CfgLODSleepThreshold;

	internal static ConfigEntry<bool> CfgLODReduceNavTick;

	internal static ConfigEntry<float> CfgLODNavTickSecs;

	internal static ConfigEntry<bool> CfgLODPulseAvoidance;

	internal static ConfigEntry<float> CfgLODAvoidanceOffSecs;

	internal static ConfigEntry<float> CfgLODAvoidanceOnSecs;

	internal static ConfigEntry<bool> CfgLODHideShadows;

	internal static ConfigEntry<bool> CfgDebugRadar;

	internal static ConfigEntry<bool> CfgGibEnabled;

	internal static ConfigEntry<float> CfgGibLinkLifetime;

	internal static ConfigEntry<float> CfgGibLifetime;

	internal static ConfigEntry<int> CfgGibMax;

	internal static ConfigEntry<float> CfgGibTagRadius;

	private static Type _h3mpGMType;

	private static PropertyInfo _h3mpSingletonProp;

	private static bool _h3mpInitDone;

	private static Type _pipControllerType;

	private static MethodInfo _getActiveScopeMethod;

	private static Object _cachedController;

	private static float _controllerRefreshTime;

	private static bool _scopeReflectionDone;

	private static bool _gibCapPending;

	private static void EnsureH3MPInit()
	{
		if (_h3mpInitDone)
		{
			return;
		}
		_h3mpInitDone = true;
		try
		{
			_h3mpGMType = AccessTools.TypeByName("H3MP.GameManager");
			if ((object)_h3mpGMType != null)
			{
				_h3mpSingletonProp = _h3mpGMType.GetProperty("singleton", BindingFlags.Static | BindingFlags.Public);
			}
		}
		catch
		{
		}
		Log.LogInfo((object)("[SosigOptimizer] H3MP: " + (((object)_h3mpGMType != null) ? "detected" : "not present")));
	}

	internal static bool IsH3MPSessionActive()
	{
		EnsureH3MPInit();
		if ((object)_h3mpGMType == null || (object)_h3mpSingletonProp == null)
		{
			return false;
		}
		try
		{
			return _h3mpSingletonProp.GetValue(null, null) != null;
		}
		catch
		{
			return false;
		}
	}

	internal static void InitScopeReflection()
	{
		if (_scopeReflectionDone)
		{
			return;
		}
		_scopeReflectionDone = true;
		try
		{
			_pipControllerType = AccessTools.TypeByName("PIPScope");
			if ((object)_pipControllerType != null)
			{
				_getActiveScopeMethod = _pipControllerType.GetMethod("GetActiveScope", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			}
		}
		catch (Exception ex)
		{
			Log.LogError((object)("[SosigOptimizer] scope reflection error: " + ex.Message));
		}
		Log.LogInfo((object)("[SosigOptimizer] PIPScope: " + (((object)_pipControllerType != null) ? "found" : "not found")));
		Log.LogInfo((object)("[SosigOptimizer] GetActiveScope: " + (((object)_getActiveScopeMethod != null) ? "found" : "not found")));
	}

	internal static bool IsScopeActive()
	{
		if ((object)_pipControllerType == null || (object)_getActiveScopeMethod == null)
		{
			return false;
		}
		try
		{
			object obj;
			if (_getActiveScopeMethod.IsStatic)
			{
				obj = null;
			}
			else
			{
				if (Time.time > _controllerRefreshTime + 1f)
				{
					_cachedController = Object.FindObjectOfType(_pipControllerType);
					_controllerRefreshTime = Time.time;
				}
				if (_cachedController == null)
				{
					return false;
				}
				obj = _cachedController;
			}
			return _getActiveScopeMethod.Invoke(obj, null) != null;
		}
		catch
		{
			return false;
		}
	}

	private void Awake()
	{
		//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		Instance = this;
		CfgLODEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("LOD - General", "Enabled", true, "Enable distance-based LOD for sosigs. Reduces CPU/GPU cost for distant enemies.");
		CfgLODInterval = ((BaseUnityPlugin)this).Config.Bind<float>("LOD - General", "Check interval seconds", 0.5f, "How often each sosig checks its distance from the player. (0.1 to 5)");
		CfgLODNearDist = ((BaseUnityPlugin)this).Config.Bind<float>("LOD - General", "Near distance meters (LOD OFF)", 150f, "LOD deactivates when a sosig comes closer than this. Must be less than Far distance. (5 to 500)");
		CfgLODFarDist = ((BaseUnityPlugin)this).Config.Bind<float>("LOD - General", "Far distance meters (LOD ON)", 150f, "LOD activates when a sosig exceeds this distance. (10 to 2000)");
		CfgLODReducePhysics = ((BaseUnityPlugin)this).Config.Bind<bool>("LOD - Physics", "Reduce physics solver iterations", true, "PERF: HIGH. Lowers joint solver iterations and disables projection for distant sosig bodies.");
		CfgLODSolverIter = ((BaseUnityPlugin)this).Config.Bind<int>("LOD - Physics", "Physics solver iterations (far)", 1, "Joint solver iterations for distant sosigs. Default game value: 6. (1 to 6)");
		CfgLODReduceInterp = ((BaseUnityPlugin)this).Config.Bind<bool>("LOD - Physics", "Disable Rigidbody interpolation when far", true, "PERF: LOW. Turns off motion interpolation on distant sosig bodies.");
		CfgLODRaiseSleepThreshold = ((BaseUnityPlugin)this).Config.Bind<bool>("LOD - Physics", "Raise sleep threshold when far", true, "PERF: HIGH. Distant sosig bodies sleep faster when idle, skipping physics simulation entirely. Restores on approach.");
		CfgLODSleepThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("LOD - Physics", "Sleep threshold (far)", 5f, "Physics sleep threshold for distant sosig bodies. Default game value: 0.005. Higher = bodies sleep sooner. (0.1 to 20)");
		CfgLODReduceNavTick = ((BaseUnityPlugin)this).Config.Bind<bool>("LOD - Navigation", "Slow NavMesh path recalculation when far", false, "PERF: MEDIUM. Distant sosigs recalculate paths less frequently. Off by default.");
		CfgLODNavTickSecs = ((BaseUnityPlugin)this).Config.Bind<float>("LOD - Navigation", "NavMesh recalc interval seconds (far)", 8f, "Seconds between path recalculations for distant sosigs. Only applies if above is ON. (2 to 30)");
		CfgLODPulseAvoidance = ((BaseUnityPlugin)this).Config.Bind<bool>("LOD - Navigation", "Pulse obstacle avoidance when far", false, "PERF: MEDIUM. Cycles avoidance OFF/ON instead of every frame. Off by default.");
		CfgLODAvoidanceOffSecs = ((BaseUnityPlugin)this).Config.Bind<float>("LOD - Navigation", "Avoidance OFF duration seconds", 8f, "How long avoidance is disabled per pulse cycle. Only applies if above is ON. (1 to 60)");
		CfgLODAvoidanceOnSecs = ((BaseUnityPlugin)this).Config.Bind<float>("LOD - Navigation", "Avoidance ON duration seconds", 2f, "How long avoidance is re-enabled per pulse cycle. (0.5 to 10)");
		CfgLODHideShadows = ((BaseUnityPlugin)this).Config.Bind<bool>("LOD - Rendering", "Disable shadow casting when far", true, "PERF: MEDIUM (GPU). Stops distant sosigs from casting shadows.");
		CfgDebugRadar = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Show sosig radar on right hand", false, "Debug radar on right wrist. 15cm disc = 1000m radius. Red = LOD active, Blue = full quality, Green = you.");
		CfgGibEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Gib Cleaner", "Enabled", true, "Enable automatic cleanup of sosig ragdoll links and explosion gib chunks.");
		CfgGibLinkLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Gib Cleaner", "Ragdoll link lifetime seconds", 12f, "How long severed sosig body parts persist before being destroyed. Held pieces are never destroyed. (1 to 120)");
		CfgGibLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Gib Cleaner", "Gib chunk lifetime seconds", 6f, "How long small gib chunks from grenade/explosion deaths persist. Lower = less physics lag. (1 to 60)");
		CfgGibMax = ((BaseUnityPlugin)this).Config.Bind<int>("Gib Cleaner", "Max simultaneous gibs", 60, "Hard cap on gib chunks. Oldest chunks destroyed first when exceeded. 0 = no cap. (0 to 500)");
		CfgGibTagRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Gib Cleaner", "Gib detection radius meters", 1.5f, "Radius around a destroyed sosig link used to detect nearby gib chunks. Increase if some gibs are missed. (0.5 to 5)");
		InitScopeReflection();
		new Harmony("h3vr.invent60.sosigoptimizer").PatchAll(typeof(SosigOptimizerPatches));
		((MonoBehaviour)this).StartCoroutine(AttachRadar());
		Log.LogInfo((object)"[SosigOptimizer] v1.0.3 Loaded.");
	}

	internal static void ScheduleGibCap()
	{
		if (!_gibCapPending)
		{
			_gibCapPending = true;
			((MonoBehaviour)Instance).StartCoroutine(Instance.EnforceGibCapNextFrame());
		}
	}

	[IteratorStateMachine(typeof(<EnforceGibCapNextFrame>d__38))]
	private IEnumerator EnforceGibCapNextFrame()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <EnforceGibCapNextFrame>d__38(0);
	}

	[IteratorStateMachine(typeof(<DestroyLinkAfterDelay>d__39))]
	internal IEnumerator DestroyLinkAfterDelay(SosigLink link, float delay)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <DestroyLinkAfterDelay>d__39(0)
		{
			link = link,
			delay = delay
		};
	}

	[IteratorStateMachine(typeof(<AttachRadar>d__40))]
	private IEnumerator AttachRadar()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <AttachRadar>d__40(0)
		{
			<>4__this = this
		};
	}
}
public class SosigRadar : MonoBehaviour
{
	private const float RadarRadius = 0.15f;

	private const float WorldRadius = 1000f;

	private const float Scale = 0.00015f;

	private const float DotSize = 0.008f;

	private const int CircleSegs = 64;

	private Mesh _circleMesh;

	private Mesh _dotMesh;

	private Material _mat;

	private MaterialPropertyBlock _mpb;

	private void Start()
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_001d: Expected O, but got Unknown
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		_mat = new Material(Shader.Find("Unlit/Color"))
		{
			hideFlags = (HideFlags)61
		};
		_mpb = new MaterialPropertyBlock();
		_circleMesh = BuildCircleMesh();
		_dotMesh = BuildDotMesh();
	}

	private void OnDestroy()
	{
		if ((Object)(object)_mat != (Object)null)
		{
			Object.Destroy((Object)(object)_mat);
		}
		if ((Object)(object)_circleMesh != (Object)null)
		{
			Object.Destroy((Object)(object)_circleMesh);
		}
		if ((Object)(object)_dotMesh != (Object)null)
		{
			Object.Destroy((Object)(object)_dotMesh);
		}
	}

	private void LateUpdate()
	{
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: 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_007c: 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_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_008e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_019a: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		if (!SosigOptimizerPlugin.CfgDebugRadar.Value || (Object)(object)_mat == (Object)null)
		{
			return;
		}
		Vector3 position;
		try
		{
			FVRPlayerBody currentPlayerBody = GM.CurrentPlayerBody;
			if ((Object)(object)currentPlayerBody == (Object)null || (Object)(object)currentPlayerBody.RightHand == (Object)null)
			{
				return;
			}
			position = ((Component)currentPlayerBody.RightHand).transform.position;
		}
		catch
		{
			return;
		}
		Quaternion val = Quaternion.Euler(-90f, 0f, 0f);
		_mpb.SetColor("_Color", Color.white);
		Graphics.DrawMesh(_circleMesh, Matrix4x4.TRS(position, val, Vector3.one * 0.15f), _mat, 0, (Camera)null, 0, _mpb);
		DrawDot(position, val, Color.green);
		Vector3 position2;
		try
		{
			position2 = ((Component)GM.CurrentPlayerBody).transform.position;
		}
		catch
		{
			return;
		}
		List<SosigLODController> allControllers = SosigLODController.AllControllers;
		for (int i = 0; i < allControllers.Count; i++)
		{
			SosigLODController sosigLODController = allControllers[i];
			if (!((Object)(object)sosigLODController == (Object)null) && !((Object)(object)sosigLODController._sosig == (Object)null))
			{
				float num = (((Component)sosigLODController._sosig).transform.position.x - position2.x) * 0.00015f;
				float num2 = (((Component)sosigLODController._sosig).transform.position.z - position2.z) * 0.00015f;
				float num3 = Mathf.Sqrt(num * num + num2 * num2);
				if (num3 > 0.15f)
				{
					float num4 = 0.15f / num3;
					num *= num4;
					num2 *= num4;
				}
				DrawDot(position + new Vector3(num, 0f, num2), val, sosigLODController._lodActive ? Color.red : Color.blue);
			}
		}
	}

	private void DrawDot(Vector3 pos, Quaternion rot, Color col)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: 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)
		_mpb.SetColor("_Color", col);
		Graphics.DrawMesh(_dotMesh, Matrix4x4.TRS(pos, rot, Vector3.one * 0.008f), _mat, 0, (Camera)null, 0, _mpb);
	}

	private static Mesh BuildCircleMesh()
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: 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)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f5: Expected O, but got Unknown
		Vector3[] array = (Vector3[])(object)new Vector3[128];
		int[] array2 = new int[384];
		for (int i = 0; i < 64; i++)
		{
			float num = (float)i * 2f * (float)Math.PI / 64f;
			float num2 = Mathf.Cos(num);
			float num3 = Mathf.Sin(num);
			array[i] = new Vector3(num2, num3, 0f);
			array[i + 64] = new Vector3(num2 * 0.88f, num3 * 0.88f, 0f);
		}
		for (int j = 0; j < 64; j++)
		{
			int num4 = (j + 1) % 64;
			int num5 = j * 6;
			array2[num5] = j;
			array2[num5 + 1] = num4;
			array2[num5 + 2] = j + 64;
			array2[num5 + 3] = num4;
			array2[num5 + 4] = num4 + 64;
			array2[num5 + 5] = j + 64;
		}
		Mesh val = new Mesh
		{
			hideFlags = (HideFlags)61,
			vertices = array,
			triangles = array2
		};
		val.RecalculateNormals();
		return val;
	}

	private static Mesh BuildDotMesh()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: 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_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Expected O, but got Unknown
		Vector3[] array = (Vector3[])(object)new Vector3[13];
		int[] array2 = new int[36];
		array[0] = Vector3.zero;
		for (int i = 0; i < 12; i++)
		{
			float num = (float)i * 2f * (float)Math.PI / 12f;
			array[i + 1] = new Vector3(Mathf.Cos(num) * 0.5f, Mathf.Sin(num) * 0.5f, 0f);
		}
		for (int j = 0; j < 12; j++)
		{
			array2[j * 3] = 0;
			array2[j * 3 + 1] = j + 1;
			array2[j * 3 + 2] = (j + 1) % 12 + 1;
		}
		Mesh val = new Mesh
		{
			hideFlags = (HideFlags)61,
			vertices = array,
			triangles = array2
		};
		val.RecalculateNormals();
		return val;
	}
}
internal static class SosigOptimizerPatches
{
	[HarmonyPatch(typeof(Sosig), "Start")]
	[HarmonyPostfix]
	private static void OnSosigStart(Sosig __instance)
	{
		if (SosigOptimizerPlugin.CfgLODEnabled.Value)
		{
			((Component)__instance).gameObject.AddComponent<SosigLODController>();
		}
	}

	[HarmonyPatch(typeof(Sosig), "SosigDies")]
	[HarmonyPostfix]
	private static void OnSosigDied(Sosig __instance)
	{
		if (!SosigOptimizerPlugin.CfgGibEnabled.Value)
		{
			return;
		}
		float value = SosigOptimizerPlugin.CfgGibLinkLifetime.Value;
		foreach (SosigLink link in __instance.Links)
		{
			if ((Object)(object)link != (Object)null)
			{
				((MonoBehaviour)SosigOptimizerPlugin.Instance).StartCoroutine(SosigOptimizerPlugin.Instance.DestroyLinkAfterDelay(link, value));
			}
		}
	}

	[HarmonyPatch(typeof(Sosig), "DestroyLink")]
	[HarmonyPostfix]
	private static void OnLinkDestroyed(SosigLink link)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: 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_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		if (!SosigOptimizerPlugin.CfgGibEnabled.Value || (Object)(object)link == (Object)null)
		{
			return;
		}
		Vector3 position = ((Component)link).transform.position;
		if (float.IsNaN(position.x) || float.IsNaN(position.y) || float.IsNaN(position.z))
		{
			return;
		}
		float value = SosigOptimizerPlugin.CfgGibTagRadius.Value;
		Collider[] array = Physics.OverlapSphere(position, value);
		for (int i = 0; i < array.Length; i++)
		{
			GameObject gameObject = ((Component)array[i]).gameObject;
			if (!((Object)(object)gameObject.GetComponent<Rigidbody>() == (Object)null) && !((Object)(object)gameObject.GetComponent<GibMarker>() != (Object)null) && !((Object)(object)gameObject.GetComponent<ParticleSystem>() != (Object)null))
			{
				Scene scene = gameObject.scene;
				if (!(((Scene)(ref scene)).name == "DontDestroyOnLoad") && !((Object)(object)gameObject.GetComponentInParent<FVRPhysicalObject>() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent<FVRViveHand>() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent<FVRPlayerBody>() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent<FVRPlayerHitbox>() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent<SosigLink>() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent<SosigWeapon>() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent<SosigWearable>() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent<ParticleSystem>() != (Object)null))
				{
					gameObject.AddComponent<GibMarker>();
					Object.Destroy((Object)(object)gameObject, SosigOptimizerPlugin.CfgGibLifetime.Value);
				}
			}
		}
		SosigOptimizerPlugin.ScheduleGibCap();
	}
}