using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ValheimBuildOptimization")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ValheimBuildOptimization")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("be15940e-381c-4623-a8d4-222869a01afc")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace BuildPieceProfiler; [BepInPlugin("valheim.buildpieceprofiler", "Build Piece Profiler", "0.2.0")] public class BuildPieceProfilerPlugin : BaseUnityPlugin { private enum AppliedFireMode { None, StaticLight, FullCull } private class FireCandidate { public Piece Piece; public MeshRenderer[] Renderers; public Light[] OriginalLights; public ParticleSystem[] Particles; } private class FireOptimizationState { public Piece Piece; public AppliedFireMode AppliedMode = AppliedFireMode.None; public readonly Dictionary OriginalLightEnabled = new Dictionary(); public readonly Dictionary OriginalParticlePlaying = new Dictionary(); public readonly Dictionary OriginalShadowModes = new Dictionary(); public GameObject ProxyLightObject; public Light ProxyLight; public float LastVisibleTime; public float LastIrrelevantTime; } private enum FireCullingMode { Off, StaticLight, FullCull } private struct FireMetrics { public int FireCandidates; public int RendererVisibleFireCandidates; public int OccludedFireCandidates; public int RelevantFireCandidates; public int HiddenOrIrrelevantFireCandidates; public int OptimizedFirePieces; public int StaticLightFirePieces; public int FullCullFirePieces; public int FireProxyLightsActive; public int FireOriginalLightsDisabled; public int FireParticlesStopped; public int FireShadowsDisabled; } private struct Counts { public int Pieces; public int WearNTear; public int ZNetView; public int MeshRenderer; public int EnabledMeshRenderer; public int VisibleMeshRenderer; public int Collider; public int EnabledCollider; public int LODGroup; public int Light; public int EnabledLight; public int ParticleSystem; public int ActiveParticleSystem; public int AudioSource; public int ActiveRigidbody; public int PieceMeshRenderer; public int PieceEnabledMeshRenderer; public int PieceVisibleMeshRenderer; public int PieceCollider; public int PieceEnabledCollider; public int PieceLODGroup; public int PieceLight; public int PieceEnabledLight; public int PieceParticleSystem; public int PieceActiveParticleSystem; public int PieceAudioSource; public int PieceRigidbody; public int PieceActiveRigidbody; public int PiecesWithinNear; public int PiecesWithinMedium; public int PiecesWithinFar; public int PiecesWithinVeryFar; public int PiecesWithinExtreme; public int PiecesBeyondExtreme; public float NearestPieceDistance; public float FarthestPieceDistance; public int FireCandidates; public int RendererVisibleFireCandidates; public int OccludedFireCandidates; public int RelevantFireCandidates; public int HiddenOrIrrelevantFireCandidates; public int OptimizedFirePieces; public int StaticLightFirePieces; public int FullCullFirePieces; public int FireProxyLightsActive; public int FireOriginalLightsDisabled; public int FireParticlesStopped; public int FireShadowsDisabled; } public const string PluginGuid = "valheim.buildpieceprofiler"; public const string PluginName = "Build Piece Profiler"; public const string PluginVersion = "0.2.0"; private const string StaticFireLightProxyName = "BuildPieceProfiler_StaticFireLightProxy"; private readonly Rect _windowRectDefault = new Rect(20f, 40f, 520f, 980f); private Rect _windowRect; private Vector2 _scrollPosition = Vector2.zero; private bool _showOverlay; private float _nextPollTime; private Counts _counts = default(Counts); private ConfigEntry _enableProfiler; private ConfigEntry _enableConsoleLogging; private ConfigEntry _showProfilerOnStart; private ConfigEntry _profilerPollInterval; private ConfigEntry _toggleProfilerKey; private ConfigEntry _enableOptimizations; private ConfigEntry _nearDistance; private ConfigEntry _mediumDistance; private ConfigEntry _farDistance; private ConfigEntry _veryFarDistance; private ConfigEntry _extremeDistance; private readonly Dictionary _fireStates = new Dictionary(); private readonly List _activeFireStates = new List(); private readonly List _fireCandidates = new List(); private FireMetrics _fireMetrics = default(FireMetrics); private float _nextOptimizerUpdateTime; private float _nextFireCandidateRefreshTime; private bool _optimizationsWereActive; private ConfigEntry _optimizerUpdateInterval; private ConfigEntry _fireCandidateRefreshInterval; private ConfigEntry _fireCullingMode; private ConfigEntry _useFireVisibilityCulling; private ConfigEntry _fireVisibilityGraceSeconds; private ConfigEntry _neverOptimizeFireWithin; private ConfigEntry _minimumFullCullDistance; private ConfigEntry _fireDistanceCullStart; private ConfigEntry _fireDistanceRestore; private ConfigEntry _staticLightIntensityMultiplier; private ConfigEntry _staticLightRangeMultiplier; private ConfigEntry _useFireOcclusionCulling; private ConfigEntry _fireOcclusionRayRadius; private ConfigEntry _debugFireOcclusion; private ConfigEntry _staticLightProxyMaxDistance; private ConfigEntry _staticLightOccludedProxyMaxDistance; private ConfigEntry _fireRestoreGraceSeconds; private Texture2D _opaqueBackground; private bool IsFireCandidate(Light[] lights, ParticleSystem[] particles) { if (lights == null || particles == null || lights.Length == 0 || particles.Length == 0) { return false; } bool flag = false; bool flag2 = false; foreach (Light val in lights) { if ((Object)(object)val != (Object)null) { flag = true; break; } } foreach (ParticleSystem val2 in particles) { if ((Object)(object)val2 != (Object)null) { flag2 = true; break; } } return flag && flag2; } private bool IsPieceVisible(MeshRenderer[] renderers) { if (renderers == null) { return false; } foreach (MeshRenderer val in renderers) { if (!((Object)(object)val == (Object)null) && ((Renderer)val).enabled && ((Component)val).gameObject.activeInHierarchy && ((Renderer)val).isVisible) { return true; } } return false; } private void LateUpdate() { if (_enableOptimizations.Value && _fireCullingMode.Value != 0) { EnforceOptimizedFireLightsOnly(); } } private void EnforceOptimizedFireLightsOnly() { for (int num = _activeFireStates.Count - 1; num >= 0; num--) { FireOptimizationState fireOptimizationState = _activeFireStates[num]; if (fireOptimizationState == null || fireOptimizationState.AppliedMode == AppliedFireMode.None) { _activeFireStates.RemoveAt(num); } else { foreach (KeyValuePair item in fireOptimizationState.OriginalLightEnabled) { Light key = item.Key; if (!((Object)(object)key == (Object)null) && !IsOurProxyLight(key) && ((Behaviour)key).enabled) { ((Behaviour)key).enabled = false; } } if (fireOptimizationState.AppliedMode == AppliedFireMode.FullCull) { DisableProxyLight(fireOptimizationState); } } } } private void RestoreFire(Piece piece) { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)piece == (Object)null || !_fireStates.TryGetValue(piece, out var value)) { return; } foreach (KeyValuePair item in value.OriginalLightEnabled) { if ((Object)(object)item.Key != (Object)null) { ((Behaviour)item.Key).enabled = item.Value; } } foreach (KeyValuePair originalShadowMode in value.OriginalShadowModes) { if ((Object)(object)originalShadowMode.Key != (Object)null) { ((Renderer)originalShadowMode.Key).shadowCastingMode = originalShadowMode.Value; } } foreach (KeyValuePair item2 in value.OriginalParticlePlaying) { ParticleSystem key = item2.Key; if (!((Object)(object)key == (Object)null)) { if (item2.Value) { key.Play(true); } else { key.Stop(true, (ParticleSystemStopBehavior)0); } } } DisableProxyLight(value); UntrackActiveFireState(value); value.AppliedMode = AppliedFireMode.None; value.OriginalLightEnabled.Clear(); value.OriginalShadowModes.Clear(); value.OriginalParticlePlaying.Clear(); } private void RestoreAllFireOptimizations() { List list = new List(_fireStates.Keys); foreach (Piece item in list) { RestoreFire(item); } DestroyAllProxyLights(); } private bool HasActiveFireOptimizations() { for (int num = _activeFireStates.Count - 1; num >= 0; num--) { FireOptimizationState fireOptimizationState = _activeFireStates[num]; if (fireOptimizationState != null && fireOptimizationState.AppliedMode != 0) { return true; } _activeFireStates.RemoveAt(num); } return false; } private void TrackActiveFireState(FireOptimizationState state) { if (state != null && state.AppliedMode != 0 && !_activeFireStates.Contains(state)) { _activeFireStates.Add(state); } } private void UntrackActiveFireState(FireOptimizationState state) { if (state != null) { _activeFireStates.Remove(state); } } private void ResetFireCandidateCache() { _fireCandidates.Clear(); _nextFireCandidateRefreshTime = 0f; _fireMetrics = default(FireMetrics); } private void CleanupDestroyedFireStates() { List> list = null; foreach (KeyValuePair fireState in _fireStates) { Piece key = fireState.Key; if (!((Object)(object)key != (Object)null)) { if (list == null) { list = new List>(); } list.Add(fireState); } } if (list == null) { return; } foreach (KeyValuePair item in list) { UntrackActiveFireState(item.Value); _fireStates.Remove(item.Key); } } private void RefreshFireCandidateCache() { _fireCandidates.Clear(); Piece[] array = Object.FindObjectsByType((FindObjectsSortMode)0); HashSet hashSet = new HashSet(); Piece[] array2 = array; foreach (Piece val in array2) { if ((Object)(object)val == (Object)null) { continue; } Light[] originalLights = GetOriginalLights(((Component)val).GetComponentsInChildren(true)); if (originalLights.Length != 0) { ParticleSystem[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); if (IsFireCandidate(originalLights, componentsInChildren)) { _fireCandidates.Add(new FireCandidate { Piece = val, Renderers = ((Component)val).GetComponentsInChildren(true), OriginalLights = originalLights, Particles = componentsInChildren }); hashSet.Add(val); } } } List list = null; foreach (KeyValuePair fireState in _fireStates) { Piece key = fireState.Key; FireOptimizationState value = fireState.Value; if (!((Object)(object)key == (Object)null) && value != null && value.AppliedMode != 0 && !hashSet.Contains(key)) { if (list == null) { list = new List(); } list.Add(key); } } if (list != null) { foreach (Piece item in list) { RestoreFire(item); } } _nextFireCandidateRefreshTime = Time.time + Mathf.Max(1f, _fireCandidateRefreshInterval.Value); } private void OnDestroy() { RestoreAllFireOptimizations(); } private void ApplyStaticLight(Piece piece, FireOptimizationState state, MeshRenderer[] renderers, Light[] lights, ParticleSystem[] particles, bool useProxyLight, bool stopParticles) { if (state.AppliedMode != AppliedFireMode.StaticLight) { RestoreFire(piece); state = new FireOptimizationState { Piece = piece, LastVisibleTime = Time.time, LastIrrelevantTime = Time.time }; Light[] lights2 = (Light[])(((object)lights) ?? ((object)new Light[0])); StoreOriginalStates(state, renderers, lights2, particles); state.AppliedMode = AppliedFireMode.StaticLight; _fireStates[piece] = state; } TrackActiveFireState(state); Light[] lights3 = (Light[])(((object)lights) ?? ((object)new Light[0])); StoreOriginalStates(state, renderers, lights3, particles); if (useProxyLight) { Light firstUsableLight = GetFirstUsableLight(lights3); if ((Object)(object)firstUsableLight != (Object)null) { EnsureProxyLight(piece, state, firstUsableLight); } else { DisableProxyLight(state); } } else { DisableProxyLight(state); } DisableOriginalLights(lights3); if (stopParticles) { StopParticles(particles); } else { RestoreParticles(state, particles); } DisableShadows(renderers); } private void ApplyFullCull(Piece piece, FireOptimizationState state, MeshRenderer[] renderers, Light[] lights, ParticleSystem[] particles) { if (state.AppliedMode != AppliedFireMode.FullCull) { RestoreFire(piece); state = GetOrCreateFireState(piece); Light[] lights2 = (Light[])(((object)lights) ?? ((object)new Light[0])); StoreOriginalStates(state, renderers, lights2, particles); state.AppliedMode = AppliedFireMode.FullCull; } TrackActiveFireState(state); Light[] lights3 = (Light[])(((object)lights) ?? ((object)new Light[0])); StoreOriginalStates(state, renderers, lights3, particles); DisableProxyLight(state); DisableOriginalLights(lights3); StopParticles(particles); DisableShadows(renderers); } private void StoreOriginalStates(FireOptimizationState state, MeshRenderer[] renderers, Light[] lights, ParticleSystem[] particles) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) foreach (Light val in lights) { if (!((Object)(object)val == (Object)null) && !state.OriginalLightEnabled.ContainsKey(val)) { state.OriginalLightEnabled[val] = ((Behaviour)val).enabled; } } foreach (ParticleSystem val2 in particles) { if (!((Object)(object)val2 == (Object)null) && !state.OriginalParticlePlaying.ContainsKey(val2)) { state.OriginalParticlePlaying[val2] = val2.IsAlive(true); } } foreach (MeshRenderer val3 in renderers) { if (!((Object)(object)val3 == (Object)null) && !state.OriginalShadowModes.ContainsKey(val3)) { state.OriginalShadowModes[val3] = ((Renderer)val3).shadowCastingMode; } } } private void DisableOriginalLights(Light[] lights) { foreach (Light val in lights) { if (!((Object)(object)val == (Object)null)) { ((Behaviour)val).enabled = false; } } } private void DestroyAllProxyLights() { Piece[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Piece val in array) { if ((Object)(object)val == (Object)null) { continue; } Transform[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && ((Object)((Component)val2).gameObject).name == "BuildPieceProfiler_StaticFireLightProxy") { Object.Destroy((Object)(object)((Component)val2).gameObject); } } } } private void RestoreParticles(FireOptimizationState state, ParticleSystem[] particles) { if (state == null || particles == null) { return; } foreach (ParticleSystem val in particles) { if (!((Object)(object)val == (Object)null) && state.OriginalParticlePlaying.TryGetValue(val, out var value) && value && ((Component)val).gameObject.activeInHierarchy && !val.isPlaying) { val.Play(true); } } } private void StopParticles(ParticleSystem[] particles) { foreach (ParticleSystem val in particles) { if (!((Object)(object)val == (Object)null)) { val.Stop(true, (ParticleSystemStopBehavior)0); } } } private void DisableShadows(MeshRenderer[] renderers) { foreach (MeshRenderer val in renderers) { if (!((Object)(object)val == (Object)null)) { ((Renderer)val).shadowCastingMode = (ShadowCastingMode)0; } } } private Light GetFirstUsableLight(Light[] lights) { foreach (Light val in lights) { if ((Object)(object)val != (Object)null) { return val; } } return null; } private void EnsureProxyLight(Piece piece, FireOptimizationState state, Light sourceLight) { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown if ((Object)(object)piece == (Object)null || (Object)(object)sourceLight == (Object)null || state == null) { return; } if ((Object)(object)state.ProxyLightObject == (Object)null) { Transform val = ((Component)piece).transform.Find("BuildPieceProfiler_StaticFireLightProxy"); if ((Object)(object)val != (Object)null) { state.ProxyLightObject = ((Component)val).gameObject; state.ProxyLight = state.ProxyLightObject.GetComponent(); if ((Object)(object)state.ProxyLight == (Object)null) { state.ProxyLight = state.ProxyLightObject.AddComponent(); } } else { state.ProxyLightObject = new GameObject("BuildPieceProfiler_StaticFireLightProxy"); state.ProxyLightObject.transform.SetParent(((Component)piece).transform, false); state.ProxyLight = state.ProxyLightObject.AddComponent(); } } state.ProxyLightObject.transform.position = ((Component)sourceLight).transform.position; state.ProxyLightObject.transform.rotation = ((Component)sourceLight).transform.rotation; state.ProxyLightObject.SetActive(true); state.ProxyLight.type = (LightType)2; state.ProxyLight.color = sourceLight.color; state.ProxyLight.intensity = sourceLight.intensity * Mathf.Max(0f, _staticLightIntensityMultiplier.Value); state.ProxyLight.range = sourceLight.range * Mathf.Max(0f, _staticLightRangeMultiplier.Value); state.ProxyLight.shadows = (LightShadows)0; ((Behaviour)state.ProxyLight).enabled = true; } private void DisableProxyLight(FireOptimizationState state) { if ((Object)(object)state.ProxyLight != (Object)null) { ((Behaviour)state.ProxyLight).enabled = false; } if ((Object)(object)state.ProxyLightObject != (Object)null) { state.ProxyLightObject.SetActive(false); } } private FireOptimizationState GetOrCreateFireState(Piece piece) { if (_fireStates.TryGetValue(piece, out var value)) { return value; } value = new FireOptimizationState { Piece = piece, LastVisibleTime = Time.time, LastIrrelevantTime = Time.time }; _fireStates[piece] = value; return value; } private Vector3 GetFireTargetPosition(Piece piece, Light[] lights, MeshRenderer[] renderers) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //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_0096: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_00dd: Unknown result type (might be due to invalid IL or missing references) if (lights != null && lights.Length != 0) { Vector3 val = Vector3.zero; int num = 0; foreach (Light val2 in lights) { if (!((Object)(object)val2 == (Object)null)) { val += ((Component)val2).transform.position; num++; } } if (num > 0) { return val / (float)num; } } if (renderers != null && renderers.Length != 0) { Bounds bounds = default(Bounds); ((Bounds)(ref bounds))..ctor(((Component)piece).transform.position, Vector3.zero); bool flag = false; foreach (MeshRenderer val3 in renderers) { if (!((Object)(object)val3 == (Object)null)) { if (!flag) { bounds = ((Renderer)val3).bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(((Renderer)val3).bounds); } } } if (flag) { return ((Bounds)(ref bounds)).center; } } return ((Component)piece).transform.position; } private bool IsOurProxyLight(Light light) { if ((Object)(object)light == (Object)null) { return false; } if ((Object)(object)((Component)light).gameObject == (Object)null) { return false; } return ((Object)((Component)light).gameObject).name == "BuildPieceProfiler_StaticFireLightProxy"; } private Light[] GetOriginalLights(Light[] lights) { if (lights == null || lights.Length == 0) { return (Light[])(object)new Light[0]; } List list = new List(); foreach (Light val in lights) { if (!((Object)(object)val == (Object)null) && !IsOurProxyLight(val)) { list.Add(val); } } return list.ToArray(); } private bool HitBelongsToPiece(RaycastHit hit, Piece piece) { if ((Object)(object)piece == (Object)null || (Object)(object)((RaycastHit)(ref hit)).collider == (Object)null) { return false; } Transform val = ((Component)((RaycastHit)(ref hit)).collider).transform; while ((Object)(object)val != (Object)null) { if ((Object)(object)val == (Object)(object)((Component)piece).transform) { return true; } val = val.parent; } return false; } private bool IsFireOccludedFromCamera(Piece piece, Light[] lights, MeshRenderer[] renderers, Camera mainCamera) { //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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: 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) if (!_useFireOcclusionCulling.Value) { return false; } if ((Object)(object)piece == (Object)null || (Object)(object)mainCamera == (Object)null) { return false; } Vector3 position = ((Component)mainCamera).transform.position; Vector3 fireTargetPosition = GetFireTargetPosition(piece, lights, renderers); Vector3 val = fireTargetPosition - position; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= 0.1f) { return false; } val /= magnitude; float num = Mathf.Max(0f, _fireOcclusionRayRadius.Value); RaycastHit hit = default(RaycastHit); bool flag = ((!(num > 0f)) ? Physics.Raycast(position, val, ref hit, magnitude, -5, (QueryTriggerInteraction)1) : Physics.SphereCast(position, num, val, ref hit, magnitude, -5, (QueryTriggerInteraction)1)); if (_debugFireOcclusion.Value) { Debug.DrawLine(position, fireTargetPosition, flag ? Color.red : Color.green, (_optimizerUpdateInterval != null) ? Mathf.Max(0.1f, _optimizerUpdateInterval.Value) : 0.5f); } if (!flag) { return false; } if (HitBelongsToPiece(hit, piece)) { return false; } return true; } private bool ShouldUseStaticProxyLight(float distance, bool relevant) { if (relevant) { return distance <= Mathf.Max(0f, _staticLightProxyMaxDistance.Value); } return distance <= Mathf.Max(0f, _staticLightOccludedProxyMaxDistance.Value); } private void AddFireOptimizationStateMetrics(ref FireMetrics metrics) { //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Invalid comparison between Unknown and I4 foreach (FireOptimizationState value in _fireStates.Values) { if (value == null || value.AppliedMode == AppliedFireMode.None) { continue; } metrics.OptimizedFirePieces++; if (value.AppliedMode == AppliedFireMode.StaticLight) { metrics.StaticLightFirePieces++; } if (value.AppliedMode == AppliedFireMode.FullCull) { metrics.FullCullFirePieces++; } if ((Object)(object)value.ProxyLight != (Object)null && ((Behaviour)value.ProxyLight).enabled && (Object)(object)value.ProxyLightObject != (Object)null && value.ProxyLightObject.activeInHierarchy) { metrics.FireProxyLightsActive++; } foreach (KeyValuePair item in value.OriginalLightEnabled) { if ((Object)(object)item.Key != (Object)null && !IsOurProxyLight(item.Key) && !((Behaviour)item.Key).enabled && item.Value) { metrics.FireOriginalLightsDisabled++; } } foreach (KeyValuePair item2 in value.OriginalParticlePlaying) { if ((Object)(object)item2.Key != (Object)null && item2.Value && !item2.Key.IsAlive(true)) { metrics.FireParticlesStopped++; } } foreach (KeyValuePair originalShadowMode in value.OriginalShadowModes) { if ((Object)(object)originalShadowMode.Key != (Object)null && (int)((Renderer)originalShadowMode.Key).shadowCastingMode == 0 && (int)originalShadowMode.Value > 0) { metrics.FireShadowsDisabled++; } } } } private void UpdateFireOptimizations() { //IL_0072: 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_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) if (_fireCullingMode.Value == FireCullingMode.Off) { if (HasActiveFireOptimizations()) { RestoreAllFireOptimizations(); } ResetFireCandidateCache(); return; } if ((Object)(object)Player.m_localPlayer == (Object)null) { if (HasActiveFireOptimizations()) { RestoreAllFireOptimizations(); } ResetFireCandidateCache(); return; } Vector3 position = ((Component)Player.m_localPlayer).transform.position; Camera main = Camera.main; if (Time.time >= _nextFireCandidateRefreshTime || _fireCandidates.Count == 0) { RefreshFireCandidateCache(); } FireMetrics metrics = default(FireMetrics); for (int num = _fireCandidates.Count - 1; num >= 0; num--) { FireCandidate fireCandidate = _fireCandidates[num]; if (fireCandidate == null || (Object)(object)fireCandidate.Piece == (Object)null) { _fireCandidates.RemoveAt(num); continue; } Piece piece = fireCandidate.Piece; if ((Object)(object)piece == (Object)null) { _fireCandidates.RemoveAt(num); continue; } MeshRenderer[] renderers = fireCandidate.Renderers; Light[] originalLights = fireCandidate.OriginalLights; ParticleSystem[] particles = fireCandidate.Particles; if (!IsFireCandidate(originalLights, particles)) { RestoreFire(piece); _fireCandidates.RemoveAt(num); continue; } bool flag = IsPieceVisible(renderers); bool flag2 = flag && IsFireOccludedFromCamera(piece, originalLights, renderers, main); bool flag3 = flag && !flag2; metrics.FireCandidates++; if (flag) { metrics.RendererVisibleFireCandidates++; } if (flag2) { metrics.OccludedFireCandidates++; } if (flag3) { metrics.RelevantFireCandidates++; } else { metrics.HiddenOrIrrelevantFireCandidates++; } float num2 = Vector3.Distance(position, ((Component)piece).transform.position); FireOptimizationState orCreateFireState = GetOrCreateFireState(piece); if (flag3) { orCreateFireState.LastVisibleTime = Time.time; } else { orCreateFireState.LastIrrelevantTime = Time.time; } bool flag4 = !flag3; bool flag5 = _useFireVisibilityCulling.Value && flag4 && Time.time - orCreateFireState.LastVisibleTime >= Mathf.Max(0f, _fireVisibilityGraceSeconds.Value); bool flag6 = flag3 && Time.time - orCreateFireState.LastIrrelevantTime >= Mathf.Max(0f, _fireRestoreGraceSeconds.Value); bool flag7 = num2 >= Mathf.Max(1f, _fireDistanceCullStart.Value); bool flag8 = num2 <= Mathf.Max(1f, _fireDistanceRestore.Value); bool flag9 = num2 <= Mathf.Max(0f, _neverOptimizeFireWithin.Value); bool flag10 = !flag9 && (flag7 || flag5); bool flag11 = orCreateFireState.AppliedMode != AppliedFireMode.None; bool flag12 = flag6 && (flag8 || !flag7); if (flag9) { RestoreFire(piece); continue; } if (flag11) { if (flag12) { RestoreFire(piece); continue; } } else if (!flag10) { continue; } if (_fireCullingMode.Value == FireCullingMode.StaticLight) { bool useProxyLight = ShouldUseStaticProxyLight(num2, flag3); bool stopParticles = !flag3; ApplyStaticLight(piece, orCreateFireState, renderers, originalLights, particles, useProxyLight, stopParticles); } else if (_fireCullingMode.Value == FireCullingMode.FullCull) { float num3 = Mathf.Max(0f, _minimumFullCullDistance.Value); if (num2 >= num3 || flag7) { ApplyFullCull(piece, orCreateFireState, renderers, originalLights, particles); continue; } bool useProxyLight2 = ShouldUseStaticProxyLight(num2, flag3); bool stopParticles2 = !flag3; ApplyStaticLight(piece, orCreateFireState, renderers, originalLights, particles, useProxyLight2, stopParticles2); } } AddFireOptimizationStateMetrics(ref metrics); _fireMetrics = metrics; CleanupDestroyedFireStates(); } private void Awake() { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) _windowRect = _windowRectDefault; _enableProfiler = ((BaseUnityPlugin)this).Config.Bind("Profiler", "EnableProfiler", true, "Enables the profiler system. If false, no polling or overlay drawing is performed."); _enableConsoleLogging = ((BaseUnityPlugin)this).Config.Bind("Profiler", "EnableConsoleLogging", false, "Writes profiler counts to the BepInEx log each poll. Useful for testing, but can create large log files."); _showProfilerOnStart = ((BaseUnityPlugin)this).Config.Bind("Profiler", "ShowProfilerOnStart", true, "Shows the profiler overlay when the world loads."); _profilerPollInterval = ((BaseUnityPlugin)this).Config.Bind("Profiler", "PollIntervalSeconds", 1f, "How often the profiler updates its counts, in seconds. Lower values update faster but cost more performance."); _toggleProfilerKey = ((BaseUnityPlugin)this).Config.Bind("Profiler", "ToggleProfilerKey", (KeyCode)288, "Keyboard key used to toggle the profiler overlay."); _enableOptimizations = ((BaseUnityPlugin)this).Config.Bind("Optimizations", "EnableOptimizations", false, "Master switch for optimization features. Currently reserved for future optimizer systems."); _nearDistance = ((BaseUnityPlugin)this).Config.Bind("DistanceThresholds", "NearDistance", 10f, "Near distance in meters. Pieces within this range should usually remain fully vanilla."); _mediumDistance = ((BaseUnityPlugin)this).Config.Bind("DistanceThresholds", "MediumDistance", 25f, "Medium distance in meters. Good candidate range for safe shadow/effect reductions."); _farDistance = ((BaseUnityPlugin)this).Config.Bind("DistanceThresholds", "FarDistance", 50f, "Far distance in meters. Good candidate range for more aggressive visual optimizations."); _veryFarDistance = ((BaseUnityPlugin)this).Config.Bind("DistanceThresholds", "VeryFarDistance", 100f, "Very far distance in meters. Future proxy/mesh-combining territory."); _extremeDistance = ((BaseUnityPlugin)this).Config.Bind("DistanceThresholds", "ExtremeDistance", 200f, "Extreme distance in meters. Future impostor/proxy-only territory."); _optimizerUpdateInterval = ((BaseUnityPlugin)this).Config.Bind("Optimizations", "OptimizerUpdateIntervalSeconds", 0.5f, "How often the optimizer checks fire pieces, in seconds. Lower values react faster but cost more performance."); _fireCandidateRefreshInterval = ((BaseUnityPlugin)this).Config.Bind("Optimizations", "FireCandidateRefreshIntervalSeconds", 5f, "How often the optimizer does a full scene scan to discover fire pieces. Cached candidates are used between scans."); _fireRestoreGraceSeconds = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "RestoreGraceSeconds", 1f, "How long a fire must remain relevant/visible before optimized fire effects are restored. Helps prevent flickering near occlusion edges."); _fireCullingMode = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "FireCullingMode", FireCullingMode.StaticLight, "Fire optimization mode. Off = no fire optimization, StaticLight = replace dynamic fire effects with a cheap static light, FullCull = disable fire visuals/effects at distance."); _useFireOcclusionCulling = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "UseOcclusionCulling", true, "If true, fire candidates that are inside the camera view but blocked by solid geometry are treated as hidden/irrelevant."); _fireOcclusionRayRadius = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "OcclusionRayRadius", 0.05f, "Radius used for fire occlusion spherecasts. 0 uses a normal raycast. Small values like 0.05-0.15 can make occlusion detection more forgiving."); _debugFireOcclusion = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "DebugFireOcclusion", false, "If true, draws debug rays for fire occlusion checks in the Unity scene view/logical debug view where supported."); _useFireVisibilityCulling = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "UseVisibilityCulling", true, "If true, fire effects may be optimized when the fire is not visible for a short grace period."); _fireVisibilityGraceSeconds = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "VisibilityGraceSeconds", 1.5f, "How long a fire must remain not visible before visibility-based optimization can activate."); _neverOptimizeFireWithin = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "NeverOptimizeFireWithin", 2f, "Fire pieces closer than this distance are never optimized."); _minimumFullCullDistance = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "MinimumFullCullDistance", 15f, "Minimum distance required before FullCull mode may fully remove fire light/effects due to visibility."); _fireDistanceCullStart = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "FireDistanceCullStart", 50f, "Distance beyond which fire optimization activates regardless of visibility."); _fireDistanceRestore = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "FireDistanceRestore", 40f, "Distance within which fire optimization restores to normal. Should be lower than FireDistanceCullStart."); _staticLightIntensityMultiplier = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "StaticLightIntensityMultiplier", 0.65f, "Multiplier for proxy static light intensity in StaticLight mode."); _staticLightRangeMultiplier = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "StaticLightRangeMultiplier", 0.85f, "Multiplier for proxy static light range in StaticLight mode."); _staticLightProxyMaxDistance = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "StaticLightProxyMaxDistance", 50f, "Maximum distance at which StaticLight mode may create a proxy light for relevant/visible fires. Beyond this, optimized fires get particles/shadows removed but no replacement light."); _staticLightOccludedProxyMaxDistance = ((BaseUnityPlugin)this).Config.Bind("FireCulling", "StaticLightOccludedProxyMaxDistance", 25f, "Maximum distance at which StaticLight mode may create a proxy light for hidden or occluded fires. Farther hidden fires receive no proxy light."); _showOverlay = _showProfilerOnStart.Value; _opaqueBackground = MakeTexture(2, 2, new Color(0.05f, 0.05f, 0.05f, 1f)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Build Piece Profiler 0.2.0 loaded."); } private void Update() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (_enableProfiler.Value) { if (Input.GetKeyDown(_toggleProfilerKey.Value)) { _showOverlay = !_showOverlay; } bool flag = _showOverlay || _enableConsoleLogging.Value; float num = Mathf.Max(0.1f, _profilerPollInterval.Value); if (flag && Time.time >= _nextPollTime) { _nextPollTime = Time.time + num; _counts = PollCounts(); if (_enableConsoleLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)($"Pieces={_counts.Pieces}, " + $"WearNTear={_counts.WearNTear}, " + $"ZNetView={_counts.ZNetView}, " + $"MeshRenderer={_counts.MeshRenderer}, " + $"EnabledMeshRenderer={_counts.EnabledMeshRenderer}, " + $"VisibleMeshRenderer={_counts.VisibleMeshRenderer}, " + $"Collider={_counts.Collider}, " + $"EnabledCollider={_counts.EnabledCollider}, " + $"LODGroup={_counts.LODGroup}, " + $"Light={_counts.Light}, " + $"EnabledLight={_counts.EnabledLight}, " + $"ParticleSystem={_counts.ParticleSystem}, " + $"ActiveParticleSystem={_counts.ActiveParticleSystem}, " + $"AudioSource={_counts.AudioSource}, " + $"ActiveRigidbody={_counts.ActiveRigidbody}, " + $"PieceMeshRenderer={_counts.PieceMeshRenderer}, " + $"PieceEnabledMeshRenderer={_counts.PieceEnabledMeshRenderer}, " + $"PieceVisibleMeshRenderer={_counts.PieceVisibleMeshRenderer}, " + $"PieceCollider={_counts.PieceCollider}, " + $"PieceEnabledCollider={_counts.PieceEnabledCollider}")); } } } if (!_enableOptimizations.Value || _fireCullingMode.Value == FireCullingMode.Off) { if (_optimizationsWereActive || HasActiveFireOptimizations()) { RestoreAllFireOptimizations(); ResetFireCandidateCache(); } _optimizationsWereActive = false; return; } if (!_optimizationsWereActive) { _nextOptimizerUpdateTime = 0f; _nextFireCandidateRefreshTime = 0f; _optimizationsWereActive = true; } float num2 = Mathf.Max(0.1f, _optimizerUpdateInterval.Value); if (Time.time >= _nextOptimizerUpdateTime) { _nextOptimizerUpdateTime = Time.time + num2; UpdateFireOptimizations(); } } private void OnGUI() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (_enableProfiler.Value && _showOverlay) { _windowRect = GUILayout.Window(872391, _windowRect, new WindowFunction(DrawWindow), "Build Piece Profiler", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(520f), GUILayout.Height(940f) }); } } private void DrawWindow(int windowId) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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) GUI.DrawTexture(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width, ((Rect)(ref _windowRect)).height), (Texture)(object)_opaqueBackground, (ScaleMode)0); _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(500f), GUILayout.Height(1050f) }); GUILayout.Label("Toggle overlay: F7", Array.Empty()); GUILayout.Label($"Poll interval: {_profilerPollInterval.Value:0.0}s", Array.Empty()); GUILayout.Label($"Optimizations enabled: {_enableOptimizations.Value}", Array.Empty()); GUILayout.Space(8f); GUILayout.Label("Global Scene Counts", Array.Empty()); GUILayout.Label($"Total Piece count: {_counts.Pieces}", Array.Empty()); GUILayout.Label($"Total WearNTear count: {_counts.WearNTear}", Array.Empty()); GUILayout.Label($"Total ZNetView count: {_counts.ZNetView}", Array.Empty()); GUILayout.Space(8f); GUILayout.Label("Global Renderers", Array.Empty()); GUILayout.Label($"Total MeshRenderer count: {_counts.MeshRenderer}", Array.Empty()); GUILayout.Label($"Enabled MeshRenderer count: {_counts.EnabledMeshRenderer}", Array.Empty()); GUILayout.Label($"Visible MeshRenderer count: {_counts.VisibleMeshRenderer}", Array.Empty()); GUILayout.Label($"Total LODGroup count: {_counts.LODGroup}", Array.Empty()); GUILayout.Space(8f); GUILayout.Label("Global Physics", Array.Empty()); GUILayout.Label($"Total Collider count: {_counts.Collider}", Array.Empty()); GUILayout.Label($"Enabled Collider count: {_counts.EnabledCollider}", Array.Empty()); GUILayout.Label($"Total active Rigidbody count: {_counts.ActiveRigidbody}", Array.Empty()); GUILayout.Space(8f); GUILayout.Label("Global Effects", Array.Empty()); GUILayout.Label($"Total Light count: {_counts.Light}", Array.Empty()); GUILayout.Label($"Enabled Light count: {_counts.EnabledLight}", Array.Empty()); GUILayout.Label($"Total ParticleSystem count: {_counts.ParticleSystem}", Array.Empty()); GUILayout.Label($"Active ParticleSystem count: {_counts.ActiveParticleSystem}", Array.Empty()); GUILayout.Label($"Total AudioSource count: {_counts.AudioSource}", Array.Empty()); GUILayout.Space(12f); GUILayout.Label("Build-Piece-Only Counts", Array.Empty()); GUILayout.Label($"Build-piece MeshRenderer count: {_counts.PieceMeshRenderer}", Array.Empty()); GUILayout.Label($"Build-piece enabled MeshRenderer count: {_counts.PieceEnabledMeshRenderer}", Array.Empty()); GUILayout.Label($"Build-piece visible MeshRenderer count: {_counts.PieceVisibleMeshRenderer}", Array.Empty()); GUILayout.Label($"Build-piece LODGroup count: {_counts.PieceLODGroup}", Array.Empty()); GUILayout.Space(8f); GUILayout.Label("Build-Piece Distance Buckets", Array.Empty()); GUILayout.Label($"Pieces within Near ({_nearDistance.Value:0}m): {_counts.PiecesWithinNear}", Array.Empty()); GUILayout.Label($"Pieces within Medium ({_mediumDistance.Value:0}m): {_counts.PiecesWithinMedium}", Array.Empty()); GUILayout.Label($"Pieces within Far ({_farDistance.Value:0}m): {_counts.PiecesWithinFar}", Array.Empty()); GUILayout.Label($"Pieces within Very Far ({_veryFarDistance.Value:0}m): {_counts.PiecesWithinVeryFar}", Array.Empty()); GUILayout.Label($"Pieces within Extreme ({_extremeDistance.Value:0}m): {_counts.PiecesWithinExtreme}", Array.Empty()); GUILayout.Label($"Pieces beyond Extreme: {_counts.PiecesBeyondExtreme}", Array.Empty()); GUILayout.Label($"Nearest piece distance: {_counts.NearestPieceDistance:0.0}m", Array.Empty()); GUILayout.Label($"Farthest piece distance: {_counts.FarthestPieceDistance:0.0}m", Array.Empty()); GUILayout.Space(8f); GUILayout.Label("Build-Piece Physics", Array.Empty()); GUILayout.Label($"Build-piece Collider count: {_counts.PieceCollider}", Array.Empty()); GUILayout.Label($"Build-piece enabled Collider count: {_counts.PieceEnabledCollider}", Array.Empty()); GUILayout.Label($"Build-piece Rigidbody count: {_counts.PieceRigidbody}", Array.Empty()); GUILayout.Label($"Build-piece active Rigidbody count: {_counts.PieceActiveRigidbody}", Array.Empty()); GUILayout.Space(8f); GUILayout.Label("Build-Piece Effects", Array.Empty()); GUILayout.Label($"Build-piece Light count: {_counts.PieceLight}", Array.Empty()); GUILayout.Label($"Build-piece enabled Light count: {_counts.PieceEnabledLight}", Array.Empty()); GUILayout.Label($"Build-piece ParticleSystem count: {_counts.PieceParticleSystem}", Array.Empty()); GUILayout.Label($"Build-piece active ParticleSystem count: {_counts.PieceActiveParticleSystem}", Array.Empty()); GUILayout.Label($"Build-piece AudioSource count: {_counts.PieceAudioSource}", Array.Empty()); GUILayout.Space(8f); GUILayout.Label("Fire Optimization Candidates", Array.Empty()); GUILayout.Label($"Fire candidates: {_counts.FireCandidates}", Array.Empty()); GUILayout.Label($"Renderer-visible fire candidates: {_counts.RendererVisibleFireCandidates}", Array.Empty()); GUILayout.Label($"Occluded fire candidates: {_counts.OccludedFireCandidates}", Array.Empty()); GUILayout.Label($"Relevant fire candidates: {_counts.RelevantFireCandidates}", Array.Empty()); GUILayout.Label($"Hidden/irrelevant fire candidates: {_counts.HiddenOrIrrelevantFireCandidates}", Array.Empty()); GUILayout.Label($"Fire culling mode: {_fireCullingMode.Value}", Array.Empty()); GUILayout.Label($"Visibility culling: {_useFireVisibilityCulling.Value}", Array.Empty()); GUILayout.Label($"Occlusion culling: {_useFireOcclusionCulling.Value}", Array.Empty()); GUILayout.Label($"Optimized fire pieces: {_counts.OptimizedFirePieces}", Array.Empty()); GUILayout.Label($"StaticLight fire pieces: {_counts.StaticLightFirePieces}", Array.Empty()); GUILayout.Label($"FullCull fire pieces: {_counts.FullCullFirePieces}", Array.Empty()); GUILayout.Label($"Fire proxy lights active: {_counts.FireProxyLightsActive}", Array.Empty()); GUILayout.Label($"Original fire lights disabled: {_counts.FireOriginalLightsDisabled}", Array.Empty()); GUILayout.Label($"Fire particles stopped: {_counts.FireParticlesStopped}", Array.Empty()); GUILayout.Label($"Fire shadows disabled: {_counts.FireShadowsDisabled}", Array.Empty()); GUILayout.Space(8f); if (GUILayout.Button("Poll now", Array.Empty())) { _counts = PollCounts(); } GUILayout.EndScrollView(); GUI.DragWindow(); } private Texture2D MakeTexture(int width, int height, Color color) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_002e: Expected O, but got Unknown Color[] array = (Color[])(object)new Color[width * height]; for (int i = 0; i < array.Length; i++) { array[i] = color; } Texture2D val = new Texture2D(width, height); val.SetPixels(array); val.Apply(); return val; } private Counts PollCounts() { //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) Piece[] array = Object.FindObjectsByType((FindObjectsSortMode)0); WearNTear[] array2 = Object.FindObjectsByType((FindObjectsSortMode)0); ZNetView[] array3 = Object.FindObjectsByType((FindObjectsSortMode)0); MeshRenderer[] array4 = Object.FindObjectsByType((FindObjectsSortMode)0); Collider[] array5 = Object.FindObjectsByType((FindObjectsSortMode)0); LODGroup[] array6 = Object.FindObjectsByType((FindObjectsSortMode)0); Light[] array7 = Object.FindObjectsByType((FindObjectsSortMode)0); ParticleSystem[] array8 = Object.FindObjectsByType((FindObjectsSortMode)0); AudioSource[] array9 = Object.FindObjectsByType((FindObjectsSortMode)0); Rigidbody[] array10 = Object.FindObjectsByType((FindObjectsSortMode)0); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; MeshRenderer[] array11 = array4; foreach (MeshRenderer val in array11) { if (!((Object)(object)val == (Object)null)) { if (((Renderer)val).enabled && ((Component)val).gameObject.activeInHierarchy) { num++; } if (((Renderer)val).enabled && ((Component)val).gameObject.activeInHierarchy && ((Renderer)val).isVisible) { num2++; } } } Collider[] array12 = array5; foreach (Collider val2 in array12) { if ((Object)(object)val2 != (Object)null && val2.enabled && ((Component)val2).gameObject.activeInHierarchy) { num3++; } } Light[] array13 = array7; foreach (Light val3 in array13) { if ((Object)(object)val3 != (Object)null && ((Behaviour)val3).enabled && ((Component)val3).gameObject.activeInHierarchy) { num4++; } } ParticleSystem[] array14 = array8; foreach (ParticleSystem val4 in array14) { if ((Object)(object)val4 != (Object)null && ((Component)val4).gameObject.activeInHierarchy && val4.IsAlive(true)) { num5++; } } Rigidbody[] array15 = array10; foreach (Rigidbody val5 in array15) { if ((Object)(object)val5 != (Object)null && ((Component)val5).gameObject.activeInHierarchy && !val5.IsSleeping()) { num6++; } } int num7 = 0; int num8 = 0; int num9 = 0; int num10 = 0; int num11 = 0; int num12 = 0; int num13 = 0; int num14 = 0; int num15 = 0; int num16 = 0; int num17 = 0; int num18 = 0; int num19 = 0; Vector3 val6 = Vector3.zero; bool flag = (Object)(object)Player.m_localPlayer != (Object)null; if (flag) { val6 = ((Component)Player.m_localPlayer).transform.position; } float num20 = Mathf.Max(1f, _nearDistance.Value); float num21 = Mathf.Max(num20, _mediumDistance.Value); float num22 = Mathf.Max(num21, _farDistance.Value); float num23 = Mathf.Max(num22, _veryFarDistance.Value); float num24 = Mathf.Max(num23, _extremeDistance.Value); int num25 = 0; int num26 = 0; int num27 = 0; int num28 = 0; int num29 = 0; int num30 = 0; float num31 = float.MaxValue; float num32 = 0f; int num33 = 0; int num34 = 0; int num35 = 0; int num36 = 0; int num37 = 0; bool flag2 = _enableOptimizations.Value && _fireCullingMode.Value != FireCullingMode.Off; Camera mainCamera = (flag2 ? null : Camera.main); Piece[] array16 = array; foreach (Piece val7 in array16) { if ((Object)(object)val7 == (Object)null) { continue; } if (flag) { float num38 = Vector3.Distance(val6, ((Component)val7).transform.position); if (num38 <= num20) { num25++; } if (num38 <= num21) { num26++; } if (num38 <= num22) { num27++; } if (num38 <= num23) { num28++; } if (num38 <= num24) { num29++; } else { num30++; } if (num38 < num31) { num31 = num38; } if (num38 > num32) { num32 = num38; } } MeshRenderer[] componentsInChildren = ((Component)val7).GetComponentsInChildren(true); Collider[] componentsInChildren2 = ((Component)val7).GetComponentsInChildren(true); LODGroup[] componentsInChildren3 = ((Component)val7).GetComponentsInChildren(true); Light[] componentsInChildren4 = ((Component)val7).GetComponentsInChildren(true); ParticleSystem[] componentsInChildren5 = ((Component)val7).GetComponentsInChildren(true); if (!flag2) { Light[] originalLights = GetOriginalLights(componentsInChildren4); if (IsFireCandidate(originalLights, componentsInChildren5)) { num33++; bool flag3 = IsPieceVisible(componentsInChildren); bool flag4 = flag3 && IsFireOccludedFromCamera(val7, originalLights, componentsInChildren, mainCamera); bool flag5 = flag3 && !flag4; if (flag3) { num34++; } if (flag4) { num35++; } if (flag5) { num36++; } else { num37++; } } } AudioSource[] componentsInChildren6 = ((Component)val7).GetComponentsInChildren(true); Rigidbody[] componentsInChildren7 = ((Component)val7).GetComponentsInChildren(true); num7 += componentsInChildren.Length; num10 += componentsInChildren2.Length; num12 += componentsInChildren3.Length; num13 += componentsInChildren4.Length; num15 += componentsInChildren5.Length; num17 += componentsInChildren6.Length; num18 += componentsInChildren7.Length; MeshRenderer[] array17 = componentsInChildren; foreach (MeshRenderer val8 in array17) { if (!((Object)(object)val8 == (Object)null)) { if (((Renderer)val8).enabled && ((Component)val8).gameObject.activeInHierarchy) { num8++; } if (((Renderer)val8).enabled && ((Component)val8).gameObject.activeInHierarchy && ((Renderer)val8).isVisible) { num9++; } } } Collider[] array18 = componentsInChildren2; foreach (Collider val9 in array18) { if ((Object)(object)val9 != (Object)null && val9.enabled && ((Component)val9).gameObject.activeInHierarchy) { num11++; } } Light[] array19 = componentsInChildren4; foreach (Light val10 in array19) { if ((Object)(object)val10 != (Object)null && ((Behaviour)val10).enabled && ((Component)val10).gameObject.activeInHierarchy) { num14++; } } ParticleSystem[] array20 = componentsInChildren5; foreach (ParticleSystem val11 in array20) { if ((Object)(object)val11 != (Object)null && ((Component)val11).gameObject.activeInHierarchy && val11.IsAlive(true)) { num16++; } } Rigidbody[] array21 = componentsInChildren7; foreach (Rigidbody val12 in array21) { if ((Object)(object)val12 != (Object)null && ((Component)val12).gameObject.activeInHierarchy && !val12.IsSleeping()) { num19++; } } } if (!flag || array.Length == 0) { num31 = 0f; num32 = 0f; } FireMetrics fireMetrics2; if (!flag2) { FireMetrics fireMetrics = default(FireMetrics); fireMetrics.FireCandidates = num33; fireMetrics.RendererVisibleFireCandidates = num34; fireMetrics.OccludedFireCandidates = num35; fireMetrics.RelevantFireCandidates = num36; fireMetrics.HiddenOrIrrelevantFireCandidates = num37; fireMetrics2 = fireMetrics; } else { fireMetrics2 = _fireMetrics; } FireMetrics metrics = fireMetrics2; if (!flag2) { AddFireOptimizationStateMetrics(ref metrics); } Counts result = default(Counts); result.Pieces = array.Length; result.WearNTear = array2.Length; result.ZNetView = array3.Length; result.MeshRenderer = array4.Length; result.EnabledMeshRenderer = num; result.VisibleMeshRenderer = num2; result.Collider = array5.Length; result.EnabledCollider = num3; result.LODGroup = array6.Length; result.Light = array7.Length; result.EnabledLight = num4; result.ParticleSystem = array8.Length; result.ActiveParticleSystem = num5; result.AudioSource = array9.Length; result.ActiveRigidbody = num6; result.PieceMeshRenderer = num7; result.PieceEnabledMeshRenderer = num8; result.PieceVisibleMeshRenderer = num9; result.PieceCollider = num10; result.PieceEnabledCollider = num11; result.PieceLODGroup = num12; result.PieceLight = num13; result.PieceEnabledLight = num14; result.PieceParticleSystem = num15; result.PieceActiveParticleSystem = num16; result.PieceAudioSource = num17; result.PieceRigidbody = num18; result.PieceActiveRigidbody = num19; result.PiecesWithinNear = num25; result.PiecesWithinMedium = num26; result.PiecesWithinFar = num27; result.PiecesWithinVeryFar = num28; result.PiecesWithinExtreme = num29; result.PiecesBeyondExtreme = num30; result.NearestPieceDistance = num31; result.FarthestPieceDistance = num32; result.FireCandidates = metrics.FireCandidates; result.RendererVisibleFireCandidates = metrics.RendererVisibleFireCandidates; result.OccludedFireCandidates = metrics.OccludedFireCandidates; result.RelevantFireCandidates = metrics.RelevantFireCandidates; result.HiddenOrIrrelevantFireCandidates = metrics.HiddenOrIrrelevantFireCandidates; result.OptimizedFirePieces = metrics.OptimizedFirePieces; result.StaticLightFirePieces = metrics.StaticLightFirePieces; result.FullCullFirePieces = metrics.FullCullFirePieces; result.FireProxyLightsActive = metrics.FireProxyLightsActive; result.FireOriginalLightsDisabled = metrics.FireOriginalLightsDisabled; result.FireParticlesStopped = metrics.FireParticlesStopped; result.FireShadowsDisabled = metrics.FireShadowsDisabled; return result; } }