Decompiled source of TurretMod v0.1.18

BepInEx/plugins/TurretMod/AASC.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using FishNet;
using FishNet.Broadcast;
using FishNet.Connection;
using FishNet.Managing;
using FishNet.Managing.Object;
using FishNet.Object;
using FishNet.Serializing;
using FishNet.Transporting;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AASC
{
	public enum GunClass
	{
		Shotgun,
		Pistol,
		SMG,
		Rifle,
		Sniper
	}
	public static class Rules
	{
		public const int KitPrice = 5000;

		public const int FishPrice = 20000;

		public const int BossPrice = 100000;

		public const int MaxLevel = 10;

		public const float ManagementRange = 12f;

		public static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		public static bool SurfaceAllowed(float normalY)
		{
			if (Finite(normalY))
			{
				return normalY >= 0.02f;
			}
			return false;
		}

		public static bool CanRecall(bool freeSlot, bool emptyHands)
		{
			return freeSlot || emptyHands;
		}

		public static bool NeedsWeaponPurchase(int currentWeaponId, int requestedWeaponId)
		{
			return currentWeaponId != requestedWeaponId;
		}

		private static int Level(int level)
		{
			return Math.Min(10, Math.Max(0, level));
		}

		private static double Growth(double rate, int level)
		{
			return Math.Pow(1.0 + rate, Level(level));
		}

		public static float ReloadSeconds(float baseline, int upgrades)
		{
			return (float)((double)Math.Max(0.01f, baseline) / Growth(0.1, upgrades));
		}

		public static string CleanName(string value)
		{
			if (value == null)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			string text = value.Trim();
			foreach (char c in text)
			{
				if (!char.IsControl(c) && c != '<' && c != '>')
				{
					stringBuilder.Append(c);
					if (stringBuilder.Length == 32)
					{
						break;
					}
				}
			}
			return stringBuilder.ToString();
		}

		public static bool InManagementRange(float distance)
		{
			if (Finite(distance))
			{
				return distance <= 12f;
			}
			return false;
		}

		public static int TurretPrice(int ownedTurrets)
		{
			return 5000 * (1 << Math.Min(7, Math.Max(0, ownedTurrets)));
		}

		public static int UpgradePrice(int level)
		{
			if (level < 0 || level >= 10)
			{
				return 0;
			}
			return 1500 * (level + 1);
		}

		public static int TierPrice(int tier)
		{
			return tier switch
			{
				1 => 100000, 
				0 => 20000, 
				_ => 0, 
			};
		}

		public static int UpgradeInvestment(int level)
		{
			int num = 0;
			for (int i = 0; i < Math.Min(10, Math.Max(0, level)); i++)
			{
				num += UpgradePrice(i);
			}
			return num;
		}

		public static int TierInvestment(int tier)
		{
			if (tier > 0)
			{
				if (tier != 1)
				{
					return 120000;
				}
				return 20000;
			}
			return 0;
		}

		public static int ResaleValue(int purchasePrice, int level, int tier)
		{
			return (Math.Max(5000, purchasePrice) + UpgradeInvestment(level) + TierInvestment(tier)) / 2;
		}

		public static int ResaleValue(int level, int tier)
		{
			return ResaleValue(5000, level, tier);
		}

		public static GunClass Classify(string name)
		{
			string text = name.ToLowerInvariant();
			if (text.Contains("snip") || text.Contains("awp") || text.Contains("scout"))
			{
				return GunClass.Sniper;
			}
			if (text.Contains("shot") || text.Contains("blunder"))
			{
				return GunClass.Shotgun;
			}
			if (text.Contains("smg") || text.Contains("uzi") || text.Contains("submachine") || text.Contains("mp5") || text.Contains("p90"))
			{
				return GunClass.SMG;
			}
			if (text.Contains("pistol") || text.Contains("revol") || text.Contains("handgun") || text.Contains("glock") || text.Contains("deagle") || text.Contains("desert eagle"))
			{
				return GunClass.Pistol;
			}
			return GunClass.Rifle;
		}

		public static float Radius(GunClass gun, int level)
		{
			return (float)((double)(new float[5] { 25f, 45f, 55f, 75f, 120f })[(int)gun] * Growth(0.05, level));
		}

		public static float Reload(GunClass gun, int level)
		{
			return (float)((double)(new float[5] { 3f, 2.4f, 2.8f, 3f, 3.5f })[(int)gun] / Growth(0.1, level));
		}

		public static float Interval(GunClass gun, int level)
		{
			return (float)((double)(new float[5] { 1.1f, 0.4f, 0.16f, 0.22f, 1.6f })[(int)gun] / Growth(0.1, level));
		}

		public static int Magazine(GunClass gun)
		{
			return (new int[5] { 2, 12, 25, 20, 5 })[(int)gun];
		}

		public static int Damage(int damage, int level)
		{
			return Math.Max(1, (int)Math.Round((double)damage * Growth(0.1, level)));
		}

		public static float Accuracy(int level)
		{
			return 0.85f + (float)Math.Min(10, Math.Max(0, level)) * 0.015f;
		}

		public static float AccuracyCone(int level)
		{
			return 3f - (float)Math.Min(10, Math.Max(0, level)) * 0.27f;
		}

		public static bool Eligible(int tier, bool seagull, bool fish, bool boss, bool dead, bool held)
		{
			if (!dead && !held && (seagull || fish))
			{
				if (!boss)
				{
					if (!seagull)
					{
						return tier >= 1 && fish;
					}
					return true;
				}
				return tier >= 2;
			}
			return false;
		}
	}
	[Serializable]
	public sealed class TurretData
	{
		public int serial;

		public int level;

		public int tier;

		public int ammo;

		public int shots;

		public int reloads;

		public int acquisition;

		public int purchasePrice;

		public ulong owner;

		public string ownerName;

		public string customName;

		public bool deployed;

		public bool friendlyFire;

		public bool acquiring;

		public bool hasTarget;

		public bool available = true;

		public string combatStatus = "Not deployed";

		public Vector3 surfaceNormal = Vector3.up;

		public Vector3 position;

		public Vector3 aim;

		public Vector3 shotAim;

		public float yaw;

		public SavedItem weapon;

		[NonSerialized]
		public float nextShot;

		[NonSerialized]
		public bool reloading;

		[NonSerialized]
		public Creature lockedTarget;

		[NonSerialized]
		public float lockUntil;

		public string DisplayName
		{
			get
			{
				if (!string.IsNullOrEmpty(customName))
				{
					return customName;
				}
				return "Turret #" + serial;
			}
		}

		public Quaternion BaseRotation => Quaternion.FromToRotation(Vector3.up, (((Vector3)(ref surfaceNormal)).sqrMagnitude > 0.01f) ? surfaceNormal : Vector3.up) * Quaternion.Euler(0f, yaw, 0f);
	}
	[Serializable]
	public sealed class WorldData
	{
		public string name;

		public List<TurretData> turrets = new List<TurretData>();

		public List<int> retired = new List<int>();
	}
	[Serializable]
	public sealed class SaveData
	{
		public int version = 1;

		public int nextSerial = 1;

		public List<WorldData> worlds = new List<WorldData>();
	}
	[Serializable]
	public sealed class Command
	{
		public int protocol = 3;

		public int sequence;

		public int serial;

		public int argument;

		public string action;

		public string text;

		public Vector3 position;

		public Vector3 normal;
	}
	[Serializable]
	public sealed class Snapshot
	{
		public int protocol = 3;

		public string world;

		public List<TurretData> turrets = new List<TurretData>();
	}
	[Serializable]
	public sealed class Reply
	{
		public int sequence;

		public int serial;

		public string message;
	}
	public struct RequestMessage : IBroadcast
	{
		public string json;
	}
	public struct StateMessage : IBroadcast
	{
		public string json;
	}
	public struct ReplyMessage : IBroadcast
	{
		public string json;
	}
	public sealed class Gun
	{
		public Weapon prefab;

		public string name;

		public GunClass kind;

		public int damage;

		public int price;

		public int magazine;

		public int extendedMagazine;

		public int[] ammoDamages;

		public float reload;

		public int Magazine(SavedItem state)
		{
			if (state == null || !state.ExtendedMag)
			{
				return magazine;
			}
			return extendedMagazine;
		}

		public int Damage(SavedItem state)
		{
			int num = state?.AmmoType ?? 0;
			if (ammoDamages == null || num < 0 || num >= ammoDamages.Length)
			{
				return damage;
			}
			return ammoDamages[num];
		}
	}
	public static class Kit
	{
		public const byte Id = 250;

		public const ushort Collection = 42420;

		public static Item Prefab;

		private static GameObject storage;

		public static bool Is(Item item)
		{
			if ((Object)(object)item != (Object)null && item.ID == 250)
			{
				return (Object)(object)((Component)item).GetComponent<KitVisual>() != (Object)null;
			}
			return false;
		}

		public static int Serial(Item item)
		{
			if (!Is(item))
			{
				return 0;
			}
			return Mathf.RoundToInt(item.BettingMultiplier);
		}

		public static void Register()
		{
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Expected O, but got Unknown
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Expected O, but got Unknown
			//IL_0300: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0460: Unknown result type (might be due to invalid IL or missing references)
			//IL_033c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Prefab != (Object)null || (Object)(object)InstanceFinder.NetworkManager == (Object)null)
			{
				return;
			}
			Dictionary<byte, Item> dictionary = (Dictionary<byte, Item>)AccessTools.Field(typeof(GameInfo), "_idToSpawnable").GetValue(null);
			if (dictionary.Count == 0)
			{
				return;
			}
			if (dictionary.ContainsKey(250))
			{
				throw new Exception("AASC item ID 250 is already in use; refusing to replace another item.");
			}
			Item val = (from i in dictionary.Values
				where (Object)(object)i != (Object)null && ((object)i).GetType() == typeof(Item) && (Object)(object)((Component)i).GetComponent<NetworkObject>() != (Object)null
				orderby i.ID
				select i).FirstOrDefault();
			if ((Object)(object)val == (Object)null)
			{
				throw new Exception("No compatible base Item prefab found for the inventory kit.");
			}
			storage = new GameObject("AASC prefab storage");
			storage.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)storage);
			Item val2 = Object.Instantiate<Item>(val, storage.transform);
			((Object)val2).name = "Turret Mod Kit";
			AccessTools.Field(typeof(Item), "_id").SetValue(val2, (byte)250);
			AccessTools.Field(typeof(Item), "_cost").SetValue(val2, 5000);
			AccessTools.Field(typeof(Item), "_worth").SetValue(val2, 0);
			AccessTools.Field(typeof(Item), "_ignoredBySeagulls").SetValue(val2, true);
			AccessTools.Field(typeof(Item), "_ignoredByMoneyNPC").SetValue(val2, true);
			AccessTools.Field(typeof(Item), "_ignoredByCloseDots").SetValue(val2, false);
			AccessTools.Field(typeof(Item), "_heldPos").SetValue(val2, (object)new Vector3(0.25f, -0.45f, 0.75f));
			Renderer[] componentsInChildren = ((Component)val2).GetComponentsInChildren<Renderer>(true);
			for (int num = 0; num < componentsInChildren.Length; num++)
			{
				componentsInChildren[num].enabled = false;
			}
			Collider[] componentsInChildren2 = ((Component)val2).GetComponentsInChildren<Collider>(true);
			foreach (Collider val3 in componentsInChildren2)
			{
				if (!val3.isTrigger)
				{
					val3.enabled = false;
				}
			}
			GameObject val4 = new GameObject("AASCBodyCollider");
			val4.transform.SetParent(((Component)val2).transform, false);
			BoxCollider val5 = val4.AddComponent<BoxCollider>();
			val5.center = new Vector3(0f, 0.35f, 0f);
			val5.size = new Vector3(0.85f, 0.7f, 0.85f);
			AccessTools.Field(typeof(Item), "_worldColliders").SetValue(val2, new Collider[1] { (Collider)val5 });
			Collider val6 = (Collider)AccessTools.Field(typeof(Item), "_pickUpCollider").GetValue(val2);
			if (val6 is SphereCollider)
			{
				((SphereCollider)val6).radius = 0.65f;
				((SphereCollider)val6).center = new Vector3(0f, 0.35f, 0f);
			}
			else if (val6 is BoxCollider)
			{
				((BoxCollider)val6).size = new Vector3(1.2f, 1f, 1.2f);
				((BoxCollider)val6).center = new Vector3(0f, 0.35f, 0f);
			}
			AccessTools.Field(typeof(Item), "_outOfHandHolder").SetValue(val2, null);
			AccessTools.Field(typeof(Item), "_inHandHolder").SetValue(val2, null);
			KitVisual kitVisual = ((Component)val2).gameObject.AddComponent<KitVisual>();
			kitVisual.Build();
			AccessTools.Field(typeof(Item), "_mesh").SetValue(val2, kitVisual.InventoryMesh());
			AccessTools.Field(typeof(Item), "_inventoryMeshScale").SetValue(val2, 0.7f);
			AccessTools.Field(typeof(Item), "_inventoryMeshPos").SetValue(val2, (object)new Vector3(0f, -0.2f, 0f));
			AccessTools.Field(typeof(Item), "_inventoryMeshRot").SetValue(val2, (object)new Vector3(0f, 35f, 0f));
			AccessTools.Field(typeof(Item), "_renderers").SetValue(val2, (from r in ((Component)kitVisual).GetComponentsInChildren<Renderer>(true)
				where r.enabled
				select r).ToList());
			NetworkObject component = ((Component)val2).GetComponent<NetworkObject>();
			component.SetIsSpawnable(true);
			PrefabObjects prefabObjects = InstanceFinder.NetworkManager.GetPrefabObjects<SinglePrefabObjects>((ushort)42420, true);
			if (prefabObjects.GetObjectCount() != 0)
			{
				throw new Exception("AASC network prefab collection 42420 is already occupied.");
			}
			prefabObjects.AddObject(component, false, true);
			dictionary.Add(250, val2);
			((Dictionary<byte, Item>)AccessTools.Field(typeof(GameInfo), "_allItems").GetValue(null)).Add(250, val2);
			((Dictionary<string, Item>)AccessTools.Field(typeof(GameInfo), "_nameToSpawnable").GetValue(null)).Add("aascturretkit", val2);
			Prefab = val2;
			Plugin.Log("Inventory kit registered using " + ((Object)val).name + "; dedicated network collection " + (ushort)42420 + ".");
		}
	}
	public sealed class KitVisual : MonoBehaviour
	{
		public Transform head;

		public Transform socket;

		private Transform aimPivot;

		private Item item;

		private int gunId = -1;

		private int gunStateSignature = int.MinValue;

		private int lastShot;

		private int lastReload;

		private int lastAcquisition;

		private LineRenderer tracer;

		private LineRenderer lockLaser;

		private float tracerUntil;

		private GameObject mountedGun;

		private Animation mountedAnimation;

		private Transform mountedMuzzle;

		private ParticleSystem mountedFireParticle;

		private BarrelAttachment mountedBarrel;

		private AudioSequence fireSequence;

		private AudioSequence fireLastSequence;

		private AudioSequence reloadSequence;

		private AudioSequence reloadLastSequence;

		private bool hasLastFire;

		private bool hasLastReload;

		private bool proceduralReload;

		private float recoilUntil;

		private float reloadStarted;

		private float reloadUntil;

		private Vector3 mountedBasePosition;

		private Quaternion mountedBaseRotation;

		private static Material metal;

		private static Material orange;

		private static Material glow;

		private static Material lockGlow;

		public Vector3 MuzzlePosition
		{
			get
			{
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: 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_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)mountedMuzzle != (Object)null))
				{
					if (!((Object)(object)head != (Object)null))
					{
						return ((Component)this).transform.position + ((Component)this).transform.up * 1.2f;
					}
					return head.position + head.forward * 0.55f;
				}
				return mountedMuzzle.position;
			}
		}

		public int InventoryGunSignature => WeaponSignature(((Object)(object)Plugin.Instance == (Object)null) ? null : Plugin.Instance.Find(Kit.Serial(item))?.weapon);

		public void Build()
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)((Component)this).transform.Find("AASCBase") != (Object)null))
			{
				if ((Object)(object)metal == (Object)null)
				{
					Shader obj = Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard");
					metal = new Material(obj)
					{
						color = new Color(0.13f, 0.18f, 0.21f)
					};
					orange = new Material(obj)
					{
						color = new Color(0.98f, 0.46f, 0.08f)
					};
					glow = new Material(Shader.Find("Sprites/Default"))
					{
						color = Color.cyan
					};
					lockGlow = new Material(Shader.Find("Sprites/Default"))
					{
						color = Color.red
					};
				}
				Part("AASCBase", ((Component)this).transform, (PrimitiveType)2, new Vector3(0f, 0.09f, 0f), new Vector3(0.7f, 0.09f, 0.7f), metal);
				for (int i = 0; i < 3; i++)
				{
					float num = (float)(i * 120) * ((float)Math.PI / 180f);
					Part("Stabilizer", ((Component)this).transform, (PrimitiveType)3, new Vector3(Mathf.Sin(num) * 0.37f, 0.06f, Mathf.Cos(num) * 0.37f), new Vector3(0.18f, 0.12f, 0.42f), orange).localEulerAngles = new Vector3(0f, (float)(i * 120), 0f);
				}
				Part("Pedestal", ((Component)this).transform, (PrimitiveType)2, new Vector3(0f, 0.32f, 0f), new Vector3(0.2f, 0.25f, 0.2f), metal);
				head = new GameObject("AASCHead").transform;
				head.SetParent(((Component)this).transform, false);
				head.localPosition = new Vector3(0f, 0.65f, 0f);
				Part("Cradle", head, (PrimitiveType)3, Vector3.zero, new Vector3(0.48f, 0.2f, 0.4f), orange);
				aimPivot = new GameObject("AASCGunAimPivot").transform;
				aimPivot.SetParent(head, false);
				aimPivot.localPosition = new Vector3(0f, 0.13f, 0f);
				socket = new GameObject("WeaponSocket").transform;
				socket.SetParent(aimPivot, false);
				socket.localPosition = Vector3.zero;
				Part("SocketEmpty", socket, (PrimitiveType)3, Vector3.zero, new Vector3(0.25f, 0.08f, 0.28f), metal);
			}
		}

		private static Transform Part(string name, Transform parent, PrimitiveType primitive, Vector3 pos, Vector3 scale, Material material)
		{
			//IL_0000: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = GameObject.CreatePrimitive(primitive);
			((Object)obj).name = name;
			obj.transform.SetParent(parent, false);
			obj.transform.localPosition = pos;
			obj.transform.localScale = scale;
			Object.DestroyImmediate((Object)(object)obj.GetComponent<Collider>());
			obj.GetComponent<Renderer>().sharedMaterial = material;
			return obj.transform;
		}

		private static string RelativePath(Transform root, Transform child)
		{
			if ((Object)(object)root == (Object)null || (Object)(object)child == (Object)null)
			{
				return null;
			}
			if ((Object)(object)root == (Object)(object)child)
			{
				return "";
			}
			List<string> list = new List<string>();
			Transform val = child;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			if ((Object)(object)val != (Object)(object)root)
			{
				return null;
			}
			list.Reverse();
			return string.Join("/", list.ToArray());
		}

		private static Transform CloneTransform(Transform sourceRoot, Transform cloneRoot, Transform source)
		{
			string text = RelativePath(sourceRoot, source);
			if (text != null)
			{
				if (text.Length != 0)
				{
					return cloneRoot.Find(text);
				}
				return cloneRoot;
			}
			return null;
		}

		private static T Private<T>(object target, string name) where T : class
		{
			FieldInfo fieldInfo = ((target == null) ? null : AccessTools.Field(target.GetType(), name));
			if (!(fieldInfo == null))
			{
				return fieldInfo.GetValue(target) as T;
			}
			return null;
		}

		private static void ActivatePath(Transform child, Transform root)
		{
			Transform val = child;
			while ((Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(true);
				if (!((Object)(object)val == (Object)(object)root))
				{
					val = val.parent;
					continue;
				}
				break;
			}
		}

		private static bool IsWeaponRenderer(Renderer renderer)
		{
			if (!(renderer is MeshRenderer))
			{
				return renderer is SkinnedMeshRenderer;
			}
			return true;
		}

		private static void EnableVisuals(Transform root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			ActivatePath(root, root);
			Renderer[] componentsInChildren = ((Component)root).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (IsWeaponRenderer(val))
				{
					ActivatePath(((Component)val).transform, root);
					val.enabled = true;
					val.forceRenderingOff = false;
					val.lightmapIndex = -1;
					val.realtimeLightmapIndex = -1;
				}
			}
		}

		private void ToggleCopies<T>(Transform sourceRoot, Transform cloneRoot, List<T> choices, int selected) where T : Component
		{
			if (choices == null)
			{
				return;
			}
			for (int i = 0; i < choices.Count; i++)
			{
				Transform val = CloneTransform(sourceRoot, cloneRoot, ((Object)(object)choices[i] == (Object)null) ? null : ((Component)choices[i]).transform);
				if (!((Object)(object)val == (Object)null))
				{
					((Component)val).gameObject.SetActive(i == selected);
					if (i == selected)
					{
						ActivatePath(val, cloneRoot);
						EnableVisuals(val);
					}
				}
			}
		}

		private void BuildMountedGun(Gun gun, SavedItem state)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0910: Unknown result type (might be due to invalid IL or missing references)
			//IL_0915: Unknown result type (might be due to invalid IL or missing references)
			//IL_0926: Unknown result type (might be due to invalid IL or missing references)
			//IL_092b: Unknown result type (might be due to invalid IL or missing references)
			//IL_07ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_080b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0817: Unknown result type (might be due to invalid IL or missing references)
			//IL_083e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0845: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0892: Unknown result type (might be due to invalid IL or missing references)
			//IL_0897: Unknown result type (might be due to invalid IL or missing references)
			//IL_08c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_08cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_08d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_08dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_08fa: Unknown result type (might be due to invalid IL or missing references)
			Transform val = socket.Find("MountedGun");
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
			mountedGun = null;
			mountedAnimation = null;
			mountedMuzzle = null;
			mountedFireParticle = null;
			mountedBarrel = null;
			fireSequence = (fireLastSequence = (reloadSequence = (reloadLastSequence = null)));
			hasLastFire = (hasLastReload = false);
			if (gun == null || (Object)(object)gun.prefab == (Object)null)
			{
				return;
			}
			mountedGun = new GameObject("MountedGun");
			mountedGun.transform.SetParent(socket, false);
			bool activeSelf = ((Component)socket).gameObject.activeSelf;
			((Component)socket).gameObject.SetActive(false);
			GameObject val2 = Object.Instantiate<GameObject>(((Component)gun.prefab).gameObject, mountedGun.transform, false);
			((Object)val2).name = "WeaponRig";
			Weapon component = val2.GetComponent<Weapon>();
			if ((Object)(object)component != (Object)null && state != null)
			{
				try
				{
					((Item)component).LoadFromSave(state);
				}
				catch (Exception ex)
				{
					Plugin.Log("Native visual configuration fallback for " + gun.name + ": " + ex.Message);
				}
			}
			MonoBehaviour[] componentsInChildren = val2.GetComponentsInChildren<MonoBehaviour>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			Collider[] componentsInChildren2 = val2.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
			}
			Rigidbody[] componentsInChildren3 = val2.GetComponentsInChildren<Rigidbody>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[i]);
			}
			((Component)socket).gameObject.SetActive(activeSelf);
			val2.SetActive(true);
			val2.transform.localPosition = Vector3.zero;
			val2.transform.localRotation = Quaternion.Euler(((Item)gun.prefab).InventoryMeshRot);
			val2.transform.localScale = Vector3.one;
			Transform transform = ((Component)gun.prefab).transform;
			Attachments attachments = gun.prefab.Attachments;
			GameObject val3 = Private<GameObject>(gun.prefab, "_outOfHandHolder");
			GameObject val4 = Private<GameObject>(gun.prefab, "_inHandHolder");
			Transform val5 = CloneTransform(transform, val2.transform, ((Object)(object)val3 == (Object)null) ? null : val3.transform);
			Transform val6 = CloneTransform(transform, val2.transform, ((Object)(object)val4 == (Object)null) ? null : val4.transform);
			Transform val7 = (((Object)(object)val5 != (Object)null && ((Component)val5).GetComponentsInChildren<Renderer>(true).Any(IsWeaponRenderer)) ? val5 : (((Object)(object)val6 != (Object)null) ? val6 : val5));
			if ((Object)(object)val5 != (Object)null)
			{
				((Component)val5).gameObject.SetActive((Object)(object)val7 == (Object)(object)val5);
			}
			if ((Object)(object)val6 != (Object)null)
			{
				((Component)val6).gameObject.SetActive((Object)(object)val7 == (Object)(object)val6);
			}
			if ((Object)(object)val7 != (Object)null)
			{
				ActivatePath(val7, val2.transform);
				EnableVisuals(val7);
			}
			List<Renderer> list = Private<List<Renderer>>(gun.prefab, "_renderers");
			if (list != null)
			{
				foreach (Renderer item in list)
				{
					Transform val8 = CloneTransform(transform, val2.transform, ((Object)(object)item == (Object)null) ? null : ((Component)item).transform);
					if (!((Object)(object)val8 == (Object)null) && (!((Object)(object)val7 != (Object)null) || val8.IsChildOf(val7) || !((Object)(object)val8 != (Object)(object)val7)))
					{
						ActivatePath(val8, val2.transform);
						Renderer component2 = ((Component)val8).GetComponent<Renderer>();
						if ((Object)(object)component2 != (Object)null)
						{
							component2.enabled = true;
							component2.forceRenderingOff = false;
							component2.lightmapIndex = -1;
							component2.realtimeLightmapIndex = -1;
						}
					}
				}
			}
			List<Sight> list2 = Private<List<Sight>>(attachments, "_sights");
			List<BarrelAttachment> list3 = Private<List<BarrelAttachment>>(attachments, "_barrelAttachments");
			int selected = Mathf.Clamp((int)(state?.Sight ?? 0), 0, (list2 != null) ? (list2.Count - 1) : 0);
			int num = Mathf.Clamp((int)(state?.BarrelAttachment ?? 0), 0, (list3 != null) ? (list3.Count - 1) : 0);
			ToggleCopies<Sight>(transform, val2.transform, list2, selected);
			ToggleCopies<BarrelAttachment>(transform, val2.transform, list3, num);
			LaserSight val9 = Private<LaserSight>(attachments, "_laserSight");
			Transform val10 = CloneTransform(transform, val2.transform, ((Object)(object)val9 == (Object)null) ? null : ((Component)val9).transform);
			if ((Object)(object)val10 != (Object)null)
			{
				((Component)val10).gameObject.SetActive(state?.LaserSight ?? false);
				if (state != null && state.LaserSight)
				{
					ActivatePath(val10, val2.transform);
					EnableVisuals(val10);
				}
			}
			if (list3 != null && list3.Count > 0)
			{
				mountedBarrel = list3[num];
				mountedMuzzle = CloneTransform(transform, val2.transform, mountedBarrel.FirePoint);
				Transform val11 = CloneTransform(transform, val2.transform, ((Object)(object)mountedBarrel.FireParticle == (Object)null) ? null : ((Component)mountedBarrel.FireParticle).transform);
				if ((Object)(object)val11 != (Object)null)
				{
					mountedFireParticle = ((Component)val11).GetComponent<ParticleSystem>();
				}
			}
			Renderer[] componentsInChildren4;
			if (!val2.GetComponentsInChildren<Renderer>(false).Any(IsWeaponRenderer))
			{
				componentsInChildren4 = val2.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val12 in componentsInChildren4)
				{
					if (IsWeaponRenderer(val12))
					{
						ActivatePath(((Component)val12).transform, val2.transform);
						val12.enabled = true;
						val12.forceRenderingOff = false;
						val12.lightmapIndex = -1;
						val12.realtimeLightmapIndex = -1;
					}
				}
			}
			if (state != null && (Object)(object)((Item)gun.prefab).SkinPreset != (Object)null && ((Item)gun.prefab).SkinPreset.Skins.Count > 0)
			{
				int index = Mathf.Clamp((int)state.SkinIndex, 0, ((Item)gun.prefab).SkinPreset.Skins.Count - 1);
				componentsInChildren4 = val2.GetComponentsInChildren<Renderer>(false);
				foreach (Renderer val13 in componentsInChildren4)
				{
					if (IsWeaponRenderer(val13))
					{
						ShaderManager.ApplyItemSkin(((Item)gun.prefab).SkinPreset.Skins[index], val13, false);
					}
				}
			}
			mountedAnimation = val2.GetComponentInChildren<Animation>(true);
			fireSequence = Private<AudioSequence>(gun.prefab, "_fireAudioSeq");
			fireLastSequence = Private<AudioSequence>(gun.prefab, "_fireLastAudioSeq");
			reloadSequence = Private<AudioSequence>(gun.prefab, "_reloadAudioSeq");
			reloadLastSequence = Private<AudioSequence>(gun.prefab, "_reloadLastAudioSeq");
			hasLastFire = (bool)AccessTools.Field(typeof(Weapon), "_hasLastFireAnim").GetValue(gun.prefab);
			hasLastReload = (bool)AccessTools.Field(typeof(Weapon), "_hasLastReloadAnim").GetValue(gun.prefab);
			Renderer[] array = val2.GetComponentsInChildren<Renderer>(false).Where(IsWeaponRenderer).ToArray();
			Bounds val14 = default(Bounds);
			bool flag = false;
			componentsInChildren4 = array;
			foreach (Renderer val15 in componentsInChildren4)
			{
				if (!flag)
				{
					val14 = val15.bounds;
					flag = true;
				}
				else
				{
					((Bounds)(ref val14)).Encapsulate(val15.bounds);
				}
			}
			if (flag)
			{
				float num2 = 1.35f / Mathf.Max(0.001f, Mathf.Max(((Bounds)(ref val14)).size.x, Mathf.Max(((Bounds)(ref val14)).size.y, ((Bounds)(ref val14)).size.z)));
				mountedGun.transform.localScale = Vector3.one * num2;
				Renderer[] array2 = val2.GetComponentsInChildren<Renderer>(false).Where(IsWeaponRenderer).ToArray();
				flag = false;
				componentsInChildren4 = array2;
				foreach (Renderer val16 in componentsInChildren4)
				{
					if (!flag)
					{
						val14 = val16.bounds;
						flag = true;
					}
					else
					{
						((Bounds)(ref val14)).Encapsulate(val16.bounds);
					}
				}
				if (flag)
				{
					Vector3 val17 = socket.InverseTransformPoint(((Bounds)(ref val14)).center);
					mountedGun.transform.localPosition = new Vector3(0f - val17.x, 0.18f - val17.y, 0f - val17.z);
				}
			}
			mountedBasePosition = mountedGun.transform.localPosition;
			mountedBaseRotation = mountedGun.transform.localRotation;
			int num3 = val2.GetComponentsInChildren<Renderer>(false).Count(IsWeaponRenderer);
			Plugin.Log("Mounted visual " + gun.name + ": skin=" + (int)(state?.SkinIndex ?? 0) + ", sight=" + (int)(state?.Sight ?? 0) + ", barrel=" + (int)(state?.BarrelAttachment ?? 0) + ", active renderers=" + num3 + ", holder=" + (((Object)(object)val7 == (Object)null) ? "fallback" : ((Object)val7).name) + ".");
		}

		private static void SetLayerRecursively(GameObject root, int layer)
		{
			Transform[] componentsInChildren = root.GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Component)componentsInChildren[i]).gameObject.layer = layer;
			}
		}

		public GameObject CreateInventoryGunPreview(Transform parent)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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)
			if ((Object)(object)mountedGun == (Object)null || (Object)(object)parent == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(mountedGun, parent, false);
			((Object)val).name = "AASCInventoryGunPreview";
			MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			Collider[] componentsInChildren2 = val.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
			}
			val.transform.localPosition = new Vector3(0f, 0.02f, 0f);
			val.transform.localRotation = Quaternion.Euler(-8f, 20f, 0f);
			val.transform.localScale = mountedGun.transform.localScale * 0.82f;
			SetLayerRecursively(val, ((Component)parent).gameObject.layer);
			val.SetActive(true);
			Renderer[] componentsInChildren3 = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren3)
			{
				if (IsWeaponRenderer(val2))
				{
					ActivatePath(((Component)val2).transform, val.transform);
					val2.enabled = true;
					val2.lightmapIndex = -1;
					val2.realtimeLightmapIndex = -1;
				}
			}
			return val;
		}

		private static int WeaponSignature(SavedItem state)
		{
			if (state == null || !state.Exists)
			{
				return -1;
			}
			return ((((((17 * 31 + state.ItemID) * 31 + state.SkinIndex) * 31 + state.Sight) * 31 + state.BarrelAttachment) * 31 + state.AmmoType) * 31 + (state.ExtendedMag ? 1 : 0)) * 31 + (state.LaserSight ? 1 : 0);
		}

		private void PlayAnimation(string name, float duration = 0f)
		{
			if (!((Object)(object)mountedAnimation == (Object)null) && !((TrackedReference)(object)mountedAnimation[name] == (TrackedReference)null))
			{
				AnimationState val = mountedAnimation[name];
				val.speed = ((duration > 0f) ? (val.clip.length / Mathf.Max(0.05f, duration)) : 1f);
				mountedAnimation.Stop();
				mountedAnimation.Play(name);
			}
		}

		private void PlaySequence(AudioSequence sequence, float speed = 1f)
		{
			if (sequence != null && sequence.Steps != null && sequence.Steps.Length != 0)
			{
				((MonoBehaviour)this).StartCoroutine(PlaySequenceRoutine(sequence, Mathf.Max(0.05f, speed)));
			}
		}

		private IEnumerator PlaySequenceRoutine(AudioSequence sequence, float speed)
		{
			AudioSequenceStep[] steps = sequence.Steps;
			foreach (AudioSequenceStep step in steps)
			{
				if (step != null)
				{
					if (step.Timer > 0f)
					{
						yield return (object)new WaitForSeconds(step.Timer / speed);
					}
					AudioClip randomClip = step.GetRandomClip();
					if ((Object)(object)randomClip != (Object)null)
					{
						AudioSource.PlayClipAtPoint(randomClip, MuzzlePosition, sequence.Volume * step.Volume);
					}
				}
			}
		}

		private void PlayFire(TurretData data)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			recoilUntil = Time.time + 0.12f;
			string name = ((data.ammo == 0 && hasLastFire) ? "FireLast" : "Fire");
			PlayAnimation(name);
			if ((Object)(object)mountedFireParticle != (Object)null)
			{
				mountedFireParticle.Play();
			}
			if ((Object)(object)mountedBarrel != (Object)null && !string.IsNullOrEmpty(mountedBarrel.GetFireSound()))
			{
				AudioManager.PlayRandomClipAt(mountedBarrel.GetFireSound(), 1, Mathf.Max(1, mountedBarrel.FireSoundCount), MuzzlePosition, false, (AudioDistance)(mountedBarrel.UseMediumSoundDistance ? 2 : 3), mountedBarrel.FireSoundVolume, 0.1f);
			}
			PlaySequence((data.ammo == 0 && fireLastSequence != null) ? fireLastSequence : fireSequence);
		}

		private void PlayReload(TurretData data, Gun gun)
		{
			float num = Rules.ReloadSeconds(gun.reload, data.level);
			reloadStarted = Time.time;
			reloadUntil = Time.time + num;
			string text = ((data.ammo == 0 && hasLastReload) ? "ReloadLast" : "Reload");
			proceduralReload = (Object)(object)mountedAnimation == (Object)null || (TrackedReference)(object)mountedAnimation[text] == (TrackedReference)null;
			PlayAnimation(text, num);
			PlaySequence((data.ammo == 0 && reloadLastSequence != null) ? reloadLastSequence : reloadSequence, gun.reload / Mathf.Max(0.05f, num));
		}

		public Mesh InventoryMesh()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			MeshFilter[] source = (from f in ((Component)this).GetComponentsInChildren<MeshFilter>(true)
				where ((Component)f).GetComponent<Renderer>().enabled
				select f).ToArray();
			Mesh val = new Mesh
			{
				name = "AASC inventory mesh"
			};
			val.CombineMeshes(source.Select(delegate(MeshFilter f)
			{
				//IL_0002: 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_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				CombineInstance result = default(CombineInstance);
				((CombineInstance)(ref result)).mesh = f.sharedMesh;
				((CombineInstance)(ref result)).transform = ((Component)this).transform.worldToLocalMatrix * ((Component)f).transform.localToWorldMatrix;
				return result;
			}).ToArray());
			return val;
		}

		private void Awake()
		{
			item = ((Component)this).GetComponent<Item>();
			head = ((Component)this).transform.Find("AASCHead");
			if ((Object)(object)head != (Object)null)
			{
				aimPivot = head.Find("AASCGunAimPivot");
				socket = (((Object)(object)aimPivot == (Object)null) ? head.Find("WeaponSocket") : aimPivot.Find("WeaponSocket"));
			}
		}

		private void AimMountedWeapon(Vector3 direction, float yawDegreesPerSecond, float aimDegreesPerSecond)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: 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_014b: 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_0158: Unknown result type (might be due to invalid IL or missing references)
			if (((Vector3)(ref direction)).sqrMagnitude < 0.0001f || (Object)(object)head == (Object)null || (Object)(object)aimPivot == (Object)null)
			{
				return;
			}
			((Vector3)(ref direction)).Normalize();
			Vector3 up = ((Component)this).transform.up;
			Vector3 val = Vector3.ProjectOnPlane(direction, up);
			if (((Vector3)(ref val)).sqrMagnitude > 0.0001f)
			{
				((Vector3)(ref val)).Normalize();
				Vector3 val2 = Vector3.ProjectOnPlane(((Component)this).transform.forward, up);
				Vector3 normalized = ((Vector3)(ref val2)).normalized;
				if (((Vector3)(ref normalized)).sqrMagnitude < 0.0001f)
				{
					val2 = Vector3.ProjectOnPlane(Vector3.forward, up);
					normalized = ((Vector3)(ref val2)).normalized;
				}
				float num = Vector3.SignedAngle(normalized, val, up);
				Quaternion val3 = Quaternion.Euler(0f, num, 0f);
				head.localRotation = ((yawDegreesPerSecond <= 0f) ? val3 : Quaternion.RotateTowards(head.localRotation, val3, yawDegreesPerSecond * Time.deltaTime));
			}
			Quaternion val5;
			if ((Object)(object)mountedMuzzle != (Object)null)
			{
				Quaternion val4 = Quaternion.Inverse(aimPivot.rotation) * mountedMuzzle.rotation;
				val5 = Quaternion.LookRotation(direction, up) * Quaternion.Inverse(val4);
			}
			else
			{
				val5 = Quaternion.LookRotation(direction, up);
			}
			aimPivot.rotation = ((aimDegreesPerSecond <= 0f) ? val5 : Quaternion.RotateTowards(aimPivot.rotation, val5, aimDegreesPerSecond * Time.deltaTime));
		}

		private void LateUpdate()
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_039b: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0414: Unknown result type (might be due to invalid IL or missing references)
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			//IL_057a: Unknown result type (might be due to invalid IL or missing references)
			//IL_058c: Unknown result type (might be due to invalid IL or missing references)
			//IL_050f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0516: Expected O, but got Unknown
			//IL_0464: Unknown result type (might be due to invalid IL or missing references)
			//IL_0469: Unknown result type (might be due to invalid IL or missing references)
			//IL_0452: Unknown result type (might be due to invalid IL or missing references)
			//IL_0457: Unknown result type (might be due to invalid IL or missing references)
			//IL_046e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0473: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_047c: Unknown result type (might be due to invalid IL or missing references)
			//IL_048a: Unknown result type (might be due to invalid IL or missing references)
			//IL_048f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04be: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_06bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_063f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0646: Expected O, but got Unknown
			//IL_06f2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null || (Object)(object)Plugin.Instance == (Object)null || (Object)(object)head == (Object)null)
			{
				return;
			}
			TurretData turretData = Plugin.Instance.Find(Kit.Serial(item));
			if (turretData == null)
			{
				return;
			}
			if (turretData.deployed && (Object)(object)item.SyncedHolder == (Object)null)
			{
				item.ReconcileLocalHolderWithSyncedHolder();
				item.RigidbodySync.SetKinematic(true);
				((Component)this).transform.SetPositionAndRotation(turretData.position, turretData.BaseRotation);
			}
			else
			{
				head.localRotation = Quaternion.identity;
				if ((Object)(object)aimPivot != (Object)null)
				{
					aimPivot.localRotation = Quaternion.identity;
				}
			}
			int wanted = ((turretData.weapon != null && turretData.weapon.Exists) ? turretData.weapon.ItemID : (-1));
			int num = WeaponSignature(turretData.weapon);
			if (wanted != gunId || num != gunStateSignature)
			{
				gunId = wanted;
				gunStateSignature = num;
				Transform val = socket.Find("SocketEmpty");
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.SetActive(wanted < 0);
				}
				Gun gun = Plugin.Instance.Guns.FirstOrDefault((Gun g) => ((Item)g.prefab).ID == wanted);
				BuildMountedGun(gun, turretData.weapon);
				lastShot = turretData.shots;
				lastReload = turretData.reloads;
				lastAcquisition = turretData.acquisition;
			}
			Vector3 val2;
			if (turretData.deployed && (Object)(object)item.SyncedHolder == (Object)null && turretData.hasTarget && (Object)(object)mountedGun != (Object)null)
			{
				Vector3 direction = turretData.aim - MuzzlePosition;
				if (((Vector3)(ref direction)).sqrMagnitude > 0.01f)
				{
					AimMountedWeapon(direction, 0f, 0f);
				}
			}
			else if (turretData.deployed && (Object)(object)item.SyncedHolder == (Object)null && (Object)(object)mountedGun != (Object)null)
			{
				float num2 = Mathf.Repeat(Time.time * 12f + (float)turretData.serial * 47f, 360f);
				Vector3 up = ((Component)this).transform.up;
				val2 = Vector3.ProjectOnPlane(((Component)this).transform.forward, up);
				Vector3 normalized = ((Vector3)(ref val2)).normalized;
				if (((Vector3)(ref normalized)).sqrMagnitude < 0.01f)
				{
					val2 = Vector3.ProjectOnPlane(Vector3.forward, up);
					normalized = ((Vector3)(ref val2)).normalized;
				}
				Vector3 val3 = Quaternion.AngleAxis(num2, up) * normalized;
				val2 = Vector3.Cross(up, val3);
				Vector3 normalized2 = ((Vector3)(ref val2)).normalized;
				Vector3 direction2 = Quaternion.AngleAxis(-30f, normalized2) * val3;
				AimMountedWeapon(direction2, 20f, 45f);
			}
			else
			{
				head.localRotation = Quaternion.RotateTowards(head.localRotation, Quaternion.identity, 90f * Time.deltaTime);
				if ((Object)(object)aimPivot != (Object)null)
				{
					aimPivot.localRotation = Quaternion.RotateTowards(aimPivot.localRotation, Quaternion.identity, 90f * Time.deltaTime);
				}
			}
			if ((Object)(object)mountedGun != (Object)null)
			{
				mountedGun.transform.localPosition = mountedBasePosition;
				mountedGun.transform.localRotation = mountedBaseRotation;
				if (proceduralReload && Time.time < reloadUntil)
				{
					float num3 = Mathf.InverseLerp(reloadStarted, reloadUntil, Time.time);
					mountedGun.transform.localRotation = mountedBaseRotation * Quaternion.Euler(Mathf.Sin(num3 * (float)Math.PI) * 32f, 0f, Mathf.Sin(num3 * (float)Math.PI * 2f) * 8f);
				}
				else if (Time.time < recoilUntil)
				{
					val2 = socket.InverseTransformDirection(((Object)(object)mountedMuzzle != (Object)null) ? (-mountedMuzzle.forward) : (-head.forward));
					Vector3 normalized3 = ((Vector3)(ref val2)).normalized;
					mountedGun.transform.localPosition = mountedBasePosition + normalized3 * (Mathf.Sin(Mathf.InverseLerp(recoilUntil - 0.12f, recoilUntil, Time.time) * (float)Math.PI) * 0.07f);
				}
			}
			if (turretData.shots != lastShot)
			{
				lastShot = turretData.shots;
				if (turretData.deployed)
				{
					PlayFire(turretData);
					if ((Object)(object)tracer == (Object)null)
					{
						GameObject val4 = new GameObject("AASC tracer");
						val4.transform.SetParent(((Component)this).transform, false);
						tracer = val4.AddComponent<LineRenderer>();
						((Renderer)tracer).sharedMaterial = glow;
						tracer.startWidth = 0.025f;
						tracer.endWidth = 0.009f;
						tracer.positionCount = 2;
					}
					tracer.SetPosition(0, MuzzlePosition);
					tracer.SetPosition(1, turretData.shotAim);
					((Renderer)tracer).enabled = true;
					tracerUntil = Time.time + 0.09f;
				}
			}
			if (turretData.reloads != lastReload)
			{
				lastReload = turretData.reloads;
				Gun gun2 = Plugin.Instance.GetGun(turretData);
				if (turretData.deployed && gun2 != null)
				{
					PlayReload(turretData, gun2);
				}
			}
			if ((Object)(object)tracer != (Object)null && Time.time > tracerUntil)
			{
				((Renderer)tracer).enabled = false;
			}
			if (turretData.deployed && turretData.acquiring)
			{
				if ((Object)(object)lockLaser == (Object)null)
				{
					GameObject val5 = new GameObject("AASC target lock laser");
					val5.transform.SetParent(((Component)this).transform, false);
					lockLaser = val5.AddComponent<LineRenderer>();
					((Renderer)lockLaser).sharedMaterial = lockGlow;
					lockLaser.startWidth = 0.018f;
					lockLaser.endWidth = 0.008f;
					lockLaser.positionCount = 2;
				}
				lockLaser.SetPosition(0, MuzzlePosition);
				lockLaser.SetPosition(1, turretData.aim);
				((Renderer)lockLaser).enabled = true;
				if (turretData.acquisition != lastAcquisition)
				{
					lastAcquisition = turretData.acquisition;
					TargetSound.Play(((Component)this).transform.position);
				}
			}
			else if ((Object)(object)lockLaser != (Object)null)
			{
				((Renderer)lockLaser).enabled = false;
			}
		}
	}
	[BepInPlugin("ponyfisher.howtofish.aasc", "TURRET MOD", "0.1.18")]
	[DefaultExecutionOrder(29000)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "ponyfisher.howtofish.aasc";

		public static Plugin Instance;

		public List<Gun> Guns = new List<Gun>();

		public List<TurretData> Current = new List<TurretData>();

		public bool Open;

		public string Status = "Load a game, then buy an empty turret kit.";

		public int Selected;

		private SaveData save = new SaveData();

		private WorldData world;

		private NetworkManager manager;

		private Harmony harmony;

		private string savePath;

		private bool persistenceReady = true;

		private bool registrationFailed;

		private bool catalogReady;

		private float nextTick;

		private float nextSave;

		private float nextState;

		private float nextHello;

		private int sequence;

		private readonly Dictionary<int, int> lastSequence = new Dictionary<int, int>();

		private readonly Dictionary<int, float> rateLimit = new Dictionary<int, float>();

		private readonly Dictionary<int, Item> kits = new Dictionary<int, Item>();

		private Rect panel = new Rect(40f, 60f, 730f, 640f);

		private Vector2 turretScroll;

		private Vector2 gunScroll;

		private bool socketOpen;

		private string nameDraft = "";

		private string confirmAction = "";

		private int nameSerial;

		private CursorLockMode oldLock;

		private GUIStyle titleStyle;

		private GUIStyle bodyStyle;

		private GUIStyle slotStyle;

		private GUIStyle windowStyle;

		private GUIStyle buttonStyle;

		private GUIStyle accentButton;

		private GUIStyle dangerButton;

		private GUIStyle selectedButton;

		private GUIStyle inputStyle;

		private GUIStyle headerStyle;

		private GUIStyle statusStyle;

		private GUIStyle toggleStyle;

		private Texture2D steel;

		private Texture2D steelInset;

		private Texture2D steelEdge;

		private Texture2D cyan;

		private Texture2D cyanHover;

		private Texture2D orange;

		private Texture2D orangeHover;

		private Texture2D red;

		private Texture2D redHover;

		private float holdStart;

		private int holdSerial;

		private bool holdFired;

		private string holdAction;

		private GUIStyle turretLabelStyle;

		private bool audited;

		private float auditAfter;

		private readonly Dictionary<int, float> missingSince = new Dictionary<int, float>();

		public static void Log(string text)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)text);
			}
		}

		private void Awake()
		{
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Expected O, but got Unknown
			Instance = this;
			savePath = Path.Combine(Paths.ConfigPath, "AASC-worlds.json");
			try
			{
				if (File.Exists(savePath))
				{
					save = Codec.FromJson<SaveData>(File.ReadAllText(savePath));
					if (save == null || save.version != 1 || save.worlds == null)
					{
						throw new Exception("Unrecognized save format");
					}
				}
			}
			catch (Exception ex)
			{
				persistenceReady = false;
				Status = "Turret Mod save could not be read. Purchases disabled to protect it.";
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
			GenericWriter<RequestMessage>.SetWrite((Action<Writer, RequestMessage>)delegate(Writer w, RequestMessage v)
			{
				w.WriteString(v.json);
			});
			GenericReader<RequestMessage>.SetRead((Func<Reader, RequestMessage>)((Reader r) => new RequestMessage
			{
				json = r.ReadStringAllocated()
			}));
			GenericWriter<StateMessage>.SetWrite((Action<Writer, StateMessage>)delegate(Writer w, StateMessage v)
			{
				w.WriteString(v.json);
			});
			GenericReader<StateMessage>.SetRead((Func<Reader, StateMessage>)((Reader r) => new StateMessage
			{
				json = r.ReadStringAllocated()
			}));
			GenericWriter<ReplyMessage>.SetWrite((Action<Writer, ReplyMessage>)delegate(Writer w, ReplyMessage v)
			{
				w.WriteString(v.json);
			});
			GenericReader<ReplyMessage>.SetRead((Func<Reader, ReplyMessage>)((Reader r) => new ReplyMessage
			{
				json = r.ReadStringAllocated()
			}));
			harmony = new Harmony("ponyfisher.howtofish.aasc");
			harmony.PatchAll(typeof(Plugin).Assembly);
			Log("TURRET MOD 0.1.18 loaded. Compound upgrades and progressive turret pricing enabled.");
		}

		private void Update()
		{
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			if (Keyboard.current != null && ((ButtonControl)Keyboard.current.f2Key).wasPressedThisFrame)
			{
				Toggle(!Open);
			}
			UpdateHoldInteraction();
			if ((Object)(object)manager != (Object)(object)InstanceFinder.NetworkManager)
			{
				RegisterNetwork();
			}
			if (!registrationFailed && (Object)(object)Kit.Prefab == (Object)null)
			{
				try
				{
					Kit.Register();
				}
				catch (Exception ex)
				{
					registrationFailed = true;
					Status = "Turret item registration failed; see BepInEx log.";
					((BaseUnityPlugin)this).Logger.LogError((object)ex);
				}
			}
			if ((Object)(object)Kit.Prefab != (Object)null && !catalogReady)
			{
				BuildCatalog();
				catalogReady = true;
			}
			if (InstanceFinder.IsServerStarted && SaveManager.CurServerSave != null)
			{
				string name = SaveManager.CurServerSave.Name;
				if (world == null || world.name != name)
				{
					world = save.worlds.FirstOrDefault((WorldData w) => w.name == name);
					if (world == null)
					{
						world = new WorldData
						{
							name = name
						};
						save.worlds.Add(world);
					}
					Current = world.turrets;
					audited = false;
					auditAfter = Time.unscaledTime + 5f;
					missingSince.Clear();
					kits.Clear();
					lastSequence.Clear();
					rateLimit.Clear();
					foreach (TurretData item in Current)
					{
						item.nextShot = Time.time + 1f;
						item.reloading = false;
						item.lockedTarget = null;
						item.acquiring = false;
						item.hasTarget = false;
					}
				}
				if (Time.unscaledTime >= nextTick)
				{
					nextTick = Time.unscaledTime + 0.1f;
					ServerTick();
				}
				if (Time.unscaledTime >= nextState)
				{
					nextState = Time.unscaledTime + 0.25f;
					Broadcast();
				}
				if (Time.unscaledTime >= nextSave)
				{
					nextSave = Time.unscaledTime + 10f;
					Persist();
				}
			}
			else if (!InstanceFinder.IsClientStarted)
			{
				world = null;
				Current = new List<TurretData>();
				kits.Clear();
			}
			if (Open && InstanceFinder.IsClientStarted && !InstanceFinder.IsServerStarted && Time.unscaledTime >= nextHello)
			{
				nextHello = Time.unscaledTime + 3f;
				Send("hello");
			}
		}

		private void LateUpdate()
		{
			if (Open)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}

		private void RegisterNetwork()
		{
			if ((Object)(object)manager != (Object)null)
			{
				manager.ServerManager.UnregisterBroadcast<RequestMessage>((Action<NetworkConnection, RequestMessage, Channel>)Receive);
				manager.ClientManager.UnregisterBroadcast<StateMessage>((Action<StateMessage, Channel>)ReceiveState);
				manager.ClientManager.UnregisterBroadcast<ReplyMessage>((Action<ReplyMessage, Channel>)ReceiveReply);
			}
			manager = InstanceFinder.NetworkManager;
			if (!((Object)(object)manager == (Object)null))
			{
				manager.ServerManager.RegisterBroadcast<RequestMessage>((Action<NetworkConnection, RequestMessage, Channel>)Receive, true);
				manager.ClientManager.RegisterBroadcast<StateMessage>((Action<StateMessage, Channel>)ReceiveState);
				manager.ClientManager.RegisterBroadcast<ReplyMessage>((Action<ReplyMessage, Channel>)ReceiveReply);
			}
		}

		private static float ReadReload(Weapon weapon, GunClass kind)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Animation val = (Animation)AccessTools.Field(typeof(Tool), "_anim").GetValue(weapon);
			bool flag = (bool)AccessTools.Field(typeof(Weapon), "_hasLastReloadAnim").GetValue(weapon);
			AnimationState val2 = (((Object)(object)val == (Object)null) ? null : val[flag ? "ReloadLast" : "Reload"]);
			if ((TrackedReference)(object)val2 != (TrackedReference)null && val2.length > 0f)
			{
				return val2.length / Mathf.Max(0.01f, Mathf.Abs(val2.speed));
			}
			Log("Missing reload animation for " + ((Object)weapon).name + "; using fallback timing.");
			return Rules.Reload(kind, 0);
		}

		private void BuildCatalog()
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			Dictionary<byte, Item> obj = (Dictionary<byte, Item>)AccessTools.Field(typeof(GameInfo), "_idToSpawnable").GetValue(null);
			Guns.Clear();
			foreach (Weapon item in from w in obj.Values.OfType<Weapon>()
				orderby ((Item)w).Cost
				select w)
			{
				WeaponInfo val = (WeaponInfo)AccessTools.Field(typeof(Weapon), "_weaponInfo").GetValue(item);
				if (val != null)
				{
					GunClass kind = Rules.Classify(((Object)item).name);
					int pellets = (int)AccessTools.Field(typeof(Weapon), "_projectileCountPerShot").GetValue(item);
					if (pellets > 1)
					{
						kind = GunClass.Shotgun;
					}
					else if ((Object)(object)item.Attachments != (Object)null && item.Attachments.UseSniperUi)
					{
						kind = GunClass.Sniper;
					}
					BulletUpgrade[] array = (BulletUpgrade[])AccessTools.Field(typeof(Attachments), "_bulletUpgrades").GetValue(item.Attachments);
					int val2 = (int)AccessTools.Field(typeof(Attachments), "_defaultAmmoPerMag").GetValue(item.Attachments);
					int val3 = (int)AccessTools.Field(typeof(Attachments), "_extendedAmmoPerMag").GetValue(item.Attachments);
					Guns.Add(new Gun
					{
						prefab = item,
						name = ((Object)item).name.Replace("(Clone)", ""),
						kind = kind,
						damage = Math.Max(1, val.ProjectileDamage) * Math.Max(1, pellets),
						ammoDamages = array?.Select((BulletUpgrade x) => Math.Max(1, x.Damage) * Math.Max(1, pellets)).ToArray(),
						price = Math.Max(250, ((Item)item).Cost),
						magazine = Math.Max(1, val2),
						extendedMagazine = Math.Max(Math.Max(1, val2), val3),
						reload = ReadReload(item, kind)
					});
				}
			}
			foreach (Gun gun in Guns)
			{
				Log("Gun " + gun.name + ": " + gun.kind.ToString() + ", range=" + Rules.Radius(gun.kind, 0) + ", magazine=" + gun.magazine + ", reload=" + gun.reload);
			}
			Log("Loaded " + Guns.Count + " socketable base-game guns.");
		}

		public TurretData Find(int id)
		{
			return Current.FirstOrDefault((TurretData t) => t.serial == id);
		}

		public Gun GetGun(TurretData t)
		{
			if (t.weapon != null)
			{
				return Guns.FirstOrDefault((Gun g) => ((Item)g.prefab).ID == t.weapon.ItemID);
			}
			return null;
		}

		public void Persist()
		{
			if (!persistenceReady || !InstanceFinder.IsServerStarted || world == null)
			{
				return;
			}
			try
			{
				string text = savePath + ".tmp";
				File.WriteAllText(text, Codec.ToJson(save, pretty: true));
				if (File.Exists(savePath))
				{
					File.Replace(text, savePath, savePath + ".bak");
				}
				else
				{
					File.Move(text, savePath);
				}
			}
			catch (Exception ex)
			{
				persistenceReady = false;
				Status = "Turret Mod could not save; purchases paused. Check disk access.";
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		public void Send(string action, int argument = 0, Vector3 position = default(Vector3), string text = null, Vector3 normal = default(Vector3))
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.LocalPlayer == (Object)null)
			{
				Status = "Load a game first.";
				return;
			}
			Command command = new Command
			{
				action = action,
				serial = Selected,
				argument = argument,
				position = position,
				normal = normal,
				text = text,
				sequence = ++sequence
			};
			if (InstanceFinder.IsServerStarted)
			{
				Execute(Player.LocalPlayer, command, null);
			}
			else if ((Object)(object)manager != (Object)null && InstanceFinder.IsClientStarted)
			{
				manager.ClientManager.Broadcast<RequestMessage>(new RequestMessage
				{
					json = Codec.ToJson(command)
				}, (Channel)0);
				if (action != "hello")
				{
					Status = "Waiting for the host...";
				}
			}
		}

		private void Receive(NetworkConnection connection, RequestMessage message, Channel channel)
		{
			if (!InstanceFinder.IsServerStarted || message.json == null || message.json.Length > 1024)
			{
				return;
			}
			try
			{
				Command command = Codec.FromJson<Command>(message.json);
				if (command != null && command.protocol == 3 && command.sequence > 0 && (!lastSequence.TryGetValue(connection.ClientId, out var value) || command.sequence > value) && (!rateLimit.TryGetValue(connection.ClientId, out var value2) || !(Time.unscaledTime - value2 < 0.12f)))
				{
					lastSequence[connection.ClientId] = command.sequence;
					rateLimit[connection.ClientId] = Time.unscaledTime;
					Player val = ((IEnumerable<Player>)Object.FindObjectsByType<Player>()).FirstOrDefault((Func<Player, bool>)((Player p) => ((NetworkBehaviour)p).Owner == connection));
					if ((Object)(object)val != (Object)null)
					{
						Execute(val, command, connection);
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Rejected AASC request: " + ex.Message));
			}
		}

		private void Respond(Command cmd, NetworkConnection connection, string message, int selected = 0)
		{
			Reply value = new Reply
			{
				sequence = cmd.sequence,
				serial = selected,
				message = message
			};
			if (connection == (NetworkConnection)null || connection.IsLocalClient)
			{
				Status = message;
				if (selected > 0)
				{
					Selected = selected;
				}
			}
			else
			{
				manager.ServerManager.Broadcast<ReplyMessage>(connection, new ReplyMessage
				{
					json = Codec.ToJson(value)
				}, true, (Channel)0);
			}
		}

		private void ReceiveReply(ReplyMessage message, Channel channel)
		{
			Reply reply = Codec.FromJson<Reply>(message.json);
			Status = reply.message;
			if (reply.serial > 0)
			{
				Selected = reply.serial;
			}
		}

		private void ReceiveState(StateMessage message, Channel channel)
		{
			if (!InstanceFinder.IsServerStarted && message.json != null && message.json.Length <= 200000)
			{
				Snapshot snapshot = Codec.FromJson<Snapshot>(message.json);
				if (snapshot != null && snapshot.protocol == 3 && snapshot.turrets != null)
				{
					Current = snapshot.turrets;
				}
			}
		}

		private void Broadcast()
		{
			if ((Object)(object)manager != (Object)null && world != null)
			{
				manager.ServerManager.Broadcast<StateMessage>(new StateMessage
				{
					json = Codec.ToJson(new Snapshot
					{
						world = world.name,
						turrets = Current
					})
				}, true, (Channel)0);
			}
		}

		private void ScanKits()
		{
			kits.Clear();
			Item[] array = Object.FindObjectsByType<Item>((FindObjectsInactive)1);
			foreach (Item val in array)
			{
				if (Kit.Is(val) && ((NetworkBehaviour)val).IsSpawned && !((NetworkBehaviour)val).IsDeinitializing)
				{
					int num = Kit.Serial(val);
					if (num > 0 && !kits.ContainsKey(num))
					{
						kits.Add(num, val);
					}
				}
			}
		}

		private Item FindKit(int serial)
		{
			if (kits.TryGetValue(serial, out var value) && (Object)(object)value != (Object)null && ((NetworkBehaviour)value).IsSpawned && !((NetworkBehaviour)value).IsDeinitializing)
			{
				return value;
			}
			value = ((IEnumerable<Item>)Object.FindObjectsByType<Item>((FindObjectsInactive)1)).FirstOrDefault((Func<Item, bool>)((Item candidate) => Kit.Is(candidate) && ((NetworkBehaviour)candidate).IsSpawned && !((NetworkBehaviour)candidate).IsDeinitializing && Kit.Serial(candidate) == serial));
			if ((Object)(object)value != (Object)null)
			{
				kits[serial] = value;
			}
			return value;
		}

		public float ManagementDistance(TurretData turret, Player player)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			if (turret == null || (Object)(object)player == (Object)null)
			{
				return float.PositiveInfinity;
			}
			Item val = FindKit(turret.serial);
			Vector3 val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform.position : turret.position);
			float num = Vector3.Distance(((Component)player).transform.position, val2);
			if ((Object)(object)player.CamObject != (Object)null)
			{
				num = Mathf.Min(num, Vector3.Distance(player.CamObject.position, val2));
			}
			if ((Object)(object)val != (Object)null)
			{
				Collider[] componentsInChildren = ((Component)val).GetComponentsInChildren<Collider>(true);
				foreach (Collider val3 in componentsInChildren)
				{
					if (!((Object)(object)val3 == (Object)null) && val3.enabled && !val3.isTrigger)
					{
						num = Mathf.Min(num, Vector3.Distance(((Component)player).transform.position, val3.ClosestPoint(((Component)player).transform.position)));
						if ((Object)(object)player.CamObject != (Object)null)
						{
							num = Mathf.Min(num, Vector3.Distance(player.CamObject.position, val3.ClosestPoint(player.CamObject.position)));
						}
					}
				}
			}
			return num;
		}

		private int OpenSlot(Player p)
		{
			int num = (int)AccessTools.Method(typeof(PlayerInventory), "GetTotalSlots", (Type[])null, (Type[])null).Invoke(p.Inventory, null);
			Item val = default(Item);
			for (byte b = 0; b < num; b++)
			{
				if (!p.Inventory._items.TryGetValue(b, ref val) || (Object)(object)val == (Object)null)
				{
					return b;
				}
			}
			return -1;
		}

		private Item SpawnForInventory(Item prefab, Player player, int slot, SavedItem data = null)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			Item val = Object.Instantiate<Item>(prefab, ((Component)player).transform.position + Vector3.up, Quaternion.identity, Server.Instance.DynamicObjectsHolder);
			if (data != null)
			{
				val.LoadFromSave(data);
			}
			InstanceFinder.ServerManager.Spawn(((Component)val).gameObject, (NetworkConnection)null, default(Scene));
			if (data != null)
			{
				val.ServerSetSkin(data.SkinIndex);
			}
			val.SetSyncedHolder(player, true);
			player.Inventory.AddItem((byte)slot, val);
			if (!player.Inventory.HasItemInInventory(val))
			{
				InstanceFinder.ServerManager.Despawn(((Component)val).gameObject, (DespawnType?)null);
				throw new Exception("The inventory did not accept the item; nothing was charged.");
			}
			return val;
		}

		private bool Ground(Player player, Vector3 requested, Vector3 requestedNormal, Item kit, out RaycastHit hit, out string reason)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			hit = default(RaycastHit);
			reason = "Look at a supported surface within 8 metres.";
			if (!Rules.Finite(requested.x) || !Rules.Finite(requested.y) || !Rules.Finite(requested.z) || !Rules.Finite(requestedNormal.x) || !Rules.Finite(requestedNormal.y) || !Rules.Finite(requestedNormal.z))
			{
				return false;
			}
			if (Vector3.Distance(requested, player.CamObject.position) > 8.35f || !Rules.SurfaceAllowed(requestedNormal.y))
			{
				return false;
			}
			Vector3 normalized = ((Vector3)(ref requestedNormal)).normalized;
			foreach (RaycastHit item in from val in Physics.RaycastAll(requested + normalized * 0.35f, -normalized, 0.7f, -1, (QueryTriggerInteraction)1)
				orderby ((RaycastHit)(ref val)).distance
				select val)
			{
				RaycastHit h = item;
				if (((Component)((RaycastHit)(ref h)).collider).gameObject.layer != LayerMask.NameToLayer("Water") && !((Object)(object)((Component)((RaycastHit)(ref h)).collider).GetComponentInParent<Player>() != (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref h)).collider).GetComponentInParent<Item>() != (Object)null) && Rules.SurfaceAllowed(((RaycastHit)(ref h)).normal.y) && !(Vector3.Dot(((RaycastHit)(ref h)).normal, normalized) < 0.5f))
				{
					if (Current.Any((TurretData t) => t.deployed && t.serial != Kit.Serial(kit) && Vector3.Distance(t.position, ((RaycastHit)(ref h)).point) < 0.55f))
					{
						reason = "Another turret is too close to that point.";
						return false;
					}
					hit = h;
					return true;
				}
			}
			return false;
		}

		private void Execute(Player player, Command cmd, NetworkConnection connection)
		{
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Expected O, but got Unknown
			//IL_0469: Unknown result type (might be due to invalid IL or missing references)
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_058c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0593: Unknown result type (might be due to invalid IL or missing references)
			//IL_059d: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05af: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0600: Unknown result type (might be due to invalid IL or missing references)
			//IL_0605: Unknown result type (might be due to invalid IL or missing references)
			//IL_060a: Unknown result type (might be due to invalid IL or missing references)
			//IL_060f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0614: Unknown result type (might be due to invalid IL or missing references)
			//IL_061b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0620: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b63: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b69: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b6d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b73: Unknown result type (might be due to invalid IL or missing references)
			//IL_0682: Unknown result type (might be due to invalid IL or missing references)
			//IL_0688: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e4e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e53: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e5a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e6c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e77: Unknown result type (might be due to invalid IL or missing references)
			//IL_0e87: Expected O, but got Unknown
			if (cmd.action == "hello")
			{
				Broadcast();
				return;
			}
			if (!persistenceReady || world == null || (Object)(object)Kit.Prefab == (Object)null || player.Dying.IsDead)
			{
				Respond(cmd, connection, "Turret Mod is not ready. Check the host's mod and save status.");
				return;
			}
			ScanKits();
			try
			{
				if (cmd.action == "buykit")
				{
					int num = OpenSlot(player);
					if (num < 0)
					{
						Respond(cmd, connection, "Free an inventory slot first.");
						return;
					}
					int num2 = Current.Count((TurretData t) => t.available && t.owner == player.SteamID);
					if (num2 >= 8 || Current.Count((TurretData t) => t.available) >= 32)
					{
						Respond(cmd, connection, "Turret limit reached (8 per player, 32 per world).");
						return;
					}
					int num3 = Rules.TurretPrice(num2);
					if (!Wallet.CanAfford(player, num3))
					{
						Respond(cmd, connection, "Not enough money. Your next empty turret costs $" + num3.ToString("N0") + ".");
						return;
					}
					if (save.nextSerial >= 16000000)
					{
						throw new Exception("Turret serial limit reached.");
					}
					int num4 = save.nextSerial++;
					Item val = SpawnForInventory(Kit.Prefab, player, num, new SavedItem
					{
						Exists = true,
						ItemID = 250,
						BettingMultiplier = num4
					});
					if (!Wallet.Charge(player, num3))
					{
						InstanceFinder.ServerManager.Despawn(((Component)val).gameObject, (DespawnType?)null);
						Respond(cmd, connection, "Payment failed; purchase cancelled.");
						return;
					}
					Current.Add(new TurretData
					{
						serial = num4,
						owner = player.SteamID,
						ownerName = player.SteamName,
						purchasePrice = num3
					});
					Persist();
					Broadcast();
					Respond(cmd, connection, "Turret kit purchased for $" + num3.ToString("N0") + " and added to your inventory.", num4);
					return;
				}
				TurretData turretData = Find(cmd.serial);
				Item val2 = FindKit(cmd.serial);
				if (turretData == null || (Object)(object)val2 == (Object)null)
				{
					Respond(cmd, connection, "That turret is no longer available.");
					return;
				}
				bool flag = (Object)(object)val2.SyncedHolder == (Object)(object)player;
				bool flag2 = (Object)(object)player.Holding.HeldItem == (Object)(object)val2 || (Object)(object)player.Holding.UninitializedHeldItem == (Object)(object)val2;
				bool flag3 = turretData.owner == player.SteamID;
				bool flag4 = cmd.action == "pickup" && turretData.deployed;
				if (!flag3 && !flag4 && cmd.action != "takeownership")
				{
					Respond(cmd, connection, "This turret belongs to " + (string.IsNullOrWhiteSpace(turretData.ownerName) ? turretData.owner.ToString() : turretData.ownerName) + ". Pick it up and use Take ownership in F2 first.");
					return;
				}
				float distance = ManagementDistance(turretData, player);
				if (cmd.action != "recall" && !flag && !Rules.InManagementRange(distance))
				{
					Respond(cmd, connection, "Move within " + 12f.ToString("0") + " metres of the turret.");
					return;
				}
				if (cmd.action == "deploy")
				{
					if (turretData.deployed)
					{
						Respond(cmd, connection, "This turret is already deployed.");
						return;
					}
					if (!Ground(player, cmd.position, cmd.normal, val2, out var hit, out var reason))
					{
						Respond(cmd, connection, reason);
						return;
					}
					val2.SpawnFromInventory();
					player.Inventory.RemoveItem(val2);
					if ((Object)(object)val2.Holder != (Object)null)
					{
						val2.Drop(false, default(Vector3), default(Vector3));
					}
					val2.SetSyncedHolder((Player)null, true);
					val2.ReconcileLocalHolderWithSyncedHolder();
					if ((Object)(object)player.Holding.HeldItem == (Object)(object)val2)
					{
						player.Hands.DropItem(false, val2);
						player.Holding.DropItem(false, val2);
					}
					if ((Object)(object)player.Holding.UninitializedHeldItem == (Object)(object)val2)
					{
						player.Holding.SetUninitializedHeldItem((Item)null);
					}
					if ((Object)(object)val2.SyncedHolder != (Object)null || (Object)(object)val2.Holder != (Object)null)
					{
						throw new Exception("Turret holder did not release; deployment cancelled.");
					}
					val2.RigidbodySync.ServerSetSyncedSimulator(((NetworkBehaviour)Server.Instance).Owner);
					turretData.position = ((RaycastHit)(ref hit)).point + ((RaycastHit)(ref hit)).normal * 0.01f;
					turretData.surfaceNormal = ((RaycastHit)(ref hit)).normal;
					Quaternion curPlayerRot = player.CurPlayerRot;
					turretData.yaw = ((Quaternion)(ref curPlayerRot)).eulerAngles.y;
					turretData.deployed = true;
					turretData.aim = turretData.position + player.CurPlayerRot * Vector3.forward * 5f + Vector3.up;
					turretData.shotAim = turretData.aim;
					turretData.lockedTarget = null;
					turretData.acquiring = false;
					turretData.hasTarget = false;
					Gun gun = GetGun(turretData);
					turretData.ammo = gun?.Magazine(turretData.weapon) ?? 0;
					turretData.reloading = false;
					turretData.nextShot = Time.time;
					((Component)val2).gameObject.SetActive(true);
					val2.RigidbodySync.TeleportToPosRot(turretData.position, turretData.BaseRotation, (float[])null, (Quaternion[])null);
					val2.RigidbodySync.SetKinematic(true);
					Status = "Turret deployed and loaded.";
					Log("Deployed #" + turretData.serial + " at " + ((object)Unsafe.As<Vector3, Vector3>(ref turretData.position)/*cast due to .constrained prefix*/).ToString() + ", gun=" + ((gun == null) ? "empty" : gun.name) + ", ammo=" + turretData.ammo);
				}
				else if (cmd.action == "pickup" || cmd.action == "recall")
				{
					if (flag)
					{
						Respond(cmd, connection, "Turret already in your inventory.");
						return;
					}
					int num5 = OpenSlot(player);
					bool emptyHands = (Object)(object)player.Holding.HeldItem == (Object)null && (Object)(object)player.Holding.UninitializedHeldItem == (Object)null && (Object)(object)player.Inventory.SyncedCurItem == (Object)null;
					if (!Rules.CanRecall(num5 >= 0, emptyHands))
					{
						Respond(cmd, connection, "Free an inventory slot or empty your hands before recalling this turret.");
						return;
					}
					turretData.deployed = false;
					turretData.lockedTarget = null;
					turretData.acquiring = false;
					turretData.hasTarget = false;
					val2.RigidbodySync.SetKinematic(false);
					int value = player.Inventory._syncedCurSlot.Value;
					val2.SetSyncedHolder(player, true);
					if (num5 >= 0)
					{
						player.Inventory.AddItem((byte)num5, val2);
					}
					val2.ReconcileLocalHolderWithSyncedHolder();
					if (num5 >= 0)
					{
						player.Inventory.ServerSetSyncedCurSlot(value);
					}
					string text = ((num5 >= 0) ? "inventory" : "empty hands");
					Status = (flag3 ? ("Turret recalled to " + text + " with its gun and upgrades.") : ("Turret picked up into your " + text + ". It is still owned by " + (string.IsNullOrWhiteSpace(turretData.ownerName) ? turretData.owner.ToString() : turretData.ownerName) + "."));
				}
				else if (cmd.action == "takeownership")
				{
					if (flag3)
					{
						Respond(cmd, connection, "You already own this turret.");
						return;
					}
					if (!flag2)
					{
						Respond(cmd, connection, "Hold this turret in your hands before taking ownership.");
						return;
					}
					if (Current.Count((TurretData x) => x.available && x.owner == player.SteamID) >= 8)
					{
						Respond(cmd, connection, "You already own the maximum of eight turrets.");
						return;
					}
					string text2 = (string.IsNullOrWhiteSpace(turretData.ownerName) ? turretData.owner.ToString() : turretData.ownerName);
					turretData.owner = player.SteamID;
					turretData.ownerName = player.SteamName;
					Status = "Ownership transferred from " + text2 + " to " + player.SteamName + ".";
				}
				else if (cmd.action == "friendlyfire")
				{
					turretData.friendlyFire = cmd.argument == 1;
					Status = (turretData.friendlyFire ? "Friendly fire enabled." : "Friendly fire disabled.");
				}
				else if (cmd.action == "sell")
				{
					if (turretData.weapon != null && turretData.weapon.Exists)
					{
						Respond(cmd, connection, "Remove the gun before selling the turret.");
						return;
					}
					int amount = Rules.ResaleValue(turretData.purchasePrice, turretData.level, turretData.tier);
					turretData.deployed = false;
					turretData.lockedTarget = null;
					turretData.acquiring = false;
					turretData.hasTarget = false;
					Player[] array = Object.FindObjectsByType<Player>((FindObjectsInactive)1);
					foreach (Player val3 in array)
					{
						val3.Inventory.RemoveItem(val2);
						if ((Object)(object)val3.Holding.HeldItem == (Object)(object)val2)
						{
							val3.Hands.DropItem(false, val2);
							val3.Holding.DropItem(false, val2);
							val3.Holding.SetHeldItem((Item)null);
						}
						if ((Object)(object)val3.Holding.UninitializedHeldItem == (Object)(object)val2)
						{
							val3.Holding.SetUninitializedHeldItem((Item)null);
						}
					}
					if ((Object)(object)val2.Holder != (Object)null)
					{
						val2.Drop(false, default(Vector3), default(Vector3));
					}
					val2.SpawnFromInventory();
					val2.SetSyncedHolder((Player)null, true);
					val2.ReconcileLocalHolderWithSyncedHolder();
					InstanceFinder.ServerManager.Despawn(((Component)val2).gameObject, (DespawnType?)null);
					Wallet.Credit(player, amount);
					world.retired.Add(turretData.serial);
					Current.Remove(turretData);
					kits.Remove(turretData.serial);
					Selected = 0;
					Status = "Turret sold for $" + amount.ToString("N0") + " (half of its kit, upgrade, and targeting-tier investment).";
				}
				else if (cmd.action == "rename")
				{
					turretData.customName = Rules.CleanName(cmd.text);
					Status = "Turret name saved.";
				}
				else if (cmd.action == "upgrade")
				{
					int num7 = Rules.UpgradePrice(turretData.level);
					if (num7 == 0)
					{
						Respond(cmd, connection, "Maximum upgrade level reached.");
						return;
					}
					if (!Wallet.Charge(player, num7))
					{
						Respond(cmd, connection, "Not enough money for this upgrade.");
						return;
					}
					turretData.level++;
					Status = "Turret upgraded to level " + turretData.level + " / 10.";
				}
				else if (cmd.action == "tier")
				{
					int num8 = Rules.TierPrice(turretData.tier);
					if (num8 == 0)
					{
						Respond(cmd, connection, "Boss targeting already unlocked.");
						return;
					}
					if (!Wallet.Charge(player, num8))
					{
						Respond(cmd, connection, "Not enough money for this targeting tier.");
						return;
					}
					turretData.tier++;
					Status = ((turretData.tier == 1) ? "Fish targeting unlocked; seagulls remain enabled." : "Boss targeting unlocked; all target tiers enabled.");
				}
				else if (cmd.action == "buygun")
				{
					Gun gun2 = Guns.FirstOrDefault((Gun g) => ((Item)g.prefab).ID == cmd.argument);
					if (gun2 == null)
					{
						return;
					}
					if (!Rules.NeedsWeaponPurchase((turretData.weapon != null && turretData.weapon.Exists) ? turretData.weapon.ItemID : (-1), ((Item)gun2.prefab).ID))
					{
						Respond(cmd, connection, gun2.name + " is already equipped. No money was charged.", turretData.serial);
						return;
					}
					if (!Wallet.Charge(player, gun2.price))
					{
						Respond(cmd, connection, "Not enough money for that weapon.");
						return;
					}
					turretData.weapon = new SavedItem
					{
						Exists = true,
						ItemID = ((Item)gun2.prefab).ID,
						BettingMultiplier = 1f,
						Weight = 1f
					};
					turretData.ammo = gun2.Magazine(turretData.weapon);
					turretData.reloading = false;
					turretData.nextShot = Time.time + 1f;
					Status = gun2.name + " purchased and equipped. The previous turret gun was replaced.";
				}
				else
				{
					if (!(cmd.action == "unequip") || turretData.weapon == null || !turretData.weapon.Exists)
					{
						return;
					}
					turretData.weapon = null;
					turretData.ammo = 0;
					turretData.reloading = false;
					turretData.hasTarget = false;
					turretData.lockedTarget = null;
					Status = "Gun removed from the turret.";
				}
				Persist();
				Broadcast();
				Respond(cmd, connection, Status, turretData.serial);
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogErr