Decompiled source of Nutcracker Fire Warning v1.0.6

BepInEx/plugins/NutcrackerFireWarning/NutcrackerFireWarning.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
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.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("NutcrackerFireWarning.Tests")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("NutcrackerFireWarning")]
[assembly: AssemblyConfiguration("Release")]
[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 readonly struct NutcrackerCombatState
	{
		public readonly bool AimingGun;

		public readonly bool ReloadingGun;

		public readonly float TimeSinceFiringGun;

		public readonly float AimDuration;

		public NutcrackerCombatState(bool aimingGun, bool reloadingGun, float timeSinceFiringGun, float aimDuration)
		{
			AimingGun = aimingGun;
			ReloadingGun = reloadingGun;
			TimeSinceFiringGun = timeSinceFiringGun;
			AimDuration = aimDuration;
		}
	}
	internal static class NutcrackerCombatStateReader
	{
		private static readonly FieldRef<NutcrackerEnemyAI, bool> AimingGunRef = CreateFieldRef<bool>("aimingGun");

		private static readonly FieldRef<NutcrackerEnemyAI, bool> ReloadingGunRef = CreateFieldRef<bool>("reloadingGun");

		private static readonly FieldRef<NutcrackerEnemyAI, float> TimeSinceFiringGunRef = CreateFieldRef<float>("timeSinceFiringGun");

		public static bool TryRead(NutcrackerEnemyAI nutcracker, out NutcrackerCombatState combatState)
		{
			combatState = default(NutcrackerCombatState);
			if ((Object)(object)nutcracker == (Object)null || AimingGunRef == null || ReloadingGunRef == null || TimeSinceFiringGunRef == null)
			{
				return false;
			}
			combatState = new NutcrackerCombatState(AimingGunRef.Invoke(nutcracker), ReloadingGunRef.Invoke(nutcracker), TimeSinceFiringGunRef.Invoke(nutcracker), GetAimDuration(nutcracker));
			return true;
		}

		public 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 FieldRef<NutcrackerEnemyAI, T> CreateFieldRef<T>(string fieldName)
		{
			try
			{
				return AccessTools.FieldRefAccess<NutcrackerEnemyAI, T>(fieldName);
			}
			catch
			{
				return null;
			}
		}
	}
	internal static class NutcrackerConfigLanguageDetector
	{
		internal const string ChineseProjectGuid = "cn.codex.v81testchn";

		private const string ChineseProjectFolderName = "V81TestChn";

		private const string ChineseProjectDllName = "V81TestChn.dll";

		public static bool ShouldUseChineseConfig()
		{
			try
			{
				if (Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey("cn.codex.v81testchn"))
				{
					return true;
				}
			}
			catch
			{
			}
			return ShouldUseChineseConfig(null, Paths.PluginPath);
		}

		internal static bool ShouldUseChineseConfig(IEnumerable<string> pluginGuids, string pluginRoot)
		{
			if (ContainsChineseProjectGuid(pluginGuids))
			{
				return true;
			}
			return ContainsChineseProjectDll(pluginRoot);
		}

		private static bool ContainsChineseProjectGuid(IEnumerable<string> pluginGuids)
		{
			if (pluginGuids == null)
			{
				return false;
			}
			foreach (string pluginGuid in pluginGuids)
			{
				if (string.Equals(pluginGuid, "cn.codex.v81testchn", StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static bool ContainsChineseProjectDll(string pluginRoot)
		{
			if (string.IsNullOrWhiteSpace(pluginRoot) || !Directory.Exists(pluginRoot))
			{
				return false;
			}
			if (File.Exists(Path.Combine(pluginRoot, "V81TestChn", "V81TestChn.dll")) || File.Exists(Path.Combine(pluginRoot, "V81TestChn.dll")))
			{
				return true;
			}
			try
			{
				foreach (string item in Directory.EnumerateFiles(pluginRoot, "V81TestChn.dll", SearchOption.AllDirectories))
				{
					if (string.Equals(Path.GetFileName(item), "V81TestChn.dll", StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
				}
			}
			catch
			{
				return false;
			}
			return false;
		}
	}
	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_006d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0072: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Expected O, but got Unknown
				//IL_0180: Unknown result type (might be due to invalid IL or missing references)
				//IL_0196: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a0: 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_0103: Unknown result type (might be due to invalid IL or missing references)
				//IL_009c: 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)
				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_0019: 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_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: 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_0015: 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_0008: 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_005d: 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_0062: 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_006f: Unknown result type (might be due to invalid IL or missing references)
				//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_007c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0104: 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_011f: 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_0096: 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_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: 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_007a: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_009c: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_00be: 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 readonly List<Renderer> eligibleRenderers = new List<Renderer>();

		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(ModelWarningPhase phase)
		{
			if (phase == ModelWarningPhase.None || (Object)(object)nutcracker == (Object)null)
			{
				loggedMeshVisible = false;
				loggedScreenVisible = false;
				SetMeshVisible(visible: false);
				SetScreenVisible(visible: false);
				return;
			}
			bool flag = IsModelStateTintEnabled();
			bool flag2 = flag && UpdateStateTint(phase);
			if (phase != ModelWarningPhase.FireWindow || !IsModelFireWindowEnabled())
			{
				loggedScreenVisible = false;
				SetCloneShellVisible(visible: false);
				SetScreenVisible(visible: false);
				if (!flag2)
				{
					RestoreSourcePulses();
				}
			}
			else if (GetMode() == ModelOutlineMode.ScreenBox)
			{
				SetCloneShellVisible(visible: false);
				if (!flag2)
				{
					RestoreSourcePulses();
				}
				UpdateScreenBox();
			}
			else
			{
				SetScreenVisible(visible: false);
				UpdateMeshSilhouette(!flag);
			}
		}

		private void UpdateMeshSilhouette(bool includeSourcePulse)
		{
			//IL_0050: 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)
			//IL_007f: 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_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: 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)
			EnsureMeshClones();
			if (meshClones.Count == 0 && (!includeSourcePulse || sourcePulses.Count == 0))
			{
				SetCloneShellVisible(visible: false);
				if (includeSourcePulse)
				{
					RestoreSourcePulses();
				}
				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;
			if (includeSourcePulse)
			{
				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)
			{
				SetCloneShellVisible(visible: false);
				if (includeSourcePulse)
				{
					RestoreSourcePulses();
				}
			}
			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 < eligibleRenderers.Count; i++)
			{
				Renderer val = eligibleRenderers[i];
				if (ShouldUseCloneShell())
				{
					MeshOutlineClone meshOutlineClone = MeshOutlineClone.TryCreate(val, meshMaterial);
					if (meshOutlineClone != null)
					{
						meshClones.Add(meshOutlineClone);
					}
				}
				if (ShouldUseSourcePulse() || IsModelStateTintEnabled())
				{
					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 bool UpdateStateTint(ModelWarningPhase phase)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			EnsureMeshClones();
			if (sourcePulses.Count == 0)
			{
				return false;
			}
			Color stateTintColor = GetStateTintColor(phase);
			float emissionMultiplier = ((phase == ModelWarningPhase.FireWindow) ? GetFireWindowTintIntensity() : GetChaseTintIntensity());
			int num = 0;
			for (int i = 0; i < sourcePulses.Count; i++)
			{
				if (sourcePulses[i].Apply(stateTintColor, emissionMultiplier))
				{
					num++;
				}
			}
			if (IsDebugLoggingEnabled() && num > 0 && !loggedMeshVisible)
			{
				loggedMeshVisible = true;
				Plugin.Log.LogInfo((object)$"Nutcracker #{((EnemyAI)nutcracker).thisEnemyIndex} model state tint visible. Phase={phase} SourcePulses={num}");
			}
			return num > 0;
		}

		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={GetRendererTypeName(val)}, 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)
		{
			SetCloneShellVisible(visible);
			if (!visible)
			{
				RestoreSourcePulses();
			}
		}

		private void SetCloneShellVisible(bool visible)
		{
			for (int i = 0; i < meshClones.Count; i++)
			{
				meshClones[i].SetVisible(visible);
			}
		}

		private void RestoreSourcePulses()
		{
			for (int i = 0; i < sourcePulses.Count; i++)
			{
				sourcePulses[i].Restore();
			}
		}

		private void UpdateScreenBox()
		{
			//IL_002e: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00cc: 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_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: 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_0191: 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)
			//IL_01ab: 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_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: 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_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_0034: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0052: 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_0076: Expected O, but got Unknown
			//IL_0077: Expected O, but got Unknown
			Material val = new Material(Shader.Find("HDRP/Unlit") ?? Shader.Find("Hidden/Internal-Colored") ?? Shader.Find("Sprites/Default") ?? Shader.Find("UI/Default"))
			{
				name = "NutcrackerMeshSilhouetteOutlineMaterial",
				hideFlags = (HideFlags)61
			};
			ConfigureOutlineMaterial(val);
			SetMaterialColor(val, new Color(1f, 0.02f, 0.02f, 0.86f));
			return val;
		}

		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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_005f: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: 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_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			Image obj = val.AddComponent<Image>();
			((Graphic)obj).raycastTarget = false;
			((Graphic)obj).color = Color.clear;
			return obj;
		}

		private static void AnchorHorizontal(RectTransform strip, float y)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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)
			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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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)
			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_0017: 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)
			strip.sizeDelta = (horizontal ? new Vector2(0f, thickness) : new Vector2(thickness, 0f));
		}

		private static bool TryProjectBounds(Bounds bounds, Camera camera, out Rect screenRect)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_000f: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_007c: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_014b: 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_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			Vector3 min = ((Bounds)(ref bounds)).min;
			Vector3 max = ((Bounds)(ref bounds)).max;
			float minX = float.MaxValue;
			float minY = float.MaxValue;
			float maxX = float.MinValue;
			float maxY = float.MinValue;
			bool anyVisible = false;
			ProjectCorner(camera, new Vector3(min.x, min.y, min.z), ref anyVisible, ref minX, ref minY, ref maxX, ref maxY);
			ProjectCorner(camera, new Vector3(max.x, min.y, min.z), ref anyVisible, ref minX, ref minY, ref maxX, ref maxY);
			ProjectCorner(camera, new Vector3(min.x, max.y, min.z), ref anyVisible, ref minX, ref minY, ref maxX, ref maxY);
			ProjectCorner(camera, new Vector3(max.x, max.y, min.z), ref anyVisible, ref minX, ref minY, ref maxX, ref maxY);
			ProjectCorner(camera, new Vector3(min.x, min.y, max.z), ref anyVisible, ref minX, ref minY, ref maxX, ref maxY);
			ProjectCorner(camera, new Vector3(max.x, min.y, max.z), ref anyVisible, ref minX, ref minY, ref maxX, ref maxY);
			ProjectCorner(camera, new Vector3(min.x, max.y, max.z), ref anyVisible, ref minX, ref minY, ref maxX, ref maxY);
			ProjectCorner(camera, new Vector3(max.x, max.y, max.z), ref anyVisible, ref minX, ref minY, ref maxX, ref maxY);
			if (!anyVisible)
			{
				screenRect = default(Rect);
				return false;
			}
			minX = Mathf.Clamp(minX, 0f, (float)Screen.width);
			maxX = Mathf.Clamp(maxX, 0f, (float)Screen.width);
			minY = Mathf.Clamp(minY, 0f, (float)Screen.height);
			maxY = Mathf.Clamp(maxY, 0f, (float)Screen.height);
			if (maxX <= minX || maxY <= minY)
			{
				screenRect = default(Rect);
				return false;
			}
			screenRect = Rect.MinMaxRect(minX, minY, maxX, maxY);
			return true;
		}

		private static void ProjectCorner(Camera camera, Vector3 corner, ref bool anyVisible, ref float minX, ref float minY, ref float maxX, ref float maxY)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = camera.WorldToScreenPoint(corner);
			if (!(val.z <= 0.01f))
			{
				anyVisible = true;
				minX = Mathf.Min(minX, val.x);
				minY = Mathf.Min(minY, val.y);
				maxX = Mathf.Max(maxX, val.x);
				maxY = Mathf.Max(maxY, val.y);
			}
		}

		private bool TryGetBounds(out Bounds bounds)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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)
			RefreshRenderersIfNeeded(force: false);
			bounds = default(Bounds);
			bool flag = false;
			if (cachedRenderers == null)
			{
				return false;
			}
			for (int i = 0; i < eligibleRenderers.Count; i++)
			{
				Renderer val = eligibleRenderers[i];
				if (!((Object)(object)val == (Object)null) && 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)
			{
				return;
			}
			cachedRenderers = ((Component)nutcracker).GetComponentsInChildren<Renderer>(false);
			eligibleRenderers.Clear();
			for (int i = 0; i < cachedRenderers.Length; i++)
			{
				Renderer val = cachedRenderers[i];
				if (IsModelOutlineRenderer(val))
				{
					eligibleRenderers.Add(val);
				}
			}
			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()
		{
			if (NutcrackerShotConfig.ModelOutlineMode != null)
			{
				return NutcrackerShotConfig.ModelOutlineMode.Value;
			}
			return ModelOutlineMode.MeshSilhouette;
		}

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

		private static bool ShouldUseSourcePulse()
		{
			ModelPulseMode pulseMode = GetPulseMode();
			if (pulseMode != 0)
			{
				return pulseMode == ModelPulseMode.Both;
			}
			return true;
		}

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

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

		private static bool IsModelStateTintEnabled()
		{
			if (NutcrackerShotConfig.EnableModelStateTint != null)
			{
				return NutcrackerShotConfig.EnableModelStateTint.Value;
			}
			return false;
		}

		private static Color GetStateTintColor(ModelWarningPhase phase)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (phase == ModelWarningPhase.FireWindow)
			{
				return new Color(1f, 0.02f, 0.02f, GetFireWindowTintAlpha());
			}
			return new Color(1f, 1f, 1f, GetChaseTintAlpha());
		}

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

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

		private static float GetChaseTintAlpha()
		{
			if (NutcrackerShotConfig.ModelChaseTintAlpha != null)
			{
				return Mathf.Clamp01(NutcrackerShotConfig.ModelChaseTintAlpha.Value);
			}
			return 0.58f;
		}

		private static float GetChaseTintIntensity()
		{
			if (NutcrackerShotConfig.ModelChaseTintIntensity != null)
			{
				return Mathf.Clamp(NutcrackerShotConfig.ModelChaseTintIntensity.Value, 0f, 12f);
			}
			return 1.8f;
		}

		private static float GetFireWindowTintAlpha()
		{
			if (NutcrackerShotConfig.ModelFireWindowTintAlpha != null)
			{
				return Mathf.Clamp01(NutcrackerShotConfig.ModelFireWindowTintAlpha.Value);
			}
			return 0.96f;
		}

		private static float GetFireWindowTintIntensity()
		{
			if (NutcrackerShotConfig.ModelFireWindowTintIntensity != null)
			{
				return Mathf.Clamp(NutcrackerShotConfig.ModelFireWindowTintIntensity.Value, 0f, 12f);
			}
			return 5f;
		}

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

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

		private static bool IsModelOutlineRenderer(Renderer renderer)
		{
			if ((Object)(object)renderer == (Object)null || renderer is LineRenderer || renderer is 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", "NutcrackerMeshOutline", "NutcrackerFireWindow"))
			{
				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);
				if (!ContainsAny(path, "LOD0"))
				{
					return ContainsAny(value, "LOD0");
				}
				return true;
			}
			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;
			if (!ContainsAny(path, "Gun", "Shotgun"))
			{
				return ContainsAny(name, "Gun", "Shotgun");
			}
			return true;
		}

		private static string GetRendererTypeName(Renderer renderer)
		{
			if (renderer is SkinnedMeshRenderer)
			{
				return "SkinnedMeshRenderer";
			}
			if (renderer is MeshRenderer)
			{
				return "MeshRenderer";
			}
			if (renderer is ParticleSystemRenderer)
			{
				return "ParticleSystemRenderer";
			}
			if (renderer is LineRenderer)
			{
				return "LineRenderer";
			}
			return "Renderer";
		}

		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;
		}
	}
	internal enum ModelWarningPhase
	{
		None,
		Chase,
		FireWindow
	}
	internal static class NutcrackerModelWarningPhaseSelector
	{
		public static ModelWarningPhase Select(bool modelEnabled, bool stateTintEnabled, bool fireWindowActive, bool chaseActive)
		{
			if (!modelEnabled)
			{
				return ModelWarningPhase.None;
			}
			if (fireWindowActive)
			{
				return ModelWarningPhase.FireWindow;
			}
			if (!(stateTintEnabled && chaseActive))
			{
				return ModelWarningPhase.None;
			}
			return ModelWarningPhase.Chase;
		}
	}
	[HarmonyPatch(typeof(NutcrackerEnemyAI))]
	internal static class NutcrackerPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void UpdatePostfix(NutcrackerEnemyAI __instance)
		{
			if (NutcrackerShotConfig.IsModEnabled() && !((Object)(object)__instance == (Object)null) && !((EnemyAI)__instance).isEnemyDead && NutcrackerCombatStateReader.TryRead(__instance, out var combatState))
			{
				NutcrackerShotIndicator nutcrackerShotIndicator = NutcrackerShotIndicator.GetExisting(__instance);
				if ((Object)(object)nutcrackerShotIndicator == (Object)null && NutcrackerShotIndicator.ShouldCreateForCombatState(__instance, combatState))
				{
					nutcrackerShotIndicator = NutcrackerShotIndicator.For(__instance);
				}
				nutcrackerShotIndicator?.ObserveCombatState(combatState);
			}
		}

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

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

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

		[HarmonyPostfix]
		[HarmonyPatch("KillEnemy")]
		private static void KillEnemyPostfix(NutcrackerEnemyAI __instance)
		{
			NutcrackerShotIndicator.Remove(__instance);
		}
	}
	internal static class NutcrackerShotConfig
	{
		internal const bool DefaultEnableModelOutlineFireWindow = false;

		internal const bool DefaultEnableModelStateTint = true;

		private static bool useChineseDescriptions;

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

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

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

		public static ConfigEntry<bool> EnableModelStateTint { 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> ModelChaseTintAlpha { get; private set; }

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

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

		public static ConfigEntry<float> ModelFireWindowTintIntensity { 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)
		{
			useChineseDescriptions = NutcrackerConfigLanguageDetector.ShouldUseChineseConfig();
			EnableMod = config.Bind<bool>("General", "EnableMod", true, Description("Enable Nutcracker Fire Warning. When disabled, the plugin does not create or update warning UI, model warnings, or fallback scans.", "启用 Nutcracker Fire Warning 总开关。关闭后不会创建或更新预警 UI、模型预警或备用扫描。"));
			EnableUiFireWindow = config.Bind<bool>("Warnings", "EnableUiFireWindow", true, Description("Show the world-space side warning bar, including countdown, FIRE pulse, reload bar, and pre-aim danger bar.", "显示胡桃身侧的世界空间竖条 UI,包括倒计时、FIRE 脉冲、换弹条和预瞄危险提示。"));
			EnableModelOutlineFireWindow = config.Bind<bool>("Warnings", "EnableModelOutlineFireWindow", false, Description("Enable the extra fire-window-only model overlay: red-white pulse, clone shell, or screen box depending on ModelOutlineMode and ModelPulseMode. Usually keep this disabled when EnableModelStateTint is enabled.", "启用仅在最终开火窗口出现的额外模型叠加预警:根据 ModelOutlineMode 和 ModelPulseMode 显示红白脉冲、克隆外壳或屏幕框。启用 EnableModelStateTint 时通常保持关闭。"));
			EnableModelStateTint = config.Bind<bool>("Warnings", "EnableModelStateTint", true, Description("Enable the recommended model state warning: white while the Nutcracker is chasing a target, red during the final fire window.", "启用推荐的模型状态预警:胡桃追击目标时模型变白,进入最终开火窗口时模型变红。"));
			ModelOutlineWidth = config.Bind<float>("Warnings", "ModelOutlineWidth", 0.075f, Description("Line width for ScreenBox mode. In MeshSilhouette mode this is the normal-expanded edge thickness.", "ScreenBox 模式的线宽;MeshSilhouette 模式下为法线扩展轮廓厚度。"));
			ModelOutlineMode = config.Bind<ModelOutlineMode>("Warnings", "ModelOutlineMode", NutcrackerShotUI.ModelOutlineMode.MeshSilhouette, Description("Model outline style. MeshSilhouette follows the Nutcracker model; ScreenBox draws a reliable HUD fallback rectangle.", "模型轮廓样式。MeshSilhouette 贴合胡桃模型;ScreenBox 绘制稳定的屏幕空间备用矩形。"));
			ModelPulseMode = config.Bind<ModelPulseMode>("Warnings", "ModelPulseMode", NutcrackerShotUI.ModelPulseMode.SourcePulse, Description("Implementation used by the extra fire-window overlay in MeshSilhouette mode. SourcePulse recolors the original model; CloneShell adds a cloned shell; Both enables both.", "MeshSilhouette 模式下额外开火窗口叠加层的实现方式。SourcePulse 重染原模型;CloneShell 添加克隆外壳;Both 同时启用两者。"));
			MeshOutlineScale = config.Bind<float>("Warnings", "MeshOutlineScale", 1f, Description("Extra transform scale for MeshSilhouette outline clones. Keep this at 1 for the most exact model edge.", "MeshSilhouette 克隆轮廓的额外缩放。保持 1 可获得最贴近模型边缘的效果。"));
			ModelPulseIntensity = config.Bind<float>("Warnings", "ModelPulseIntensity", 4f, Description("Emission multiplier for the extra red-white fire-window overlay.", "额外红白开火窗口叠加层的发光强度倍率。"));
			ModelPulseAlpha = config.Bind<float>("Warnings", "ModelPulseAlpha", 0.92f, Description("Alpha used by the extra red-white fire-window overlay.", "额外红白开火窗口叠加层的不透明度。"));
			ModelChaseTintAlpha = config.Bind<float>("Warnings", "ModelChaseTintAlpha", 0.58f, Description("Alpha used when the Nutcracker model is tinted white while chasing.", "胡桃追击目标时白色模型染色的不透明度。"));
			ModelChaseTintIntensity = config.Bind<float>("Warnings", "ModelChaseTintIntensity", 1.8f, Description("Emission multiplier for the white chase-state model tint.", "胡桃追击目标时白色模型染色的发光强度倍率。"));
			ModelFireWindowTintAlpha = config.Bind<float>("Warnings", "ModelFireWindowTintAlpha", 0.96f, Description("Alpha used when the Nutcracker model is tinted red during the final fire window.", "胡桃进入最终开火窗口时红色模型染色的不透明度。"));
			ModelFireWindowTintIntensity = config.Bind<float>("Warnings", "ModelFireWindowTintIntensity", 5f, Description("Emission multiplier for the red fire-window model tint.", "胡桃进入最终开火窗口时红色模型染色的发光强度倍率。"));
			ModelWarningMaxDistance = config.Bind<float>("Warnings", "ModelWarningMaxDistance", 45f, Description("Maximum local-player distance for model warnings. Set to 0 or lower to disable distance filtering.", "模型预警相对本地玩家的最大显示距离。设为 0 或更低可关闭距离过滤。"));
			ModelWarningRequireCameraVisible = config.Bind<bool>("Warnings", "ModelWarningRequireCameraVisible", false, Description("Only show model warnings when the Nutcracker is inside the local camera viewport.", "仅当胡桃位于本地摄像机视野内时显示模型预警。"));
			FireWindowSeconds = config.Bind<float>("Warnings", "FireWindowSeconds", 0.35f, Description("Seconds before the predicted shot when fire-window warnings activate.", "预测开火前多少秒进入最终开火窗口预警。"));
			PreAimMaxDistance = config.Bind<float>("Warnings", "PreAimMaxDistance", 30f, Description("Maximum distance for the yellow pre-aim danger bar. Set to 0 or lower to disable the pre-aim bar.", "黄色预瞄危险条的最大距离。设为 0 或更低可关闭预瞄条。"));
			MonitorActiveScanInterval = config.Bind<float>("Performance", "MonitorActiveScanInterval", 0.5f, Description("Fallback monitor scan interval while Nutcrackers are present.", "场上存在胡桃时,备用监视器的扫描间隔。"));
			MonitorIdleScanInterval = config.Bind<float>("Performance", "MonitorIdleScanInterval", 2f, Description("Fallback monitor scan interval while no Nutcrackers are present.", "场上没有胡桃时,备用监视器的扫描间隔。"));
			EnableDebugLogs = config.Bind<bool>("Debug", "EnableDebugLogs", false, Description("Log aim/fire warning events to BepInEx LogOutput.log.", "将瞄准/开火预警事件记录到 BepInEx LogOutput.log。"));
			DumpModelAudit = config.Bind<bool>("Debug", "DumpModelAudit", false, Description("Log Nutcracker renderer and mesh names/counts once when the model outline is built.", "构建模型轮廓时记录一次胡桃 Renderer 和 Mesh 的名称/数量。"));
		}

		public static bool IsModEnabled()
		{
			if (EnableMod != null)
			{
				return EnableMod.Value;
			}
			return true;
		}

		private static string Description(string english, string chinese)
		{
			if (!useChineseDescriptions)
			{
				return english;
			}
			return chinese;
		}
	}
	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 const float PreAimCheckInterval = 0.12f;

		private const float PreAimAngleDegrees = 35f;

		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 static readonly float PreAimMinimumDot = Mathf.Cos(0.61086524f);

		private static readonly string[] CountdownLabels = CreateCountdownLabels();

		private static readonly Dictionary<NutcrackerEnemyAI, NutcrackerShotIndicator> Indicators = new Dictionary<NutcrackerEnemyAI, NutcrackerShotIndicator>();

		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 float nextPreAimCheckTime;

		private float cachedPreAimDanger;

		private bool observedAimingLastFrame;

		private bool observedReloadingLastFrame;

		private NutcrackerCombatState lastCombatState;

		public static NutcrackerShotIndicator For(NutcrackerEnemyAI nutcracker)
		{
			//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)
			if (!NutcrackerShotConfig.IsModEnabled() || (Object)(object)nutcracker == (Object)null)
			{
				return null;
			}
			NutcrackerShotIndicator existing = GetExisting(nutcracker);
			if ((Object)(object)existing != (Object)null)
			{
				return existing;
			}
			GameObject val = new GameObject("NutcrackerShotUI");
			val.transform.SetParent(((Component)nutcracker).transform, false);
			existing = val.AddComponent<NutcrackerShotIndicator>();
			existing.Initialize(nutcracker);
			Indicators[nutcracker] = existing;
			return existing;
		}

		public static NutcrackerShotIndicator GetExisting(NutcrackerEnemyAI nutcracker)
		{
			if ((Object)(object)nutcracker == (Object)null)
			{
				return null;
			}
			if (Indicators.TryGetValue(nutcracker, out var value))
			{
				if ((Object)(object)value != (Object)null)
				{
					return value;
				}
				Indicators.Remove(nutcracker);
			}
			return null;
		}

		public static bool ShouldCreateForCombatState(NutcrackerEnemyAI nutcracker, NutcrackerCombatState combatState)
		{
			if (!NutcrackerShotConfig.IsModEnabled() || (Object)(object)nutcracker == (Object)null || ((EnemyAI)nutcracker).isEnemyDead)
			{
				return false;
			}
			if (combatState.AimingGun || combatState.ReloadingGun)
			{
				return true;
			}
			if (IsModelStateTintEnabled() && IsChaseTintCandidate(nutcracker, combatState))
			{
				return true;
			}
			if (IsUiFireWindowEnabled() && GetPreAimMaxDistance() > 0f && ((EnemyAI)nutcracker).currentBehaviourStateIndex == 2 && (Object)(object)nutcracker.gun != (Object)null)
			{
				return nutcracker.gun.shellsLoaded > 0;
			}
			return false;
		}

		public static void Remove(NutcrackerEnemyAI nutcracker)
		{
			if (!((Object)(object)nutcracker == (Object)null))
			{
				NutcrackerShotIndicator existing = GetExisting(nutcracker);
				if ((Object)(object)existing != (Object)null)
				{
					Indicators.Remove(nutcracker);
					Object.Destroy((Object)(object)((Component)existing).gameObject);
				}
			}
		}

		public void BeginAim(float duration)
		{
			if (NutcrackerShotConfig.IsModEnabled())
			{
				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()
		{
			if (NutcrackerShotConfig.IsModEnabled())
			{
				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)
		{
			if (NutcrackerShotConfig.IsModEnabled())
			{
				state = WarningState.Reloading;
				stateStartedAt = Time.time;
				stateDuration = duration;
				SetVisible(visible: true);
			}
		}

		public void ObserveCombatState(bool aimingGun, bool reloadingGun, float timeSinceFiringGun, float aimDuration)
		{
			if (!NutcrackerShotConfig.IsModEnabled())
			{
				return;
			}
			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);
				UpdateModelWarningPhase(fireWindowActive: false);
			}
			if (reloadingGun && !observedReloadingLastFrame && state != WarningState.Aiming)
			{
				BeginReload(1.74f);
			}
			observedAimingLastFrame = aimingGun;
			observedReloadingLastFrame = reloadingGun;
		}

		public void ObserveCombatState(NutcrackerCombatState combatState)
		{
			lastCombatState = combatState;
			ObserveCombatState(combatState.AimingGun, combatState.ReloadingGun, combatState.TimeSinceFiringGun, combatState.AimDuration);
		}

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

		private void OnDestroy()
		{
			modelOutline?.Dispose();
			if ((Object)(object)nutcracker != (Object)null && Indicators.TryGetValue(nutcracker, out var value) && (Object)(object)value == (Object)(object)this)
			{
				Indicators.Remove(nutcracker);
			}
		}

		private void OnDisable()
		{
			SetModelWarningPhase(ModelWarningPhase.None);
		}

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

		private void BuildWorldBar()
		{
			//IL_0043: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: 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_009e: 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_0108: 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_0128: 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_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: 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)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: 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_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			Image obj = val.AddComponent<Image>();
			((Graphic)obj).color = color;
			((Graphic)obj).raycastTarget = false;
			return obj;
		}

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

		private void UpdateTransform()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_003c: 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_0066: 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_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_0091: 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_0034: 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)
			bool flag = IsUiFireWindowEnabled();
			if (!flag)
			{
				HideUiElements();
			}
			switch (state)
			{
			case WarningState.Aiming:
				UpdateAimingState();
				return;
			case WarningState.Fired:
				UpdateTimedState(FiredColor, 1f, hideWhenFinished: true);
				return;
			case WarningState.Reloading:
				UpdateTimedState(ReloadColor, reverse: true, hideWhenFinished: true);
				return;
			}
			if (flag)
			{
				UpdatePreAim();
				return;
			}
			lastPreAimAmount = 0f;
			UpdateModelWarningPhase(fireWindowActive: false);
		}

		private void UpdateTimedState(Color color, float alpha, bool hideWhenFinished)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: 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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp01((Time.time - stateStartedAt) / Mathf.Max(0.01f, stateDuration));
			if (IsUiFireWindowEnabled())
			{
				((Graphic)fill).color = color;
				fill.fillAmount = (reverse ? (1f - num) : num);
				SetCountdownText(null, Color.white);
				SetCriticalPulse(0f);
			}
			else
			{
				HideUiElements();
			}
			UpdateModelWarningPhase(fireWindowActive: false);
			if (num >= 1f)
			{
				state = WarningState.Idle;
				if (hideWhenFinished)
				{
					SetVisible(visible: false);
				}
			}
		}

		private void UpdateAimingState()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: 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_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: 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);
			bool flag = IsUiFireWindowEnabled();
			if (flag)
			{
				fill.fillAmount = num3;
				((Graphic)fill).color = Color.Lerp(AimColor, FiredColor, num5 * 0.45f);
			}
			else
			{
				HideUiElements();
			}
			if (num4 <= fireWindowSeconds)
			{
				UpdateModelWarningPhase(fireWindowActive: true);
				if (flag)
				{
					float num6 = 0.45f + Mathf.PingPong(Time.time * 12f, 0.55f);
					SetCriticalPulse(num6);
					SetCountdownText("FIRE", Color.Lerp(AimColor, FiredColor, num6));
				}
			}
			else
			{
				UpdateModelWarningPhase(fireWindowActive: false);
				if (flag)
				{
					SetCriticalPulse(0f);
					SetRemainingCountdown(num4);
				}
			}
			if (num3 >= 1f)
			{
				state = WarningState.Idle;
				UpdateModelWarningPhase(fireWindowActive: false);
				if (flag)
				{
					fill.fillAmount = 1f;
					SetCountdownText("NOW", FiredColor);
					SetCriticalPulse(0.85f);
				}
				else
				{
					SetCountdownText(null, Color.white);
					SetCriticalPulse(0f);
				}
			}
		}

		private void UpdatePreAim()
		{
			//IL_009e: 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_00ce: 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)
			if (Time.time >= nextPreAimCheckTime)
			{
				cachedPreAimDanger = GetPreAimDanger();
				nextPreAimCheckTime = Time.time + 0.12f;
			}
			float num = cachedPreAimDanger;
			lastPreAimAmount = Mathf.MoveTowards(lastPreAimAmount, num, Time.deltaTime * 4f);
			if (lastPreAimAmount <= 0.01f)
			{
				SetVisible(visible: false);
				fill.fillAmount = 0f;
				SetCountdownText(null, Color.white);
				SetCriticalPulse(0f);
				UpdateModelWarningPhase(fireWindowActive: false);
			}
			else
			{
				SetVisible(visible: true);
				((Graphic)fill).color = PreAimColor;
				fill.fillAmount = Mathf.Clamp01(lastPreAimAmount);
				SetCountdownText("!", PreAimColor.WithAlpha(0.92f));
				SetCriticalPulse(0f);
				UpdateModelWarningPhase(fireWindowActive: false);
			}
		}

		private float GetPreAimDanger()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_0097: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_00dc: 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_00f6: 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_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			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 preAimMaxDistance = GetPreAimMaxDistance();
			if (preAimMaxDistance <= 0f || ((Vector3)(ref val2)).sqrMagnitude > preAimMaxDistance * preAimMaxDistance)
			{
				return 0f;
			}
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (magnitude <= 0.001f)
			{
				return 0f;
			}
			Vector3 val3 = val2 / magnitude;
			float num = Vector3.Dot(nutcracker.gun.shotgunRayPoint.forward, val3);
			if (num < PreAimMinimumDot)
			{
				return 0f;
			}
			if (Physics.Linecast(position2, position, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1))
			{
				return 0f;
			}
			float num2 = 1f - Mathf.Clamp01(magnitude / preAimMaxDistance);
			float num3 = Mathf.InverseLerp(PreAimMinimumDot, 1f, num);
			return Mathf.Clamp01(0.2f + num2 * 0.35f + num3 * 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)
		{
			bool flag = visible && IsUiFireWindowEnabled();
			if ((Object)(object)canvas != (Object)null && ((Behaviour)canvas).enabled != flag)
			{
				((Behaviour)canvas).enabled = flag;
			}
		}

		private void HideUiElements()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			SetVisible(visible: false);
			if ((Object)(object)fill != (Object)null)
			{
				fill.fillAmount = 0f;
			}
			SetCountdownText(null, Color.white);
			SetCriticalPulse(0f);
		}

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

		private void SetRemainingCountdown(float remaining)
		{
			//IL_0024: 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)
			int num = Mathf.Clamp(Mathf.RoundToInt(remaining * 10f), 0, CountdownLabels.Length - 1);
			SetCountdownText(CountdownLabels[num], AimColor.WithAlpha(0.96f));
		}

		private static string[] CreateCountdownLabels()
		{
			string[] array = new string[21];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = ((float)i * 0.1f).ToString("0.0");
			}
			return array;
		}

		private void SetCriticalPulse(float alpha)
		{
			//IL_0015: 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_0034: 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 SetModelWarningPhase(ModelWarningPhase phase)
		{
			modelOutline?.Update(phase);
		}

		private void UpdateModelWarningPhase(bool fireWindowActive)
		{
			bool flag = IsAnyModelWarningEnabled();
			bool flag2 = IsModelStateTintEnabled();
			bool flag3 = flag && ShouldShowModelWarningByDistanceAndCamera();
			bool fireWindowActive2 = fireWindowActive && flag3 && (IsModelFireWindowEnabled() || flag2);
			bool chaseActive = flag3 && flag2 && IsChaseTintCandidate(nutcracker, lastCombatState);
			SetModelWarningPhase(NutcrackerModelWarningPhaseSelector.Select(flag, flag2, fireWindowActive2, chaseActive));
		}

		private bool ShouldShowModelWarningByDistanceAndCamera()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_0080: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: 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)
			if (!IsAnyModelWarningEnabled())
			{
				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 IsChaseTintCandidate(NutcrackerEnemyAI nutcracker, NutcrackerCombatState combatState)
		{
			if ((Object)(object)nutcracker == (Object)null || ((EnemyAI)nutcracker).isEnemyDead || ((EnemyAI)nutcracker).currentBehaviourStateIndex != 2)
			{
				return false;
			}
			if (combatState.ReloadingGun || (Object)(object)nutcracker.gun == (Object)null || nutcracker.gun.shellsLoaded <= 0)
			{
				return false;
			}
			if (combatState.AimingGun)
			{
				return true;
			}
			if (nutcracker.lastPlayerSeenMoving != -1 && (Object)(object)((EnemyAI)nutcracker).targetPlayer != (Object)null)
			{
				return ((EnemyAI)nutcracker).movingTowardsTargetPlayer;
			}
			return false;
		}

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

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

		private static bool IsModelStateTintEnabled()
		{
			if (NutcrackerShotConfig.EnableModelStateTint != null)
			{
				return NutcrackerShotConfig.EnableModelStateTint.Value;
			}
			return false;
		}

		private static bool IsAnyModelWarningEnabled()
		{
			if (!IsModelFireWindowEnabled())
			{
				return IsModelStateTintEnabled();
			}
			return true;
		}

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

		private static float GetPreAimMaxDistance()
		{
			if (NutcrackerShotConfig.PreAimMaxDistance == null)
			{
				return 30f;
			}
			float value = NutcrackerShotConfig.PreAimMaxDistance.Value;
			if (!(value <= 0f))
			{
				return Mathf.Clamp(value, 1f, 100f);
			}
			return 0f;
		}

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

		private static bool IsDebugLoggingEnabled()
		{
			if (NutcrackerShotConfig.EnableDebugLogs != null)
			{
				return NutcrackerShotConfig.EnableDebugLogs.Value;
			}
			return false;
		}
	}
	internal static class ColorExtensions
	{
		public static Color WithAlpha(this Color color, float alpha)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			color.a = alpha;
			return color;
		}
	}
	internal sealed class NutcrackerShotMonitor : MonoBehaviour
	{
		private float nextScanTime;

		private int lastObservedCount = -1;

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

		private void Update()
		{
			if (!NutcrackerShotConfig.IsModEnabled())
			{
				nextScanTime = Time.time + GetConfigInterval(NutcrackerShotConfig.MonitorIdleScanInterval, 2f);
			}
			else
			{
				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 && NutcrackerCombatStateReader.TryRead(val, out var combatState))
					{
						NutcrackerShotIndicator nutcrackerShotIndicator = NutcrackerShotIndicator.GetExisting(val);
						if ((Object)(object)nutcrackerShotIndicator == (Object)null && NutcrackerShotIndicator.ShouldCreateForCombatState(val, combatState))
						{
							nutcrackerShotIndicator = NutcrackerShotIndicator.For(val);
						}
						nutcrackerShotIndicator?.ObserveCombatState(combatState);
					}
				}
			}
		}

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

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

		private static bool IsDebugLoggingEnabled()
		{
			if (NutcrackerShotConfig.EnableDebugLogs != null)
			{
				return NutcrackerShotConfig.EnableDebugLogs.Value;
			}
			return false;
		}
	}
	[BepInPlugin("aueser.lethalcompany.nutcrackerfirewarning", "Nutcracker Fire Warning", "1.0.6")]
	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.6";

		private Harmony harmony;

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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. enabled={2}, UI fire window={3}, model outline={4}, debug={5}.", "Nutcracker Fire Warning", "1.0.6", NutcrackerShotConfig.EnableMod.Value, 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_0005: Unknown result type (might be due to invali