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 All = new List(); 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 AllControllers = new List(); 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(); 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 d__40 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SosigOptimizerPlugin <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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(); 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 d__39 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float delay; public SosigLink link; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 d__38 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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() != (Object)null) && !((Object)(object)((Component)gibMarker2).GetComponentInParent() != (Object)null) && !((Object)(object)((Component)gibMarker2).GetComponentInParent() != (Object)null)) { FVRInteractiveObject componentInParent = ((Component)gibMarker2).GetComponentInParent(); 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 CfgLODEnabled; internal static ConfigEntry CfgLODInterval; internal static ConfigEntry CfgLODNearDist; internal static ConfigEntry CfgLODFarDist; internal static ConfigEntry CfgLODReducePhysics; internal static ConfigEntry CfgLODSolverIter; internal static ConfigEntry CfgLODReduceInterp; internal static ConfigEntry CfgLODRaiseSleepThreshold; internal static ConfigEntry CfgLODSleepThreshold; internal static ConfigEntry CfgLODReduceNavTick; internal static ConfigEntry CfgLODNavTickSecs; internal static ConfigEntry CfgLODPulseAvoidance; internal static ConfigEntry CfgLODAvoidanceOffSecs; internal static ConfigEntry CfgLODAvoidanceOnSecs; internal static ConfigEntry CfgLODHideShadows; internal static ConfigEntry CfgDebugRadar; internal static ConfigEntry CfgGibEnabled; internal static ConfigEntry CfgGibLinkLifetime; internal static ConfigEntry CfgGibLifetime; internal static ConfigEntry CfgGibMax; internal static ConfigEntry 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("LOD - General", "Enabled", true, "Enable distance-based LOD for sosigs. Reduces CPU/GPU cost for distant enemies."); CfgLODInterval = ((BaseUnityPlugin)this).Config.Bind("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("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("LOD - General", "Far distance meters (LOD ON)", 150f, "LOD activates when a sosig exceeds this distance. (10 to 2000)"); CfgLODReducePhysics = ((BaseUnityPlugin)this).Config.Bind("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("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("LOD - Physics", "Disable Rigidbody interpolation when far", true, "PERF: LOW. Turns off motion interpolation on distant sosig bodies."); CfgLODRaiseSleepThreshold = ((BaseUnityPlugin)this).Config.Bind("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("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("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("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("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("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("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("LOD - Rendering", "Disable shadow casting when far", true, "PERF: MEDIUM (GPU). Stops distant sosigs from casting shadows."); CfgDebugRadar = ((BaseUnityPlugin)this).Config.Bind("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("Gib Cleaner", "Enabled", true, "Enable automatic cleanup of sosig ragdoll links and explosion gib chunks."); CfgGibLinkLifetime = ((BaseUnityPlugin)this).Config.Bind("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("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("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("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(d__38))] private IEnumerator EnforceGibCapNextFrame() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__38(0); } [IteratorStateMachine(typeof(d__39))] internal IEnumerator DestroyLinkAfterDelay(SosigLink link, float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__39(0) { link = link, delay = delay }; } [IteratorStateMachine(typeof(d__40))] private IEnumerator AttachRadar() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new 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 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(); } } [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() == (Object)null) && !((Object)(object)gameObject.GetComponent() != (Object)null) && !((Object)(object)gameObject.GetComponent() != (Object)null)) { Scene scene = gameObject.scene; if (!(((Scene)(ref scene)).name == "DontDestroyOnLoad") && !((Object)(object)gameObject.GetComponentInParent() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent() != (Object)null) && !((Object)(object)gameObject.GetComponentInParent() != (Object)null)) { gameObject.AddComponent(); Object.Destroy((Object)(object)gameObject, SosigOptimizerPlugin.CfgGibLifetime.Value); } } } SosigOptimizerPlugin.ScheduleGibCap(); } }