Decompiled source of Weapon Framework v1.0.2

WeaponFramework.dll

Decompiled 12 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using InControl;
using LevelEditor;
using MenuOverhaul;
using SFQoL;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("WeaponFramework")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+562f2a5697c435654782039a6e570db5445afc1f")]
[assembly: AssemblyProduct("WeaponFramework")]
[assembly: AssemblyTitle("WeaponFramework")]
[assembly: AssemblyVersion("1.0.2.0")]
namespace SFQoL
{
	internal static class Ui
	{
		public static readonly Color Panel = new Color(0.176f, 0.176f, 0.176f);

		public static readonly Color Strip = new Color(0.147f, 0.147f, 0.147f);

		public static readonly Color Item = new Color(0.265f, 0.265f, 0.265f);

		public static readonly Color Grey = new Color(0.6f, 0.6f, 0.6f);

		private static TMP_FontAsset font;

		private static Sprite box;

		private static bool boxSearched;

		private static Camera menuCam;

		private static float menuCamSearchAt;

		public static TMP_FontAsset Font
		{
			get
			{
				if ((Object)(object)font == (Object)null)
				{
					GameManager instance = GameManager.Instance;
					if ((Object)(object)instance != (Object)null && (Object)(object)instance.winText != (Object)null)
					{
						font = ((TMP_Text)instance.winText).font;
					}
					if ((Object)(object)font == (Object)null)
					{
						TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
						foreach (TMP_FontAsset val in array)
						{
							if (((Object)val).name.StartsWith("Anton"))
							{
								font = val;
								break;
							}
						}
					}
				}
				return font;
			}
		}

		public static Sprite BoxSprite
		{
			get
			{
				if ((Object)(object)box == (Object)null && !boxSearched)
				{
					boxSearched = true;
					Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
					foreach (Sprite val in array)
					{
						if (((Object)val).name == "box")
						{
							box = val;
							break;
						}
					}
				}
				return box;
			}
		}

		public static int MenuLayer
		{
			get
			{
				int num = LayerMask.NameToLayer("MENU");
				if (num < 0)
				{
					return 31;
				}
				return num;
			}
		}

		public static void Attach(Canvas c)
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Invalid comparison between Unknown and I4
			if ((Object)(object)c == (Object)null)
			{
				return;
			}
			if (((Object)(object)menuCam == (Object)null || !((Behaviour)menuCam).isActiveAndEnabled) && Time.unscaledTime >= menuCamSearchAt)
			{
				menuCamSearchAt = Time.unscaledTime + 1f;
				menuCam = null;
				Camera[] allCameras = Camera.allCameras;
				foreach (Camera val in allCameras)
				{
					if (((Object)val).name == "Camera_Pause" && (val.cullingMask & (1 << MenuLayer)) != 0)
					{
						menuCam = val;
						break;
					}
				}
			}
			if ((Object)(object)menuCam != (Object)null && ((Behaviour)menuCam).isActiveAndEnabled)
			{
				if ((int)c.renderMode != 1 || (Object)(object)c.worldCamera != (Object)(object)menuCam)
				{
					c.renderMode = (RenderMode)1;
					c.worldCamera = menuCam;
					c.planeDistance = 1f;
				}
			}
			else if ((int)c.renderMode != 0)
			{
				c.renderMode = (RenderMode)0;
			}
		}

		public static Canvas MakeCanvas(string name, int order)
		{
			//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_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name)
			{
				layer = MenuLayer
			};
			Object.DontDestroyOnLoad((Object)val);
			Canvas val2 = val.AddComponent<Canvas>();
			val2.renderMode = (RenderMode)0;
			val2.sortingOrder = order;
			Attach(val2);
			CanvasScaler obj = val.AddComponent<CanvasScaler>();
			obj.uiScaleMode = (ScaleMode)1;
			obj.referenceResolution = new Vector2(1920f, 1080f);
			obj.matchWidthOrHeight = 0.5f;
			return val2;
		}

		public static RectTransform Rect(Transform parent, string name)
		{
			//IL_0014: 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_002a: 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_0041: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) })
			{
				layer = ((Component)parent).gameObject.layer
			};
			val.transform.SetParent(parent, false);
			RectTransform val2 = (RectTransform)val.transform;
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0.5f, 0.5f);
			val2.anchorMax = val3;
			val2.anchorMin = val3;
			val2.pivot = new Vector2(0.5f, 0.5f);
			return val2;
		}

		public static Image Box(Transform parent, string name, Color color, Vector2 pos, Vector2 size, bool rounded = false)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			RectTransform obj = Rect(parent, name);
			obj.anchoredPosition = pos;
			obj.sizeDelta = size;
			Image val = ((Component)obj).gameObject.AddComponent<Image>();
			((Graphic)val).color = color;
			((Graphic)val).raycastTarget = false;
			if (rounded && (Object)(object)BoxSprite != (Object)null)
			{
				val.sprite = BoxSprite;
				Vector4 border = BoxSprite.border;
				if (((Vector4)(ref border)).sqrMagnitude > 0f)
				{
					val.type = (Type)1;
				}
			}
			return val;
		}

		public static void Fill(RectTransform rt, float inset)
		{
			//IL_0001: 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_0019: 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)
			rt.anchorMin = Vector2.zero;
			rt.anchorMax = Vector2.one;
			rt.offsetMin = new Vector2(inset, inset);
			rt.offsetMax = new Vector2(0f - inset, 0f - inset);
		}

		public static TextMeshProUGUI Text(Transform parent, string name, string text, float size, Color color, TextAlignmentOptions align)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			TextMeshProUGUI val = ((Component)Rect(parent, name)).gameObject.AddComponent<TextMeshProUGUI>();
			if ((Object)(object)Font != (Object)null)
			{
				((TMP_Text)val).font = Font;
			}
			((TMP_Text)val).fontSize = size;
			((Graphic)val).color = color;
			((TMP_Text)val).alignment = align;
			((TMP_Text)val).enableWordWrapping = false;
			((TMP_Text)val).richText = true;
			((Graphic)val).raycastTarget = false;
			((TMP_Text)val).text = text;
			return val;
		}

		public static Color PlayerColor(Controller c)
		{
			//IL_00bf: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)c != (Object)null)
			{
				SpriteRenderer componentInChildren = ((Component)c).GetComponentInChildren<SpriteRenderer>();
				SetColorWhenDamaged val = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).GetComponent<SetColorWhenDamaged>() : null);
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)c).GetComponentInChildren<SetColorWhenDamaged>(true);
				}
				if ((Object)(object)val != (Object)null && val.startColor.a > 0f)
				{
					Color startColor = val.startColor;
					startColor.a = 1f;
					return startColor;
				}
				ControllerHandler instance = ControllerHandler.Instance;
				if ((Object)(object)instance != (Object)null && instance.colors != null && c.playerID >= 0 && c.playerID < instance.colors.Length && (Object)(object)instance.colors[c.playerID] != (Object)null)
				{
					return instance.colors[c.playerID].color;
				}
			}
			return Color.white;
		}

		public static Color SlotColor(int id)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			ControllerHandler instance = ControllerHandler.Instance;
			if ((Object)(object)instance != (Object)null && instance.colors != null && id >= 0 && id < instance.colors.Length && (Object)(object)instance.colors[id] != (Object)null)
			{
				Color color = instance.colors[id].color;
				color.a = 1f;
				return color;
			}
			return Color.white;
		}

		public static string Hex(Color c)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			return "#" + ((int)(Mathf.Clamp01(c.r) * 255f)).ToString("X2") + ((int)(Mathf.Clamp01(c.g) * 255f)).ToString("X2") + ((int)(Mathf.Clamp01(c.b) * 255f)).ToString("X2");
		}

		public static string Colored(string text, Color c)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return "<color=" + Hex(c) + ">" + text + "</color>";
		}

		public static Color WithAlpha(Color c, float a)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			c.a = a;
			return c;
		}
	}
}
namespace WeaponFramework
{
	public enum SoundKind
	{
		Shoot,
		Draw,
		Drop
	}
	public static class Sounds
	{
		internal sealed class Pack
		{
			public AudioClip[] Shoot;

			public AudioClip[] Draw;

			public AudioClip[] Drop;

			public float? Volume;

			public float? Pitch;
		}

		private static readonly Dictionary<string, AudioClip> cache = new Dictionary<string, AudioClip>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, Pack> packs = new Dictionary<string, Pack>();

		internal static string Root => Path.Combine(Path.Combine(Paths.ConfigPath, "WeaponFramework"), "Sounds");

		public static AudioClip Load(string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return null;
			}
			if (cache.TryGetValue(path, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			try
			{
				value = Wav.Read(path);
				if ((Object)(object)value != (Object)null)
				{
					cache[path] = value;
				}
				return value;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't load sound " + path + ": " + ex.Message));
				return null;
			}
		}

		public static AudioClip[] LoadFolder(string folder, string prefix = null)
		{
			if (string.IsNullOrEmpty(folder) || !Directory.Exists(folder))
			{
				return null;
			}
			List<string> list = new List<string>(Directory.GetFiles(folder, "*.wav"));
			list.Sort(StringComparer.OrdinalIgnoreCase);
			List<AudioClip> list2 = new List<AudioClip>();
			foreach (string item in list)
			{
				if (prefix == null || Path.GetFileName(item).StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
				{
					AudioClip val = Load(item);
					if ((Object)(object)val != (Object)null)
					{
						list2.Add(val);
					}
				}
			}
			if (list2.Count <= 0)
			{
				return null;
			}
			return list2.ToArray();
		}

		public static AudioClip[] Of(VanillaWeapon weapon, SoundKind kind)
		{
			Weapon val = Core.PrefabWeapon((int)weapon);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			AudioClip[] array = kind switch
			{
				SoundKind.Draw => val.drawSounds, 
				SoundKind.Shoot => val.clips, 
				_ => val.dropSound, 
			};
			if (array == null || array.Length == 0)
			{
				return null;
			}
			return array;
		}

		public static void Play(Controller player, AudioClip clip, float volume = 1f)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)clip == (Object)null))
			{
				AudioSource componentInChildren = ((Component)player).GetComponentInChildren<AudioSource>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.PlayOneShot(clip, volume);
				}
			}
		}

		public static void Play(Controller player, VanillaWeapon weapon, SoundKind kind = SoundKind.Shoot, float volume = 1f)
		{
			AudioClip[] array = Of(weapon, kind);
			if (array != null)
			{
				Play(player, array[Random.Range(0, array.Length)], volume);
			}
		}

		internal static void ScanPacks(IList<WeaponInfo> weapons)
		{
			packs.Clear();
			cache.Clear();
			try
			{
				string root = Root;
				Directory.CreateDirectory(root);
				WriteGuide(root, weapons);
				Dictionary<string, WeaponInfo> dictionary = new Dictionary<string, WeaponInfo>(StringComparer.OrdinalIgnoreCase);
				foreach (WeaponInfo weapon in weapons)
				{
					dictionary[weapon.Id] = weapon;
					if (!dictionary.ContainsKey(weapon.OriginalName))
					{
						dictionary[weapon.OriginalName] = weapon;
					}
				}
				string[] directories = Directory.GetDirectories(root);
				foreach (string text in directories)
				{
					if (!dictionary.TryGetValue(Path.GetFileName(text), out var value))
					{
						Plugin.Log.LogWarning((object)("Sound folder '" + Path.GetFileName(text) + "' doesn't match a weapon id or name (see " + Path.Combine(root, "weapons.txt") + ")."));
						continue;
					}
					Pack pack = new Pack
					{
						Shoot = LoadFolder(text, "shoot"),
						Draw = LoadFolder(text, "draw"),
						Drop = LoadFolder(text, "drop")
					};
					ReadSettings(Path.Combine(text, "sound.txt"), pack);
					if (pack.Shoot != null || pack.Draw != null || pack.Drop != null || pack.Volume.HasValue || pack.Pitch.HasValue)
					{
						packs[value.Id] = pack;
						Plugin.Log.LogInfo((object)("Custom sounds for " + value.Name + ": " + Count(pack.Shoot) + " shoot, " + Count(pack.Draw) + " draw, " + Count(pack.Drop) + " drop."));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't read the sound folders: " + ex.Message));
			}
		}

		internal static Pack PackFor(WeaponInfo w)
		{
			if (w == null || !packs.TryGetValue(w.Id, out var value))
			{
				return null;
			}
			return value;
		}

		private static int Count(AudioClip[] a)
		{
			if (a == null)
			{
				return 0;
			}
			return a.Length;
		}

		private static void ReadSettings(string file, Pack p)
		{
			if (!File.Exists(file))
			{
				return;
			}
			string[] array = File.ReadAllLines(file);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				int num = text.IndexOf('=');
				if (num <= 0 || text.StartsWith("#"))
				{
					continue;
				}
				string text2 = text.Substring(0, num).Trim().ToLowerInvariant();
				if (float.TryParse(text.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					result = Mathf.Clamp(result, 0f, 4f);
					if (text2 == "volume")
					{
						p.Volume = result;
					}
					else if (text2 == "pitch")
					{
						p.Pitch = result;
					}
				}
			}
		}

		private static void WriteGuide(string root, IList<WeaponInfo> weapons)
		{
			List<string> list = new List<string>
			{
				"Custom weapon sounds (Weapon Framework)", "", "Make a folder here named after a weapon's id or name (both listed below), e.g.", "  Sounds\\vanilla.ak47\\   or   Sounds\\AK 47\\", "and put .wav files in it:", "  shoot*.wav  played when it fires or swings (one picked at random)", "  draw*.wav   played when it is picked up", "  drop*.wav   played when it is dropped", "  sound.txt   optional, lines like:  volume = 0.8   pitch = 1.1", "Anything you leave out keeps the weapon's own sound. Changes load the next time the lobby",
				"loads (start the game, or finish a match). This file is rewritten every time.", "", "id = name"
			};
			foreach (WeaponInfo weapon in weapons)
			{
				list.Add(weapon.Id + " = " + weapon.OriginalName);
			}
			File.WriteAllText(Path.Combine(root, "weapons.txt"), string.Join(Environment.NewLine, list.ToArray()));
		}
	}
	internal static class Wav
	{
		public static AudioClip Read(string path)
		{
			byte[] array = File.ReadAllBytes(path);
			if (array.Length < 44 || Ascii(array, 0) != "RIFF" || Ascii(array, 8) != "WAVE")
			{
				throw new Exception("not a WAV file");
			}
			int num = 12;
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			int num6 = -1;
			int num7 = 0;
			while (num + 8 <= array.Length)
			{
				string text = Ascii(array, num);
				int num8 = BitConverter.ToInt32(array, num + 4);
				int num9 = num + 8;
				if (text == "fmt ")
				{
					num2 = BitConverter.ToUInt16(array, num9);
					num3 = BitConverter.ToUInt16(array, num9 + 2);
					num4 = BitConverter.ToInt32(array, num9 + 4);
					num5 = BitConverter.ToUInt16(array, num9 + 14);
					if (num2 == 65534 && num8 >= 26)
					{
						num2 = BitConverter.ToUInt16(array, num9 + 24);
					}
				}
				else if (text == "data")
				{
					num6 = num9;
					num7 = Math.Min(num8, array.Length - num9);
					break;
				}
				num = num9 + num8 + (num8 & 1);
			}
			if (num6 < 0 || num3 < 1 || num4 < 1)
			{
				throw new Exception("no audio data");
			}
			if (num2 != 1 && num2 != 3)
			{
				throw new Exception("only PCM or float WAV files are supported (format " + num2 + ")");
			}
			int num10 = num5 / 8;
			if (num10 < 1 || (num2 == 3 && num5 != 32))
			{
				throw new Exception(num5 + "-bit audio isn't supported");
			}
			int num11 = num7 / num10;
			float[] array2 = new float[num11];
			for (int i = 0; i < num11; i++)
			{
				int num12 = num6 + i * num10;
				switch ((num2 != 3) ? num5 : 0)
				{
				case 0:
					array2[i] = BitConverter.ToSingle(array, num12);
					break;
				case 8:
					array2[i] = (float)(array[num12] - 128) / 128f;
					break;
				case 16:
					array2[i] = (float)BitConverter.ToInt16(array, num12) / 32768f;
					break;
				case 24:
					array2[i] = (float)(((array[num12] << 8) | (array[num12 + 1] << 16) | (array[num12 + 2] << 24)) >> 8) / 8388608f;
					break;
				case 32:
					array2[i] = (float)BitConverter.ToInt32(array, num12) / 2.1474836E+09f;
					break;
				default:
					throw new Exception(num5 + "-bit audio isn't supported");
				}
			}
			AudioClip obj = AudioClip.Create(Path.GetFileNameWithoutExtension(path), num11 / num3, num3, num4, false);
			obj.SetData(array2, 0);
			return obj;
		}

		private static string Ascii(byte[] b, int at)
		{
			if (at + 4 > b.Length)
			{
				return "";
			}
			return Encoding.ASCII.GetString(b, at, 4);
		}
	}
	public static class SpawnWeights
	{
		public const int MaxTickets = 1000;

		public static readonly int[] Steps = new int[19]
		{
			0, 1, 2, 3, 4, 5, 6, 8, 10, 12,
			15, 20, 25, 30, 40, 50, 60, 80, 100
		};

		private static Func<WeaponInfo, int> getter;

		private static Action<WeaponInfo, int> setter;

		private static readonly HashSet<string> failed = new HashSet<string>();

		public static bool HasProvider => getter != null;

		public static string ProviderName { get; private set; }

		public static bool SetProvider(string modName, Func<WeaponInfo, int> get, Action<WeaponInfo, int> set)
		{
			if (get == null)
			{
				throw new ArgumentNullException("get");
			}
			if (getter != null)
			{
				Plugin.Log.LogWarning((object)(modName + " tried to provide spawn weights, but " + ProviderName + " already does. Only one mod may change spawn odds."));
				return false;
			}
			getter = get;
			setter = set;
			ProviderName = (string.IsNullOrEmpty(modName) ? "?" : modName);
			Plugin.Log.LogInfo((object)("Spawn weights come from " + ProviderName + "."));
			Core.MenuChanged();
			Refresh();
			return true;
		}

		public static void Refresh()
		{
			Core.RebuildBag();
		}

		public static int Override(WeaponInfo w)
		{
			if (getter == null || w == null)
			{
				return -1;
			}
			try
			{
				int num = getter(w);
				return (num < 0) ? (-1) : Math.Min(num, 1000);
			}
			catch (Exception ex)
			{
				if (failed.Add(w.Id))
				{
					Plugin.Log.LogError((object)(ProviderName + " failed to give a spawn weight for " + w.Id + " (its default is used; further errors for it aren't logged): " + ex.Message));
				}
				return -1;
			}
		}

		internal static void Set(WeaponInfo w, int tickets)
		{
			if (setter != null && w != null)
			{
				try
				{
					setter(w, tickets);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)(ProviderName + " failed to store a spawn weight for " + w.Id + ": " + ex.Message));
				}
				Refresh();
			}
		}

		internal static int Step(int current, int dir)
		{
			if (dir > 0)
			{
				int[] steps = Steps;
				foreach (int num in steps)
				{
					if (num > current)
					{
						return num;
					}
				}
				if (Steps[Steps.Length - 1] <= current)
				{
					return current;
				}
				return Steps[Steps.Length - 1];
			}
			for (int num2 = Steps.Length - 1; num2 >= 0; num2--)
			{
				if (Steps[num2] < current)
				{
					return Steps[num2];
				}
			}
			return 0;
		}
	}
	public enum VanillaWeapon
	{
		Pistol,
		AK47,
		Sword,
		GrenadeLauncher,
		BlinkDagger,
		Sniper,
		Revolver,
		IceGun,
		Shield,
		Fan,
		MilitaryShotgun,
		BallLauncher,
		Thruster,
		Bow,
		Laser,
		Lightsaber,
		Uzi,
		OldMinigun,
		TinyMinigun,
		Minigun,
		Bouncer,
		TimeBubble,
		RPG,
		FlameThrower,
		SnakeGun,
		SnakeGrenade,
		SnakeLauncher,
		GlueGun,
		LaserPlanter,
		HolySword,
		GodMinigun,
		GodPistol,
		M1,
		SnakeMinigun,
		LavaWhip,
		LavaStream,
		LavaSpray,
		SnakeShotgun,
		LavaSpikeBall,
		LavaBeam,
		LavaSpikeGun,
		BlackHole,
		HalloweenShotgun,
		HalloweenSaw,
		HalloweenLaser,
		HalloweenAK,
		HalloweenRing,
		HalloweenPew,
		HalloweenPewPew,
		HalloweenBlocker,
		HalloweenPew2,
		HalloweenRevolver,
		HalloweenBlocker2,
		HalloweenPistol,
		HalloweenWaves,
		HalloweenInverse,
		HalloweenPewRainbow,
		HalloweenSniper,
		HalloweenBouncePew,
		PumpkinGun,
		M16,
		Deagle,
		SawedOff,
		Spear,
		FlyingSnake
	}
	public abstract class WeaponBehaviour : MonoBehaviour
	{
		private Weapon weapon;

		private Controller owner;

		private Fighting fighting;

		private Rigidbody torso;

		private Transform aim;

		protected bool CountsAttackAsShot = true;

		public WeaponInfo Info { get; internal set; }

		public Weapon Weapon
		{
			get
			{
				if ((Object)(object)weapon == (Object)null)
				{
					weapon = ((Component)this).GetComponent<Weapon>();
				}
				return weapon;
			}
		}

		public Controller Owner
		{
			get
			{
				if ((Object)(object)owner == (Object)null)
				{
					owner = ((Component)((Component)this).transform.root).GetComponent<Controller>();
				}
				return owner;
			}
		}

		public Fighting Fighting
		{
			get
			{
				if ((Object)(object)fighting == (Object)null)
				{
					fighting = ((Component)((Component)this).transform.root).GetComponent<Fighting>();
				}
				return fighting;
			}
		}

		public Rigidbody Torso
		{
			get
			{
				if ((Object)(object)torso == (Object)null)
				{
					Torso componentInChildren = ((Component)((Component)this).transform.root).GetComponentInChildren<Torso>();
					if ((Object)(object)componentInChildren != (Object)null)
					{
						torso = ((Component)componentInChildren).GetComponent<Rigidbody>();
					}
				}
				return torso;
			}
		}

		public Vector3 Aim
		{
			get
			{
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: 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_006e: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)aim == (Object)null)
				{
					AimTarget componentInChildren = ((Component)((Component)this).transform.root).GetComponentInChildren<AimTarget>();
					if ((Object)(object)componentInChildren != (Object)null)
					{
						aim = ((Component)componentInChildren).transform;
					}
				}
				if ((Object)(object)aim == (Object)null)
				{
					return Vector3.forward;
				}
				Vector3 forward = aim.forward;
				forward.x = 0f;
				if (!(((Vector3)(ref forward)).sqrMagnitude > 1E-06f))
				{
					return Vector3.forward;
				}
				return ((Vector3)(ref forward)).normalized;
			}
		}

		public Vector3 Muzzle
		{
			get
			{
				//IL_0039: 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_001d: 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_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				Shoot componentInChildren = ((Component)this).GetComponentInChildren<Shoot>(true);
				Vector3 result = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).transform.position : (((Component)this).transform.position + Aim * 0.5f));
				result.x = 0f;
				return result;
			}
		}

		public Transform MuzzleTransform
		{
			get
			{
				Shoot componentInChildren = ((Component)this).GetComponentInChildren<Shoot>(true);
				if (!((Object)(object)componentInChildren != (Object)null))
				{
					return ((Component)this).transform;
				}
				return ((Component)componentInChildren).transform;
			}
		}

		public float Charge { get; internal set; }

		public int AmmoLeft
		{
			get
			{
				if (!((Object)(object)Fighting != (Object)null))
				{
					return 0;
				}
				return Access.BulletsLeft.Invoke(Fighting);
			}
			set
			{
				if ((Object)(object)Fighting != (Object)null)
				{
					Access.BulletsLeft.Invoke(Fighting) = value;
				}
			}
		}

		public bool IsHeld
		{
			get
			{
				if ((Object)(object)Fighting != (Object)null)
				{
					return (Object)(object)Fighting.weapon == (Object)(object)Weapon;
				}
				return false;
			}
		}

		internal bool CountsAsShot => CountsAttackAsShot;

		public void SetVisible(bool on)
		{
			Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!(val is ParticleSystemRenderer))
				{
					val.enabled = on;
				}
			}
			Collider[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].enabled = on;
			}
		}

		internal void UseAmmoInternal(int shots)
		{
			UseAmmo(shots);
		}

		public virtual void OnEquip()
		{
		}

		public virtual void OnUnequip()
		{
		}

		public virtual bool OnAttack()
		{
			return false;
		}

		public virtual void AfterAttack()
		{
		}

		public virtual void OnAttackHeld(float seconds)
		{
		}

		public virtual void OnAttackReleased(float heldFor)
		{
		}

		public virtual void OnAltPressed()
		{
		}

		public virtual void OnAltHeld(float seconds)
		{
		}

		public virtual void OnAltReleased(float heldFor)
		{
		}

		public virtual void OnShot(GameObject projectile)
		{
		}

		public virtual float ModifyDamage(Controller victim, float damage)
		{
			return damage;
		}

		public virtual void OnDamageDealt(Controller victim, float damage, bool killed)
		{
		}

		protected void UseAmmo(int shots = 1)
		{
			Fighting val = Fighting;
			if (!((Object)(object)val == (Object)null) && IsHeld)
			{
				int num = Access.BulletsLeft.Invoke(val) - shots;
				Access.BulletsLeft.Invoke(val) = num;
				if (num <= 0)
				{
					val.ThrowWeapon(true);
				}
			}
		}

		protected void Drop()
		{
			if (IsHeld)
			{
				Fighting.ThrowWeapon(true);
			}
		}

		protected void PlayShootSound()
		{
			Weapon val = Weapon;
			if ((Object)(object)val != (Object)null && val.clips != null && val.clips.Length != 0)
			{
				Sounds.Play(Owner, val.clips[Random.Range(0, val.clips.Length)], val.volumeFix);
			}
		}

		protected void ResetCooldown()
		{
			if ((Object)(object)Fighting != (Object)null)
			{
				Fighting.counter = 0f;
			}
		}
	}
	public sealed class WeaponCategory
	{
		public const string Pistols = "pistols";

		public const string Rifles = "rifles";

		public const string Shotguns = "shotguns";

		public const string Heavy = "heavy";

		public const string Explosives = "explosives";

		public const string Melee = "melee";

		public const string Control = "control";

		public const string Gadgets = "gadgets";

		public const string Party = "party";

		public const string Lava = "lava";

		public const string Snake = "snake";

		public const string Godlike = "godlike";

		internal int Added;

		public string Id { get; private set; }

		public string Name { get; internal set; }

		public string Description { get; internal set; }

		public int Order { get; internal set; }

		public string Mod { get; internal set; }

		internal WeaponCategory(string id, string name, int order, string description, string mod)
		{
			Id = id;
			Name = name;
			Order = order;
			Description = description;
			Mod = mod;
		}

		public override string ToString()
		{
			return Name + " (" + Id + ")";
		}
	}
	public sealed class WeaponDefinition
	{
		public string Id;

		public string Name;

		public string Category = "gadgets";

		public string Description;

		public string Mod;

		public VanillaWeapon Base;

		public VanillaWeapon? Existing;

		public int Rarity = 5;

		public bool OnByDefault = true;

		public int Ammo;

		public float? Cooldown;

		public float ChargeTime;

		public float ChargePower = 1f;

		public Type Behaviour;

		public WeaponModel Model;

		public Color? Tint;

		public bool GiftBox;

		public VanillaWeapon? SoundsFrom;

		public AudioClip[] ShootSounds;

		public AudioClip[] DrawSounds;

		public AudioClip[] DropSounds;

		public float? Volume;

		public float? Pitch;

		public Action<Weapon> Configure;

		public Action<GameObject> ConfigureModel;

		public Action<GameObject> ConfigurePickup;

		internal int BaseIndex => (int)(Existing ?? Base);

		public WeaponDefinition()
		{
		}

		public WeaponDefinition(string id, string name, VanillaWeapon baseWeapon)
		{
			Id = id;
			Name = name;
			Base = baseWeapon;
		}

		public static WeaponDefinition FromExisting(string id, string name, VanillaWeapon weapon)
		{
			return new WeaponDefinition
			{
				Id = id,
				Name = name,
				Existing = weapon,
				Base = weapon
			};
		}
	}
	public sealed class WeaponInfo
	{
		internal bool OnByDefault;

		internal int VanillaRow = -1;

		internal int VanillaTickets;

		internal GameObject Pickup;

		public string Id { get; private set; }

		public string Name { get; internal set; }

		public string OriginalName { get; private set; }

		public string Category { get; internal set; }

		public string Description { get; internal set; }

		public string Mod { get; internal set; }

		public int Index { get; internal set; }

		public int DefaultTickets { get; internal set; }

		public bool IsVanilla { get; private set; }

		public string MenuLabel { get; private set; }

		public WeaponDefinition Definition { get; private set; }

		public GameObject PickupPrefab => Pickup;

		public bool AllowedOnline => IsVanilla;

		public bool Enabled => Core.IsEnabled(this);

		public int Tickets => Core.TicketsFor(this, online: false);

		public float Chance => Core.ChanceOf(this);

		internal WeaponInfo(string id, string name, string category, bool vanilla, string menuLabel, WeaponDefinition def)
		{
			Id = id;
			Name = name;
			OriginalName = name;
			Category = category;
			IsVanilla = vanilla;
			MenuLabel = menuLabel;
			Definition = def;
			Index = -1;
		}

		public override string ToString()
		{
			return Name + " (" + Id + ", #" + Index + ")";
		}
	}
	public static class WeaponModels
	{
		public static void Build(Transform parent, WeaponModel model)
		{
			if ((Object)(object)parent != (Object)null && model != null)
			{
				ModelBuilder.BuildVisual(parent, model);
			}
		}
	}
	public static class GameMaterials
	{
		public const string Weapon = "WeaponMaterial";

		public const string Blink = "Blink";

		public const string Explosive = "Explosive";

		public const string Gray = "gray";
	}
	public sealed class WeaponModel
	{
		internal sealed class Part
		{
			public PrimitiveType Shape;

			public Vector3 Position;

			public Vector3 Size;

			public float Pitch;

			public Color? Color;

			public float Glow;

			public bool Solid;

			public string Material;

			public bool FaceCamera;

			public string Name;
		}

		internal readonly List<Part> Parts = new List<Part>();

		public Vector3 Grip = Vector3.zero;

		public Vector3? OffHandGrip;

		public Vector3 Muzzle = new Vector3(0f, 0.08f, 0.35f);

		public Vector3 PickupCollider = Vector3.zero;

		public WeaponModel Paint(string gameMaterial)
		{
			if (Parts.Count > 0)
			{
				Parts[Parts.Count - 1].Material = gameMaterial;
			}
			return this;
		}

		public WeaponModel Named(string name)
		{
			if (Parts.Count > 0)
			{
				Parts[Parts.Count - 1].Name = name;
			}
			return this;
		}

		public WeaponModel Box(Vector3 center, Vector3 size, float pitch = 0f, Color? color = null, bool solid = true)
		{
			//IL_000d: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			Parts.Add(new Part
			{
				Shape = (PrimitiveType)3,
				Position = center,
				Size = size,
				Pitch = pitch,
				Color = color,
				Solid = solid
			});
			return this;
		}

		public WeaponModel Cylinder(Vector3 center, float diameter, float length, float pitch = 0f, Color? color = null, bool solid = true)
		{
			//IL_000d: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Parts.Add(new Part
			{
				Shape = (PrimitiveType)2,
				Position = center,
				Size = new Vector3(diameter, diameter, length),
				Pitch = pitch,
				Color = color,
				Solid = solid
			});
			return this;
		}

		public WeaponModel Disc(Vector3 center, float diameter, float thickness = 0.06f, Color? color = null, bool solid = true)
		{
			//IL_000d: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Parts.Add(new Part
			{
				Shape = (PrimitiveType)2,
				Position = center,
				Size = new Vector3(diameter, diameter, thickness),
				Pitch = 0f,
				Color = color,
				Solid = solid,
				FaceCamera = true
			});
			return this;
		}

		public WeaponModel Ball(Vector3 center, float diameter, Color? color = null, bool solid = true)
		{
			//IL_000d: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Parts.Add(new Part
			{
				Shape = (PrimitiveType)0,
				Position = center,
				Size = Vector3.one * diameter,
				Color = color,
				Solid = solid
			});
			return this;
		}

		public WeaponModel Glow(Vector3 center, Vector3 size, Color color, float brightness = 2f, float pitch = 0f, bool solid = false)
		{
			//IL_000d: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			Parts.Add(new Part
			{
				Shape = (PrimitiveType)3,
				Position = center,
				Size = size,
				Pitch = pitch,
				Color = color,
				Glow = brightness,
				Solid = solid
			});
			return this;
		}

		internal Bounds LocalBounds()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if (Parts.Count == 0)
			{
				return new Bounds(Vector3.zero, Vector3.one * 0.3f);
			}
			Bounds result = default(Bounds);
			((Bounds)(ref result))..ctor(Parts[0].Position, Vector3.zero);
			Vector3 val3 = default(Vector3);
			foreach (Part part in Parts)
			{
				Quaternion val = Quaternion.Euler(part.Pitch, 0f, 0f);
				Vector3 val2 = (Vector3)(part.FaceCamera ? new Vector3(part.Size.z, part.Size.x, part.Size.x) : part.Size) * 0.5f;
				for (int i = 0; i < 8; i++)
				{
					((Vector3)(ref val3))..ctor(((i & 1) == 0) ? (0f - val2.x) : val2.x, ((i & 2) == 0) ? (0f - val2.y) : val2.y, ((i & 4) == 0) ? (0f - val2.z) : val2.z);
					((Bounds)(ref result)).Encapsulate(part.Position + val * val3);
				}
			}
			return result;
		}
	}
	public static class WeaponRegistry
	{
		public static bool IsReady => Core.Built;

		public static IList<WeaponInfo> All => Core.Weapons.AsReadOnly();

		public static IList<WeaponCategory> Categories => Core.SortedCategories().AsReadOnly();

		public static event Action Ready;

		public static event Action<Controller> PlayerArmed;

		[MethodImpl(MethodImplOptions.NoInlining)]
		public static WeaponCategory AddCategory(string id, string name, int order = 0, string description = null)
		{
			return Core.AddCategory(id, name, order, description, ModOf(Assembly.GetCallingAssembly()));
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		public static WeaponInfo Add(WeaponDefinition definition)
		{
			if (definition == null)
			{
				throw new ArgumentNullException("definition");
			}
			if (string.IsNullOrEmpty(definition.Mod))
			{
				definition.Mod = ModOf(Assembly.GetCallingAssembly());
			}
			return Core.AddWeapon(definition);
		}

		public static WeaponInfo Get(string id)
		{
			return Core.Find(id);
		}

		public static WeaponCategory GetCategory(string id)
		{
			return Core.FindCategory(id);
		}

		public static WeaponInfo GetByIndex(int index)
		{
			return Core.ByIndex(index);
		}

		public static WeaponInfo Of(Weapon weapon)
		{
			return Core.Of(weapon);
		}

		public static WeaponInfo Held(Controller player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			Fighting component = ((Component)player).GetComponent<Fighting>();
			if (!((Object)(object)component != (Object)null))
			{
				return null;
			}
			return Core.Of(component.weapon);
		}

		public static void SetName(string id, string name)
		{
			if (!string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(name))
			{
				Core.SetName(id, name);
			}
		}

		public static void SetCategoryName(string id, string name)
		{
			WeaponCategory weaponCategory = Core.FindCategory(id);
			if (weaponCategory != null && !string.IsNullOrEmpty(name))
			{
				weaponCategory.Name = name;
				Core.MenuChanged();
			}
		}

		public static void SetCategory(string id, string category)
		{
			if (!string.IsNullOrEmpty(id) && Core.FindCategory(category) != null)
			{
				Core.SetCategory(id, category);
			}
		}

		public static void SetDefaultTickets(string id, int tickets)
		{
			if (!string.IsNullOrEmpty(id) && tickets >= 0)
			{
				Core.SetDefaultTickets(id, Math.Min(tickets, 1000));
			}
		}

		public static bool IsEnabled(string id)
		{
			WeaponInfo weaponInfo = Core.Find(id);
			if (weaponInfo != null)
			{
				return Core.IsEnabled(weaponInfo);
			}
			return false;
		}

		public static void SetEnabled(string id, bool on)
		{
			WeaponInfo weaponInfo = Core.Find(id);
			if (weaponInfo != null)
			{
				Settings.SetWeapon(weaponInfo.Id, on);
				Core.SyncGameLists();
				Core.MenuChanged();
				SpawnWeights.Refresh();
			}
		}

		internal static void RaiseReady()
		{
			if (WeaponRegistry.Ready == null)
			{
				return;
			}
			Delegate[] invocationList = WeaponRegistry.Ready.GetInvocationList();
			foreach (Delegate obj in invocationList)
			{
				try
				{
					((Action)obj)();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("A WeaponRegistry.Ready handler failed: " + ex));
				}
			}
		}

		internal static void RaisePlayerArmed(Controller c)
		{
			if (WeaponRegistry.PlayerArmed == null)
			{
				return;
			}
			Delegate[] invocationList = WeaponRegistry.PlayerArmed.GetInvocationList();
			foreach (Delegate obj in invocationList)
			{
				try
				{
					((Action<Controller>)obj)(c);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("A WeaponRegistry.PlayerArmed handler failed: " + ex));
				}
			}
		}

		internal static string ModOf(Assembly asm)
		{
			if ((object)asm == typeof(WeaponRegistry).Assembly)
			{
				return "Weapon Framework";
			}
			try
			{
				string location = asm.Location;
				foreach (PluginInfo value in Chainloader.PluginInfos.Values)
				{
					if ((Object)(object)value.Instance != (Object)null && (object)((object)value.Instance).GetType().Assembly == asm)
					{
						return value.Metadata.Name;
					}
					if (!string.IsNullOrEmpty(location) && string.Equals(value.Location, location, StringComparison.OrdinalIgnoreCase))
					{
						return value.Metadata.Name;
					}
				}
			}
			catch
			{
			}
			if ((object)asm == null)
			{
				return "?";
			}
			return asm.GetName().Name;
		}
	}
	internal static class Access
	{
		public static readonly FieldRef<Fighting, int> BulletsLeft = AccessTools.FieldRefAccess<Fighting, int>("bulletsLeft");

		public static readonly FieldRef<Fighting, bool> JustAttacked = AccessTools.FieldRefAccess<Fighting, bool>("mJustAttacked");

		public static readonly FieldRef<Fighting, BlockHandler> FightingBlock = AccessTools.FieldRefAccess<Fighting, BlockHandler>("blockHandler");

		public static readonly FieldRef<Controller, CharacterActions> Actions = AccessTools.FieldRefAccess<Controller, CharacterActions>("mPlayerActions");

		public static readonly FieldRef<Controller, bool> HasControl = AccessTools.FieldRefAccess<Controller, bool>("mHasControl");

		public static readonly FieldRef<Controller, CharacterInformation> Info = AccessTools.FieldRefAccess<Controller, CharacterInformation>("info");

		public static readonly FieldRef<Controller, Fighting> ControllerFighting = AccessTools.FieldRefAccess<Controller, Fighting>("fighting");

		public static readonly FieldRef<WeaponSelectionHandler, List<byte>> Bag = AccessTools.FieldRefAccess<WeaponSelectionHandler, List<byte>>("m_WeaponRaritiesArray");

		public static readonly FieldRef<WeaponSelectionHandler, GameObject[]> WeaponObjects = AccessTools.FieldRefAccess<WeaponSelectionHandler, GameObject[]>("m_WeaponObjects");

		public static readonly FieldRef<WeaponSelectionHandler, GameObject> PlayerObject = AccessTools.FieldRefAccess<WeaponSelectionHandler, GameObject>("m_PlayerObject");

		public static readonly FieldRef<WeaponSelectionHandler, List<SingleWeaponUI>> MenuWeapons = AccessTools.FieldRefAccess<WeaponSelectionHandler, List<SingleWeaponUI>>("m_Weapons");

		public static readonly FieldRef<WeaponSelectionHandler, List<WeaponCategoryUI>> MenuCategories = AccessTools.FieldRefAccess<WeaponSelectionHandler, List<WeaponCategoryUI>>("m_Categories");

		public static readonly FieldRef<WeaponSelectionHandler, int> NumberOfWeapons = AccessTools.FieldRefAccess<WeaponSelectionHandler, int>("m_NumberOfWeapons");

		public static readonly FieldRef<WeaponSelectionHandler, int> NumberOfCategories = AccessTools.FieldRefAccess<WeaponSelectionHandler, int>("m_NumberOfCategories");

		public static readonly FieldRef<PauseManager, CodeStateAnimation> WeaponAnim = AccessTools.FieldRefAccess<PauseManager, CodeStateAnimation>("weaponAnim");
	}
	internal static class Catalog
	{
		internal struct Entry
		{
			public string Id;

			public string Name;

			public string Category;

			public Entry(string id, string name, string category)
			{
				Id = id;
				Name = name;
				Category = category;
			}
		}

		private static readonly Dictionary<int, Entry> byIndex = new Dictionary<int, Entry>
		{
			{
				0,
				new Entry("vanilla.pistol", null, "pistols")
			},
			{
				6,
				new Entry("vanilla.revolver", null, "pistols")
			},
			{
				61,
				new Entry("vanilla.deagle", null, "pistols")
			},
			{
				16,
				new Entry("vanilla.uzi", null, "pistols")
			},
			{
				31,
				new Entry("vanilla.godpistol", null, "godlike")
			},
			{
				1,
				new Entry("vanilla.ak47", null, "rifles")
			},
			{
				60,
				new Entry("vanilla.m16", null, "rifles")
			},
			{
				32,
				new Entry("vanilla.m1", null, "rifles")
			},
			{
				5,
				new Entry("vanilla.sniper", null, "rifles")
			},
			{
				62,
				new Entry("vanilla.sawedoff", null, "shotguns")
			},
			{
				10,
				new Entry("vanilla.militaryshotgun", null, "shotguns")
			},
			{
				20,
				new Entry("vanilla.bouncer", null, "rifles")
			},
			{
				3,
				new Entry("vanilla.grenadelauncher", null, "explosives")
			},
			{
				12,
				new Entry("vanilla.thruster", null, "explosives")
			},
			{
				22,
				new Entry("vanilla.rpg", null, "explosives")
			},
			{
				24,
				new Entry("vanilla.snakegun", "SNAKE GUN", "snake")
			},
			{
				37,
				new Entry("vanilla.snakeshotgun", "SNAKE SHOTGUN", "snake")
			},
			{
				25,
				new Entry("vanilla.snakegrenade", "SNAKE GRENADE", "snake")
			},
			{
				26,
				new Entry("vanilla.snakelauncher", "SNAKE LAUNCHER", "snake")
			},
			{
				33,
				new Entry("vanilla.snakeminigun", null, "snake")
			},
			{
				64,
				new Entry("vanilla.flyingsnake", null, "snake")
			},
			{
				38,
				new Entry("vanilla.spikeball", null, "lava")
			},
			{
				39,
				new Entry("vanilla.beam", null, "lava")
			},
			{
				35,
				new Entry("vanilla.stream", null, "lava")
			},
			{
				36,
				new Entry("vanilla.spray", null, "lava")
			},
			{
				40,
				new Entry("vanilla.spikegun", null, "lava")
			},
			{
				2,
				new Entry("vanilla.sword", null, "melee")
			},
			{
				4,
				new Entry("vanilla.blinkdagger", null, "melee")
			},
			{
				63,
				new Entry("vanilla.spear", null, "melee")
			},
			{
				21,
				new Entry("vanilla.timebubble", null, "control")
			},
			{
				14,
				new Entry("vanilla.laser", null, "heavy")
			},
			{
				7,
				new Entry("vanilla.icegun", null, "control")
			},
			{
				41,
				new Entry("vanilla.blackhole", null, "control")
			},
			{
				27,
				new Entry("vanilla.gluegun", null, "control")
			},
			{
				19,
				new Entry("vanilla.minigun", null, "heavy")
			},
			{
				23,
				new Entry("vanilla.flamethrower", null, "heavy")
			}
		};

		private static readonly Dictionary<string, string> byRow = new Dictionary<string, string>
		{
			{ "pistols", "pistols" },
			{ "rifles", "rifles" },
			{ "explosives", "explosives" },
			{ "snake", "snake" },
			{ "lava", "lava" },
			{ "melee", "melee" },
			{ "other", "control" }
		};

		public static Entry For(int index, string label, string row)
		{
			if (byIndex.TryGetValue(index, out var value))
			{
				return value;
			}
			if (row == null || !byRow.TryGetValue(row.ToLowerInvariant(), out var value2))
			{
				value2 = "gadgets";
			}
			return new Entry("vanilla." + Squash(label), null, value2);
		}

		public static void AddBuiltInCategories()
		{
			Core.AddCategory("pistols", "PISTOLS", 100, "Sidearms. Quick, light and common.", "Stick Fight");
			Core.AddCategory("rifles", "RIFLES", 200, "Long guns and precision.", "Stick Fight");
			Core.AddCategory("shotguns", "SHOTGUNS", 300, "Close range, big push.", "Stick Fight");
			Core.AddCategory("heavy", "HEAVY", 400, "Sustained fire and beams.", "Stick Fight");
			Core.AddCategory("explosives", "EXPLOSIVES", 500, "Area damage.", "Stick Fight");
			Core.AddCategory("melee", "MELEE", 600, "Blades and close fights.", "Stick Fight");
			Core.AddCategory("control", "CONTROL", 700, "Freeze, stick, pull and push.", "Stick Fight");
			Core.AddCategory("gadgets", "GADGETS", 800, "Mobility, traps and tools.", "Stick Fight");
			Core.AddCategory("party", "PARTY", 900, "Silly ones.", "Stick Fight");
			Core.AddCategory("lava", "LAVA", 1000, "The lava set.", "Stick Fight");
			Core.AddCategory("snake", "SNAKE", 1100, "The snake set.", "Stick Fight");
			Core.AddCategory("godlike", "GODLIKE", 1200, "Overpowered. One press turns them all off.", "Stick Fight");
		}

		public static string Squash(string s)
		{
			if (s != null)
			{
				return s.Trim().Replace(" ", string.Empty).ToLowerInvariant();
			}
			return "";
		}
	}
	internal static class Core
	{
		private static readonly Dictionary<string, WeaponCategory> categories;

		private static readonly List<WeaponInfo> modded;

		internal static readonly List<WeaponInfo> Weapons;

		private static WeaponInfo[] byIndex;

		private static readonly Dictionary<string, string> renames;

		private static readonly Dictionary<string, string> moves;

		private static readonly Dictionary<string, int> tickets;

		private static WeaponSelectionHandler handler;

		private static Transform prefabWeapons;

		private static GameObject templates;

		private static GameObject basePickup;

		private static bool bagOnline;

		private static int categoriesAdded;

		internal static bool Built;

		internal static int VanillaCount;

		private static readonly Dictionary<string, GameObject> pickups;

		internal static WeaponSelectionHandler Handler => handler;

		internal static bool BagIsStale
		{
			get
			{
				if (Built)
				{
					return bagOnline != MatchmakingHandler.IsNetworkMatch;
				}
				return false;
			}
		}

		static Core()
		{
			categories = new Dictionary<string, WeaponCategory>(StringComparer.OrdinalIgnoreCase);
			modded = new List<WeaponInfo>();
			Weapons = new List<WeaponInfo>();
			byIndex = new WeaponInfo[0];
			renames = new Dictionary<string, string>();
			moves = new Dictionary<string, string>();
			tickets = new Dictionary<string, int>();
			pickups = new Dictionary<string, GameObject>();
			Catalog.AddBuiltInCategories();
		}

		internal static WeaponCategory AddCategory(string id, string name, int order, string description, string mod)
		{
			if (string.IsNullOrEmpty(id))
			{
				throw new ArgumentException("A category needs an id.");
			}
			if (categories.TryGetValue(id, out var value))
			{
				return value;
			}
			value = new WeaponCategory(id, string.IsNullOrEmpty(name) ? id.ToUpperInvariant() : name, (order > 0) ? order : 2000, description, mod);
			value.Added = categoriesAdded++;
			categories[id] = value;
			MenuChanged();
			return value;
		}

		internal static WeaponInfo AddWeapon(WeaponDefinition d)
		{
			if (string.IsNullOrEmpty(d.Id))
			{
				throw new ArgumentException("A weapon needs an id.");
			}
			if (string.IsNullOrEmpty(d.Name))
			{
				d.Name = d.Id.ToUpperInvariant();
			}
			foreach (WeaponInfo item in modded)
			{
				if (string.Equals(item.Id, d.Id, StringComparison.OrdinalIgnoreCase))
				{
					Plugin.Log.LogWarning((object)("Weapon id '" + d.Id + "' was added twice; the second one is ignored."));
					return item;
				}
			}
			if ((object)d.Behaviour != null && !typeof(WeaponBehaviour).IsAssignableFrom(d.Behaviour))
			{
				Plugin.Log.LogError((object)(d.Id + ": Behaviour " + d.Behaviour.Name + " isn't a WeaponBehaviour; ignored."));
				d.Behaviour = null;
			}
			WeaponInfo weaponInfo = new WeaponInfo(d.Id, d.Name, d.Category, vanilla: false, null, d)
			{
				Description = d.Description,
				Mod = d.Mod,
				DefaultTickets = Mathf.Clamp(d.Rarity, 0, 1000),
				OnByDefault = d.OnByDefault
			};
			modded.Add(weaponInfo);
			if (Built)
			{
				Plugin.Log.LogWarning((object)(d.Id + " was added after the weapon list was built; it appears after the lobby reloads."));
			}
			return weaponInfo;
		}

		internal static void SetName(string id, string name)
		{
			renames[id] = name;
			WeaponInfo weaponInfo = Find(id);
			if (weaponInfo != null)
			{
				weaponInfo.Name = name;
			}
			MenuChanged();
		}

		internal static void SetCategory(string id, string cat)
		{
			WeaponCategory weaponCategory = FindCategory(cat);
			if (weaponCategory != null)
			{
				cat = weaponCategory.Id;
			}
			moves[id] = cat;
			WeaponInfo weaponInfo = Find(id);
			if (weaponInfo != null)
			{
				weaponInfo.Category = cat;
			}
			MenuChanged();
			RebuildBag();
		}

		internal static void SetDefaultTickets(string id, int n)
		{
			tickets[id] = n;
			WeaponInfo weaponInfo = Find(id);
			if (weaponInfo != null)
			{
				weaponInfo.DefaultTickets = n;
			}
			MenuChanged();
			RebuildBag();
		}

		internal static WeaponInfo Find(string id)
		{
			if (id == null)
			{
				return null;
			}
			foreach (WeaponInfo weapon in Weapons)
			{
				if (string.Equals(weapon.Id, id, StringComparison.OrdinalIgnoreCase))
				{
					return weapon;
				}
			}
			foreach (WeaponInfo item in modded)
			{
				if (string.Equals(item.Id, id, StringComparison.OrdinalIgnoreCase))
				{
					return item;
				}
			}
			return null;
		}

		internal static WeaponCategory FindCategory(string id)
		{
			if (id == null || !categories.TryGetValue(id, out var value))
			{
				return null;
			}
			return value;
		}

		internal static WeaponInfo ByIndex(int i)
		{
			if (i < 0 || i >= byIndex.Length)
			{
				return null;
			}
			return byIndex[i];
		}

		internal static WeaponInfo Of(Weapon w)
		{
			if ((Object)(object)w == (Object)null || (Object)(object)((Component)w).transform.parent == (Object)null || (Object)(object)((Component)((Component)w).transform.parent).GetComponent<Weapons>() == (Object)null)
			{
				return null;
			}
			return ByIndex(((Component)w).transform.GetSiblingIndex());
		}

		internal static Weapon PrefabWeapon(int index)
		{
			Transform val = PrefabHolder();
			if (!((Object)(object)val != (Object)null) || index < 0 || index >= val.childCount)
			{
				return null;
			}
			return ((Component)val.GetChild(index)).GetComponent<Weapon>();
		}

		private static Transform PrefabHolder()
		{
			if ((Object)(object)prefabWeapons == (Object)null && (Object)(object)ResourcesManager.Instance != (Object)null && (Object)(object)ResourcesManager.Instance.CharacterObject != (Object)null)
			{
				prefabWeapons = ResourcesManager.Instance.CharacterObject.transform.Find("Weapons");
			}
			return prefabWeapons;
		}

		internal static List<WeaponCategory> SortedCategories()
		{
			List<WeaponCategory> list = new List<WeaponCategory>(categories.Values);
			list.Sort((WeaponCategory a, WeaponCategory b) => (a.Order == b.Order) ? a.Added.CompareTo(b.Added) : a.Order.CompareTo(b.Order));
			return list;
		}

		internal static List<WeaponInfo> InCategory(string id)
		{
			List<WeaponInfo> list = new List<WeaponInfo>();
			foreach (WeaponInfo weapon in Weapons)
			{
				if (string.Equals(weapon.Category, id, StringComparison.OrdinalIgnoreCase))
				{
					list.Add(weapon);
				}
			}
			return list;
		}

		internal static bool IsEnabled(WeaponInfo w)
		{
			if (w != null && w.Index >= 0 && Settings.CategoryOn(w.Category))
			{
				return Settings.WeaponOn(w);
			}
			return false;
		}

		internal static int TicketsFor(WeaponInfo w, bool online)
		{
			if (!IsEnabled(w) || (Object)(object)w.Pickup == (Object)null)
			{
				return 0;
			}
			if (online)
			{
				if (!w.AllowedOnline)
				{
					return 0;
				}
				return w.VanillaTickets;
			}
			int num = SpawnWeights.Override(w);
			if (num < 0)
			{
				return w.DefaultTickets;
			}
			return num;
		}

		internal static float ChanceOf(WeaponInfo w)
		{
			int num = 0;
			foreach (WeaponInfo weapon in Weapons)
			{
				num += TicketsFor(weapon, online: false);
			}
			if (num <= 0)
			{
				return 0f;
			}
			return (float)TicketsFor(w, online: false) / (float)num;
		}

		internal static void MenuChanged()
		{
			if ((Object)(object)WeaponPage.Instance != (Object)null)
			{
				((TwoPanePage)WeaponPage.Instance).MarkDirty();
			}
		}

		internal static void Build(WeaponSelectionHandler h)
		{
			Built = false;
			handler = h;
			prefabWeapons = null;
			Transform val = PrefabHolder();
			if ((Object)(object)val == (Object)null)
			{
				throw new Exception("the player prefab has no Weapons object");
			}
			Access.PlayerObject.Invoke(h) = ResourcesManager.Instance.CharacterObject;
			VanillaCount = val.childCount;
			Weapons.Clear();
			Settings.Load();
			HashSet<int> hashSet = new HashSet<int>();
			WeaponCategoryTAG[] componentsInChildren = ((Component)h).GetComponentsInChildren<WeaponCategoryTAG>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (((Object)componentsInChildren[i]).name == "Special")
				{
					continue;
				}
				Transform val2 = ((Component)componentsInChildren[i]).transform.Find("Grid");
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				Toggle[] componentsInChildren2 = ((Component)val2).GetComponentsInChildren<Toggle>(true);
				foreach (Toggle val3 in componentsInChildren2)
				{
					TextMeshProUGUI componentInChildren = ((Component)val3).GetComponentInChildren<TextMeshProUGUI>(true);
					if ((Object)(object)componentInChildren == (Object)null)
					{
						continue;
					}
					int num = IndexOfName(val, ((TMP_Text)componentInChildren).text);
					if (num >= 0 && hashSet.Add(num))
					{
						Catalog.Entry entry = Catalog.For(num, ((TMP_Text)componentInChildren).text, ((Object)componentsInChildren[i]).name);
						Weapon component = ((Component)val.GetChild(num)).GetComponent<Weapon>();
						WeaponInfo item = new WeaponInfo(entry.Id, entry.Name ?? ((TMP_Text)componentInChildren).text.Trim().ToUpperInvariant(), entry.Category, vanilla: true, ((TMP_Text)componentInChildren).text, null)
						{
							Mod = "Stick Fight",
							Index = num,
							DefaultTickets = component.Rarity,
							VanillaTickets = component.Rarity,
							OnByDefault = val3.isOn,
							VanillaRow = i,
							Pickup = component.weaponDrop
						};
						Weapons.Add(item);
						if ((Object)(object)basePickup == (Object)null && (Object)(object)component.weaponDrop != (Object)null && (Object)(object)component.weaponDrop.GetComponent<WeaponPickUp>() != (Object)null)
						{
							basePickup = component.weaponDrop;
						}
					}
				}
			}
			int vanillaCount = VanillaCount;
			foreach (WeaponInfo item2 in modded)
			{
				WeaponDefinition definition = item2.Definition;
				item2.Index = -1;
				int baseIndex = definition.BaseIndex;
				if (baseIndex < 0 || baseIndex >= VanillaCount)
				{
					Plugin.Log.LogError((object)(item2.Id + ": no game weapon #" + baseIndex + "; skipped."));
					continue;
				}
				if (definition.Existing.HasValue)
				{
					if (!hashSet.Add(baseIndex))
					{
						Plugin.Log.LogError((object)(item2.Id + ": game weapon #" + baseIndex + " is already in the menu; skipped."));
						continue;
					}
					item2.Index = baseIndex;
				}
				else
				{
					if (vanillaCount > 254)
					{
						Plugin.Log.LogError((object)(item2.Id + ": too many weapons (the game counts them in a byte); skipped."));
						continue;
					}
					item2.Index = vanillaCount++;
				}
				WeaponCategory weaponCategory = FindCategory(item2.Category);
				if (weaponCategory == null)
				{
					Plugin.Log.LogWarning((object)(item2.Id + ": no category '" + item2.Category + "' (add it with WeaponRegistry.AddCategory); put in Gadgets."));
					item2.Category = "gadgets";
				}
				else
				{
					item2.Category = weaponCategory.Id;
				}
				item2.Pickup = PickupFor(item2, val);
				Weapons.Add(item2);
			}
			foreach (WeaponInfo weapon in Weapons)
			{
				if (renames.TryGetValue(weapon.Id, out var value))
				{
					weapon.Name = value;
				}
				WeaponCategory weaponCategory2;
				if (moves.TryGetValue(weapon.Id, out value) && (weaponCategory2 = FindCategory(value)) != null)
				{
					weapon.Category = weaponCategory2.Id;
				}
				if (tickets.TryGetValue(weapon.Id, out var value2))
				{
					weapon.DefaultTickets = value2;
				}
			}
			byIndex = new WeaponInfo[Math.Max(vanillaCount, VanillaCount)];
			foreach (WeaponInfo weapon2 in Weapons)
			{
				byIndex[weapon2.Index] = weapon2;
			}
			Settings.ImportIfNew(Weapons, VanillaCount);
			FillGameLists(h);
			Sounds.ScanPacks(Weapons);
			Built = true;
			RebuildBag();
			Plugin.Log.LogInfo((object)("Weapon list: " + Weapons.Count + " weapons (" + (Weapons.Count - modded.Count) + " from the game) in " + categories.Count + " categories."));
			WeaponRegistry.RaiseReady();
		}

		private static void FillGameLists(WeaponSelectionHandler h)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			GameObject[] array = (GameObject[])(object)new GameObject[byIndex.Length];
			List<SingleWeaponUI> list = new List<SingleWeaponUI>();
			List<SelectableWeapon> list2 = new List<SelectableWeapon>();
			foreach (WeaponInfo weapon in Weapons)
			{
				array[weapon.Index] = weapon.Pickup;
				SingleWeaponUI val = new SingleWeaponUI(weapon.Name, weapon.Category, (byte)weapon.Index, (byte)Mathf.Clamp(weapon.DefaultTickets, 0, 255));
				val.IsLocallyActive = Settings.WeaponOn(weapon);
				list.Add(val);
				if (weapon.IsVanilla)
				{
					list2.Add(new SelectableWeapon(weapon.Index, weapon.MenuLabel, weapon.Pickup));
				}
			}
			List<WeaponCategoryUI> list3 = new List<WeaponCategoryUI>();
			byte b = 0;
			foreach (WeaponCategory item in SortedCategories())
			{
				WeaponCategoryUI val2 = new WeaponCategoryUI(item.Id, b++);
				val2.IsActive = Settings.CategoryOn(item.Id);
				list3.Add(val2);
			}
			Access.WeaponObjects.Invoke(h) = array;
			Access.MenuWeapons.Invoke(h) = list;
			Access.MenuCategories.Invoke(h) = list3;
			Access.NumberOfWeapons.Invoke(h) = array.Length;
			Access.NumberOfCategories.Invoke(h) = list3.Count;
			AccessTools.Property(typeof(WeaponSelectionHandler), "SelectableWeapons").SetValue(null, list2, null);
		}

		internal static void SyncGameLists()
		{
			if ((Object)(object)handler == (Object)null)
			{
				return;
			}
			List<SingleWeaponUI> list = Access.MenuWeapons.Invoke(handler);
			if (list != null)
			{
				foreach (SingleWeaponUI item in list)
				{
					WeaponInfo weaponInfo = ByIndex(item.WeaponIndex);
					if (weaponInfo != null)
					{
						item.IsLocallyActive = Settings.WeaponOn(weaponInfo);
					}
				}
			}
			List<WeaponCategoryUI> list2 = Access.MenuCategories.Invoke(handler);
			if (list2 == null)
			{
				return;
			}
			foreach (WeaponCategoryUI item2 in list2)
			{
				item2.IsActive = Settings.CategoryOn(item2.Category);
			}
		}

		internal static void RebuildBag()
		{
			if (Built && !((Object)(object)handler == (Object)null))
			{
				List<byte> list = Access.Bag.Invoke(handler);
				if (list == null)
				{
					list = new List<byte>();
					Access.Bag.Invoke(handler) = list;
				}
				FillBag(list);
			}
		}

		internal static void FillBag(List<byte> bag)
		{
			bagOnline = MatchmakingHandler.IsNetworkMatch;
			bag.Clear();
			foreach (WeaponInfo weapon in Weapons)
			{
				int num = TicketsFor(weapon, bagOnline);
				for (int i = 0; i < num; i++)
				{
					bag.Add((byte)weapon.Index);
				}
			}
		}

		private static GameObject Templates()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if ((Object)(object)templates == (Object)null)
			{
				templates = new GameObject("WeaponFramework Templates");
				templates.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)templates);
			}
			return templates;
		}

		private static GameObject PickupFor(WeaponInfo w, Transform holder)
		{
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			if (pickups.TryGetValue(w.Id, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			WeaponDefinition definition = w.Definition;
			Weapon component = ((Component)holder.GetChild(definition.BaseIndex)).GetComponent<Weapon>();
			GameObject val = (((Object)(object)component != (Object)null) ? component.weaponDrop : null);
			WeaponPickUp val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<WeaponPickUp>() : null);
			GameObject val3;
			if (definition.Existing.HasValue && (Object)(object)val2 != (Object)null && val2.id == w.Index && !definition.GiftBox && definition.ConfigurePickup == null && !definition.Tint.HasValue)
			{
				val3 = val;
			}
			else
			{
				bool flag = definition.Model != null && !definition.Existing.HasValue;
				bool flag2 = definition.GiftBox || (!flag && ((Object)(object)val2 == (Object)null || (definition.Existing.HasValue && val2.id != w.Index)));
				GameObject val4 = (((Object)(object)val2 != (Object)null) ? val : basePickup);
				if ((Object)(object)val4 == (Object)null)
				{
					Plugin.Log.LogError((object)(w.Id + ": no pickup to copy."));
					return null;
				}
				val3 = Object.Instantiate<GameObject>(val4, Templates().transform, false);
				((Object)val3).name = "Pickup " + w.Id;
				val3.GetComponent<WeaponPickUp>().id = w.Index;
				if (flag2)
				{
					MakePresent(val3);
				}
				else if (flag)
				{
					ModelBuilder.ApplyPickup(val3, definition.Model);
				}
				if (definition.Tint.HasValue && !flag2)
				{
					Looks.Tint(val3, definition.Tint.Value);
				}
				if (definition.ConfigurePickup != null)
				{
					try
					{
						definition.ConfigurePickup(val3);
					}
					catch (Exception ex)
					{
						Plugin.Log.LogError((object)(w.Id + ": ConfigurePickup failed: " + ex));
					}
				}
			}
			pickups[w.Id] = val3;
			return val3;
		}

		private static void MakePresent(GameObject p)
		{
			for (int num = p.transform.childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)p.transform.GetChild(num)).gameObject);
			}
			ConstantForce component = p.GetComponent<ConstantForce>();
			p.GetComponent<Rigidbody>().constraints = (RigidbodyConstraints)98;
			GameObject val = Resources.Load<GameObject>("PacketGFX");
			if ((Object)(object)val != (Object)null)
			{
				Object.Instantiate<GameObject>(val, p.transform, false);
			}
			if ((Object)(object)component == (Object)null)
			{
				((Behaviour)p.AddComponent<ConstantForce>()).enabled = false;
			}
		}

		private static int IndexOfName(Transform holder, string label)
		{
			string text = Catalog.Squash(label);
			for (int i = 0; i < holder.childCount; i++)
			{
				string name = ((Object)holder.GetChild(i)).name;
				int num = name.IndexOf(' ');
				if (num > 0 && Catalog.Squash(name.Substring(num)) == text)
				{
					return i;
				}
			}
			return -1;
		}

		internal static IEnumerable<WeaponInfo> ModdedCopies()
		{
			foreach (WeaponInfo weapon in Weapons)
			{
				if (!weapon.IsVanilla && weapon.Definition != null && !weapon.Definition.Existing.HasValue && weapon.Index >= VanillaCount)
				{
					yield return weapon;
				}
			}
		}
	}
	internal sealed class DebugLog : ILogListener, IDisposable
	{
		private readonly StreamWriter writer;

		private DebugLog(string path)
		{
			writer = new StreamWriter(new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
			{
				AutoFlush = true
			};
		}

		public static void Start()
		{
			try
			{
				Logger.Listeners.Add((ILogListener)(object)new DebugLog(Path.Combine(Paths.BepInExRootPath, "WeaponFramework-debug.log")));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Couldn't open the debug log: " + ex.Message));
			}
		}

		public void LogEvent(object sender, LogEventArgs e)
		{
			//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)
			try
			{
				string text = ((e.Data != null) ? e.Data.ToString() : "");
				if (text.IndexOf("Steamworks", StringComparison.Ordinal) < 0)
				{
					writer.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") + " [" + ((object)e.Level/*cast due to .constrained prefix*/).ToString() + ":" + e.Source.SourceName + "] " + text);
				}
			}
			catch
			{
			}
		}

		public void Dispose()
		{
			try
			{
				writer.Dispose();
			}
			catch
			{
			}
		}
	}
	internal sealed class HoldMass : MonoBehaviour
	{
		internal struct Layout
		{
			public Vector3 Centre;

			public Vector3 Inertia;

			public Quaternion Rotation;
		}

		private static readonly Dictionary<string, Layout> measured = new Dictionary<string, Layout>();

		public Layout Base;

		internal static Layout? Measure(GameObject weapon, string key)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			if (measured.TryGetValue(key, out var value))
			{
				return value;
			}
			GameObject val = new GameObject("WF mass probe");
			try
			{
				val.transform.position = new Vector3(0f, -5000f, 0f);
				Rigidbody val2 = val.AddComponent<Rigidbody>();
				val2.useGravity = false;
				Transform transform = weapon.transform;
				int num = 0;
				Collider[] componentsInChildren = weapon.GetComponentsInChildren<Collider>(true);
				foreach (Collider val3 in componentsInChildren)
				{
					if (!val3.isTrigger)
					{
						GameObject val4 = new GameObject("part");
						Transform transform2 = val4.transform;
						transform2.SetParent(val.transform, false);
						transform2.localPosition = transform.InverseTransformPoint(((Component)val3).transform.position);
						transform2.localRotation = Quaternion.Inverse(transform.rotation) * ((Component)val3).transform.rotation;
						Vector3 lossyScale = transform.lossyScale;
						Vector3 lossyScale2 = ((Component)val3).transform.lossyScale;
						transform2.localScale = new Vector3(lossyScale2.x / lossyScale.x, lossyScale2.y / lossyScale.y, lossyScale2.z / lossyScale.z);
						if (!Copy(val3, val4))
						{
							Object.DestroyImmediate((Object)(object)val4);
						}
						else
						{
							num++;
						}
					}
				}
				if (num == 0)
				{
					return null;
				}
				val2.ResetCenterOfMass();
				val2.ResetInertiaTensor();
				value = new Layout
				{
					Centre = val2.centerOfMass,
					Inertia = val2.inertiaTensor,
					Rotation = val2.inertiaTensorRotation
				};
				measured[key] = value;
				if (Plugin.DebugKeys.Value)
				{
					Plugin.Log.LogInfo((object)("Hold mass of " + key + ": centre " + ((Vector3)(ref value.Centre)).ToString("F3") + ", inertia " + ((Vector3)(ref value.Inertia)).ToString("F4") + " from " + num + " parts"));
				}
				return value;
			}
			finally
			{
				Object.DestroyImmediate((Object)(object)val);
			}
		}

		private static bool Copy(Collider c, GameObject to)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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)
			BoxCollider val = (BoxCollider)(object)((c is BoxCollider) ? c : null);
			if ((Object)(object)val != (Object)null)
			{
				BoxCollider obj = to.AddComponent<BoxCollider>();
				obj.center = val.center;
				obj.size = val.size;
				return true;
			}
			SphereCollider val2 = (SphereCollider)(object)((c is SphereCollider) ? c : null);
			if ((Object)(object)val2 != (Object)null)
			{
				SphereCollider obj2 = to.AddComponent<SphereCollider>();
				obj2.center = val2.center;
				obj2.radius = val2.radius;
				return true;
			}
			CapsuleCollider val3 = (CapsuleCollider)(object)((c is CapsuleCollider) ? c : null);
			if ((Object)(object)val3 != (Object)null)
			{
				CapsuleCollider obj3 = to.AddComponent<CapsuleCollider>();
				obj3.center = val3.center;
				obj3.radius = val3.radius;
				obj3.height = val3.height;
				obj3.direction = val3.direction;
				return true;
			}
			MeshCollider val4 = (MeshCollider)(object)((c is MeshCollider) ? c : null);
			if ((Object)(object)val4 != (Object)null && (Object)(object)val4.sharedMesh != (Object)null)
			{
				MeshCollider obj4 = to.AddComponent<MeshCollider>();
				obj4.sharedMesh = val4.sharedMesh;
				obj4.convex = true;
				return true;
			}
			return false;
		}

		private void OnEnable()
		{
			Apply();
		}

		private void Start()
		{
			Apply();
		}

		private void Apply()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody component = ((Component)this).GetComponent<Rigidbody>();
			if (!((Object)(object)component == (Object)null))
			{
				component.centerOfMass = Base.Centre;
				if ((component.constraints & 0x70) == 0)
				{
					component.inertiaTensor = Base.Inertia * component.mass;
					component.inertiaTensorRotation = Base.Rotation;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Hooks
	{
		private sealed class Held
		{
			public float Attack;

			public float Alt;

			public float Charge;
		}

		private const float MinCharge = 0.15f;

		private static readonly Dictionary<int, Held> held = new Dictionary<int, Held>();

		private static readonly Dictionary<string, int> failures = new Dictionary<string, int>();

		private static readonly Dictionary<Type, bool> wantsShots = new Dictionary<Type, bool>();

		private static readonly Dictionary<GameObject, GameObject> markedProjectiles = new Dictionary<GameObject, GameObject>();

		private static GameObject markerHolder;

		private static bool Local => !MatchmakingHandler.IsNetworkMatch;

		private static WeaponBehaviour BehaviourOf(Weapon w)
		{
			if (!((Object)(object)w != (Object)null))
			{
				return null;
			}
			return ((Component)w).GetComponent<WeaponBehaviour>();
		}

		private static bool IsCharged(Weapon w, out float drawTime, out float power)
		{
			drawTime = 0f;
			power = 1f;
			WeaponInfo weaponInfo = Core.Of(w);
			if (weaponInfo == null || weaponInfo.Definition == null)
			{
				return false;
			}
			WeaponDefinition definition = weaponInfo.Definition;
			if (definition.ChargeTime <= 0f && !w.isCharged)
			{
				return false;
			}
			drawTime = ((definition.ChargeTime > 0f) ? definition.ChargeTime : 0.6f);
			power = ((definition.ChargePower > 0f) ? definition.ChargePower : 1f);
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Fighting), "Attack")]
		private static bool BeforeAttack(Fighting __instance, out float __state)
		{
			__state = __instance.counter;
			if (!Local)
			{
				return true;
			}
			Weapon weapon = __instance.weapon;
			WeaponBehaviour weaponBehaviour = BehaviourOf(weapon);
			if ((Object)(object)weaponBehaviour == (Object)null || Access.FightingBlock.Invoke(__instance).isBlocking || __instance.counter <= weapon.cd)
			{
				return true;
			}
			bool flag;
			try
			{
				flag = weaponBehaviour.OnAttack();
			}
			catch (Exception e)
			{
				Fail(weaponBehaviour, "OnAttack", e);
				return true;
			}
			if (!flag)
			{
				return true;
			}
			__instance.counter = 0f;
			Access.JustAttacked.Invoke(__instance) = true;
			if (weaponBehaviour.CountsAsShot)
			{
				weaponBehaviour.UseAmmoInternal(1);
			}
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Fighting), "Attack")]
		private static void AfterAttack(Fighting __instance, bool __runOriginal, float __state)
		{
			if (!Local || !__runOriginal)
			{
				return;
			}
			WeaponBehaviour weaponBehaviour = BehaviourOf(__instance.weapon);
			if ((Object)(object)weaponBehaviour == (Object)null || !(__instance.counter < __state) || __instance.counter != 0f)
			{
				return;
			}
			try
			{
				weaponBehaviour.AfterAttack();
			}
			catch (Exception e)
			{
				Fail(weaponBehaviour, "AfterAttack", e);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Controller), "Attack")]
		private static bool BeforeControllerAttack(Fighting ___fighting)
		{
			float drawTime;
			float power;
			if (Local && (Object)(object)___fighting != (Object)null && (Object)(object)___fighting.weapon != (Object)null)
			{
				return !IsCharged(___fighting.weapon, out drawTime, out power);
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Controller), "Update")]
		private static void AfterUpdate(Controller __instance)
		{
			if (!Local || __instance.inactive || __instance.isAI || PauseManager.isPaused || (!GameManager.inFight && !GameManager.stillInMenu))
			{
				return;
			}
			CharacterInformation val = Access.Info.Invoke(__instance);
			CharacterActions val2 = Access.Actions.Invoke(__instance);
			Fighting val3 = Access.ControllerFighting.Invoke(__instance);
			if ((Object)(object)val == (Object)null || val.isDead || val2 == null || (Object)(object)val3 == (Object)null || !Access.HasControl.Invoke(__instance))
			{
				return;
			}
			Weapon weapon = val3.weapon;
			if (!held.TryGetValue(((Object)__instance).GetInstanceID(), out var value))
			{
				value = new Held();
				held[((Object)__instance).GetInstanceID()] = value;
			}
			if ((Object)(object)weapon == (Object)null)
			{
				value.Attack = (value.Alt = (value.Charge = 0f));
				return;
			}
			WeaponBehaviour weaponBehaviour = BehaviourOf(weapon);
			float deltaTime = Time.deltaTime;
			if (IsCharged(weapon, out var drawTime, out var power))
			{
				if (((OneAxisInputControl)val2.PunchOrFire).IsPressed)
				{
					value.Charge = Mathf.Min(1f, value.Charge + deltaTime / drawTime);
					if (weapon.isCharged)
					{
						weapon.currentCharge = value.Charge * weapon.maxChargeTime * power;
					}
					if ((Object)(object)weaponBehaviour != (Object)null)
					{
						weaponBehaviour.Charge = value.Charge;
					}
				}
				else if (((OneAxisInputControl)val2.PunchOrFire).WasReleased && value.Charge > 0f)
				{
					if (value.Charge >= 0.15f || !weapon.isCharged)
					{
						if (weapon.isCharged)
						{
							weapon.currentCharge = value.Charge * weapon.maxChargeTime * power;
						}
						if ((Object)(object)weaponBehaviour != (Object)null)
						{
							weaponBehaviour.Charge = value.Charge;
						}
						val3.Attack();
					}
					value.Charge = 0f;
					if ((Object)(object)weapon != (Object)null && weapon.isCharged)
					{
						weapon.currentCharge = 0f;
					}
					if ((Object)(object)weaponBehaviour != (Object)null)
					{
						weaponBehaviour.Charge = 0f;
					}
				}
			}
			if ((Object)(object)weaponBehaviour == (Object)null)
			{
				return;
			}
			try
			{
				if (((OneAxisInputControl)val2.PunchOrFire).IsPressed)
				{
					value.Attack += deltaTime;
					weaponBehaviour.OnAttackHeld(value.Attack);
				}
				else if (value.Attack > 0f)
				{
					float attack = value.Attack;
					value.Attack = 0f;
					weaponBehaviour.OnAttackReleased(attack);
				}
			}
			catch (Exception e)
			{
				Fail(weaponBehaviour, "OnAttackHeld/Released", e);
			}
			try
			{
				if (((OneAxisInputControl)val2.Block).WasPressed)
				{
					value.Alt = 0f;
					weaponBehaviour.OnAltPressed();
				}
				if (((OneAxisInputControl)val2.Block).IsPressed)
				{
					value.Alt += deltaTime;
					weaponBehaviour.OnAltHeld(value.Alt);
				}
				else if (value.Alt > 0f)
				{
					float alt = value.Alt;
					value.Alt = 0f;
					weaponBehaviour.OnAltReleased(alt);
				}
			}
			catch (Exception e2)
			{
				Fail(weaponBehaviour, "OnAlt", e2);
			}
		}

		private static void Call(WeaponBehaviour b, string what, Action a)
		{
			try
			{
				a();
			}
			catch (Exception e)
			{
				Fail(b, what, e);
			}
		}

		private static void Fail(WeaponBehaviour b, string what, Exception e)
		{
			string text = (((Object)(object)b != (Object)null) ? ((object)b).GetType().Name : "?") + "." + what;
			failures.TryGetValue(text, out var value);
			value = (failures[text] = value + 1);
			if (value == 1)
			{
				Plugin.Log.LogError((object)(text + " failed (later failures of it aren't logged): " + e));
			}
		}

		private static bool WantsShots(WeaponBehaviour b)
		{
			Type type = ((object)b).GetType();
			if (!wantsShots.TryGetValue(type, out var value))
			{
				MethodInfo method = type.GetMethod("OnShot", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(GameObject) }, null);
				value = (object)method != null && (object)method.DeclaringType != typeof(WeaponBehaviour);
				wantsShots[type] = value;
			}
			return value;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Weapon), "ActuallyShoot")]
		private static void BeforeShoot(Weapon __instance, out GameObject __state)
		{
			__state = null;
			if (Local && !((Object)(object)__instance.projectile == (Object)null))
			{
				WeaponBehaviour weaponBehaviour = BehaviourOf(__instance);
				if (!((Object)(object)weaponBehaviour == (Object)null) && WantsShots(weaponBehaviour))
				{
					__state = __instance.projectile;
					__instance.projectile = Marked(__instance.projectile);
					ShotMarker.Pending.Clear();
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Weapon), "ActuallyShoot")]
		private static void AfterShoot(Weapon __instance, GameObject __state)
		{
			if ((Object)(object)__state != (Object)null)
			{
				__instance.projectile = __state;
				WeaponBehaviour b = BehaviourOf(__instance);
				List<GameObject> list = new List<GameObject>(ShotMarker.Pending);
				ShotMarker.Pending.Clear();
				if ((Object)(object)b != (Object)null)
				{
					foreach (GameObject p in list)
					{
						if ((Object)(object)p != (Object)null)
						{
							Call(b, "OnShot", delegate
							{
								b.OnShot(p);
							});
						}
					}
				}
			}
			if (Local && __instance.isCharged && Core.Of(__instance) != null)
			{
				__instance.currentCharge = 0f;
			}
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Weapon), "ActuallyShoot")]
		private static Exception ShootFinalizer(Weapon __instance, GameObject __state, Exception __exception)
		{
			if ((Object)(object)__state != (Object)null && (Object)(object)__instance.projectile != (Object)(object)__state)
			{
				__instance.projectile = __state;
			}
			return __exception;
		}

		private static GameObject Marked(GameObject prefab)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			if (markedProjectiles.TryGetValue(prefab, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			if ((Object)(object)markerHolder == (Object)null)
			{
				markerHolder = new GameObject("WeaponFramework Projectiles");
				markerHolder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)markerHolder);
			}
			value = Object.Instantiate<GameObject>(prefab, markerHolder.transform, false);
			((Object)value).name = ((Object)prefab).name;
			value.AddComponent<ShotMarker>();
			markedProjectiles[prefab] = value;
			return value;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Fighting), "SetWeapon")]
		private static void BeforeSetWeapon(Fighting __instance)
		{
			Unequip(__instance.weapon);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Fighting), "SetWeapon")]
		private static void AfterSetWeapon(Fighting __instance)
		{
			if (Local)
			{
				WeaponBehaviour weaponBehaviour = BehaviourOf(__instance.weapon);
				if (!((Object)(object)weaponBehaviour == (Object)null))
				{
					weaponBehaviour.Charge = 0f;
					Call(weaponBehaviour, "OnEquip", weaponBehaviour.OnEquip);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Fighting), "Dissarm")]
		private static void BeforeDisarm(Fighting __instance)
		{
			Unequip(__instance.weapon);
		}

		private static void Unequip(Weapon w)
		{
			if (Local)
			{
				WeaponBehaviour weaponBehaviour = BehaviourOf(w);
				if (!((Object)(object)weaponBehaviour == (Object)null) && ((Component)weaponBehaviour).gameObject.activeSelf)
				{
					weaponBehaviour.Charge = 0f;
					Call(weaponBehaviour, "OnUnequip", weaponBehaviour.OnUnequip);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Fighting), "ThrowWeapon")]
		private static void BeforeThrow(Fighting __instance, bool justDrop, out List<MonoBehaviour> __state)
		{
			__state = null;
			if (!justDrop || !Local || (Object)(object)__instance.weapon == (Object)null)
			{
				return;
			}
			MonoBehaviour[] componentsInChildren = ((Component)__instance.weapon).GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && ((Behaviour)val).enabled && (val is WeaponBehaviour || val is OffHand || val is Deflector))
				{
					if (__state == null)
					{
						__state = new List<MonoBehaviour>();
					}
					((Behaviour)val).enabled = false;
					__state.Add(val);
				}
			}
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Fighting), "ThrowWeapon")]
		private static Exception ThrowFinalizer(List<MonoBehaviour> __state, Exception __exception)
		{
			if (__state != null)
			{
				foreach (MonoBehaviour item in __state)
				{
					if ((Object)(object)item != (Object)null)
					{
						((Behaviour)item).enabled = true;
					}
				}
			}
			return __exception;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(HealthHandler), "TakeDamage", new Type[]
		{
			typeof(float),
			typeof(Controller),
			typeof(DamageType),
			typeof(bool),
			typeof(Vector3),
			typeof(Vector3)
		})]
		private static void BeforeDamage(HealthHandler __instance, ref float damage, Controller damager, out WeaponBehaviour __state)
		{
			__state = null;
			if (!Local || (Object)(object)damager == (Object)null)
			{
				return;
			}
			Fighting component = ((Component)damager).GetComponent<Fighting>();
			WeaponBehaviour weaponBehaviour = (((Object)(object)component != (Object)null) ? BehaviourOf(component.weapon) : null);
			if (!((Object)(object)weaponBehaviour == (Object)null))
			{
				Controller component2 = ((Component)((Component)__instance).transform.root).GetComponent<Controller>();
				try
				{
					damage = weaponBehaviour.ModifyDamage(component2, damage);
				}
				catch (Exception e)
				{
					Fail(weaponBehaviour, "ModifyDamage", e);
				}
				__state = weaponBehaviour;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(HealthHandler), "TakeDamage", new Type[]
		{
			typeof(float),
			typeof(Controller),
			typeof(DamageType),
			typeof(bool),
			typeof(Vector3),
			typeof(Vector3)
		})]
		private static void AfterDamage(HealthHandler __instance, bool __result, float damage, WeaponBehaviour __state)
		{
			if (!((Object)(object)__state == (Object)null) && __result)
			{
				Controller victim = ((Component)((Component)__instance).transform.root).GetComponent<Controller>();
				bool killed = __instance.health <= 0f;
				Call(__state, "OnDamageDealt", delegate
				{
					__state.OnDamageDealt(victim, damage, killed);
				});
			}
		}
	}
	internal sealed class ShotMarker : MonoBehaviour
	{
		internal static readonly List<GameObject> Pending = new List<GameObject>();

		private void Awake()
		{
			Pending.Add(((Component)this).gameObject);
		}
	}
	internal static class ModelBuilder
	{
		private static readonly Dictionary<string, Material> mats = new Dictionary<string, Material>();

		private static readonly Dictionary<string, Material> gameMats = new Dictionary<string, Material>();

		public static void ApplyHeld(GameObject weapon, WeaponModel m, string baseKey)
		{
			//IL_00c2: 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_0067: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			HoldMass.Layout? layout = HoldMass.Measure(weapon, baseKey);
			Material black = StripParts(weapon.transform, null);
			Transform val = ((weapon.transform.childCount > 0) ? weapon.transform.GetChild(0) : null);
			if ((Object)(object)val != (Object)null && ((Object)val).name == "handPosition")
			{
				if (layout.HasValue)
				{
					HoldMass.Layout value = layout.Value;
					ref Vector3 centre = ref value.Centre;
					centre += m.Grip - val.localPosition;
					(weapon.GetComponent<HoldMass>() ?? weapon.AddComponent<HoldMass>()).Base = value;
				}
				val.localPosition = m.Grip;
			}
			Shoot[] componentsInChildren = weapon.GetComponentsInChildren<Shoot>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Component)componentsInChildren[i]).transform.localPosition = m.Muzzle;
			}
			ParticleSystem[] componentsInChildren2 = weapon.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val2 in componentsInChildren2)
			{
				if ((Object)(object)((Component)val2).transform.parent == (Object)(object)weapon.transform)
				{
					((Component)val2).transform.localPosition = m.Muzzle;
				}
			}
			Build(weapon.transform, m, weapon.layer, black, colliders: true);
			if (m.OffHandGrip.HasValue)
			{
				(weapon.GetComponent<OffHand>() ?? weapon.AddComponent<OffHand>()).Local = m.OffHandGrip.Value;
			}
		}

		public static void ApplyPickup(GameObject pickup, WeaponModel m)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			Transform val = null;
			foreach (Transform item in pickup.transform)
			{
				Transform val2 = item;
				if ((Object)(object)((Component)val2).GetComponent<Collider>() != (Object)null && (Object)(object)((Component)val2).GetComponent<MeshFilter>() != (Object)null)
				{
					val = val2;
					break;
				}
			}
			Material black = StripParts(pickup.transform, val);
			Build(pickup.transform, m, pickup.layer, black, colliders: false);
			Bounds val3 = m.LocalBounds();
			if ((Object)(object)val == (Object)null)
			{
				val = GameObject.CreatePrimitive((PrimitiveType)3).transform;
				val.SetParent(pickup.transform, false);
				((Component)val).gameObject.layer = pickup.layer;
			}
			((Object)val).name = "Cube";
			MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
			if ((Object)(object)component != (Object)null)
			{
				((Renderer)component).enabled = false;
			}
			val.localRotation = Quaternion.identity;
			val.localPosition = ((Bounds)(ref val3)).center;
			val.localScale = ((m.PickupCollider != Vector3.zero) ? m.PickupCollider : Vector3.Max(((Bounds)(ref val3)).size + new Vector3(0.2f, 0.12f, 0.12f), new Vector3(0.36f, 0.36f, 0.64f)));
		}

		public static void BuildVisual(Transform parent, WeaponModel m)
		{
			Build(parent, m, ((Component)parent).gameObject.layer, GameMaterial("WeaponMaterial"), colliders: false);
		}

		private static Material StripParts(Transform root, Transform except)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			Material val = null;
			List<GameObject> list = new List<GameObject>();
			foreach (Transform item in root)
			{
				Transform val2 = item;
				if (!((Object)(object)val2 == (Object)(object)except) && !((Object)(object)((Component)val2).GetComponent<MeshFilter>() == (Object)null))
				{
					MeshRenderer component = ((Component)val2).GetComponent<MeshRenderer>();
					if ((Object)(object)val == (Object)null && (Object)(object)component != (Object)null && (Object)(object)((Renderer)component).sharedMaterial != (Object)null && ((Object)((Renderer)component).sharedMaterial).name.StartsWith("WeaponMaterial"))
					{
						val = ((Renderer)component).sharedMaterial;
					}
					list.Add(((Component)val2).gameObject);
				}
			}
			foreach (GameObject item2 in list)
			{
				if ((Object)(object)val == (Object)null)
				{
					MeshRenderer component2 = item2.GetComponent<MeshRenderer>();
					if ((Object)(object)component2 != (Object)null)
					{
						val = ((Renderer)component2).sharedMaterial;
					}
				}
				Object.DestroyImmediate((Object)(object)item2);
			}
			return val;
		}

		private static void Build(Transform parent, WeaponModel m, int layer, Material black, bool colliders)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Invalid comparison between Unknown and I4
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Invalid comparison between Unknown and I4
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: 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)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might b