Decompiled source of Endgame Arsenal v1.0.2

ScheduleIEndgameArsenal.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using HarmonyLib;
using Il2Cpp;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppRootMotion;
using Il2CppRootMotion.FinalIK;
using Il2CppScheduleOne;
using Il2CppScheduleOne.Audio;
using Il2CppScheduleOne.AvatarFramework;
using Il2CppScheduleOne.AvatarFramework.Animation;
using Il2CppScheduleOne.AvatarFramework.Equipping;
using Il2CppScheduleOne.Core.Audio;
using Il2CppScheduleOne.Core.Items.Framework;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Equipping;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Levelling;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.Persistence;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Storage;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.UI.Items;
using Il2CppScheduleOne.UI.Shop;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using ScheduleIEndgameArsenal;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(ArsenalMod), "Schedule I Endgame Arsenal", "1.0.2", "nacho", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: MelonPlatformDomain(/*Could not decode attribute arguments.*/)]
[assembly: HarmonyDontPatchAll]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("ScheduleIEndgameArsenal")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+c02009702c06e41397470955ed5c61813b6c6995")]
[assembly: AssemblyProduct("ScheduleIEndgameArsenal")]
[assembly: AssemblyTitle("ScheduleIEndgameArsenal")]
[assembly: AssemblyVersion("1.0.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 ScheduleIEndgameArsenal
{
	public sealed class ArsenalMod : MelonMod
	{
		private Harmony? patches;

		private ArsenalSettings? settings;

		private bool settingsDirty = true;

		private float nextAttempt;

		private int failureCount;

		private bool ready;

		public override void OnInitializeMelon()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			settings = new ArsenalSettings(delegate
			{
				settingsDirty = true;
				nextAttempt = 0f;
			});
			RegistryAndShop.BindSettings(settings);
			patches = new Harmony("nacho.schedulei.endgamearsenal");
			RegistryAndShop.Initialize(patches);
			WeaponBehavior.Initialize(patches);
			AvatarWeapons.Initialize(patches);
			HandPoses.Initialize(patches);
			SniperScope.Initialize(patches);
			SniperTargets.Initialize(patches);
			SniperChamber.Initialize(patches);
			((MelonBase)this).LoggerInstance.Msg("Endgame Arsenal 1.0.2: weapon unlock ranks, gun prices and ammo prices are available in Mod Manager & Phone App settings.");
		}

		public override void OnUpdate()
		{
			SniperChamber.Update();
			if (ready)
			{
				SniperScope.Update();
			}
			if ((ready && RegistryAndShop.PortraitsComplete && !settingsDirty) || Time.unscaledTime < nextAttempt)
			{
				return;
			}
			nextAttempt = Time.unscaledTime + 1f;
			try
			{
				if (ready)
				{
					if (settingsDirty)
					{
						settingsDirty = !RegistryAndShop.ApplySettings();
					}
					if (!RegistryAndShop.PortraitsComplete)
					{
						RegistryAndShop.RetryModelPortraits();
					}
					return;
				}
				bool flag = RegistryAndShop.TryRegister();
				LoadManager instance = Singleton<LoadManager>.Instance;
				if ((Object)(object)instance == (Object)null || !instance.IsGameLoaded || instance.IsLoading)
				{
					return;
				}
				if (!flag)
				{
					nextAttempt = Time.unscaledTime + 5f;
					if (failureCount++ < 3)
					{
						((MelonBase)this).LoggerInstance.Warning("Arsenal items could not initialize from the game's M1911 and magazine templates. Retrying in 5 seconds.");
					}
					return;
				}
				if (RegistryAndShop.TryAddToStan() && !ready)
				{
					ready = true;
					settingsDirty = !RegistryAndShop.ApplySettings();
					((MelonBase)this).LoggerInstance.Msg("Stan's shop has the three endgame weapons and their matching rounds. Native rank requirements apply.");
				}
				failureCount = 0;
			}
			catch (Exception ex)
			{
				nextAttempt = Time.unscaledTime + 5f;
				if (failureCount++ < 3)
				{
					((MelonBase)this).LoggerInstance.Warning("Arsenal setup will retry: " + ex.GetType().Name + ": " + ex.Message);
				}
			}
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			nextAttempt = 0f;
			ready = false;
			settingsDirty = true;
			failureCount = 0;
			WeaponBehavior.Reset();
			SniperScope.Reset();
			SniperChamber.Reset();
			HandPoses.Reset();
		}

		public override void OnDeinitializeMelon()
		{
			SniperChamber.Reset();
			SniperScope.Reset();
			HandPoses.Reset();
			settings?.Dispose();
			Harmony? obj = patches;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	internal sealed class ArsenalSettings : IDisposable
	{
		private sealed class WeaponEntries
		{
			private readonly WeaponShopSettings defaults;

			private readonly MelonPreferences_Entry<ArsenalUnlockRank> rank;

			private readonly MelonPreferences_Entry<int> tier;

			private readonly MelonPreferences_Entry<float> price;

			private readonly MelonPreferences_Entry<float> ammoPrice;

			internal WeaponShopSettings Value { get; private set; }

			internal WeaponEntries(ArsenalSettings owner, string prefix, WeaponSpec spec)
			{
				defaults = Defaults(spec);
				string text = spec.Name + ": ";
				rank = owner.Add(prefix + "UnlockRank", (ArsenalUnlockRank)spec.Rank, text + "unlock rank", "Street Rat through Kingpin. Applies to this gun and its matching ammunition at Stan's shop.");
				tier = owner.Add(prefix + "UnlockTier", spec.Tier, text + "unlock tier", "1–5 (I–V) within the chosen rank. Applies to this gun and its matching ammunition.");
				price = owner.Add(prefix + "Price", spec.Price, text + "gun price", "$0–$1,000,000 per gun at Stan's shop. Zero makes the gun free.");
				ammoPrice = owner.Add(prefix + "AmmoPrice", spec.AmmoPrice, text + "ammunition price", $"$0–$100,000 per {spec.Capacity}-round pack at Stan's shop. Zero makes ammunition free.");
			}

			internal void Refresh()
			{
				WeaponShopSettings value = ArsenalSettingsPolicy.Normalize(rank.Value, tier.Value, price.Value, ammoPrice.Value, defaults);
				if (rank.Value != (ArsenalUnlockRank)value.Rank)
				{
					rank.Value = (ArsenalUnlockRank)value.Rank;
				}
				if (tier.Value != value.Tier)
				{
					tier.Value = value.Tier;
				}
				if (price.Value != value.Price)
				{
					price.Value = value.Price;
				}
				if (ammoPrice.Value != value.AmmoPrice)
				{
					ammoPrice.Value = value.AmmoPrice;
				}
				Value = value;
			}
		}

		private readonly MelonPreferences_Category category;

		private readonly Action changed;

		private readonly List<Action> unsubscribe = new List<Action>(12);

		private readonly WeaponEntries automaticPistol;

		private readonly WeaponEntries m4;

		private readonly WeaponEntries sniper;

		private bool refreshing = true;

		private bool disposed;

		internal ArsenalSettings(Action changed)
		{
			this.changed = changed ?? throw new ArgumentNullException("changed");
			category = MelonPreferences.CreateCategory("ScheduleIEndgameArsenal", "Endgame Arsenal");
			automaticPistol = new WeaponEntries(this, "AutomaticPistol", FindDefaults("eg_auto_pistol"));
			m4 = new WeaponEntries(this, "M4", FindDefaults("eg_m4"));
			sniper = new WeaponEntries(this, "Sniper", FindDefaults("eg_sniper"));
			Refresh();
			refreshing = false;
			category.SaveToFile(false);
		}

		internal WeaponShopSettings For(WeaponSpec spec)
		{
			return spec.Id switch
			{
				"eg_auto_pistol" => automaticPistol.Value, 
				"eg_m4" => m4.Value, 
				"eg_sniper" => sniper.Value, 
				_ => ArsenalSettingsPolicy.Normalize((ArsenalUnlockRank)spec.Rank, spec.Tier, spec.Price, spec.AmmoPrice, Defaults(spec)), 
			};
		}

		internal void Save()
		{
			if (!disposed)
			{
				category.SaveToFile(false);
			}
		}

		public void Dispose()
		{
			if (disposed)
			{
				return;
			}
			disposed = true;
			foreach (Action item in unsubscribe)
			{
				item();
			}
			unsubscribe.Clear();
		}

		private void EntryChanged()
		{
			if (!refreshing && !disposed)
			{
				refreshing = true;
				try
				{
					Refresh();
				}
				finally
				{
					refreshing = false;
				}
				category.SaveToFile(false);
				changed();
			}
		}

		private void Refresh()
		{
			automaticPistol.Refresh();
			m4.Refresh();
			sniper.Refresh();
		}

		private MelonPreferences_Entry<T> Add<T>(string key, T defaultValue, string title, string description)
		{
			MelonPreferences_Entry<T> entry = category.CreateEntry<T>(key, defaultValue, title, description, false, false, (ValueValidator)null, (string)null);
			LemonAction<T, T> handler = delegate
			{
				EntryChanged();
			};
			((MelonEventBase<LemonAction<T, T>>)(object)entry.OnEntryValueChanged).Subscribe(handler, 0, false);
			unsubscribe.Add(delegate
			{
				((MelonEventBase<LemonAction<T, T>>)(object)entry.OnEntryValueChanged).Unsubscribe(handler);
			});
			return entry;
		}

		private static WeaponSpec FindDefaults(string id)
		{
			return WeaponCatalog.Find(id) ?? throw new InvalidOperationException("Missing weapon settings defaults: " + id);
		}

		private static WeaponShopSettings Defaults(WeaponSpec spec)
		{
			return new WeaponShopSettings(spec.Rank, spec.Tier, spec.Price, spec.AmmoPrice);
		}
	}
	public enum ArsenalUnlockRank
	{
		Street_Rat,
		Hoodlum,
		Peddler,
		Hustler,
		Bagman,
		Enforcer,
		Shot_Caller,
		Block_Boss,
		Underlord,
		Baron,
		Kingpin
	}
	internal readonly record struct WeaponShopSettings(int Rank, int Tier, float Price, float AmmoPrice);
	internal static class ArsenalSettingsPolicy
	{
		internal const float MaximumWeaponPrice = 1000000f;

		internal const float MaximumAmmoPrice = 100000f;

		internal static WeaponShopSettings Normalize(ArsenalUnlockRank rank, int tier, float price, float ammoPrice, WeaponShopSettings defaults)
		{
			return new WeaponShopSettings(Math.Clamp((int)rank, 0, 10), Math.Clamp(tier, 1, 5), Price(price, defaults.Price, 1000000f), Price(ammoPrice, defaults.AmmoPrice, 100000f));
		}

		private static float Price(float value, float fallback, float maximum)
		{
			return Math.Clamp(float.IsFinite(value) ? value : fallback, 0f, maximum);
		}
	}
	internal static class AvatarWeapons
	{
		public const string PathPrefix = "EndgameArsenal/";

		public static void Initialize(Harmony harmony)
		{
			//IL_0027: 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_0049: Expected O, but got Unknown
			//IL_0049: Expected O, but got Unknown
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Avatar), "SetEquippable", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AvatarWeapons), "BeforeSet", (Type[])null), new HarmonyMethod(typeof(AvatarWeapons), "AfterSet", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void BeforeSet(Avatar __instance, ref string assetPath, out WeaponSpec? __state)
		{
			HandPoses.ClearAvatar(__instance);
			__state = null;
			if (string.IsNullOrEmpty(assetPath) || !assetPath.StartsWith("EndgameArsenal/", StringComparison.Ordinal))
			{
				return;
			}
			WeaponSpec weaponSpec = WeaponCatalog.Find(assetPath.Substring("EndgameArsenal/".Length));
			if (weaponSpec == null)
			{
				return;
			}
			RegistryAndShop.TryRegister();
			if (string.IsNullOrEmpty(RegistryAndShop.BaseAvatarAssetPath))
			{
				return;
			}
			__state = weaponSpec;
			object obj2;
			if (HandPoses.IsLongGun(weaponSpec))
			{
				GameObject obj = Resources.Load<GameObject>("Avatar/Equippables/PumpShotgun");
				if ((Object)(object)((obj != null) ? obj.GetComponent<AvatarEquippable>() : null) != (Object)null)
				{
					obj2 = "Avatar/Equippables/PumpShotgun";
					goto IL_008c;
				}
			}
			obj2 = RegistryAndShop.BaseAvatarAssetPath;
			goto IL_008c;
			IL_008c:
			assetPath = (string)obj2;
		}

		private static void AfterSet(AvatarEquippable? __result, WeaponSpec? __state)
		{
			if (__state == null || (Object)(object)__result == (Object)null)
			{
				return;
			}
			try
			{
				ApplyAppearance(__result, __state);
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("Unable to create held " + __state.Name + ": " + ex.Message);
			}
		}

		public static void ApplyAppearance(AvatarEquippable avatar, WeaponSpec spec)
		{
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			string text = spec.Id + "_OriginalModel";
			if ((Object)(object)((Component)avatar).transform.Find(text) == (Object)null)
			{
				foreach (Renderer componentsInChild in ((Component)avatar).GetComponentsInChildren<Renderer>(true))
				{
					componentsInChild.enabled = false;
				}
				AvatarRangedWeapon val = ((Il2CppObjectBase)avatar).TryCast<AvatarRangedWeapon>();
				GameObject val2 = WeaponVisuals.Build(spec.Id, ((Component)avatar).transform);
				if ((Object)(object)val != (Object)null && (Object)(object)val.MuzzlePoint != (Object)null)
				{
					val2.transform.rotation = val.MuzzlePoint.rotation;
				}
				if ((Object)(object)avatar.AlignmentPoint != (Object)null)
				{
					val2.transform.position = avatar.AlignmentPoint.position;
				}
			}
			avatar.AssetPath = "EndgameArsenal/" + spec.Id;
			AvatarRangedWeapon val3 = ((Il2CppObjectBase)avatar).TryCast<AvatarRangedWeapon>();
			if ((Object)(object)val3 == (Object)null)
			{
				return;
			}
			val3.MagazineSize = spec.Capacity;
			val3.Damage = spec.Damage;
			val3.MaxFireRate = 1f / spec.FireInterval;
			val3.ImpactForce = Math.Max(100f, spec.Damage * 2.5f);
			Transform val4 = ((Component)avatar).transform.Find(text);
			if (!((Object)(object)val4 == (Object)null))
			{
				Transform val5 = val4.Find("ArsenalMuzzle");
				if ((Object)(object)val5 == (Object)null)
				{
					val5 = new GameObject("ArsenalMuzzle").transform;
					val5.SetParent(val4, false);
					Transform val6 = val5;
					string id = spec.Id;
					Vector3 localPosition = ((id == "eg_auto_pistol") ? new Vector3(0f, 0.101f, 0.2f) : ((!(id == "eg_m4")) ? new Vector3(0f, 0.097f, 0.713f) : new Vector3(0f, 0.095f, 0.476f)));
					val6.localPosition = localPosition;
				}
				val3.MuzzlePoint = val5;
				HandPoses.BindAvatar(avatar, spec, val4);
			}
		}
	}
	internal readonly record struct BallisticsTuning(float BloomPerShot, float HipBloomDegrees, float AimBloomDegrees, float PitchPerShot, float YawPerShot, float AimRecoilScale, float MaxPitch, float MaxYaw, float RecoveryDelay, float BloomRecoveryPerSecond, float RecoilRecoveryPerSecond)
	{
		public static BallisticsTuning For(string id)
		{
			return id switch
			{
				"eg_auto_pistol" => new BallisticsTuning(0.14f, 3.4f, 1.7f, 0.72f, 0.25f, 0.65f, 7f, 1.6f, 0.18f, 1.3f, 6f), 
				"eg_m4" => new BallisticsTuning(0.11f, 2.6f, 1.15f, 0.48f, 0.15f, 0.65f, 5.5f, 1.1f, 0.2f, 1.2f, 5f), 
				"eg_sniper" => new BallisticsTuning(0.3f, 2f, 0.12f, 1.8f, 0.22f, 0.4f, 4f, 0.8f, 0.3f, 1.4f, 5.5f), 
				_ => default(BallisticsTuning), 
			};
		}
	}
	internal readonly record struct BallisticsSample(float PitchDegrees, float YawDegrees, float BloomDegrees);
	internal sealed class BallisticsState
	{
		private double lastUpdate = double.NaN;

		private double lastShot = double.NegativeInfinity;

		public float Bloom { get; private set; }

		public float Pitch { get; private set; }

		public float Yaw { get; private set; }

		public void Advance(double now, BallisticsTuning tuning)
		{
			if (double.IsFinite(now))
			{
				if (double.IsNaN(lastUpdate) || now < lastUpdate)
				{
					float num = (Yaw = 0f);
					float bloom = (Pitch = num);
					Bloom = bloom;
					lastShot = double.NegativeInfinity;
					lastUpdate = now;
				}
				else
				{
					float num4 = (float)Math.Max(0.0, now - Math.Max(lastUpdate, lastShot + (double)tuning.RecoveryDelay));
					Bloom = TowardZero(Bloom, num4 * tuning.BloomRecoveryPerSecond);
					Pitch = TowardZero(Pitch, num4 * tuning.RecoilRecoveryPerSecond);
					Yaw = TowardZero(Yaw, num4 * tuning.RecoilRecoveryPerSecond);
					lastUpdate = now;
				}
			}
		}

		public void RecordShot(double now, float aim, float lateralSample, BallisticsTuning tuning)
		{
			Advance(now, tuning);
			if (double.IsFinite(now))
			{
				float num = 1f + (tuning.AimRecoilScale - 1f) * Unit(aim);
				Bloom = Math.Clamp(Bloom + tuning.BloomPerShot, 0f, 1f);
				Pitch = Math.Clamp(Pitch + tuning.PitchPerShot * num, 0f, tuning.MaxPitch);
				Yaw = Math.Clamp(Yaw + Math.Clamp(Finite(lateralSample), -1f, 1f) * tuning.YawPerShot * num, 0f - tuning.MaxYaw, tuning.MaxYaw);
				lastShot = now;
			}
		}

		public BallisticsSample Sample(float aim, BallisticsTuning tuning)
		{
			float num = tuning.HipBloomDegrees + (tuning.AimBloomDegrees - tuning.HipBloomDegrees) * Unit(aim);
			return new BallisticsSample(Pitch, Yaw, Bloom * num);
		}

		internal static float Unit(float value)
		{
			return Math.Clamp(Finite(value), 0f, 1f);
		}

		private static float Finite(float value)
		{
			if (!float.IsFinite(value))
			{
				return 0f;
			}
			return value;
		}

		private static float TowardZero(float value, float amount)
		{
			return (float)Math.Sign(value) * Math.Max(0f, Math.Abs(value) - Math.Max(0f, amount));
		}
	}
	internal static class BallisticsMath
	{
		private const float ToRadians = (float)Math.PI / 180f;

		public static Vector3 OffsetDirection(Vector3 nativeDirection, Vector3 cameraUp, BallisticsSample sample, float areaSample, float azimuthSample)
		{
			Vector3 vector = NormalizeOr(nativeDirection, Vector3.UnitZ);
			Vector3 vector2 = Right(vector, cameraUp);
			Vector3 vector3 = Vector3.Cross(vector, vector2);
			float x = sample.PitchDegrees * ((float)Math.PI / 180f);
			float x2 = sample.YawDegrees * ((float)Math.PI / 180f);
			Vector3 vector4 = vector * (MathF.Cos(x) * MathF.Cos(x2)) + vector2 * (MathF.Cos(x) * MathF.Sin(x2)) + vector3 * MathF.Sin(x);
			float x3 = Math.Clamp(sample.BloomDegrees, 0f, 45f) * ((float)Math.PI / 180f);
			float num = 1f - BallisticsState.Unit(areaSample) * (1f - MathF.Cos(x3));
			float num2 = MathF.Sqrt(Math.Max(0f, 1f - num * num));
			float x4 = BallisticsState.Unit(azimuthSample) * ((float)Math.PI * 2f);
			Vector3 vector5 = Right(vector4, cameraUp);
			Vector3 vector6 = Vector3.Cross(vector4, vector5);
			return NormalizeOr(vector4 * num + vector5 * (num2 * MathF.Cos(x4)) + vector6 * (num2 * MathF.Sin(x4)), vector);
		}

		private static Vector3 Right(Vector3 forward, Vector3 up)
		{
			Vector3 vector = Vector3.Cross(up, forward);
			if (!Valid(vector) || vector.LengthSquared() < 1E-06f)
			{
				vector = Vector3.Cross((Math.Abs(forward.Y) < 0.99f) ? Vector3.UnitY : Vector3.UnitX, forward);
			}
			return Vector3.Normalize(vector);
		}

		private static Vector3 NormalizeOr(Vector3 vector, Vector3 fallback)
		{
			if (!Valid(vector) || !(vector.LengthSquared() >= 1E-06f))
			{
				return fallback;
			}
			return Vector3.Normalize(vector);
		}

		private static bool Valid(Vector3 vector)
		{
			if (float.IsFinite(vector.X) && float.IsFinite(vector.Y))
			{
				return float.IsFinite(vector.Z);
			}
			return false;
		}
	}
	internal static class HandPoses
	{
		private sealed class SupportState
		{
			private readonly Avatar avatar;

			private readonly Transform model;

			private readonly AvatarEquippable? equippable;

			private readonly IKSolverLimb solver;

			private readonly Transform palm;

			private readonly Transform wristTarget;

			private readonly Transform wrist;

			private readonly Vector3 palmOffset;

			private readonly Transform? oldTarget;

			private readonly Vector3 oldPosition;

			private readonly Quaternion oldRotation;

			private readonly float oldPositionWeight;

			private readonly float oldRotationWeight;

			private bool applied;

			private float blend;

			private SupportState(Avatar avatar, Transform model, WeaponSpec spec, AvatarEquippable? equippable, IKSolverLimb solver)
			{
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: 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_00b5: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e5: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
				this.avatar = avatar;
				this.model = model;
				this.equippable = equippable;
				this.solver = solver;
				wrist = ((Point)((IKSolverTrigonometric)solver).bone3).transform;
				palmOffset = (((Object)(object)avatar.LeftHandAlignmentPoint != (Object)null) ? wrist.InverseTransformPoint(avatar.LeftHandAlignmentPoint.position) : Vector3.zero);
				palm = Child(model, "ArsenalSupportPalm");
				palm.localPosition = ((spec.Id == "eg_m4") ? new Vector3(0f, 0.07f, 0.255f) : new Vector3(0f, 0.057f, 0.292f));
				wristTarget = Child(model, "ArsenalSupportWrist");
				oldTarget = ((IKSolverTrigonometric)solver).target;
				oldPosition = ((IKSolver)solver).IKPosition;
				oldRotation = ((IKSolverTrigonometric)solver).IKRotation;
				oldPositionWeight = ((IKSolver)solver).IKPositionWeight;
				oldRotationWeight = ((IKSolverTrigonometric)solver).IKRotationWeight;
			}

			public static SupportState? TryCreate(Avatar avatar, Animator? animator, Transform model, WeaponSpec spec, AvatarEquippable? equippable)
			{
				//IL_0121: Unknown result type (might be due to invalid IL or missing references)
				//IL_0126: Unknown result type (might be due to invalid IL or missing references)
				//IL_012d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0134: Unknown result type (might be due to invalid IL or missing references)
				//IL_0140: Expected O, but got Unknown
				AvatarAnimation animation = avatar.Animation;
				object obj;
				if (animation == null)
				{
					obj = null;
				}
				else
				{
					AvatarIKController ikController = animation._ikController;
					obj = ((ikController != null) ? ikController.BodyIK : null);
				}
				BipedIK val = (BipedIK)obj;
				IKSolverLimb val2 = ((val != null) ? val.GetGoalIK((AvatarIKGoal)2) : null);
				object obj2;
				if (val2 == null)
				{
					obj2 = null;
				}
				else
				{
					TrigonometricBone bone = ((IKSolverTrigonometric)val2).bone1;
					obj2 = ((bone != null) ? ((Point)bone).transform : null);
				}
				if (!((Object)obj2 == (Object)null))
				{
					TrigonometricBone bone2 = ((IKSolverTrigonometric)val2).bone2;
					if (!((Object)(object)((bone2 != null) ? ((Point)bone2).transform : null) == (Object)null))
					{
						TrigonometricBone bone3 = ((IKSolverTrigonometric)val2).bone3;
						if (!((Object)(object)((bone3 != null) ? ((Point)bone3).transform : null) == (Object)null))
						{
							goto IL_015a;
						}
					}
				}
				BipedReferences obj3 = ((val != null) ? val.references : null);
				Transform val3 = ((obj3 != null) ? obj3.leftUpperArm : null);
				Transform val4 = ((obj3 != null) ? obj3.leftForearm : null);
				Transform val5 = ((obj3 != null) ? obj3.leftHand : null);
				if (((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null) && (Object)(object)animator != (Object)null && animator.isHuman)
				{
					val3 = animator.GetBoneTransform((HumanBodyBones)13);
					val4 = animator.GetBoneTransform((HumanBodyBones)15);
					val5 = animator.GetBoneTransform((HumanBodyBones)17);
				}
				if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null)
				{
					return null;
				}
				val2 = new IKSolverLimb
				{
					goal = (AvatarIKGoal)2,
					bendModifier = (BendModifier)0,
					bendModifierWeight = 1f
				};
				if (!((IKSolverTrigonometric)val2).SetChain(val3, val4, val5, ((Component)avatar).transform))
				{
					return null;
				}
				((IKSolverTrigonometric)val2).SetBendPlaneToCurrent();
				goto IL_015a;
				IL_015a:
				if (!((IKSolver)val2).initiated)
				{
					((IKSolver)val2).Initiate(((Component)avatar).transform);
				}
				return new SupportState(avatar, model, spec, equippable, val2);
			}

			public bool Matches(Avatar candidate, Transform candidateModel)
			{
				if ((Object)(object)avatar == (Object)(object)candidate)
				{
					return (Object)(object)model == (Object)(object)candidateModel;
				}
				return false;
			}

			public bool IsEquipped()
			{
				if ((Object)(object)avatar != (Object)null && (Object)(object)model != (Object)null && (Object)(object)equippable != (Object)null && (Object)(object)avatar.CurrentEquippable != (Object)null)
				{
					return ((Il2CppObjectBase)avatar.CurrentEquippable).Pointer == ((Il2CppObjectBase)equippable).Pointer;
				}
				return false;
			}

			public void Apply()
			{
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
				//IL_010b: 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_0148: Unknown result type (might be due to invalid IL or missing references)
				AvatarEquippable? obj = equippable;
				AvatarRangedWeapon val = ((obj != null) ? ((Il2CppObjectBase)obj).TryCast<AvatarRangedWeapon>() : null);
				if (!((Object)(object)avatar == (Object)null) && !((Object)(object)model == (Object)null) && !((Object)(object)wrist == (Object)null) && !avatar.Ragdolled && !avatar.IsCulled)
				{
					AvatarAnimation animation = avatar.Animation;
					if (animation == null || !animation.IsSeated)
					{
						AvatarAnimation animation2 = avatar.Animation;
						if ((animation2 == null || !animation2.StandUpAnimationPlaying) && (!((Object)(object)val != (Object)null) || (!val.isReloading && !(val.timeEquipped < val.EquipTime))))
						{
							blend = Mathf.MoveTowards(blend, 1f, Time.deltaTime * 7f);
							wristTarget.position = palm.position - wrist.TransformVector(palmOffset);
							wristTarget.rotation = wrist.rotation;
							((IKSolverTrigonometric)solver).target = wristTarget;
							((IKSolver)solver).IKPosition = wristTarget.position;
							((IKSolverTrigonometric)solver).IKRotation = wristTarget.rotation;
							((IKSolver)solver).IKPositionWeight = blend;
							((IKSolverTrigonometric)solver).IKRotationWeight = blend;
							applied = true;
							((IKSolver)solver).Update();
							return;
						}
					}
				}
				Release();
			}

			public void Release()
			{
				//IL_0054: 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)
				blend = 0f;
				if (applied && solver != null)
				{
					applied = false;
					if (!((Object)(object)((IKSolverTrigonometric)solver).target != (Object)(object)wristTarget))
					{
						((IKSolverTrigonometric)solver).target = oldTarget;
						((IKSolver)solver).IKPosition = oldPosition;
						((IKSolverTrigonometric)solver).IKRotation = oldRotation;
						((IKSolver)solver).IKPositionWeight = oldPositionWeight;
						((IKSolverTrigonometric)solver).IKRotationWeight = oldRotationWeight;
					}
				}
			}

			private static Transform Child(Transform parent, string name)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				Transform val = parent.Find(name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
				val = new GameObject(name).transform;
				val.SetParent(parent, false);
				return val;
			}
		}

		private static readonly Dictionary<IntPtr, SupportState> Avatars = new Dictionary<IntPtr, SupportState>();

		private static Equippable_RangedWeapon? firstPersonWeapon;

		private static SupportState? firstPersonState;

		private static int failures;

		public static void Initialize(Harmony harmony)
		{
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Equippable_RangedWeapon), "Equip", (Type[])null, (Type[])null), (HarmonyMethod)null, Patch("AfterEquip"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Equippable_RangedWeapon), "Unequip", (Type[])null, (Type[])null), Patch("BeforeUnequip"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(ViewmodelAvatar), "SetBoneTransforms", (Type[])null, (Type[])null), (HarmonyMethod)null, Patch("AfterViewmodelTransforms"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(AvatarAnimation), "LateUpdate", (Type[])null, (Type[])null), (HarmonyMethod)null, Patch("AfterAvatarAnimation"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static HarmonyMethod Patch(string name)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			return new HarmonyMethod(typeof(HandPoses), name, (Type[])null);
		}

		internal static bool IsLongGun(WeaponSpec? spec)
		{
			if (!(spec?.Id == "eg_m4"))
			{
				return spec?.Id == "eg_sniper";
			}
			return true;
		}

		private static void AfterEquip(Equippable_RangedWeapon __instance)
		{
			ClearFirstPerson();
			if (IsLongGun(WeaponBehavior.GetSpec(__instance)))
			{
				firstPersonWeapon = __instance;
			}
		}

		private static void BeforeUnequip(Equippable_RangedWeapon __instance)
		{
			if ((Object)(object)firstPersonWeapon != (Object)null && ((Il2CppObjectBase)firstPersonWeapon).Pointer == ((Il2CppObjectBase)__instance).Pointer)
			{
				ClearFirstPerson();
			}
		}

		private static void AfterViewmodelTransforms(ViewmodelAvatar __instance)
		{
			if ((Object)(object)firstPersonWeapon == (Object)null)
			{
				return;
			}
			try
			{
				Equippable_RangedWeapon val = firstPersonWeapon;
				WeaponSpec spec = WeaponBehavior.GetSpec(val);
				PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance;
				if (!IsLongGun(spec) || (Object)(object)((instance != null) ? instance.Equippable : null) == (Object)null || ((Il2CppObjectBase)instance.Equippable).Pointer != ((Il2CppObjectBase)val).Pointer)
				{
					ClearFirstPerson();
					return;
				}
				Avatar avatar = __instance.Avatar;
				Transform val2 = ((Component)val).transform.Find(spec.Id + "_OriginalModel");
				if ((Object)(object)avatar == (Object)null || (Object)(object)val2 == (Object)null)
				{
					return;
				}
				if (firstPersonState == null || !firstPersonState.Matches(avatar, val2))
				{
					firstPersonState?.Release();
					firstPersonState = SupportState.TryCreate(avatar, __instance.Animator, val2, spec, null);
				}
				if (firstPersonState != null)
				{
					if (!__instance.IsVisible || !((Behaviour)val).isActiveAndEnabled || !((Equippable_AvatarViewmodel)val).equipAnimDone || val.IsReloading || val.IsCocking)
					{
						firstPersonState.Release();
					}
					else
					{
						firstPersonState.Apply();
					}
				}
			}
			catch (Exception ex)
			{
				ClearFirstPerson();
				Warn(ex);
			}
		}

		internal static void BindAvatar(AvatarEquippable equippable, WeaponSpec spec, Transform model)
		{
			Avatar avatar = equippable.avatar;
			if (!IsLongGun(spec) || (Object)(object)((avatar != null) ? avatar.Animation : null) == (Object)null)
			{
				return;
			}
			IntPtr pointer = ((Il2CppObjectBase)avatar.Animation).Pointer;
			if (Avatars.TryGetValue(pointer, out SupportState value))
			{
				if (value.Matches(avatar, model))
				{
					return;
				}
				value.Release();
			}
			SupportState supportState = SupportState.TryCreate(avatar, avatar.Animation._animator, model, spec, equippable);
			if (supportState != null)
			{
				Avatars[pointer] = supportState;
			}
		}

		internal static void ClearAvatar(Avatar? avatar)
		{
			if (!((Object)(object)((avatar != null) ? avatar.Animation : null) == (Object)null) && Avatars.Remove(((Il2CppObjectBase)avatar.Animation).Pointer, out SupportState value))
			{
				value.Release();
			}
		}

		private static void AfterAvatarAnimation(AvatarAnimation __instance)
		{
			if (!Avatars.TryGetValue(((Il2CppObjectBase)__instance).Pointer, out SupportState value))
			{
				return;
			}
			try
			{
				if (!value.IsEquipped())
				{
					value.Release();
					Avatars.Remove(((Il2CppObjectBase)__instance).Pointer);
				}
				else
				{
					value.Apply();
				}
			}
			catch (Exception ex)
			{
				value.Release();
				Avatars.Remove(((Il2CppObjectBase)__instance).Pointer);
				Warn(ex);
			}
		}

		public static void Reset()
		{
			ClearFirstPerson();
			foreach (SupportState value in Avatars.Values)
			{
				value.Release();
			}
			Avatars.Clear();
			failures = 0;
		}

		private static void ClearFirstPerson()
		{
			firstPersonState?.Release();
			firstPersonState = null;
			firstPersonWeapon = null;
		}

		private static void Warn(Exception ex)
		{
			if (failures++ < 3)
			{
				MelonLogger.Warning("Long-gun support hand could not update: " + ex.GetType().Name + ": " + ex.Message);
			}
		}
	}
	internal static class ModelIcons
	{
		private const int Resolution = 256;

		internal static Sprite Render(string id, bool ammo)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Unknown result type (might be due to invalid IL or missing references)
			//IL_0436: Unknown result type (might be due to invalid IL or missing references)
			//IL_043d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Expected O, but got Unknown
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: 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_0221: Expected O, but got Unknown
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
			Vector3 previewDirection = RuntimePreviewGenerator.PreviewDirection;
			float padding = RuntimePreviewGenerator.Padding;
			Color backgroundColor = RuntimePreviewGenerator.BackgroundColor;
			bool orthographicMode = RuntimePreviewGenerator.OrthographicMode;
			bool useLocalBounds = RuntimePreviewGenerator.UseLocalBounds;
			float renderSupersampling = RuntimePreviewGenerator.RenderSupersampling;
			bool markTextureNonReadable = RuntimePreviewGenerator.MarkTextureNonReadable;
			Camera previewRenderCamera = RuntimePreviewGenerator.PreviewRenderCamera;
			Camera renderCamera = RuntimePreviewGenerator.renderCamera;
			Vector3 camPos = RuntimePreviewGenerator.CamPos;
			Quaternion camRot = RuntimePreviewGenerator.CamRot;
			GameObject val = null;
			GameObject val2 = null;
			GameObject val3 = null;
			Texture2D val4 = null;
			try
			{
				val = (ammo ? WeaponVisuals.BuildAmmo(id, null) : WeaponVisuals.Build(id, null));
				((Object)val).hideFlags = (HideFlags)61;
				val.transform.rotation = (ammo ? Quaternion.Euler(-28f, 0f, 0f) : Quaternion.Euler(-32f, 0f, 0f));
				val.transform.position = RuntimePreviewGenerator.PREVIEW_POSITION;
				RuntimePreviewGenerator.PreviewDirection = new Vector3(-1f, -0.18f, -0.15f);
				RuntimePreviewGenerator.Padding = 0.12f;
				RuntimePreviewGenerator.BackgroundColor = Color.clear;
				RuntimePreviewGenerator.OrthographicMode = true;
				RuntimePreviewGenerator.UseLocalBounds = false;
				RuntimePreviewGenerator.RenderSupersampling = 2f;
				RuntimePreviewGenerator.MarkTextureNonReadable = false;
				RuntimePreviewGenerator.SetLayerRecursively(val.transform);
				val3 = new GameObject("EndgameArsenal_PortraitCamera");
				((Object)val3).hideFlags = (HideFlags)61;
				Camera val5 = val3.AddComponent<Camera>();
				((Behaviour)val5).enabled = false;
				val5.orthographic = true;
				val5.aspect = 1f;
				val5.cullingMask = 1 << RuntimePreviewGenerator.PREVIEW_LAYER;
				val5.clearFlags = (CameraClearFlags)2;
				val5.backgroundColor = Color.clear;
				val5.nearClipPlane = 0.01f;
				val5.allowHDR = false;
				val5.allowMSAA = false;
				((Component)val5).transform.rotation = Quaternion.LookRotation(RuntimePreviewGenerator.PreviewDirection, Vector3.up);
				Bounds val6 = default(Bounds);
				if (!RuntimePreviewGenerator.CalculateBounds(val.transform, true, ((Component)val5).transform.rotation, ref val6))
				{
					throw new InvalidOperationException("Item portrait model has no visible render bounds.");
				}
				RuntimePreviewGenerator.CalculateCameraPosition(val5, val6, RuntimePreviewGenerator.Padding);
				RuntimePreviewGenerator.PreviewRenderCamera = val5;
				RuntimePreviewGenerator.CamPos = ((Component)val5).transform.position;
				RuntimePreviewGenerator.CamRot = ((Component)val5).transform.rotation;
				ValidateFraming(val5, val.transform);
				val2 = new GameObject("EndgameArsenal_PortraitLighting");
				((Object)val2).hideFlags = (HideFlags)61;
				AddLight(val2.transform, "Key", new Vector3(45f, -45f, 0f), 1.55f);
				AddLight(val2.transform, "Fill", new Vector3(325f, 145f, 0f), 0.65f);
				val4 = RuntimePreviewGenerator.GenerateModelPreview(val.transform, 256, 256, false, true);
				if ((Object)(object)val4 == (Object)null)
				{
					throw new InvalidOperationException("Native item portrait renderer returned no texture.");
				}
				bool flag = false;
				Il2CppStructArray<Color32> pixels = val4.GetPixels32();
				foreach (Color32 item in (Il2CppArrayBase<Color32>)(object)pixels)
				{
					if (item.a > 32)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					throw new InvalidOperationException("Native item portrait renderer returned a blank image for " + id + "; model layer and camera framing were validated.");
				}
				if (((Il2CppArrayBase<Color32>)(object)pixels)[0].a > 8 || ((Il2CppArrayBase<Color32>)(object)pixels)[((Texture)val4).width - 1].a > 8 || ((Il2CppArrayBase<Color32>)(object)pixels)[((Il2CppArrayBase<Color32>)(object)pixels).Length - 1].a > 8)
				{
					throw new InvalidOperationException("Native item portrait renderer did not preserve the transparent background.");
				}
				((Object)val4).name = id + (ammo ? "_ammo" : "_weapon") + "_ModelPortrait";
				((Object)val4).hideFlags = (HideFlags)61;
				((Texture)val4).filterMode = (FilterMode)1;
				((Texture)val4).wrapMode = (TextureWrapMode)1;
				val4.Apply(false, true);
				Sprite obj = Sprite.Create(val4, new Rect(0f, 0f, (float)((Texture)val4).width, (float)((Texture)val4).height), new Vector2(0.5f, 0.5f), 256f);
				((Object)obj).name = ((Object)val4).name + "_Sprite";
				((Object)obj).hideFlags = (HideFlags)61;
				val4 = null;
				return obj;
			}
			finally
			{
				RuntimePreviewGenerator.PreviewDirection = previewDirection;
				RuntimePreviewGenerator.Padding = padding;
				RuntimePreviewGenerator.BackgroundColor = backgroundColor;
				RuntimePreviewGenerator.OrthographicMode = orthographicMode;
				RuntimePreviewGenerator.UseLocalBounds = useLocalBounds;
				RuntimePreviewGenerator.RenderSupersampling = renderSupersampling;
				RuntimePreviewGenerator.MarkTextureNonReadable = markTextureNonReadable;
				RuntimePreviewGenerator.PreviewRenderCamera = previewRenderCamera;
				RuntimePreviewGenerator.renderCamera = renderCamera;
				RuntimePreviewGenerator.CamPos = camPos;
				RuntimePreviewGenerator.CamRot = camRot;
				if ((Object)(object)val3 != (Object)null)
				{
					val3.SetActive(false);
					Object.Destroy((Object)(object)val3);
				}
				if ((Object)(object)val2 != (Object)null)
				{
					val2.SetActive(false);
					Object.Destroy((Object)(object)val2);
				}
				if ((Object)(object)val != (Object)null)
				{
					val.SetActive(false);
					Object.Destroy((Object)(object)val);
				}
				if ((Object)(object)val4 != (Object)null)
				{
					Object.Destroy((Object)(object)val4);
				}
			}
		}

		private static void ValidateFraming(Camera camera, Transform model)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			foreach (Renderer componentsInChild in ((Component)model).GetComponentsInChildren<Renderer>(true))
			{
				if (componentsInChild.enabled && ((Component)componentsInChild).gameObject.activeInHierarchy)
				{
					if ((camera.cullingMask & (1 << ((Component)componentsInChild).gameObject.layer)) == 0)
					{
						throw new InvalidOperationException("Item portrait camera excludes a model renderer's layer.");
					}
					Bounds bounds = componentsInChild.bounds;
					Vector3 val = camera.WorldToViewportPoint(((Bounds)(ref bounds)).center);
					if (val.z > camera.nearClipPlane && val.x >= 0f && val.x <= 1f && val.y >= 0f && val.y <= 1f)
					{
						flag = true;
					}
				}
			}
			if (!flag)
			{
				throw new InvalidOperationException("Item portrait model is outside its calculated camera frame.");
			}
		}

		private static void AddLight(Transform parent, string name, Vector3 rotation, float intensity)
		{
			//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_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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			val.transform.SetParent(parent, false);
			val.transform.rotation = Quaternion.Euler(rotation);
			Light obj = val.AddComponent<Light>();
			obj.type = (LightType)1;
			obj.color = Color.white;
			obj.intensity = intensity;
			obj.shadows = (LightShadows)0;
			obj.cullingMask = 1 << RuntimePreviewGenerator.PREVIEW_LAYER;
		}
	}
	internal static class RegistryAndShop
	{
		private static readonly Dictionary<string, IntegerItemDefinition> definitions = new Dictionary<string, IntegerItemDefinition>(StringComparer.Ordinal);

		private static readonly HashSet<string> modelPortraits = new HashSet<string>(StringComparer.Ordinal);

		private static readonly HashSet<string> itemIds = new HashSet<string>(WeaponCatalog.All.SelectMany((WeaponSpec spec) => new string[2] { spec.Id, spec.AmmoId }), StringComparer.Ordinal);

		private static readonly Dictionary<string, (FullRank Rank, Unlockable Unlock)> ownedUnlocks = new Dictionary<string, (FullRank, Unlockable)>(StringComparer.Ordinal);

		private static ArsenalSettings? settings;

		private static IntPtr unlockManagerPointer;

		private static GameObject? prototypes;

		private static bool registering;

		private static int hookFailures;

		private static int portraitFailures;

		private static float nextPortraitAttempt;

		public static string BaseAvatarAssetPath { get; private set; } = "Avatar/Equippables/M1911";

		public static bool PortraitsComplete => modelPortraits.Count == WeaponCatalog.All.Length * 2;

		public static void BindSettings(ArsenalSettings value)
		{
			settings = value;
		}

		public static void Initialize(Harmony harmony)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Registry), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(RegistryAndShop), "RegistryAwake", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Registry), "_GetItem", new Type[2]
			{
				typeof(string),
				typeof(bool)
			}, (Type[])null), new HarmonyMethod(typeof(RegistryAndShop), "BeforeLookup", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void RegistryAwake(Registry __instance)
		{
			RegisterFromHook(__instance);
		}

		private static void BeforeLookup(Registry __instance, string ID)
		{
			if (IsArsenalId(ID))
			{
				RegisterFromHook(__instance);
			}
		}

		private static void RegisterFromHook(Registry registry)
		{
			try
			{
				TryRegister(registry);
			}
			catch (Exception ex)
			{
				if (hookFailures++ < 3)
				{
					MelonLogger.Warning("Endgame Arsenal registration will retry: " + ex.GetType().Name + ": " + ex.Message);
				}
			}
		}

		public static bool TryRegister()
		{
			return TryRegister(Singleton<Registry>.Instance);
		}

		private static bool TryRegister(Registry? registry)
		{
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Expected O, but got Unknown
			if (registering || (Object)(object)registry == (Object)null || registry.ItemDictionary == null)
			{
				return false;
			}
			registering = true;
			try
			{
				if (definitions.Count == WeaponCatalog.All.Length * 2)
				{
					bool flag = true;
					foreach (IntegerItemDefinition value2 in definitions.Values)
					{
						if ((Object)(object)value2 == (Object)null || !Registry.ItemExists(((BaseItemDefinition)value2).ID))
						{
							flag = false;
							break;
						}
					}
					if (flag)
					{
						return true;
					}
				}
				IntegerItemDefinition val = Resources.Load<IntegerItemDefinition>("Weapons/M1911/M1911");
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				Equippable equippable = ((ItemDefinition)val).Equippable;
				Equippable_RangedWeapon val2 = ((equippable != null) ? ((Il2CppObjectBase)equippable).TryCast<Equippable_RangedWeapon>() : null);
				object obj;
				if (val2 == null)
				{
					obj = null;
				}
				else
				{
					StorableItemDefinition magazine = val2.Magazine;
					obj = ((magazine != null) ? ((Il2CppObjectBase)magazine).TryCast<IntegerItemDefinition>() : null);
				}
				IntegerItemDefinition val3 = (IntegerItemDefinition)obj;
				if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)((StorableItemDefinition)val).StoredItem == (Object)null || (Object)(object)((StorableItemDefinition)val3).StoredItem == (Object)null)
				{
					return false;
				}
				if ((Object)(object)prototypes == (Object)null)
				{
					prototypes = new GameObject("EndgameArsenal_Prototypes");
					prototypes.SetActive(false);
					Object.DontDestroyOnLoad((Object)(object)prototypes);
				}
				if ((Object)(object)((Equippable_Viewmodel)val2).AvatarEquippable != (Object)null && !string.IsNullOrWhiteSpace(((Equippable_Viewmodel)val2).AvatarEquippable.AssetPath))
				{
					BaseAvatarAssetPath = ((Equippable_Viewmodel)val2).AvatarEquippable.AssetPath;
				}
				WeaponSpec[] all = WeaponCatalog.All;
				foreach (WeaponSpec weaponSpec in all)
				{
					if (!definitions.TryGetValue(weaponSpec.Id, out IntegerItemDefinition value) || (Object)(object)value == (Object)null)
					{
						BuildDefinitions(weaponSpec, val, val2, val3);
					}
					AddIfMissing(registry, definitions[weaponSpec.AmmoId]);
					AddIfMissing(registry, definitions[weaponSpec.Id]);
				}
				hookFailures = 0;
				return true;
			}
			finally
			{
				registering = false;
			}
		}

		private static void AddIfMissing(Registry registry, IntegerItemDefinition definition)
		{
			if (!Registry.ItemExists(((BaseItemDefinition)definition).ID))
			{
				registry.AddToRegistry((ItemDefinition)(object)definition);
			}
		}

		private static void BuildDefinitions(WeaponSpec spec, IntegerItemDefinition template, Equippable_RangedWeapon weaponTemplate, IntegerItemDefinition ammoTemplate)
		{
			IntegerItemDefinition val = Object.Instantiate<IntegerItemDefinition>(ammoTemplate);
			ConfigureDefinition(val, spec, ammo: true);
			val.DefaultValue = spec.Capacity;
			((StorableItemDefinition)val).StoredItem = CloneStored(((StorableItemDefinition)ammoTemplate).StoredItem, spec, customGunModel: false);
			if ((Object)(object)((ItemDefinition)ammoTemplate).Equippable != (Object)null)
			{
				GameObject val2 = ClonePrototype(((Component)((ItemDefinition)ammoTemplate).Equippable).gameObject, spec.AmmoId + "_Equippable");
				HideRenderers(val2.transform);
				WeaponVisuals.BuildAmmo(spec.Id, val2.transform);
				((ItemDefinition)val).Equippable = val2.GetComponent<Equippable>();
			}
			IntegerItemDefinition val3 = Object.Instantiate<IntegerItemDefinition>(template);
			ConfigureDefinition(val3, spec, ammo: false);
			val3.DefaultValue = spec.Capacity;
			((StorableItemDefinition)val3).StoredItem = CloneStored(((StorableItemDefinition)template).StoredItem, spec, customGunModel: true);
			GameObject val4 = ClonePrototype(((Component)weaponTemplate).gameObject, spec.Id + "_Equippable");
			Equippable_RangedWeapon component = val4.GetComponent<Equippable_RangedWeapon>();
			if ((Object)(object)component == (Object)null)
			{
				throw new InvalidOperationException("Native M1911 clone has no ranged weapon component.");
			}
			HideRenderers(val4.transform);
			WeaponVisuals.Build(spec.Id, val4.transform);
			if ((Object)(object)((Equippable_Viewmodel)weaponTemplate).AvatarEquippable != (Object)null)
			{
				AvatarEquippable component2 = ClonePrototype(((Component)((Equippable_Viewmodel)weaponTemplate).AvatarEquippable).gameObject, spec.Id + "_AvatarEquippable").GetComponent<AvatarEquippable>();
				component2.AssetPath = "EndgameArsenal/" + spec.Id;
				((Equippable_Viewmodel)component).AvatarEquippable = component2;
			}
			WeaponBehavior.Configure(component, spec, (StorableItemDefinition)(object)val);
			((ItemDefinition)val3).Equippable = (Equippable)(object)component;
			definitions[spec.AmmoId] = val;
			definitions[spec.Id] = val3;
		}

		private static void ConfigureDefinition(IntegerItemDefinition definition, WeaponSpec spec, bool ammo)
		{
			((Object)definition).name = (ammo ? spec.AmmoId : spec.Id);
			((BaseItemDefinition)definition).ID = (ammo ? spec.AmmoId : spec.Id);
			((BaseItemDefinition)definition).Name = (ammo ? spec.AmmoName : spec.Name);
			((BaseItemDefinition)definition).StackLimit = 1;
			ApplyDefinitionSettings(definition, spec, ammo);
			((BaseItemDefinition)definition).UsableInFilters = true;
			((Object)definition).hideFlags = (HideFlags)32;
		}

		private static void ApplyDefinitionSettings(IntegerItemDefinition definition, WeaponSpec spec, bool ammo)
		{
			//IL_0031: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			WeaponShopSettings weaponShopSettings = settings?.For(spec) ?? new WeaponShopSettings(spec.Rank, spec.Tier, spec.Price, spec.AmmoPrice);
			FullRank val = new FullRank
			{
				Rank = (ERank)weaponShopSettings.Rank,
				Tier = weaponShopSettings.Tier
			};
			((StorableItemDefinition)definition).BasePurchasePrice = (ammo ? weaponShopSettings.AmmoPrice : weaponShopSettings.Price);
			((StorableItemDefinition)definition).RequiresLevelToPurchase = true;
			((StorableItemDefinition)definition).RequiredRank = val;
			((BaseItemDefinition)definition).Description = (ammo ? $"A {spec.Capacity}-round magazine of ammunition for the {spec.Name}. Compatible only with this weapon." : $"{spec.Name}. Holds {spec.Capacity} rounds and uses {spec.AmmoName}. Available from Stan at {RankLabel(val)}.");
		}

		private unsafe static string RankLabel(FullRank rank)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			return ((object)(*(ERank*)(&rank.Rank))/*cast due to .constrained prefix*/).ToString().Replace('_', ' ') + " " + (new string[6] { "", "I", "II", "III", "IV", "V" })[rank.Tier];
		}

		private static GameObject ClonePrototype(GameObject original, string name)
		{
			GameObject obj = Object.Instantiate<GameObject>(original, prototypes.transform, false);
			((Object)obj).name = name;
			obj.SetActive(true);
			return obj;
		}

		private static StoredItem CloneStored(StoredItem original, WeaponSpec spec, bool customGunModel)
		{
			GameObject val = ClonePrototype(((Component)original).gameObject, (customGunModel ? spec.Id : spec.AmmoId) + "_Stored");
			StoredItem component = val.GetComponent<StoredItem>();
			if ((Object)(object)component == (Object)null)
			{
				throw new InvalidOperationException("Native item clone has no storage component.");
			}
			HideRenderers(val.transform);
			if (customGunModel)
			{
				WeaponVisuals.Build(spec.Id, val.transform);
				return component;
			}
			WeaponVisuals.BuildAmmo(spec.Id, val.transform);
			return component;
		}

		private static void HideRenderers(Transform parent)
		{
			foreach (Renderer componentsInChild in ((Component)parent).GetComponentsInChildren<Renderer>(true))
			{
				componentsInChild.enabled = false;
			}
		}

		private static bool IsArsenalId(string? id)
		{
			if (id != null)
			{
				return itemIds.Contains(id);
			}
			return false;
		}

		public static StorableItemDefinition? GetDefinition(string id)
		{
			if (!definitions.TryGetValue(id, out IntegerItemDefinition value))
			{
				return null;
			}
			return (StorableItemDefinition?)(object)value;
		}

		public static bool TryAddToStan()
		{
			if (!TryRegister())
			{
				return false;
			}
			ShopInterface shop = FindStanShop();
			if ((Object)(object)shop == (Object)null || shop.Listings == null || (Object)(object)shop.ListingContainer == (Object)null)
			{
				return false;
			}
			bool unlocksRegistered = false;
			ShopInitialization.Complete(delegate
			{
				bool flag = false;
				WeaponSpec[] all = WeaponCatalog.All;
				foreach (WeaponSpec weaponSpec in all)
				{
					flag |= AddListing(shop, (StorableItemDefinition)(object)definitions[weaponSpec.Id]);
					flag |= AddListing(shop, (StorableItemDefinition)(object)definitions[weaponSpec.AmmoId]);
				}
				if (flag)
				{
					shop.RefreshUnlockStatus();
					shop.RefreshShownItems();
				}
				unlocksRegistered = RegisterUnlocks();
			}, RefreshModelPortraits, ReportPortraitFailure);
			return unlocksRegistered;
		}

		private static ShopInterface? FindStanShop()
		{
			foreach (Stan item in Resources.FindObjectsOfTypeAll<Stan>())
			{
				if ((Object)(object)item != (Object)null && (Object)(object)item.ShopInterface != (Object)null)
				{
					return item.ShopInterface;
				}
			}
			GameObject obj = GameObject.Find("ArmsDealerInterface");
			if (obj == null)
			{
				return null;
			}
			return obj.GetComponent<ShopInterface>();
		}

		public static bool ApplySettings()
		{
			if (settings == null || definitions.Count != WeaponCatalog.All.Length * 2)
			{
				return false;
			}
			WeaponSpec[] all = WeaponCatalog.All;
			foreach (WeaponSpec weaponSpec in all)
			{
				ApplyDefinitionSettings(definitions[weaponSpec.Id], weaponSpec, ammo: false);
				ApplyDefinitionSettings(definitions[weaponSpec.AmmoId], weaponSpec, ammo: true);
			}
			ShopInterface val = FindStanShop();
			if ((Object)(object)val == (Object)null || val.Listings == null || !RegisterUnlocks())
			{
				return false;
			}
			Cart cart = val.Cart;
			if ((Object)(object)cart != (Object)null)
			{
				Enumerator<ShopListing> enumerator = val.Listings.GetEnumerator();
				while (enumerator.MoveNext())
				{
					ShopListing current = enumerator.Current;
					if ((Object)(object)((current != null) ? current.Item : null) != (Object)null && IsArsenalId(((BaseItemDefinition)current.Item).ID) && cart.GetCartCount(current) > 0 && !current.Item.IsUnlocked)
					{
						cart.RemoveListing(current);
					}
				}
				if (cart.cartEntries != null)
				{
					Enumerator<CartEntry> enumerator2 = cart.cartEntries.GetEnumerator();
					while (enumerator2.MoveNext())
					{
						CartEntry current2 = enumerator2.Current;
						object obj;
						if (current2 == null)
						{
							obj = null;
						}
						else
						{
							ShopListing listing = current2.Listing;
							obj = ((listing != null) ? listing.Item : null);
						}
						if ((Object)obj != (Object)null && IsArsenalId(((BaseItemDefinition)current2.Listing.Item).ID))
						{
							current2.UpdatePrice();
						}
					}
				}
				cart.UpdateTotal();
				cart.UpdateProblem();
			}
			val.RefreshUnlockStatus();
			if (val.listingUI != null)
			{
				Enumerator<ListingUI> enumerator3 = val.listingUI.GetEnumerator();
				while (enumerator3.MoveNext())
				{
					ListingUI current3 = enumerator3.Current;
					object obj2;
					if (current3 == null)
					{
						obj2 = null;
					}
					else
					{
						ShopListing listing2 = current3.Listing;
						obj2 = ((listing2 != null) ? listing2.Item : null);
					}
					if ((Object)obj2 != (Object)null && IsArsenalId(((BaseItemDefinition)current3.Listing.Item).ID))
					{
						current3.UpdatePrice();
						current3.UpdateButtons();
					}
				}
			}
			val.RefreshShownItems();
			ShopInterfaceDetailPanel detailPanel = val.DetailPanel;
			if ((Object)(object)((detailPanel != null) ? detailPanel.Panel : null) != (Object)null && ((Component)detailPanel.Panel).gameObject.activeSelf)
			{
				ListingUI listingUI = detailPanel._listingUI;
				object obj3;
				if (listingUI == null)
				{
					obj3 = null;
				}
				else
				{
					ShopListing listing3 = listingUI.Listing;
					obj3 = ((listing3 != null) ? listing3.Item : null);
				}
				if ((Object)obj3 != (Object)null && IsArsenalId(((BaseItemDefinition)detailPanel._listingUI.Listing.Item).ID))
				{
					detailPanel.Open(detailPanel._listingUI);
				}
			}
			return true;
		}

		public static void RetryModelPortraits()
		{
			ShopInitialization.RefreshOptional(RefreshModelPortraits, ReportPortraitFailure);
		}

		private static void RefreshModelPortraits()
		{
			if (PortraitsComplete || Time.unscaledTime < nextPortraitAttempt)
			{
				return;
			}
			nextPortraitAttempt = Time.unscaledTime + 5f;
			bool changed = false;
			WeaponSpec[] all = WeaponCatalog.All;
			foreach (WeaponSpec spec in all)
			{
				ShopInitialization.RefreshOptional(delegate
				{
					if (!modelPortraits.Contains(spec.Id))
					{
						((BaseItemDefinition)definitions[spec.Id]).Icon = WeaponVisuals.Icon(spec.Id, ammo: false);
						modelPortraits.Add(spec.Id);
						changed = true;
					}
				}, ReportPortraitFailure);
				ShopInitialization.RefreshOptional(delegate
				{
					if (!modelPortraits.Contains(spec.AmmoId))
					{
						((BaseItemDefinition)definitions[spec.AmmoId]).Icon = WeaponVisuals.Icon(spec.Id, ammo: true);
						modelPortraits.Add(spec.AmmoId);
						changed = true;
					}
				}, ReportPortraitFailure);
			}
			if (!changed)
			{
				return;
			}
			foreach (ListingUI item in Resources.FindObjectsOfTypeAll<ListingUI>())
			{
				object obj;
				if (item == null)
				{
					obj = null;
				}
				else
				{
					ShopListing listing = item.Listing;
					obj = ((listing != null) ? listing.Item : null);
				}
				StorableItemDefinition val = (StorableItemDefinition)obj;
				if ((Object)(object)val != (Object)null && IsArsenalId(((BaseItemDefinition)val).ID) && (Object)(object)item.Icon != (Object)null)
				{
					item.Icon.sprite = ((BaseItemDefinition)val).Icon;
				}
			}
			foreach (ItemUI item2 in Resources.FindObjectsOfTypeAll<ItemUI>())
			{
				object obj2;
				if (item2 == null)
				{
					obj2 = null;
				}
				else
				{
					ItemInstance itemInstance = item2.itemInstance;
					obj2 = ((itemInstance != null) ? itemInstance.Definition : null);
				}
				ItemDefinition val2 = (ItemDefinition)obj2;
				if ((Object)(object)val2 != (Object)null && IsArsenalId(((BaseItemDefinition)val2).ID) && (Object)(object)item2.IconImg != (Object)null)
				{
					item2.IconImg.sprite = ((BaseItemDefinition)val2).Icon;
				}
			}
			LevelManager instance = NetworkSingleton<LevelManager>.Instance;
			if ((Object)(object)instance == (Object)null || unlockManagerPointer != ((Il2CppObjectBase)instance).Pointer)
			{
				return;
			}
			foreach (KeyValuePair<string, (FullRank, Unlockable)> ownedUnlock in ownedUnlocks)
			{
				if (definitions.TryGetValue(ownedUnlock.Key, out IntegerItemDefinition value) && (Object)(object)value != (Object)null)
				{
					ownedUnlock.Value.Item2.Icon = ((BaseItemDefinition)value).Icon;
				}
			}
		}

		private static void ReportPortraitFailure(Exception ex)
		{
			if (portraitFailures++ < 3)
			{
				MelonLogger.Warning("Arsenal portrait update will retry; Stan's items remain available: " + ex.GetType().Name + ": " + ex.Message);
			}
		}

		private static bool AddListing(ShopInterface shop, StorableItemDefinition definition)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: 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_002f: 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_003d: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			if (shop.GetListing(((BaseItemDefinition)definition).ID) != null)
			{
				return false;
			}
			ShopListing val = new ShopListing
			{
				name = ((BaseItemDefinition)definition).Name,
				Item = definition,
				OverridePrice = false,
				LimitedStock = false,
				DefaultStock = 0,
				RestockRate = (ERestockRate)2,
				CanBeDelivered = false,
				ConditionalVisibility = false
			};
			shop.Listings.Add(val);
			val.Initialize(shop);
			shop.CreateListingUI(val);
			return true;
		}

		private static bool RegisterUnlocks()
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Expected O, but got Unknown
			//IL_007d: 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_0087: 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_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			LevelManager instance = NetworkSingleton<LevelManager>.Instance;
			if ((Object)(object)instance == (Object)null || instance.Unlockables == null)
			{
				return false;
			}
			if (unlockManagerPointer != ((Il2CppObjectBase)instance).Pointer)
			{
				ownedUnlocks.Clear();
				unlockManagerPointer = ((Il2CppObjectBase)instance).Pointer;
			}
			foreach (IntegerItemDefinition value2 in definitions.Values)
			{
				FullRank requiredRank = ((StorableItemDefinition)value2).RequiredRank;
				Unlockable val;
				if (ownedUnlocks.TryGetValue(((BaseItemDefinition)value2).ID, out (FullRank, Unlockable) value))
				{
					if (value.Item1.Rank == requiredRank.Rank && value.Item1.Tier == requiredRank.Tier && ContainsUnlock(instance, requiredRank, value.Item2))
					{
						value.Item2.Icon = ((BaseItemDefinition)value2).Icon;
						continue;
					}
					RemoveOwnedUnlock(instance, value.Item1, value.Item2);
					val = value.Item2;
					val.Rank = requiredRank;
					val.Icon = ((BaseItemDefinition)value2).Icon;
				}
				else
				{
					val = new Unlockable(requiredRank, ((BaseItemDefinition)value2).Name, ((BaseItemDefinition)value2).Icon);
				}
				instance.AddUnlockable(val);
				if (ContainsUnlock(instance, requiredRank, val))
				{
					ownedUnlocks[((BaseItemDefinition)value2).ID] = (requiredRank, val);
				}
				else
				{
					ownedUnlocks.Remove(((BaseItemDefinition)value2).ID);
				}
			}
			return true;
		}

		private static bool ContainsUnlock(LevelManager manager, FullRank rank, Unlockable unlock)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!manager.Unlockables.ContainsKey(rank))
			{
				return false;
			}
			Enumerator<Unlockable> enumerator = manager.Unlockables[rank].GetEnumerator();
			while (enumerator.MoveNext())
			{
				Unlockable current = enumerator.Current;
				if (current != null && ((Il2CppObjectBase)current).Pointer == ((Il2CppObjectBase)unlock).Pointer)
				{
					return true;
				}
			}
			return false;
		}

		private static void RemoveOwnedUnlock(LevelManager manager, FullRank rank, Unlockable unlock)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!manager.Unlockables.ContainsKey(rank))
			{
				return;
			}
			List<Unlockable> val = manager.Unlockables[rank];
			for (int num = val.Count - 1; num >= 0; num--)
			{
				if (val[num] != null && ((Il2CppObjectBase)val[num]).Pointer == ((Il2CppObjectBase)unlock).Pointer)
				{
					val.RemoveAt(num);
				}
			}
		}
	}
	internal sealed class ScopeOverlay : IDisposable
	{
		private readonly GameObject root;

		private readonly RectTransform eyepiece;

		private readonly RectTransform[] shades = (RectTransform[])(object)new RectTransform[4];

		private readonly RectTransform labelRect;

		private readonly Text label;

		private Texture2D? lensTexture;

		private Texture2D? blackTexture;

		private bool disposed;

		private int width;

		private int height;

		private float magnification = -1f;

		internal bool IsAlive
		{
			get
			{
				if (!disposed)
				{
					return (Object)(object)root != (Object)null;
				}
				return false;
			}
		}

		internal bool IsVisible
		{
			get
			{
				if (IsAlive)
				{
					return root.activeSelf;
				}
				return false;
			}
		}

		internal ScopeOverlay()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			root = new GameObject("Endgame Arsenal Sniper Eyepiece");
			try
			{
				root.AddComponent<RectTransform>();
				Canvas obj = root.AddComponent<Canvas>();
				obj.renderMode = (RenderMode)0;
				obj.sortingOrder = 250;
				CanvasGroup obj2 = root.AddComponent<CanvasGroup>();
				obj2.interactable = false;
				obj2.blocksRaycasts = false;
				root.SetActive(false);
				blackTexture = MakeTexture("EndgameArsenal_ScopeOutside", 1, new byte[4] { 0, 0, 0, 255 });
				lensTexture = MakeTexture("EndgameArsenal_ScopeEyepiece", 1024, ScopeOverlayPixels.Generate());
				for (int i = 0; i < shades.Length; i++)
				{
					shades[i] = MakeImage("Opaque outside " + i, root.transform, (Texture)(object)blackTexture);
				}
				eyepiece = MakeImage("Lens and reticle", root.transform, (Texture)(object)lensTexture);
				labelRect = NewRect("Magnification", root.transform);
				label = ((Component)labelRect).gameObject.AddComponent<Text>();
				((Graphic)label).raycastTarget = false;
				label.alignment = (TextAnchor)4;
				((Graphic)label).color = new Color(0.79f, 0.83f, 0.84f, 1f);
				label.supportRichText = false;
				label.horizontalOverflow = (HorizontalWrapMode)1;
				label.verticalOverflow = (VerticalWrapMode)1;
				HUD instance = Singleton<HUD>.Instance;
				label.font = (((Object)(object)instance != (Object)null && (Object)(object)instance.fpsLabel != (Object)null && (Object)(object)instance.fpsLabel.font != (Object)null) ? instance.fpsLabel.font : Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf"));
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		internal void Show(float zoom)
		{
			if (!IsAlive)
			{
				return;
			}
			int num = Screen.width;
			int num2 = Screen.height;
			if (num <= 0 || num2 <= 0)
			{
				Hide();
				return;
			}
			if (num != width || num2 != height)
			{
				width = num;
				height = num2;
				float num3 = (float)Math.Min(width, height) * 0.9f;
				float num4 = ((float)width - num3) * 0.5f;
				float num5 = ((float)height - num3) * 0.5f;
				Layout(eyepiece, 0f, 0f, num3, num3);
				Layout(shades[0], 0f, (num3 + num5) * 0.5f, width, num5);
				Layout(shades[1], 0f, (0f - (num3 + num5)) * 0.5f, width, num5);
				Layout(shades[2], (0f - (num3 + num4)) * 0.5f, 0f, num4, num3);
				Layout(shades[3], (num3 + num4) * 0.5f, 0f, num4, num3);
				label.fontSize = (int)Math.Clamp(Math.Round((double)height / 60.0), 13.0, 24.0);
				Layout(labelRect, 0f, (0f - num3) * 0.5f - num5 * 0.5f, Math.Max(num3, 280f), Math.Max(num5, (float)label.fontSize * 1.8f));
			}
			if (magnification != zoom)
			{
				magnification = zoom;
				label.text = $"{zoom:0}×  ·  Scroll to zoom";
			}
			if (!root.activeSelf)
			{
				root.SetActive(true);
			}
		}

		internal void Hide()
		{
			if (IsAlive && root.activeSelf)
			{
				root.SetActive(false);
			}
		}

		public void Dispose()
		{
			if (!disposed)
			{
				disposed = true;
				if ((Object)(object)root != (Object)null)
				{
					root.SetActive(false);
					Object.Destroy((Object)(object)root);
				}
				if ((Object)(object)lensTexture != (Object)null)
				{
					Object.Destroy((Object)(object)lensTexture);
				}
				if ((Object)(object)blackTexture != (Object)null)
				{
					Object.Destroy((Object)(object)blackTexture);
				}
				lensTexture = null;
				blackTexture = null;
			}
		}

		private static RectTransform NewRect(string name, Transform parent)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			RectTransform obj = new GameObject(name).AddComponent<RectTransform>();
			((Transform)obj).SetParent(parent, false);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			obj.pivot = val;
			Vector2 anchorMin = (obj.anchorMax = val);
			obj.anchorMin = anchorMin;
			return obj;
		}

		private static RectTransform MakeImage(string name, Transform parent, Texture texture)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			RectTransform obj = NewRect(name, parent);
			RawImage obj2 = ((Component)obj).gameObject.AddComponent<RawImage>();
			obj2.texture = texture;
			((Graphic)obj2).color = Color.white;
			((Graphic)obj2).raycastTarget = false;
			return obj;
		}

		private static void Layout(RectTransform rect, float x, float y, float width, float height)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			rect.anchoredPosition = new Vector2(x, y);
			rect.sizeDelta = new Vector2(width, height);
		}

		private static Texture2D MakeTexture(string name, int side, byte[] rgba)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(side, side, (TextureFormat)4, false)
			{
				name = name,
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1,
				hideFlags = (HideFlags)32
			};
			try
			{
				Il2CppStructArray<Color32> val2 = new Il2CppStructArray<Color32>((long)(side * side));
				for (int i = 0; i < ((Il2CppArrayBase<Color32>)(object)val2).Length; i++)
				{
					int num = i * 4;
					((Il2CppArrayBase<Color32>)(object)val2)[i] = new Color32(rgba[num], rgba[num + 1], rgba[num + 2], rgba[num + 3]);
				}
				val.SetPixels32(val2);
				val.Apply(false, true);
				return val;
			}
			catch
			{
				Object.Destroy((Object)(object)val);
				throw;
			}
		}
	}
	internal static class ScopeOverlayPixels
	{
		internal const int Size = 1024;

		private const double LensRadius = 0.851;

		internal static byte[] Generate()
		{
			byte[] array = new byte[4194304];
			for (int i = 0; i < 1024; i++)
			{
				for (int j = 0; j < 1024; j++)
				{
					double num = ((double)j + 0.5 - 512.0) / 512.0;
					double num2 = ((double)i + 0.5 - 512.0) / 512.0;
					double num3 = Math.Sqrt(num * num + num2 * num2);
					int at = (i * 1024 + j) * 4;
					if (num3 >= 0.851)
					{
						Ring(array, at, num, num2, num3);
						continue;
					}
					double num4 = Smooth((num3 - 0.69) / 0.16100000000000003);
					Set(array, at, 3, 9, 12, (int)(num4 * num4 * 202.0));
					double a = Math.Atan2(num2, num);
					double alpha = Gaussian((num3 - 0.814) / 0.014) * (Gaussian(AngleDistance(a, 2.24) / 0.36) * 0.24 + Gaussian(AngleDistance(a, -0.86) / 0.46) * 0.1);
					Blend(array, at, 103, 145, 158, alpha);
					Reticle(array, at, num, num2);
				}
			}
			return array;
		}

		private static void Ring(byte[] rgba, int at, double dx, double dy, double r)
		{
			if (r >= 0.985)
			{
				Set(rgba, at, 0, 0, 0, 255);
				return;
			}
			double num = Math.Clamp((0.0 - dx + dy) / Math.Max(r, 0.001) * 0.46 + 0.36, 0.0, 1.0);
			double num2;
			double num3;
			if (r >= 0.97)
			{
				num2 = 4.0 + Smooth((0.985 - r) / 0.015) * (10.0 + num * 15.0);
				num3 = 1.0;
			}
			else if (r >= 0.913)
			{
				double num4 = 0.5 + 0.5 * Math.Cos((r - 0.913) * 920.0);
				num2 = 13.0 + num * 10.0 - num4 * 5.0;
				num3 = 1.0;
			}
			else if (r >= 0.898)
			{
				double num5 = Math.Sin((r - 0.898) / 0.015 * Math.PI);
				num2 = 21.0 + num5 * (8.0 + num * 30.0);
				num3 = 4.0;
			}
			else if (r >= 0.863)
			{
				double num6 = (r - 0.863) / 0.035;
				num2 = 4.0 + num6 * num6 * (12.0 + num * 12.0);
				num3 = 2.0;
			}
			else
			{
				double num7 = Gaussian((r - 0.857) / 0.0025);
				num2 = 4.0 + num7 * (10.0 + num * 18.0);
				num3 = 2.0;
			}
			Set(rgba, at, (int)num2, (int)(num2 + num3), (int)(num2 + num3 * 1.7), 255);
		}

		private static void Reticle(byte[] rgba, int at, double x, double y)
		{
			double num = Math.Abs(x);
			double num2 = Math.Abs(y);
			double val = Math.Max(Coverage(num2, 0.0015) * Smooth((num - 0.012) / 0.004), Coverage(num, 0.0015) * Smooth((num2 - 0.012) / 0.004));
			val = Math.Max(val, Coverage(num2, 0.0047) * Smooth((num - 0.62) / 0.025));
			val = Math.Max(val, Coverage(num, 0.0047) * Smooth((num2 - 0.62) / 0.025));
			val = Math.Max(val, Coverage(Math.Sqrt(x * x + y * y), 0.0032));
			for (int i = 1; i <= 5; i++)
			{
				double num3 = (double)i * 0.1;
				double val2 = Math.Sqrt((num - num3) * (num - num3) + y * y);
				double val3 = Math.Sqrt(x * x + (num2 - num3) * (num2 - num3));
				val = Math.Max(val, Coverage(Math.Min(val2, val3), 0.0047));
				double num4 = num3 - 0.05;
				double val4 = Coverage(Math.Abs(num - num4), 0.0011) * Coverage(num2, 0.0095);
				double val5 = Coverage(Math.Abs(num2 - num4), 0.0011) * Coverage(num, 0.0095);
				val = Math.Max(val, Math.Max(val4, val5));
			}
			Blend(rgba, at, 8, 10, 10, val * 0.96);
		}

		private static double Coverage(double distance, double halfWidth)
		{
			return Math.Clamp((halfWidth + 0.0009765625 - distance) * 1024.0 * 0.5, 0.0, 1.0);
		}

		private static double Smooth(double value)
		{
			value = Math.Clamp(value, 0.0, 1.0);
			return value * value * (3.0 - 2.0 * value);
		}

		private static double Gaussian(double value)
		{
			return Math.Exp((0.0 - value) * value * 2.0);
		}

		private static double AngleDistance(double a, double b)
		{
			double num;
			for (num = a - b; num > Math.PI; num -= Math.PI * 2.0)
			{
			}
			for (; num < -Math.PI; num += Math.PI * 2.0)
			{
			}
			return num;
		}

		private static void Set(byte[] rgba, int at, int r, int g, int b, int a)
		{
			rgba[at] = (byte)Math.Clamp(r, 0, 255);
			rgba[at + 1] = (byte)Math.Clamp(g, 0, 255);
			rgba[at + 2] = (byte)Math.Clamp(b, 0, 255);
			rgba[at + 3] = (byte)Math.Clamp(a, 0, 255);
		}

		private static void Blend(byte[] rgba, int at, int r, int g, int b, double alpha)
		{
			alpha = Math.Clamp(alpha, 0.0, 1.0);
			if (!(alpha <= 0.0))
			{
				double num = (double)(int)rgba[at + 3] / 255.0;
				double num2 = alpha + num * (1.0 - alpha);
				rgba[at] = (byte)Math.Clamp(((double)r * alpha + (double)(int)rgba[at] * num * (1.0 - alpha)) / num2, 0.0, 255.0);
				rgba[at + 1] = (byte)Math.Clamp(((double)g * alpha + (double)(int)rgba[at + 1] * num * (1.0 - alpha)) / num2, 0.0, 255.0);
				rgba[at + 2] = (byte)Math.Clamp(((double)b * alpha + (double)(int)rgba[at + 2] * num * (1.0 - alpha)) / num2, 0.0, 255.0);
				rgba[at + 3] = (byte)(num2 * 255.0);
			}
		}
	}
	internal static class ScopeZoomPolicy
	{
		public static readonly float[] Magnifications = new float[4] { 2f, 4f, 6f, 8f };

		public const int DefaultStep = 1;

		public static int Step(int current, float wheel)
		{
			current = Math.Clamp(current, 0, Magnifications.Length - 1);
			if (float.IsNaN(wheel) || wheel == 0f)
			{
				return current;
			}
			return Math.Clamp(current + ((wheel > 0f) ? 1 : (-1)), 0, Magnifications.Length - 1);
		}

		public static float FieldOfView(float normalFov, float magnification)
		{
			if (!float.IsFinite(normalFov))
			{
				normalFov = 75f;
			}
			if (!float.IsFinite(magnification))
			{
				magnification = 4f;
			}
			normalFov = Math.Clamp(normalFov, 20f, 140f);
			magnification = Math.Clamp(magnification, 1f, 8f);
			double num = (double)normalFov * Math.PI / 180.0;
			return (float)Math.Clamp(2.0 * Math.Atan(Math.Tan(num / 2.0) / (double)magnification) * 180.0 / Math.PI, 5.0, normalFov);
		}
	}
	internal static class ShopInitialization
	{
		public static void Complete(Action initializeShop, Action refreshPortraits, Action<Exception> reportPortraitFailure)
		{
			initializeShop();
			RefreshOptional(refreshPortraits, reportPortraitFailure);
		}

		public static void RefreshOptional(Action refresh, Action<Exception> reportFailure)
		{
			try
			{
				refresh();
			}
			catch (Exception obj)
			{
				reportFailure(obj);
			}
		}
	}
	internal static class SniperChamber
	{
		private sealed class Cycle
		{
			public Equippable_RangedWeapon? LocalWeapon;

			public AvatarRangedWeapon? AvatarWeapon;

			public float Due;

			public AudioSourceController? Sound;

			public float End;
		}

		private const float ShotDelay = 0.2f;

		private const string NativeRackPrefab = "Weapons/Shotty/PumpShotgun_Equipped";

		private static readonly Dictionary<IntPtr, Cycle> Cycles = new Dictionary<IntPtr, Cycle>();

		private static AudioClip? boltClip;

		private static bool reportedFailure;

		public static void Initialize(Harmony harmony)
		{
			//IL_0027: 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_0049: Expected O, but got Unknown
			//IL_0049: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00c9: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Equippable_RangedWeapon), "Fire", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SniperChamber), "BeforeFire", (Type[])null), new HarmonyMethod(typeof(SniperChamber), "AfterFire", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Equippable_RangedWeapon), "Unequip", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SniperChamber), "BeforeUnequip", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(AvatarRangedWeapon), "Shoot", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SniperChamber), "BeforeAvatarShoot", (Type[])null), new HarmonyMethod(typeof(SniperChamber), "AfterAvatarShoot", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.Method(typeof(AvatarRangedWeapon), "Unequip", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SniperChamber), "BeforeAvatarUnequip", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static void BeforeFire(Equippable_RangedWeapon __instance, out int __state)
		{
			__state = ((WeaponBehavior.GetSpec(__instance)?.Id == "eg_sniper") ? __instance.Ammo : (-1));
		}

		private static void AfterFire(Equippable_RangedWeapon __instance, int __state)
		{
			try
			{
				if (__state > 0 && __instance.Ammo < __state)
				{
					Schedule(((Il2CppObjectBase)__instance).Pointer, new Cycle
					{
						LocalWeapon = __instance
					});
				}
			}
			catch (Exception ex)
			{
				ReportFailure(ex);
			}
		}

		private static void BeforeUnequip(Equippable_RangedWeapon __instance)
		{
			Cancel(((Il2CppObjectBase)__instance).Pointer);
		}

		private static void BeforeAvatarShoot(AvatarRangedWeapon __instance, out bool __state)
		{
			__state = false;
			try
			{
				if (!(((AvatarEquippable)__instance).AssetPath != "EndgameArsenal/eg_sniper"))
				{
					Player local = Player.Local;
					Avatar val = ((local != null) ? local.Avatar : null);
					if (!((Object)(object)val != (Object)null) || !((Object)(object)((AvatarEquippable)__instance).avatar != (Object)null) || !(((Il2CppObjectBase)val).Pointer == ((Il2CppObjectBase)((AvatarEquippable)__instance).avatar).Pointer))
					{
						__state = __instance.timeSinceLastShot > 0f;
					}
				}
			}
			catch (Exception ex)
			{
				ReportFailure(ex);
			}
		}

		private static void AfterAvatarShoot(AvatarRangedWeapon __instance, bool __state)
		{
			try
			{
				if (__state)
				{
					Schedule(((Il2CppObjectBase)__instance).Pointer, new Cycle
					{
						AvatarWeapon = __instance
					});
				}
			}
			catch (Exception ex)
			{
				ReportFailure(ex);
			}
		}

		private static void BeforeAvatarUnequip(AvatarRangedWeapon __instance)
		{
			Cancel(((Il2CppObjectBase)__instance).Pointer);
		}

		private static void Schedule(IntPtr key, Cycle cycle)
		{
			Cancel(key);
			cycle.Due = Time.time + 0.2f;
			Cycles[key] = cycle;
		}

		public static void Update()
		{
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			if (Cycles.Count == 0)
			{
				return;
			}
			IntPtr[] array = Cycles.Keys.ToArray();
			foreach (IntPtr key in array)
			{
				Cycle cycle = Cycles[key];
				try
				{
					if (!StillEquipped(cycle))
					{
						Cancel(key);
					}
					else if ((Object)(object)cycle.Sound != (Object)null)
					{
						if (Time.time >= cycle.End)
						{
							Cancel(key);
						}
					}
					else
					{
						if (Time.time < cycle.Due || Time.timeScale <= 0f)
						{
							continue;
						}
						AudioManager instance = Singleton<AudioManager>.Instance;
						if ((Object)(object)instance == (Object)null)
						{
							Cancel(key);
							continue;
						}
						AudioClip clip = GetClip();
						Transform val = (((Object)(object)cycle.LocalWeapon != (Object)null) ? ((Component)cycle.LocalWeapon).transform : ((Component)cycle.AvatarWeapon).transform);
						float num = Random.Range(0.94f, 1f);
						AudioSourceController val2 = (cycle.Sound = instance.CreateAudioSourceController((EAudioType)2, clip, 0.13f, (Object)(object)cycle.LocalWeapon == (Object)null));
						((Object)((Component)val2).gameObject).name = "ArsenalSniperBoltSound";
						((Component)val2).transform.SetParent(val, false);
						((Component)val2).transform.localPosition = Vector3.zero;
						val2.SetLoop(false);
						val2.SetBasePitch(num);
						val2.SetSpacialBlend(((Object)(object)cycle.LocalWeapon == (Object)null) ? 1f : 0f);
						val2.ApplyMixer();
						AudioSource component = ((Component)val2).GetComponent<AudioSource>();
						if ((Object)(object)component != (Object)null)
						{
							component.playOnAwake = false;
							component.dopplerLevel = 0f;
							component.minDistance = 1.5f;
							component.maxDistance = 20f;
							component.rolloffMode = (AudioRolloffMode)0;
						}
						val2.Play();
						cycle.End = Time.time + clip.length / num + 0.05f;
						continue;
					}
				}
				catch (Exception ex)
				{
					Cancel(key);
					ReportFailure(ex);
				}
			}
		}

		private static bool StillEquipped(Cycle cycle)
		{
			if ((Object)(object)cycle.LocalWeapon != (Object)null)
			{
				Equippable_RangedWeapon localWeapon = cycle.LocalWeapon;
				PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance;
				Equippable val = ((instance != null) ? instance.Equippable : null);
				if (((Behaviour)localWeapon).isActiveAndEnabled && (Object)(object)val != (Object)null && ((Il2CppObjectBase)val).Pointer == ((Il2CppObjectBase)localWeapon).Pointer && WeaponBehavior.GetSpec(localWeapon)?.Id == "eg_sniper")
				{
					return !localWeapon.IsReloading;
				}
				return false;
			}
			AvatarRangedWeapon avatarWeapon = cycle.AvatarWeapon;
			if ((Object)(object)avatarWeapon == (Object)null || !((Behaviour)avatarWeapon).isActiveAndEnabled || !((AvatarEquippable)avatarWeapon)._equipped || ((AvatarEquippable)avatarWeapon).AssetPath != "EndgameArsenal/eg_sniper")
			{
				return false;
			}
			Avatar avatar = ((AvatarEquippable)avatarWeapon).avatar;
			AvatarEquippable val2 = ((avatar != null) ? avatar.CurrentEquippable : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return ((Il2CppObjectBase)val2).Pointer == ((Il2CppObjectBase)avatarWeapon).Pointer;
			}
			return false;
		}

		public static void Reset()
		{
			IntPtr[] array = Cycles.Keys.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				Cancel(array[i]);
			}
			boltClip = null;
			reportedFailure = false;
		}

		private static void Cancel(IntPtr key)
		{
			if (!Cycles.Remove(key, out Cycle value) || (Object)(object)value.Sound == (Object)null)
			{
				return;
			}
			try
			{
				value.Sound.Stop();
				Object.Destroy((Object)(object)((Component)value.Sound).gameObject);
			}
			catch
			{
			}
		}

		private static void ReportFailure(Exception ex)
		{
			if (!reportedFailure)
			{
				reportedFailure = true;
				MelonLogger.Warning("Sniper bolt audio could not play: " + ex.GetType().Name + ": " + ex.Message);
			}
		}

		private static AudioClip GetClip()
		{
			if ((Object)(object)boltClip != (Object)null)
			{
				return boltClip;
			}
			GameObject val = Resources.Load<GameObject>("Weapons/Shotty/PumpShotgun_Equipped");
			if ((Object)(object)val != (Object)null)
			{
				foreach (AudioSource componentsInChild in val.GetComponentsInChildren<AudioSource>(true))
				{
					if (!(((Object)((Component)componentsInChild).gameObject).name != "Cock sound"))
					{
						AudioClip clip = componentsInChild.clip;
						if (!((Object)(object)clip == (Object)null) && !(clip.length <= 0f))
						{
							boltClip = clip;
							return clip;
						}
					}
				}
			}
			throw new InvalidOperationException("The installed pump-action cocking clip could not be found.");
		}
	}
	internal static class SniperScope
	{
		private static ScopeOverlay? overlay;

		private static float nextOverlayAttempt;

		private static int overlayFailures;

		private static readonly List<(Renderer Renderer, bool Enabled)> hiddenRenderers = new List<(Renderer, bool)>();

		private static IntPtr hiddenWeaponPointer;

		private static int zoomStep = 1;

		private static int lastWheelFrame = -1;

		private static IntPtr equippedPointer;

		public static void Initialize(Harmony harmony)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			harmony.Patch((MethodBase)AccessTools.Method(typeof(Equippable_RangedWeapon), "UpdateInput", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SniperScope), "BeforeInput", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)AccessTools.PropertyGetter(typeof(GameInput), "MouseScrollDelta"), (HarmonyMethod)null, new HarmonyMethod(typeof(SniperScope), "AfterMouseScroll", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		public static void Reset()
		{
			ResetScopeState();
			overlay?.Dispose();
			overlay = null;
			nextOverlayAttempt = 0f;
			overlayFailures = 0;
		}

		private static void ResetScopeState()
		{
			SniperTargets.Reset();
			zoomStep = 1;
			lastWheelFrame = -1;
			equippedPointer = IntPtr.Zero;
			RestoreModel();
			overlay?.Hide();
		}

		public static void Update()
		{
			Equippable_RangedWeapon val = ActiveSniper();
			if (val == null || (Object)(object)val == (Object)null)
			{
				if (equippedPointer != IntPtr.Zero)
				{
					ResetScopeState();
				}
				return;
			}
			if (equippedPointer != ((Il2CppObjectBase)val).Pointer)
			{
				ResetScopeState();
				equippedPointer = ((Il2CppObjectBase)val).Pointer;
			}
			bool flag = ScopeAllowsZoom(val);
			if (flag)
			{
				ReadWheel();
			}
			SniperTargets.UpdateScope(val, flag && val.Aim >= 0.98f);
			bool scoped = UpdateOverlay(flag && val.Aim >= 0.98f);
			UpdateModelVisibility(val, scoped);
		}

		private static Equippable_RangedWeapon? ActiveSniper()
		{
			PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				Equippable equippable = instance.Equippable;
				obj = ((equippable != null) ? ((Il2CppObjectBase)equippable).TryCast<Equippable_RangedWeapon>() : null);
			}
			Equippable_RangedWeapon val = (Equippable_RangedWeapon)obj;
			if (val == null || !((Object)(object)val != (Object)null) || !(WeaponBehavior.GetSpec(val)?.Id == "eg_sniper"))
			{
				return null;
			}
			return val;
		}

		private static bool ScopeAllowsZoom(Equippable_RangedWeapon weapon)
		{
			PlayerCamera instance = PlayerSingleton<PlayerCamera>.Instance;
			PlayerInventory instance2 = PlayerSingleton<PlayerInventory>.Instance;
			Player local = Player.Local;
			if (Application.isFocused && Time.timeScale > 0f && !GameInput.IsTyping && ((Behaviour)weapon).isActiveAndEnabled && !weapon.IsReloading && weapon.aimStarted && GameInput.GetButton((ButtonCode)1) && (Object)(object)instance2 != (Object)null && instance2.HotbarEnabled && instance2.EquippingEnabled && (Object)(object)local != (Object)null && !local.IsArrested && !local.IsTased && !local.IsUnconscious && !local.IsRagdolled && !local.IsSleeping && !local.IsInVehicle && (Object)(object)instance != (Object)null && instance.ActiveUIElementCount == 0 && !instance.FreeCamEnabled)
			{
				if (!((Object)(object)Singleton<PauseMenu>.Instance == (Object)null))
				{
					return !Singleton<PauseMenu>.Instance.IsPaused;
				}
				return true;
			}
			return false;
		}

		internal static bool IsFullyScoped(Equippable_RangedWeapon weapon)
		{
			if (weapon.Aim >= 0.98f)
			{
				return ScopeAllowsZoom(weapon);
			}
			return false;
		}

		private static void ReadWheel()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (lastWheelFrame != Time.frameCount)
			{
				float y = GameInput.MouseWheelAxis.y;
				if (y != 0f)
				{
					lastWheelFrame = Time.frameCount;
					zoomStep = ScopeZoomPolicy.Step(zoomStep, y);
				}
			}
		}

		private static void AfterMouseScroll(ref float __result)
		{
			Equippable_RangedWeapon val = ActiveSniper();
			if (val != null && !((Object)(object)val == (Object)null) && ScopeAllowsZoom(val))
			{
				if (equippedPointer != ((Il2CppObjectBase)val).Pointer)
				{
					ResetScopeState();
					equippedPointer = ((Il2CppObjectBase)val).Pointer;
				}
				ReadWheel();
				__result = 0f;
			}
		}

		private static void BeforeInput(Equippable_RangedWeapon __instance)
		{
			if (!(WeaponBehavior.GetSpec(__instance)?.Id != "eg_sniper"))
			{
				if (equippedPointer != ((Il2CppObjectBase)__instance).Pointer)
				{
					ResetScopeState();
					equippedPointer = ((Il2CppObjectBase)__instance).Pointer;
				}
				bool num = ScopeAllowsZoom(__instance);
				if (num)
				{
					ReadWheel();
				}
				Settings instance = Singleton<Settings>.Instance;
				float num2 = ((instance != null) ? instance.CameraFOV : 75f);
				float num3 = (num ? ScopeZoomPolicy.FieldOfView(num2, ScopeZoomPolicy.Magnifications[zoomStep]) : num2);
				__instance.MinAimFOVReduction = num2 - num3;
				__instance.MaxAimFOVReduction = num2 - num3;
			}
		}

		private static bool UpdateOverlay(bool visible)
		{
			if (!visible)
			{
				overlay?.Hide();
				return false;
			}
			if (Screen.width <= 0 || Screen.height <= 0)
			{
				overlay?.Hide();
				return false;
			}
			if (Time.unscaledTime < nextOverlayAttempt)
			{
				return false;
			}
			try
			{
				if (overlay == null || !overlay.IsAlive)
				{
					overlay?.Dispose();
					overlay = new ScopeOverlay();
				}
				overlay.Show(ScopeZoomPolicy.Magnifications[zoomStep]);
				overlayFailures = 0;
				return overlay.IsVisible;
			}
			catch (Exception ex)
			{
				overlay?.Dispose();
				overlay = null;
				nextOverlayAttempt = Time.unscaledTime + 5f;
				if (overlayFailures++ < 3)
				{
					MelonLogger.Warning("Sniper eyepiece UI will retry: " + ex.GetType().Name + ": " + ex.Message);
				}
				return false;
			}
		}

		private static void UpdateModelVisibility(Equippable_RangedWeapon weapon, bool scoped)
		{
			if (!scoped)
			{
				RestoreModel();
				return;
			}
			if (hiddenWeaponPointer != ((Il2CppObjectBase)weapon).Pointer)
			{
				RestoreModel();
				Transform val = ((Component)weapon).transform.Find("eg_sniper_OriginalModel");
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				foreach (Renderer componentsInChild in ((Component)val).GetComponentsInChildren<Renderer>(true))
				{
					hiddenRenderers.Add((componentsInChild, componentsInChild.enable