Decompiled source of Nutcracker Fire Warning v1.0.2

BepInEx/plugins/NutcrackerFireWarning/NutcrackerFireWarning.dll

Decompiled 3 hours ago
using System;
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 GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("NutcrackerFireWarning")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("NutcrackerFireWarning")]
[assembly: AssemblyTitle("NutcrackerFireWarning")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace NutcrackerShotUI
{
	internal sealed class NutcrackerModelFireWindowOutline
	{
		private sealed class MeshOutlineClone
		{
			private readonly Renderer source;

			private readonly GameObject cloneObject;

			private readonly MeshFilter cloneFilter;

			private readonly MeshRenderer cloneMeshRenderer;

			private readonly SkinnedMeshRenderer cloneSkinnedRenderer;

			private readonly SkinnedMeshRenderer skinnedSource;

			private readonly Mesh sourceSkinnedMesh;

			private readonly Mesh sourceStaticMesh;

			private readonly Mesh expandedMesh;

			private readonly Material[] outlineMaterials;

			private readonly Vector3 sourceLocalScale;

			private readonly bool canExpandMesh;

			private float lastOutlineWidth = -1f;

			private MeshOutlineClone(Renderer source, GameObject cloneObject, MeshFilter cloneFilter, MeshRenderer cloneMeshRenderer, SkinnedMeshRenderer cloneSkinnedRenderer, SkinnedMeshRenderer skinnedSource, Mesh sourceSkinnedMesh, Mesh sourceStaticMesh, Mesh expandedMesh, Material[] outlineMaterials, bool canExpandMesh)
			{
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				this.source = source;
				this.cloneObject = cloneObject;
				this.cloneFilter = cloneFilter;
				this.cloneMeshRenderer = cloneMeshRenderer;
				this.cloneSkinnedRenderer = cloneSkinnedRenderer;
				this.skinnedSource = skinnedSource;
				this.sourceSkinnedMesh = sourceSkinnedMesh;
				this.sourceStaticMesh = sourceStaticMesh;
				this.expandedMesh = expandedMesh;
				this.outlineMaterials = outlineMaterials;
				this.canExpandMesh = canExpandMesh;
				sourceLocalScale = ((Component)source).transform.localScale;
			}

			public static MeshOutlineClone TryCreate(Renderer source, Material material)
			{
				//IL_012e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0135: Expected O, but got Unknown
				//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)source == (Object)null || (Object)(object)material == (Object)null)
				{
					return null;
				}
				Mesh val = null;
				Mesh val2 = null;
				Mesh val3 = null;
				Mesh val4 = null;
				bool flag = false;
				SkinnedMeshRenderer val5 = (SkinnedMeshRenderer)(object)((source is SkinnedMeshRenderer) ? source : null);
				if ((Object)(object)val5 != (Object)null)
				{
					if ((Object)(object)val5.sharedMesh == (Object)null)
					{
						return null;
					}
					val4 = val5.sharedMesh;
					flag = val4.isReadable;
					if (flag)
					{
						val2 = Object.Instantiate<Mesh>(val4);
						((Object)val2).name = ((Object)source).name + "_NutcrackerOutlineExpandedMesh";
						val2.MarkDynamic();
						val = val2;
					}
					else
					{
						val = val4;
					}
				}
				else
				{
					MeshFilter component = ((Component)source).GetComponent<MeshFilter>();
					if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null)
					{
						return null;
					}
					val3 = component.sharedMesh;
					flag = val3.isReadable;
					if (flag)
					{
						val2 = Object.Instantiate<Mesh>(val3);
						((Object)val2).name = ((Object)source).name + "_NutcrackerOutlineExpandedMesh";
						val = val2;
					}
					else
					{
						val = val3;
					}
				}
				GameObject val6 = new GameObject(((Object)source).name + "_NutcrackerMeshOutline");
				((Object)val6).hideFlags = (HideFlags)61;
				val6.layer = ((Component)source).gameObject.layer;
				val6.transform.SetParent(((Component)source).transform.parent, false);
				MeshFilter val7 = null;
				MeshRenderer val8 = null;
				SkinnedMeshRenderer val9 = null;
				Material[] sharedMaterials = CreateOutlineMaterials(source.sharedMaterials, material);
				if ((Object)(object)val5 != (Object)null)
				{
					val9 = val6.AddComponent<SkinnedMeshRenderer>();
					val9.sharedMesh = val;
					((Renderer)val9).sharedMaterials = sharedMaterials;
					val9.bones = val5.bones;
					val9.rootBone = val5.rootBone;
					val9.quality = val5.quality;
					val9.updateWhenOffscreen = true;
					((Renderer)val9).localBounds = ExpandBounds(((Renderer)val5).localBounds, 0.25f);
					ConfigureCloneRenderer((Renderer)(object)val9);
				}
				else
				{
					val7 = val6.AddComponent<MeshFilter>();
					val8 = val6.AddComponent<MeshRenderer>();
					val7.sharedMesh = val;
					((Renderer)val8).sharedMaterials = sharedMaterials;
					ConfigureCloneRenderer((Renderer)(object)val8);
				}
				val6.SetActive(false);
				MeshOutlineClone meshOutlineClone = new MeshOutlineClone(source, val6, val7, val8, val9, val5, val4, val3, val2, sharedMaterials, flag);
				meshOutlineClone.CopyTransform(1f);
				return meshOutlineClone;
			}

			public bool Update(Color color, float outlineWidth, float scale)
			{
				//IL_0129: 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_00bd: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)source == (Object)null || (Object)(object)cloneObject == (Object)null || !source.enabled)
				{
					SetVisible(visible: false);
					return false;
				}
				if ((Object)(object)skinnedSource != (Object)null)
				{
					if (canExpandMesh && (Object)(object)expandedMesh != (Object)null && !Mathf.Approximately(lastOutlineWidth, outlineWidth))
					{
						ExpandMeshAlongNormals(sourceSkinnedMesh, expandedMesh, outlineWidth);
						cloneSkinnedRenderer.sharedMesh = expandedMesh;
						((Renderer)cloneSkinnedRenderer).localBounds = ExpandBounds(((Renderer)skinnedSource).localBounds, outlineWidth + 0.25f);
					}
				}
				else if (canExpandMesh && (Object)(object)expandedMesh != (Object)null && !Mathf.Approximately(lastOutlineWidth, outlineWidth))
				{
					ExpandMeshAlongNormals(sourceStaticMesh, expandedMesh, outlineWidth);
					cloneFilter.sharedMesh = expandedMesh;
				}
				lastOutlineWidth = outlineWidth;
				SetMaterialsColor(color);
				CopyTransform(scale);
				SetVisible(visible: true);
				return true;
			}

			public string GetShaderSummary()
			{
				if (outlineMaterials == null || outlineMaterials.Length == 0 || (Object)(object)outlineMaterials[0] == (Object)null || (Object)(object)outlineMaterials[0].shader == (Object)null)
				{
					return "none";
				}
				return ((Object)outlineMaterials[0].shader).name;
			}

			public void SetVisible(bool visible)
			{
				if ((Object)(object)cloneObject != (Object)null && cloneObject.activeSelf != visible)
				{
					cloneObject.SetActive(visible);
				}
			}

			public void Dispose()
			{
				if ((Object)(object)expandedMesh != (Object)null)
				{
					Object.Destroy((Object)(object)expandedMesh);
				}
				if (outlineMaterials != null)
				{
					for (int i = 0; i < outlineMaterials.Length; i++)
					{
						if ((Object)(object)outlineMaterials[i] != (Object)null)
						{
							Object.Destroy((Object)(object)outlineMaterials[i]);
						}
					}
				}
				if ((Object)(object)cloneObject != (Object)null)
				{
					Object.Destroy((Object)(object)cloneObject);
				}
			}

			private void CopyTransform(float scale)
			{
				//IL_001b: 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_0035: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				Transform transform = ((Component)source).transform;
				Transform transform2 = cloneObject.transform;
				transform2.localPosition = transform.localPosition;
				transform2.localRotation = transform.localRotation;
				transform2.localScale = sourceLocalScale * scale;
			}

			private void SetMaterialsColor(Color color)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				if (outlineMaterials != null)
				{
					for (int i = 0; i < outlineMaterials.Length; i++)
					{
						SetMaterialColor(outlineMaterials[i], color);
					}
				}
			}

			private static void ConfigureCloneRenderer(Renderer renderer)
			{
				renderer.shadowCastingMode = (ShadowCastingMode)0;
				renderer.receiveShadows = false;
				renderer.allowOcclusionWhenDynamic = false;
				renderer.forceRenderingOff = false;
				renderer.enabled = true;
			}

			private static Bounds ExpandBounds(Bounds bounds, float amount)
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				((Bounds)(ref bounds)).Expand(amount);
				return bounds;
			}

			private static void ExpandMeshAlongNormals(Mesh sourceMesh, Mesh targetMesh, float outlineWidth)
			{
				//IL_007a: 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_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: 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_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_0139: Unknown result type (might be due to invalid IL or missing references)
				//IL_013e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0155: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)sourceMesh == (Object)null) && !((Object)(object)targetMesh == (Object)null))
				{
					Vector3[] vertices = sourceMesh.vertices;
					Vector3[] normals = sourceMesh.normals;
					if (normals == null || normals.Length != vertices.Length)
					{
						sourceMesh.RecalculateNormals();
						normals = sourceMesh.normals;
					}
					Vector3[] array = (Vector3[])(object)new Vector3[vertices.Length];
					for (int i = 0; i < vertices.Length; i++)
					{
						Vector3 val = ((normals.Length > i) ? ((Vector3)(ref normals[i])).normalized : Vector3.zero);
						array[i] = vertices[i] + val * outlineWidth;
					}
					targetMesh.Clear();
					targetMesh.vertices = array;
					targetMesh.normals = normals;
					targetMesh.tangents = sourceMesh.tangents;
					targetMesh.uv = sourceMesh.uv;
					targetMesh.uv2 = sourceMesh.uv2;
					targetMesh.colors = sourceMesh.colors;
					targetMesh.subMeshCount = sourceMesh.subMeshCount;
					for (int j = 0; j < sourceMesh.subMeshCount; j++)
					{
						targetMesh.SetTriangles(sourceMesh.GetTriangles(j), j);
					}
					Bounds bounds = sourceMesh.bounds;
					((Bounds)(ref bounds)).Expand(outlineWidth * 2f + 0.02f);
					targetMesh.bounds = bounds;
				}
			}

			private static Material[] CreateOutlineMaterials(Material[] sourceMaterials, Material fallbackMaterial)
			{
				//IL_009b: Unknown result type (might be due to invalid IL or missing references)
				int num = ((sourceMaterials != null) ? sourceMaterials.Length : 0);
				num = Mathf.Max(1, num);
				Material[] array = (Material[])(object)new Material[num];
				for (int i = 0; i < array.Length; i++)
				{
					Material val = ((sourceMaterials != null && i < sourceMaterials.Length) ? sourceMaterials[i] : null);
					Material val2 = (((Object)(object)val != (Object)null) ? Object.Instantiate<Material>(val) : Object.Instantiate<Material>(fallbackMaterial));
					((Object)val2).name = (((Object)(object)val != (Object)null) ? ((Object)val).name : "Fallback") + "_NutcrackerOutlineMaterial";
					((Object)val2).hideFlags = (HideFlags)61;
					ConfigureOutlineMaterial(val2);
					SetMaterialColor(val2, new Color(1f, 0.02f, 0.02f, 0.86f));
					array[i] = val2;
				}
				return array;
			}
		}

		private sealed class SourceRendererPulse
		{
			private static readonly int BaseColorId = Shader.PropertyToID("_BaseColor");

			private static readonly int ColorId = Shader.PropertyToID("_Color");

			private static readonly int UnlitColorId = Shader.PropertyToID("_UnlitColor");

			private static readonly int EmissionColorId = Shader.PropertyToID("_EmissionColor");

			private static readonly int EmissiveColorId = Shader.PropertyToID("_EmissiveColor");

			private static readonly int EmissiveColorLdrId = Shader.PropertyToID("_EmissiveColorLDR");

			private readonly Renderer renderer;

			private readonly MaterialPropertyBlock originalBlock = new MaterialPropertyBlock();

			private readonly MaterialPropertyBlock pulseBlock = new MaterialPropertyBlock();

			private bool capturedOriginalBlock;

			private bool hadOriginalBlock;

			private bool active;

			private SourceRendererPulse(Renderer renderer)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Expected O, but got Unknown
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Expected O, but got Unknown
				this.renderer = renderer;
			}

			public static SourceRendererPulse TryCreate(Renderer renderer)
			{
				if ((Object)(object)renderer == (Object)null)
				{
					return null;
				}
				return new SourceRendererPulse(renderer);
			}

			public bool Apply(Color color, float emissionMultiplier)
			{
				//IL_004e: 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_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: 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_009f: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)renderer == (Object)null || !renderer.enabled)
				{
					Restore();
					return false;
				}
				CaptureOriginalBlockIfNeeded();
				renderer.GetPropertyBlock(pulseBlock);
				Color val = default(Color);
				((Color)(ref val))..ctor(color.r * emissionMultiplier, color.g * emissionMultiplier, color.b * emissionMultiplier, 1f);
				pulseBlock.SetColor(BaseColorId, color);
				pulseBlock.SetColor(ColorId, color);
				pulseBlock.SetColor(UnlitColorId, color);
				pulseBlock.SetColor(EmissionColorId, val);
				pulseBlock.SetColor(EmissiveColorId, val);
				pulseBlock.SetColor(EmissiveColorLdrId, val);
				renderer.SetPropertyBlock(pulseBlock);
				active = true;
				return true;
			}

			public void Restore()
			{
				if (!((Object)(object)renderer == (Object)null) && active)
				{
					if (hadOriginalBlock)
					{
						renderer.SetPropertyBlock(originalBlock);
					}
					else
					{
						renderer.SetPropertyBlock((MaterialPropertyBlock)null);
					}
					active = false;
				}
			}

			public void Dispose()
			{
				Restore();
			}

			private void CaptureOriginalBlockIfNeeded()
			{
				if (!capturedOriginalBlock)
				{
					renderer.GetPropertyBlock(originalBlock);
					hadOriginalBlock = !originalBlock.isEmpty;
					capturedOriginalBlock = true;
				}
			}
		}

		private const float ScreenPadding = 18f;

		private const float MinScreenWidth = 72f;

		private const float MinScreenHeight = 120f;

		private readonly NutcrackerEnemyAI nutcracker;

		private readonly Material meshMaterial;

		private readonly List<MeshOutlineClone> meshClones = new List<MeshOutlineClone>();

		private readonly List<SourceRendererPulse> sourcePulses = new List<SourceRendererPulse>();

		private GameObject screenRoot;

		private Canvas screenCanvas;

		private RectTransform screenCanvasRect;

		private RectTransform screenBoxRect;

		private Image screenTop;

		private Image screenBottom;

		private Image screenLeft;

		private Image screenRight;

		private Renderer[] cachedRenderers;

		private float nextRendererRefreshTime;

		private bool meshBuilt;

		private bool loggedMeshVisible;

		private bool loggedScreenVisible;

		public NutcrackerModelFireWindowOutline(NutcrackerEnemyAI nutcracker, Transform parent)
		{
			this.nutcracker = nutcracker;
			meshMaterial = CreateMeshMaterial();
		}

		public void Dispose()
		{
			ClearMeshClones();
			if ((Object)(object)meshMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)meshMaterial);
			}
			if ((Object)(object)screenRoot != (Object)null)
			{
				Object.Destroy((Object)(object)screenRoot);
			}
		}

		public void Update(bool active)
		{
			if (!active || (Object)(object)nutcracker == (Object)null)
			{
				loggedMeshVisible = false;
				loggedScreenVisible = false;
				SetMeshVisible(visible: false);
				SetScreenVisible(visible: false);
			}
			else if (GetMode() == ModelOutlineMode.ScreenBox)
			{
				SetMeshVisible(visible: false);
				UpdateScreenBox();
			}
			else
			{
				SetScreenVisible(visible: false);
				UpdateMeshSilhouette();
			}
		}

		private void UpdateMeshSilhouette()
		{
			//IL_0056: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			EnsureMeshClones();
			if (meshClones.Count == 0 && sourcePulses.Count == 0)
			{
				SetMeshVisible(visible: false);
				return;
			}
			float pulseAlpha = GetPulseAlpha();
			float pulseIntensity = GetPulseIntensity();
			Color color = Color.Lerp(new Color(1f, 0.02f, 0.02f, pulseAlpha), new Color(1f, 1f, 1f, pulseAlpha), Mathf.PingPong(Time.time * 10f, 1f));
			SetMaterialColor(meshMaterial, color, pulseIntensity);
			float num = Mathf.Max(0.01f, NutcrackerShotConfig.ModelOutlineWidth.Value);
			float num2 = Mathf.Max(1f, NutcrackerShotConfig.MeshOutlineScale.Value);
			int num3 = 0;
			int num4 = 0;
			for (int i = 0; i < sourcePulses.Count; i++)
			{
				if (sourcePulses[i].Apply(color, pulseIntensity))
				{
					num4++;
				}
			}
			for (int j = 0; j < meshClones.Count; j++)
			{
				if (meshClones[j].Update(color, num, num2))
				{
					num3++;
				}
			}
			if (num3 == 0 && num4 == 0)
			{
				SetMeshVisible(visible: false);
			}
			else if (IsDebugLoggingEnabled() && !loggedMeshVisible)
			{
				loggedMeshVisible = true;
				string text = ((meshClones.Count > 0) ? meshClones[0].GetShaderSummary() : "none");
				Plugin.Log.LogInfo((object)$"Nutcracker #{((EnemyAI)nutcracker).thisEnemyIndex} mesh silhouette outline visible. CloneRenderers={num3} SourcePulses={num4} Width={num:0.000} Scale={num2:0.000} Shader={text}");
			}
		}

		private void EnsureMeshClones()
		{
			if (meshBuilt)
			{
				return;
			}
			meshBuilt = true;
			RefreshRenderersIfNeeded(force: true);
			if (cachedRenderers == null)
			{
				return;
			}
			for (int i = 0; i < cachedRenderers.Length; i++)
			{
				Renderer val = cachedRenderers[i];
				if (!IsModelOutlineRenderer(val))
				{
					continue;
				}
				if (ShouldUseCloneShell())
				{
					MeshOutlineClone meshOutlineClone = MeshOutlineClone.TryCreate(val, meshMaterial);
					if (meshOutlineClone != null)
					{
						meshClones.Add(meshOutlineClone);
					}
				}
				if (ShouldUseSourcePulse())
				{
					SourceRendererPulse sourceRendererPulse = SourceRendererPulse.TryCreate(val);
					if (sourceRendererPulse != null)
					{
						sourcePulses.Add(sourceRendererPulse);
					}
				}
			}
			if (IsDebugLoggingEnabled())
			{
				Plugin.Log.LogInfo((object)$"Nutcracker #{((EnemyAI)nutcracker).thisEnemyIndex} built mesh silhouette outline clones: {meshClones.Count}, source pulses: {sourcePulses.Count}");
			}
			if (ShouldDumpModelAudit())
			{
				DumpModelAudit();
			}
		}

		private void DumpModelAudit()
		{
			if (cachedRenderers == null)
			{
				return;
			}
			Plugin.Log.LogInfo((object)$"Nutcracker #{((EnemyAI)nutcracker).thisEnemyIndex} model audit: renderers={cachedRenderers.Length}, outlineClones={meshClones.Count}");
			for (int i = 0; i < cachedRenderers.Length; i++)
			{
				Renderer val = cachedRenderers[i];
				if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).GetComponentInParent<NutcrackerShotIndicator>() != (Object)null)
				{
					continue;
				}
				string text = "none";
				int num = 0;
				int num2 = 0;
				SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null);
				if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMesh != (Object)null)
				{
					text = ((Object)val2.sharedMesh).name;
					num = val2.sharedMesh.vertexCount;
					num2 = val2.sharedMesh.subMeshCount;
				}
				else
				{
					MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
					if ((Object)(object)component != (Object)null && (Object)(object)component.sharedMesh != (Object)null)
					{
						text = ((Object)component.sharedMesh).name;
						num = component.sharedMesh.vertexCount;
						num2 = component.sharedMesh.subMeshCount;
					}
				}
				Plugin.Log.LogInfo((object)$"Nutcracker model audit renderer[{i}]: type={((object)val).GetType().Name}, eligible={IsModelOutlineRenderer(val)}, path={GetPath(((Component)val).transform)}, mesh={text}, vertices={num}, subMeshes={num2}, materials={val.sharedMaterials.Length}");
			}
		}

		private void ClearMeshClones()
		{
			for (int i = 0; i < meshClones.Count; i++)
			{
				meshClones[i].Dispose();
			}
			meshClones.Clear();
			for (int j = 0; j < sourcePulses.Count; j++)
			{
				sourcePulses[j].Dispose();
			}
			sourcePulses.Clear();
			meshBuilt = false;
		}

		private void SetMeshVisible(bool visible)
		{
			for (int i = 0; i < meshClones.Count; i++)
			{
				meshClones[i].SetVisible(visible);
			}
			if (!visible)
			{
				for (int j = 0; j < sourcePulses.Count; j++)
				{
					sourcePulses[j].Restore();
				}
			}
		}

		private void UpdateScreenBox()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: 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_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: 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)
			EnsureScreenBox();
			if (!TryGetBounds(out var bounds))
			{
				loggedScreenVisible = false;
				SetScreenVisible(visible: false);
				return;
			}
			Camera activeCamera = GetActiveCamera();
			if ((Object)(object)activeCamera == (Object)null || !TryProjectBounds(bounds, activeCamera, out var screenRect))
			{
				loggedScreenVisible = false;
				SetScreenVisible(visible: false);
				return;
			}
			screenCanvasRect.sizeDelta = new Vector2((float)Screen.width, (float)Screen.height);
			float num = Mathf.Max(72f, ((Rect)(ref screenRect)).width + 36f);
			float num2 = Mathf.Max(120f, ((Rect)(ref screenRect)).height + 36f);
			Vector2 center = ((Rect)(ref screenRect)).center;
			screenBoxRect.anchoredPosition = new Vector2(center.x - (float)Screen.width * 0.5f, center.y - (float)Screen.height * 0.5f);
			screenBoxRect.sizeDelta = new Vector2(num, num2);
			float thickness = Mathf.Max(3f, NutcrackerShotConfig.ModelOutlineWidth.Value * 120f);
			SetStripThickness(((Graphic)screenTop).rectTransform, thickness, horizontal: true);
			SetStripThickness(((Graphic)screenBottom).rectTransform, thickness, horizontal: true);
			SetStripThickness(((Graphic)screenLeft).rectTransform, thickness, horizontal: false);
			SetStripThickness(((Graphic)screenRight).rectTransform, thickness, horizontal: false);
			Color color = Color.Lerp(new Color(1f, 0.02f, 0.02f, 0.96f), Color.white, Mathf.PingPong(Time.unscaledTime * 10f, 1f));
			((Graphic)screenTop).color = color;
			((Graphic)screenBottom).color = color;
			((Graphic)screenLeft).color = color;
			((Graphic)screenRight).color = color;
			SetScreenVisible(visible: true);
			if (IsDebugLoggingEnabled() && !loggedScreenVisible)
			{
				loggedScreenVisible = true;
				Plugin.Log.LogInfo((object)$"Nutcracker #{((EnemyAI)nutcracker).thisEnemyIndex} screen outline visible. Rect={num:0}x{num2:0} Center={center.x:0},{center.y:0}");
			}
		}

		private void EnsureScreenBox()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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)
			if (!((Object)(object)screenRoot != (Object)null))
			{
				screenRoot = new GameObject("NutcrackerFireWindowScreenOutline");
				((Object)screenRoot).hideFlags = (HideFlags)61;
				screenCanvas = screenRoot.AddComponent<Canvas>();
				screenCanvas.renderMode = (RenderMode)0;
				screenCanvas.sortingOrder = 2500;
				screenCanvasRect = ((Component)screenCanvas).GetComponent<RectTransform>();
				GameObject val = new GameObject("ProjectedModelBox");
				val.transform.SetParent(screenRoot.transform, false);
				screenBoxRect = val.AddComponent<RectTransform>();
				screenBoxRect.anchorMin = new Vector2(0.5f, 0.5f);
				screenBoxRect.anchorMax = new Vector2(0.5f, 0.5f);
				screenBoxRect.pivot = new Vector2(0.5f, 0.5f);
				screenTop = CreateStrip("Top", (Transform)(object)screenBoxRect);
				screenBottom = CreateStrip("Bottom", (Transform)(object)screenBoxRect);
				screenLeft = CreateStrip("Left", (Transform)(object)screenBoxRect);
				screenRight = CreateStrip("Right", (Transform)(object)screenBoxRect);
				AnchorHorizontal(((Graphic)screenTop).rectTransform, 1f);
				AnchorHorizontal(((Graphic)screenBottom).rectTransform, 0f);
				AnchorVertical(((Graphic)screenLeft).rectTransform, 0f);
				AnchorVertical(((Graphic)screenRight).rectTransform, 1f);
				SetScreenVisible(visible: false);
			}
		}

		private static Material CreateMeshMaterial()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			Shader val = Shader.Find("HDRP/Unlit") ?? Shader.Find("Hidden/Internal-Colored") ?? Shader.Find("Sprites/Default") ?? Shader.Find("UI/Default");
			Material val2 = new Material(val);
			((Object)val2).name = "NutcrackerMeshSilhouetteOutlineMaterial";
			((Object)val2).hideFlags = (HideFlags)61;
			ConfigureOutlineMaterial(val2);
			SetMaterialColor(val2, new Color(1f, 0.02f, 0.02f, 0.86f));
			return val2;
		}

		private static void ConfigureOutlineMaterial(Material material)
		{
			if (!((Object)(object)material == (Object)null))
			{
				material.renderQueue = 5500;
				material.SetOverrideTag("RenderType", "Transparent");
				TrySetInt(material, "_Cull", 0);
				TrySetInt(material, "_CullMode", 0);
				TrySetInt(material, "_CullModeForward", 0);
				TrySetInt(material, "_SrcBlend", 5);
				TrySetInt(material, "_DstBlend", 10);
				TrySetInt(material, "_AlphaSrcBlend", 5);
				TrySetInt(material, "_AlphaDstBlend", 10);
				TrySetInt(material, "_ZWrite", 0);
				TrySetInt(material, "_ZTest", 8);
				TrySetInt(material, "_ZTestTransparent", 8);
				TrySetInt(material, "_ZTestDepthEqualForOpaque", 8);
				TrySetFloat(material, "_SurfaceType", 1f);
				TrySetFloat(material, "_BlendMode", 0f);
				TrySetFloat(material, "_AlphaCutoffEnable", 0f);
				TrySetFloat(material, "_EnableFogOnTransparent", 0f);
				TrySetFloat(material, "_UseEmissiveIntensity", 1f);
				TrySetFloat(material, "_EmissiveIntensity", 2.5f);
				material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
				material.EnableKeyword("_BLENDMODE_ALPHA");
			}
		}

		private static void SetMaterialColor(Material material, Color color, float emissionMultiplier = 3f)
		{
			//IL_0028: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)material == (Object)null))
			{
				if (material.HasProperty("_BaseColor"))
				{
					material.SetColor("_BaseColor", color);
				}
				if (material.HasProperty("_UnlitColor"))
				{
					material.SetColor("_UnlitColor", color);
				}
				if (material.HasProperty("_Color"))
				{
					material.SetColor("_Color", color);
				}
				Color val = default(Color);
				((Color)(ref val))..ctor(color.r * emissionMultiplier, color.g * emissionMultiplier, color.b * emissionMultiplier, color.a);
				if (material.HasProperty("_EmissionColor"))
				{
					material.SetColor("_EmissionColor", val);
				}
				if (material.HasProperty("_EmissiveColor"))
				{
					material.SetColor("_EmissiveColor", val);
				}
				if (material.HasProperty("_EmissiveColorLDR"))
				{
					material.SetColor("_EmissiveColorLDR", val);
				}
			}
		}

		private static void TrySetInt(Material material, string property, int value)
		{
			if ((Object)(object)material != (Object)null && material.HasProperty(property))
			{
				material.SetInt(property, value);
			}
		}

		private static void TrySetFloat(Material material, string property, float value)
		{
			if ((Object)(object)material != (Object)null && material.HasProperty(property))
			{
				material.SetFloat(property, value);
			}
		}

		private static Image CreateStrip(string name, Transform parent)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			Image val2 = val.AddComponent<Image>();
			((Graphic)val2).raycastTarget = false;
			((Graphic)val2).color = Color.clear;
			return val2;
		}

		private static void AnchorHorizontal(RectTransform strip, float y)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			strip.anchorMin = new Vector2(0f, y);
			strip.anchorMax = new Vector2(1f, y);
			strip.pivot = new Vector2(0.5f, 0.5f);
			strip.anchoredPosition = Vector2.zero;
		}

		private static void AnchorVertical(RectTransform strip, float x)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			strip.anchorMin = new Vector2(x, 0f);
			strip.anchorMax = new Vector2(x, 1f);
			strip.pivot = new Vector2(0.5f, 0.5f);
			strip.anchoredPosition = Vector2.zero;
		}

		private static void SetStripThickness(RectTransform strip, float thickness, bool horizontal)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			strip.sizeDelta = (horizontal ? new Vector2(0f, thickness) : new Vector2(thickness, 0f));
		}

		private static bool TryProjectBounds(Bounds bounds, Camera camera, out Rect screenRect)
		{
			//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_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_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0037: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_00cd: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: 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_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 min = ((Bounds)(ref bounds)).min;
			Vector3 max = ((Bounds)(ref bounds)).max;
			Vector3[] array = (Vector3[])(object)new Vector3[8]
			{
				new Vector3(min.x, min.y, min.z),
				new Vector3(max.x, min.y, min.z),
				new Vector3(min.x, max.y, min.z),
				new Vector3(max.x, max.y, min.z),
				new Vector3(min.x, min.y, max.z),
				new Vector3(max.x, min.y, max.z),
				new Vector3(min.x, max.y, max.z),
				new Vector3(max.x, max.y, max.z)
			};
			float num = float.MaxValue;
			float num2 = float.MaxValue;
			float num3 = float.MinValue;
			float num4 = float.MinValue;
			bool flag = false;
			for (int i = 0; i < array.Length; i++)
			{
				Vector3 val = camera.WorldToScreenPoint(array[i]);
				if (!(val.z <= 0.01f))
				{
					flag = true;
					num = Mathf.Min(num, val.x);
					num2 = Mathf.Min(num2, val.y);
					num3 = Mathf.Max(num3, val.x);
					num4 = Mathf.Max(num4, val.y);
				}
			}
			if (!flag)
			{
				screenRect = default(Rect);
				return false;
			}
			num = Mathf.Clamp(num, 0f, (float)Screen.width);
			num3 = Mathf.Clamp(num3, 0f, (float)Screen.width);
			num2 = Mathf.Clamp(num2, 0f, (float)Screen.height);
			num4 = Mathf.Clamp(num4, 0f, (float)Screen.height);
			if (num3 <= num || num4 <= num2)
			{
				screenRect = default(Rect);
				return false;
			}
			screenRect = Rect.MinMaxRect(num, num2, num3, num4);
			return true;
		}

		private bool TryGetBounds(out Bounds bounds)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			RefreshRenderersIfNeeded(force: false);
			bounds = default(Bounds);
			bool flag = false;
			if (cachedRenderers == null)
			{
				return false;
			}
			for (int i = 0; i < cachedRenderers.Length; i++)
			{
				Renderer val = cachedRenderers[i];
				if (IsModelOutlineRenderer(val) && val.enabled)
				{
					if (!flag)
					{
						bounds = val.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref bounds)).Encapsulate(val.bounds);
					}
				}
			}
			return flag;
		}

		private void RefreshRenderersIfNeeded(bool force)
		{
			if (force || cachedRenderers == null || !(Time.time < nextRendererRefreshTime))
			{
				cachedRenderers = ((Component)nutcracker).GetComponentsInChildren<Renderer>(false);
				nextRendererRefreshTime = Time.time + 1f;
			}
		}

		private static Camera GetActiveCamera()
		{
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			if ((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null)
			{
				return val.gameplayCamera;
			}
			return Camera.main;
		}

		private void SetScreenVisible(bool visible)
		{
			if ((Object)(object)screenCanvas != (Object)null && ((Behaviour)screenCanvas).enabled != visible)
			{
				((Behaviour)screenCanvas).enabled = visible;
			}
		}

		private static ModelOutlineMode GetMode()
		{
			return (NutcrackerShotConfig.ModelOutlineMode != null) ? NutcrackerShotConfig.ModelOutlineMode.Value : ModelOutlineMode.MeshSilhouette;
		}

		private static ModelPulseMode GetPulseMode()
		{
			return (NutcrackerShotConfig.ModelPulseMode != null) ? NutcrackerShotConfig.ModelPulseMode.Value : ModelPulseMode.SourcePulse;
		}

		private static bool ShouldUseSourcePulse()
		{
			ModelPulseMode pulseMode = GetPulseMode();
			return pulseMode == ModelPulseMode.SourcePulse || pulseMode == ModelPulseMode.Both;
		}

		private static bool ShouldUseCloneShell()
		{
			ModelPulseMode pulseMode = GetPulseMode();
			return pulseMode == ModelPulseMode.CloneShell || pulseMode == ModelPulseMode.Both;
		}

		private static float GetPulseIntensity()
		{
			return (NutcrackerShotConfig.ModelPulseIntensity == null) ? 4f : Mathf.Clamp(NutcrackerShotConfig.ModelPulseIntensity.Value, 0f, 12f);
		}

		private static float GetPulseAlpha()
		{
			return (NutcrackerShotConfig.ModelPulseAlpha == null) ? 0.92f : Mathf.Clamp01(NutcrackerShotConfig.ModelPulseAlpha.Value);
		}

		private static bool IsDebugLoggingEnabled()
		{
			return NutcrackerShotConfig.EnableDebugLogs != null && NutcrackerShotConfig.EnableDebugLogs.Value;
		}

		private static bool ShouldDumpModelAudit()
		{
			return NutcrackerShotConfig.DumpModelAudit != null && NutcrackerShotConfig.DumpModelAudit.Value;
		}

		private static bool IsModelOutlineRenderer(Renderer renderer)
		{
			if ((Object)(object)renderer == (Object)null || renderer is LineRenderer || ((object)renderer).GetType().Name == "ParticleSystemRenderer")
			{
				return false;
			}
			if ((Object)(object)((Component)renderer).GetComponentInParent<NutcrackerShotIndicator>() != (Object)null)
			{
				return false;
			}
			string path = GetPath(((Component)renderer).transform);
			if (ContainsAny(path, "MapDot", "ScanNode", "BloodSpurtParticle", "Collider"))
			{
				return false;
			}
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
			if ((Object)(object)val != (Object)null)
			{
				string value = (((Object)(object)val.sharedMesh == (Object)null) ? string.Empty : ((Object)val.sharedMesh).name);
				return ContainsAny(path, "LOD0") || ContainsAny(value, "LOD0");
			}
			MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>();
			if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null)
			{
				return false;
			}
			string name = ((Object)component.sharedMesh).name;
			return ContainsAny(path, "Gun", "Shotgun") || ContainsAny(name, "Gun", "Shotgun");
		}

		private static bool ContainsAny(string value, params string[] fragments)
		{
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			for (int i = 0; i < fragments.Length; i++)
			{
				if (value.IndexOf(fragments[i], StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}

		private static string GetPath(Transform transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return string.Empty;
			}
			string text = ((Object)transform).name;
			Transform parent = transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}
	}
	[HarmonyPatch(typeof(NutcrackerEnemyAI))]
	internal static class NutcrackerPatches
	{
		private static readonly FieldInfo AimingGunField = AccessTools.Field(typeof(NutcrackerEnemyAI), "aimingGun");

		private static readonly FieldInfo ReloadingGunField = AccessTools.Field(typeof(NutcrackerEnemyAI), "reloadingGun");

		private static readonly FieldInfo TimeSinceFiringGunField = AccessTools.Field(typeof(NutcrackerEnemyAI), "timeSinceFiringGun");

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void UpdatePostfix(NutcrackerEnemyAI __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && !((EnemyAI)__instance).isEnemyDead)
			{
				bool aimingGun = ReadBool(AimingGunField, __instance);
				bool reloadingGun = ReadBool(ReloadingGunField, __instance);
				float timeSinceFiringGun = ReadFloat(TimeSinceFiringGunField, __instance);
				NutcrackerShotIndicator.For(__instance).ObserveCombatState(aimingGun, reloadingGun, timeSinceFiringGun, GetAimDuration(__instance));
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("AimGunClientRpc")]
		private static void AimGunClientRpcPostfix(NutcrackerEnemyAI __instance)
		{
			NutcrackerShotIndicator.For(__instance).BeginAim(GetAimDuration(__instance));
		}

		[HarmonyPostfix]
		[HarmonyPatch("FireGunClientRpc")]
		private static void FireGunClientRpcPostfix(NutcrackerEnemyAI __instance)
		{
			NutcrackerShotIndicator.For(__instance).MarkFired();
		}

		[HarmonyPostfix]
		[HarmonyPatch("ReloadGunClientRpc")]
		private static void ReloadGunClientRpcPostfix(NutcrackerEnemyAI __instance)
		{
			NutcrackerShotIndicator.For(__instance).BeginReload(1.74f);
		}

		[HarmonyPostfix]
		[HarmonyPatch("KillEnemy")]
		private static void KillEnemyPostfix(NutcrackerEnemyAI __instance)
		{
			NutcrackerShotIndicator.Remove(__instance);
		}

		private static float GetAimDuration(NutcrackerEnemyAI nutcracker)
		{
			if (((EnemyAI)nutcracker).enemyHP <= 1)
			{
				return 0.5f;
			}
			ShotgunItem gun = nutcracker.gun;
			if ((Object)(object)gun != (Object)null && gun.shellsLoaded == 1)
			{
				return 1.3f;
			}
			return 1.75f;
		}

		private static bool ReadBool(FieldInfo field, NutcrackerEnemyAI instance)
		{
			bool flag = default(bool);
			int num;
			if (field != null)
			{
				object value = field.GetValue(instance);
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static float ReadFloat(FieldInfo field, NutcrackerEnemyAI instance)
		{
			return (field != null && field.GetValue(instance) is float num) ? num : 0f;
		}
	}
	internal static class NutcrackerShotConfig
	{
		public static ConfigEntry<bool> EnableUiFireWindow { get; private set; }

		public static ConfigEntry<bool> EnableModelOutlineFireWindow { get; private set; }

		public static ConfigEntry<float> ModelOutlineWidth { get; private set; }

		public static ConfigEntry<ModelOutlineMode> ModelOutlineMode { get; private set; }

		public static ConfigEntry<ModelPulseMode> ModelPulseMode { get; private set; }

		public static ConfigEntry<float> MeshOutlineScale { get; private set; }

		public static ConfigEntry<float> ModelPulseIntensity { get; private set; }

		public static ConfigEntry<float> ModelPulseAlpha { get; private set; }

		public static ConfigEntry<float> ModelWarningMaxDistance { get; private set; }

		public static ConfigEntry<bool> ModelWarningRequireCameraVisible { get; private set; }

		public static ConfigEntry<float> FireWindowSeconds { get; private set; }

		public static ConfigEntry<float> PreAimMaxDistance { get; private set; }

		public static ConfigEntry<float> MonitorActiveScanInterval { get; private set; }

		public static ConfigEntry<float> MonitorIdleScanInterval { get; private set; }

		public static ConfigEntry<bool> EnableDebugLogs { get; private set; }

		public static ConfigEntry<bool> DumpModelAudit { get; private set; }

		public static void Bind(ConfigFile config)
		{
			EnableUiFireWindow = config.Bind<bool>("Warnings", "EnableUiFireWindow", true, "Show the FIRE text and red-white pulse on the side bar during the final shot window.");
			EnableModelOutlineFireWindow = config.Bind<bool>("Warnings", "EnableModelOutlineFireWindow", true, "Flash a red-white outline around the Nutcracker model during the final shot window.");
			ModelOutlineWidth = config.Bind<float>("Warnings", "ModelOutlineWidth", 0.075f, "Line width for ScreenBox mode. In MeshSilhouette mode this is the normal-expanded edge thickness.");
			ModelOutlineMode = config.Bind<ModelOutlineMode>("Warnings", "ModelOutlineMode", NutcrackerShotUI.ModelOutlineMode.MeshSilhouette, "Model outline style. MeshSilhouette follows the Nutcracker model; ScreenBox draws a reliable HUD fallback rectangle.");
			ModelPulseMode = config.Bind<ModelPulseMode>("Warnings", "ModelPulseMode", NutcrackerShotUI.ModelPulseMode.SourcePulse, "Model warning implementation for MeshSilhouette mode. SourcePulse recolors the original model; CloneShell adds a cloned shell; Both enables both.");
			MeshOutlineScale = config.Bind<float>("Warnings", "MeshOutlineScale", 1f, "Extra transform scale for MeshSilhouette outline clones. Keep this at 1 for the most exact model edge.");
			ModelPulseIntensity = config.Bind<float>("Warnings", "ModelPulseIntensity", 4f, "Emission multiplier for model red-white pulse.");
			ModelPulseAlpha = config.Bind<float>("Warnings", "ModelPulseAlpha", 0.92f, "Alpha used by model red-white pulse colors.");
			ModelWarningMaxDistance = config.Bind<float>("Warnings", "ModelWarningMaxDistance", 45f, "Maximum local-player distance for model fire-window warnings. Set to 0 or lower to disable distance filtering.");
			ModelWarningRequireCameraVisible = config.Bind<bool>("Warnings", "ModelWarningRequireCameraVisible", false, "Only show model fire-window warnings when the Nutcracker is inside the local camera viewport.");
			FireWindowSeconds = config.Bind<float>("Warnings", "FireWindowSeconds", 0.35f, "Seconds before the predicted shot when fire-window warnings activate.");
			PreAimMaxDistance = config.Bind<float>("Warnings", "PreAimMaxDistance", 30f, "Maximum distance for the yellow pre-aim danger bar.");
			MonitorActiveScanInterval = config.Bind<float>("Performance", "MonitorActiveScanInterval", 0.1f, "Fallback monitor scan interval while Nutcrackers are present.");
			MonitorIdleScanInterval = config.Bind<float>("Performance", "MonitorIdleScanInterval", 0.75f, "Fallback monitor scan interval while no Nutcrackers are present.");
			EnableDebugLogs = config.Bind<bool>("Debug", "EnableDebugLogs", false, "Log aim/fire warning events to BepInEx LogOutput.log.");
			DumpModelAudit = config.Bind<bool>("Debug", "DumpModelAudit", false, "Log Nutcracker renderer and mesh names/counts once when the model outline is built.");
		}
	}
	internal enum ModelOutlineMode
	{
		MeshSilhouette,
		ScreenBox
	}
	internal enum ModelPulseMode
	{
		SourcePulse,
		CloneShell,
		Both
	}
	internal sealed class NutcrackerShotIndicator : MonoBehaviour
	{
		private enum WarningState
		{
			Idle,
			Aiming,
			Fired,
			Reloading
		}

		private const float BarWidth = 0.09f;

		private const float BarHeight = 1.35f;

		private const float SideOffset = 1.08f;

		private const float HeightOffset = 2.05f;

		private const float FiredHoldTime = 0.35f;

		private const float DefaultCriticalAimWindow = 0.35f;

		private const float PreAimMaxDistance = 30f;

		private static readonly Color BackgroundColor = new Color(0.02f, 0.02f, 0.02f, 0.55f);

		private static readonly Color PreAimColor = new Color(1f, 0.72f, 0.12f, 0.55f);

		private static readonly Color AimColor = new Color(1f, 0.12f, 0.06f, 0.92f);

		private static readonly Color FiredColor = new Color(1f, 1f, 1f, 0.96f);

		private static readonly Color ReloadColor = new Color(0.2f, 0.65f, 1f, 0.55f);

		private NutcrackerEnemyAI nutcracker;

		private Canvas canvas;

		private Image background;

		private Image fill;

		private Image rim;

		private Image criticalPulse;

		private Text countdownText;

		private NutcrackerModelFireWindowOutline modelOutline;

		private WarningState state;

		private float stateStartedAt;

		private float stateDuration;

		private float lastPreAimAmount;

		private bool observedAimingLastFrame;

		private bool observedReloadingLastFrame;

		public static NutcrackerShotIndicator For(NutcrackerEnemyAI nutcracker)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			if ((Object)(object)nutcracker == (Object)null)
			{
				return null;
			}
			NutcrackerShotIndicator componentInChildren = ((Component)nutcracker).GetComponentInChildren<NutcrackerShotIndicator>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				return componentInChildren;
			}
			GameObject val = new GameObject("NutcrackerShotUI");
			val.transform.SetParent(((Component)nutcracker).transform, false);
			componentInChildren = val.AddComponent<NutcrackerShotIndicator>();
			componentInChildren.Initialize(nutcracker);
			return componentInChildren;
		}

		public static void Remove(NutcrackerEnemyAI nutcracker)
		{
			if (!((Object)(object)nutcracker == (Object)null))
			{
				NutcrackerShotIndicator componentInChildren = ((Component)nutcracker).GetComponentInChildren<NutcrackerShotIndicator>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)componentInChildren).gameObject);
				}
			}
		}

		public void BeginAim(float duration)
		{
			if (duration <= 0f)
			{
				duration = 0.5f;
			}
			state = WarningState.Aiming;
			stateStartedAt = Time.time;
			stateDuration = duration;
			SetVisible(visible: true);
			if (IsDebugLoggingEnabled())
			{
				Plugin.Log.LogInfo((object)$"Nutcracker #{((EnemyAI)nutcracker).thisEnemyIndex} aim warning started. Duration={duration:0.00}s Shells={nutcracker.gun?.shellsLoaded ?? (-1)} HP={((EnemyAI)nutcracker).enemyHP}");
			}
		}

		public void MarkFired()
		{
			state = WarningState.Fired;
			stateStartedAt = Time.time;
			stateDuration = 0.35f;
			SetVisible(visible: true);
			if (IsDebugLoggingEnabled())
			{
				Plugin.Log.LogInfo((object)$"Nutcracker #{((EnemyAI)nutcracker).thisEnemyIndex} fired.");
			}
		}

		public void BeginReload(float duration)
		{
			state = WarningState.Reloading;
			stateStartedAt = Time.time;
			stateDuration = duration;
			SetVisible(visible: true);
		}

		public void ObserveCombatState(bool aimingGun, bool reloadingGun, float timeSinceFiringGun, float aimDuration)
		{
			if (aimingGun)
			{
				float num = Mathf.Max(0.05f, aimDuration);
				float num2 = Mathf.Clamp(timeSinceFiringGun, 0f, num);
				if (!observedAimingLastFrame || state != WarningState.Aiming)
				{
					state = WarningState.Aiming;
					stateDuration = num;
					stateStartedAt = Time.time - num2;
					SetVisible(visible: true);
					if (IsDebugLoggingEnabled())
					{
						Plugin.Log.LogInfo((object)$"Nutcracker #{((EnemyAI)nutcracker).thisEnemyIndex} aim warning observed from Update. Duration={num:0.00}s Elapsed={num2:0.00}s Shells={nutcracker.gun?.shellsLoaded ?? (-1)} HP={((EnemyAI)nutcracker).enemyHP}");
					}
				}
			}
			else if (observedAimingLastFrame && state == WarningState.Aiming)
			{
				state = WarningState.Idle;
				SetCriticalPulse(0f);
				SetModelFireWindow(active: false);
			}
			if (reloadingGun && !observedReloadingLastFrame && state != WarningState.Aiming)
			{
				BeginReload(1.74f);
			}
			observedAimingLastFrame = aimingGun;
			observedReloadingLastFrame = reloadingGun;
		}

		private void Initialize(NutcrackerEnemyAI owner)
		{
			nutcracker = owner;
			BuildWorldBar();
			modelOutline = new NutcrackerModelFireWindowOutline(owner, ((Component)this).transform);
			SetVisible(visible: false);
		}

		private void OnDestroy()
		{
			modelOutline?.Dispose();
		}

		private void OnDisable()
		{
			SetModelFireWindow(active: false);
		}

		private void LateUpdate()
		{
			if ((Object)(object)nutcracker == (Object)null || ((EnemyAI)nutcracker).isEnemyDead)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			UpdateTransform();
			UpdateState();
		}

		private void BuildWorldBar()
		{
			//IL_0047: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: 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_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			canvas = ((Component)this).gameObject.AddComponent<Canvas>();
			canvas.renderMode = (RenderMode)2;
			canvas.sortingOrder = 200;
			RectTransform component = ((Component)canvas).GetComponent<RectTransform>();
			component.sizeDelta = new Vector2(0.09f, 1.35f);
			((Transform)component).localScale = Vector3.one;
			background = CreateImage("Background", ((Component)this).transform, BackgroundColor);
			RectTransform rectTransform = ((Graphic)background).rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			rectTransform.offsetMin = Vector2.zero;
			rectTransform.offsetMax = Vector2.zero;
			fill = CreateImage("Fill", ((Component)background).transform, AimColor);
			fill.type = (Type)3;
			fill.fillMethod = (FillMethod)1;
			fill.fillOrigin = 0;
			fill.fillAmount = 0f;
			RectTransform rectTransform2 = ((Graphic)fill).rectTransform;
			rectTransform2.anchorMin = Vector2.zero;
			rectTransform2.anchorMax = Vector2.one;
			rectTransform2.offsetMin = new Vector2(0.012f, 0.012f);
			rectTransform2.offsetMax = new Vector2(-0.012f, -0.012f);
			rim = CreateImage("Rim", ((Component)this).transform, new Color(1f, 1f, 1f, 0.26f));
			RectTransform rectTransform3 = ((Graphic)rim).rectTransform;
			rectTransform3.anchorMin = Vector2.zero;
			rectTransform3.anchorMax = Vector2.one;
			rectTransform3.offsetMin = Vector2.zero;
			rectTransform3.offsetMax = Vector2.zero;
			criticalPulse = CreateImage("CriticalPulse", ((Component)this).transform, new Color(1f, 0f, 0f, 0f));
			RectTransform rectTransform4 = ((Graphic)criticalPulse).rectTransform;
			rectTransform4.anchorMin = Vector2.zero;
			rectTransform4.anchorMax = Vector2.one;
			rectTransform4.offsetMin = new Vector2(-0.018f, -0.018f);
			rectTransform4.offsetMax = new Vector2(0.018f, 0.018f);
			countdownText = CreateText("Countdown", ((Component)this).transform);
			RectTransform rectTransform5 = ((Graphic)countdownText).rectTransform;
			rectTransform5.anchorMin = new Vector2(0.5f, 1f);
			rectTransform5.anchorMax = new Vector2(0.5f, 1f);
			rectTransform5.pivot = new Vector2(0.5f, 0f);
			rectTransform5.sizeDelta = new Vector2(0.58f, 0.22f);
			rectTransform5.anchoredPosition = new Vector2(0f, 0.08f);
		}

		private static Image CreateImage(string name, Transform parent, Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			Image val2 = val.AddComponent<Image>();
			((Graphic)val2).color = color;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		private static Text CreateText(string name, Transform parent)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			Text val2 = val.AddComponent<Text>();
			val2.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			val2.alignment = (TextAnchor)4;
			((Graphic)val2).color = new Color(1f, 1f, 1f, 0.95f);
			val2.fontSize = 42;
			val2.resizeTextForBestFit = true;
			val2.resizeTextMinSize = 14;
			val2.resizeTextMaxSize = 42;
			((Graphic)val2).raycastTarget = false;
			return val2;
		}

		private void UpdateTransform()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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)
			Transform transform = ((Component)nutcracker).transform;
			((Component)this).transform.position = transform.position + transform.right * 1.08f + Vector3.up * 2.05f;
			Camera activeCamera = GetActiveCamera();
			if ((Object)(object)activeCamera != (Object)null)
			{
				Vector3 val = ((Component)this).transform.position - ((Component)activeCamera).transform.position;
				if (((Vector3)(ref val)).sqrMagnitude > 0.001f)
				{
					((Component)this).transform.rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up);
				}
			}
		}

		private void UpdateState()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			switch (state)
			{
			case WarningState.Aiming:
				UpdateAimingState();
				break;
			case WarningState.Fired:
				UpdateTimedState(FiredColor, 1f, hideWhenFinished: true);
				break;
			case WarningState.Reloading:
				UpdateTimedState(ReloadColor, reverse: true, hideWhenFinished: true);
				break;
			default:
				UpdatePreAim();
				break;
			}
		}

		private void UpdateTimedState(Color color, float alpha, bool hideWhenFinished)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			UpdateTimedState(color.WithAlpha(alpha), reverse: false, hideWhenFinished);
		}

		private void UpdateTimedState(Color color, bool reverse, bool hideWhenFinished)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			float num = Time.time - stateStartedAt;
			float num2 = Mathf.Clamp01(num / Mathf.Max(0.01f, stateDuration));
			((Graphic)fill).color = color;
			fill.fillAmount = (reverse ? (1f - num2) : num2);
			SetCountdownText(null, Color.white);
			SetCriticalPulse(0f);
			SetModelFireWindow(active: false);
			if (num2 >= 1f)
			{
				state = WarningState.Idle;
				if (hideWhenFinished)
				{
					SetVisible(visible: false);
				}
			}
		}

		private void UpdateAimingState()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			float num = Time.time - stateStartedAt;
			float num2 = Mathf.Max(0.01f, stateDuration);
			float num3 = Mathf.Clamp01(num / num2);
			float num4 = Mathf.Max(0f, num2 - num);
			float fireWindowSeconds = GetFireWindowSeconds();
			float num5 = 1f - Mathf.Clamp01(num4 / fireWindowSeconds);
			fill.fillAmount = num3;
			((Graphic)fill).color = Color.Lerp(AimColor, FiredColor, num5 * 0.45f);
			if (num4 <= fireWindowSeconds)
			{
				SetModelFireWindow(ShouldShowModelFireWindow());
				if (IsUiFireWindowEnabled())
				{
					float num6 = 0.45f + Mathf.PingPong(Time.time * 12f, 0.55f);
					SetCriticalPulse(num6);
					SetCountdownText("FIRE", Color.Lerp(AimColor, FiredColor, num6));
				}
				else
				{
					SetCriticalPulse(0f);
					SetCountdownText(num4.ToString("0.0"), AimColor.WithAlpha(0.96f));
				}
			}
			else
			{
				SetCriticalPulse(0f);
				SetModelFireWindow(active: false);
				SetCountdownText(num4.ToString("0.0"), AimColor.WithAlpha(0.96f));
			}
			if (num3 >= 1f)
			{
				state = WarningState.Idle;
				fill.fillAmount = 1f;
				SetModelFireWindow(active: false);
				if (IsUiFireWindowEnabled())
				{
					SetCountdownText("NOW", FiredColor);
					SetCriticalPulse(0.85f);
				}
				else
				{
					SetCountdownText(null, Color.white);
					SetCriticalPulse(0f);
				}
			}
		}

		private void UpdatePreAim()
		{
			//IL_0084: 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)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			float preAimDanger = GetPreAimDanger();
			lastPreAimAmount = Mathf.MoveTowards(lastPreAimAmount, preAimDanger, Time.deltaTime * 4f);
			if (lastPreAimAmount <= 0.01f)
			{
				SetVisible(visible: false);
				fill.fillAmount = 0f;
				SetCountdownText(null, Color.white);
				SetCriticalPulse(0f);
				SetModelFireWindow(active: false);
			}
			else
			{
				SetVisible(visible: true);
				((Graphic)fill).color = PreAimColor;
				fill.fillAmount = Mathf.Clamp01(lastPreAimAmount);
				SetCountdownText("!", PreAimColor.WithAlpha(0.92f));
				SetCriticalPulse(0f);
				SetModelFireWindow(active: false);
			}
		}

		private float GetPreAimDanger()
		{
			//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_00b4: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			if (((EnemyAI)nutcracker).currentBehaviourStateIndex != 2 || (Object)(object)nutcracker.gun == (Object)null || nutcracker.gun.shellsLoaded <= 0)
			{
				return 0f;
			}
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			if ((Object)(object)val == (Object)null || val.isPlayerDead || (Object)(object)val.gameplayCamera == (Object)null)
			{
				return 0f;
			}
			Vector3 position = ((Component)val.gameplayCamera).transform.position;
			Vector3 position2 = nutcracker.gun.shotgunRayPoint.position;
			Vector3 val2 = position - position2;
			float magnitude = ((Vector3)(ref val2)).magnitude;
			float preAimMaxDistance = GetPreAimMaxDistance();
			if (magnitude > preAimMaxDistance)
			{
				return 0f;
			}
			if (Vector3.Angle(nutcracker.gun.shotgunRayPoint.forward, val2) > 35f)
			{
				return 0f;
			}
			if (Physics.Linecast(position2, position, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1))
			{
				return 0f;
			}
			float num = 1f - Mathf.Clamp01(magnitude / preAimMaxDistance);
			float num2 = 1f - Mathf.Clamp01(Vector3.Angle(nutcracker.gun.shotgunRayPoint.forward, val2) / 35f);
			return Mathf.Clamp01(0.2f + num * 0.35f + num2 * 0.45f);
		}

		private static Camera GetActiveCamera()
		{
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			if ((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null)
			{
				return val.gameplayCamera;
			}
			return Camera.main;
		}

		private void SetVisible(bool visible)
		{
			if ((Object)(object)canvas != (Object)null && ((Behaviour)canvas).enabled != visible)
			{
				((Behaviour)canvas).enabled = visible;
			}
		}

		private void SetCountdownText(string text, Color color)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)countdownText == (Object)null))
			{
				((Behaviour)countdownText).enabled = !string.IsNullOrEmpty(text);
				countdownText.text = text ?? string.Empty;
				((Graphic)countdownText).color = color;
			}
		}

		private void SetCriticalPulse(float alpha)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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)
			if (!((Object)(object)criticalPulse == (Object)null))
			{
				Color color = ((Graphic)criticalPulse).color;
				color.a = Mathf.Clamp01(alpha) * 0.55f;
				((Graphic)criticalPulse).color = color;
			}
		}

		private void SetModelFireWindow(bool active)
		{
			modelOutline?.Update(active);
		}

		private bool ShouldShowModelFireWindow()
		{
			//IL_00af: 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_00b6: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			if (!IsModelFireWindowEnabled())
			{
				return false;
			}
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			Camera val2 = (((Object)(object)val != (Object)null && (Object)(object)val.gameplayCamera != (Object)null) ? val.gameplayCamera : Camera.main);
			if ((Object)(object)val != (Object)null && val.isPlayerDead)
			{
				return false;
			}
			float modelWarningMaxDistance = GetModelWarningMaxDistance();
			if (modelWarningMaxDistance > 0f)
			{
				Vector3 val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).transform.position : (((Object)(object)val != (Object)null) ? ((Component)val).transform.position : Vector3.zero));
				if (val3 != Vector3.zero && Vector3.Distance(val3, ((Component)nutcracker).transform.position) > modelWarningMaxDistance)
				{
					return false;
				}
			}
			if (NutcrackerShotConfig.ModelWarningRequireCameraVisible != null && NutcrackerShotConfig.ModelWarningRequireCameraVisible.Value)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					return false;
				}
				Vector3 val4 = val2.WorldToViewportPoint(((Component)nutcracker).transform.position + Vector3.up * 1.4f);
				if (val4.z <= 0f || val4.x < -0.1f || val4.x > 1.1f || val4.y < -0.1f || val4.y > 1.1f)
				{
					return false;
				}
			}
			return true;
		}

		private static bool IsUiFireWindowEnabled()
		{
			return NutcrackerShotConfig.EnableUiFireWindow == null || NutcrackerShotConfig.EnableUiFireWindow.Value;
		}

		private static bool IsModelFireWindowEnabled()
		{
			return NutcrackerShotConfig.EnableModelOutlineFireWindow == null || NutcrackerShotConfig.EnableModelOutlineFireWindow.Value;
		}

		private static float GetFireWindowSeconds()
		{
			return (NutcrackerShotConfig.FireWindowSeconds == null) ? 0.35f : Mathf.Clamp(NutcrackerShotConfig.FireWindowSeconds.Value, 0.05f, 2f);
		}

		private static float GetPreAimMaxDistance()
		{
			return (NutcrackerShotConfig.PreAimMaxDistance == null) ? 30f : Mathf.Clamp(NutcrackerShotConfig.PreAimMaxDistance.Value, 1f, 100f);
		}

		private static float GetModelWarningMaxDistance()
		{
			return (NutcrackerShotConfig.ModelWarningMaxDistance == null) ? 45f : NutcrackerShotConfig.ModelWarningMaxDistance.Value;
		}

		private static bool IsDebugLoggingEnabled()
		{
			return NutcrackerShotConfig.EnableDebugLogs != null && NutcrackerShotConfig.EnableDebugLogs.Value;
		}
	}
	internal static class ColorExtensions
	{
		public static Color WithAlpha(this Color color, float alpha)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			color.a = alpha;
			return color;
		}
	}
	internal sealed class NutcrackerShotMonitor : MonoBehaviour
	{
		private static readonly FieldInfo AimingGunField = typeof(NutcrackerEnemyAI).GetField("aimingGun", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo ReloadingGunField = typeof(NutcrackerEnemyAI).GetField("reloadingGun", BindingFlags.Instance | BindingFlags.NonPublic);

		private static readonly FieldInfo TimeSinceFiringGunField = typeof(NutcrackerEnemyAI).GetField("timeSinceFiringGun", BindingFlags.Instance | BindingFlags.NonPublic);

		private float nextScanTime;

		private int lastObservedCount = -1;

		private void Awake()
		{
			Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
		}

		private void Update()
		{
			if (Time.time < nextScanTime)
			{
				return;
			}
			NutcrackerEnemyAI[] array = Object.FindObjectsOfType<NutcrackerEnemyAI>();
			nextScanTime = Time.time + GetNextScanInterval(array.Length);
			if (IsDebugLoggingEnabled() && array.Length != lastObservedCount)
			{
				lastObservedCount = array.Length;
				Plugin.Log.LogInfo((object)$"Nutcracker monitor found {array.Length} NutcrackerEnemyAI instance(s).");
			}
			foreach (NutcrackerEnemyAI val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((EnemyAI)val).isEnemyDead)
				{
					bool aimingGun = ReadBool(AimingGunField, val);
					bool reloadingGun = ReadBool(ReloadingGunField, val);
					float timeSinceFiringGun = ReadFloat(TimeSinceFiringGunField, val);
					NutcrackerShotIndicator.For(val).ObserveCombatState(aimingGun, reloadingGun, timeSinceFiringGun, GetAimDuration(val));
				}
			}
		}

		private static float GetAimDuration(NutcrackerEnemyAI nutcracker)
		{
			if (((EnemyAI)nutcracker).enemyHP <= 1)
			{
				return 0.5f;
			}
			ShotgunItem gun = nutcracker.gun;
			if ((Object)(object)gun != (Object)null && gun.shellsLoaded == 1)
			{
				return 1.3f;
			}
			return 1.75f;
		}

		private static bool ReadBool(FieldInfo field, NutcrackerEnemyAI instance)
		{
			bool flag = default(bool);
			int num;
			if (field != null)
			{
				object value = field.GetValue(instance);
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static float ReadFloat(FieldInfo field, NutcrackerEnemyAI instance)
		{
			return (field != null && field.GetValue(instance) is float num) ? num : 0f;
		}

		private static float GetNextScanInterval(int observedCount)
		{
			float num = ((observedCount > 0) ? GetConfigInterval(NutcrackerShotConfig.MonitorActiveScanInterval, 0.1f) : GetConfigInterval(NutcrackerShotConfig.MonitorIdleScanInterval, 0.75f));
			return Mathf.Clamp(num, 0.02f, 5f);
		}

		private static float GetConfigInterval(ConfigEntry<float> entry, float fallback)
		{
			return entry?.Value ?? fallback;
		}

		private static bool IsDebugLoggingEnabled()
		{
			return NutcrackerShotConfig.EnableDebugLogs != null && NutcrackerShotConfig.EnableDebugLogs.Value;
		}
	}
	[BepInPlugin("aueser.lethalcompany.nutcrackerfirewarning", "Nutcracker Fire Warning", "1.0.2")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "aueser.lethalcompany.nutcrackerfirewarning";

		public const string PluginName = "Nutcracker Fire Warning";

		public const string PluginVersion = "1.0.2";

		private Harmony harmony;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			NutcrackerShotConfig.Bind(((BaseUnityPlugin)this).Config);
			CreateMonitor();
			harmony = new Harmony("aueser.lethalcompany.nutcrackerfirewarning");
			harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. UI fire window={2}, model outline={3}, debug={4}.", "Nutcracker Fire Warning", "1.0.2", NutcrackerShotConfig.EnableUiFireWindow.Value, NutcrackerShotConfig.EnableModelOutlineFireWindow.Value, NutcrackerShotConfig.EnableDebugLogs.Value));
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}

		private static void CreateMonitor()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("NutcrackerShotUIMonitor");
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<NutcrackerShotMonitor>();
		}
	}
}