Decompiled source of Portable Grill Mod v0.1.2

BepInEx/plugins/PortableGrillMod/PortableGrillMod.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Bootstrap;
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 PortableGrillMod
{
	public static class Rules
	{
		public const byte ItemId = 247;

		public const ushort PrefabCollection = 42423;

		public const int Price = 2500;

		public const int ResalePrice = 1250;

		public const float UseRange = 5f;

		public const float VendorRange = 5f;

		public const float VendorLookDot = 0.72f;

		public const float DeployRange = 8f;

		public const float HoldSeconds = 1f;

		public const float VanillaCookPerTick = 0.025f;

		public const float CookSpeedMultiplier = 0.9f;

		public const float CookPerTick = 0.022499999f;

		public const float CookingTriggerWidth = 0.88f;

		public const float CookingTriggerHeight = 1.1f;

		public const float CookingTriggerDepth = 0.68f;

		public const float CookingTriggerCenterY = 0.8f;

		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 CanPickUp(bool freeSlot, bool emptyHands)
		{
			return freeSlot || emptyHands;
		}

		public static bool CanUseVendor(float distance, float lookDot)
		{
			if (Finite(distance) && Finite(lookDot) && distance <= 5.35f)
			{
				return lookDot >= 0.72f;
			}
			return false;
		}
	}
	[Serializable]
	public sealed class GrillData
	{
		public int serial;

		public ulong owner;

		public string ownerName;

		public bool deployed;

		public bool available = true;

		public Vector3 position;

		public Vector3 surfaceNormal = Vector3.up;

		public float yaw;

		public Quaternion Rotation => 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<GrillData> grills = new List<GrillData>();
	}
	[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 = 1;

		public int sequence;

		public int serial;

		public string action;

		public Vector3 position;

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

		public string world;

		public List<GrillData> grills = new List<GrillData>();
	}
	[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 static class Codec
	{
		private sealed class Fields : DefaultContractResolver
		{
			protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization mode)
			{
				return (from f in type.GetFields(BindingFlags.Instance | BindingFlags.Public)
					where !f.IsNotSerialized
					select ((DefaultContractResolver)this).CreateProperty((MemberInfo)f, (MemberSerialization)2)).ToList();
			}
		}

		private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
		{
			ContractResolver = (IContractResolver)(object)new Fields(),
			TypeNameHandling = (TypeNameHandling)0,
			ObjectCreationHandling = (ObjectCreationHandling)2,
			MaxDepth = 24
		};

		public static string ToJson(object value, bool pretty = false)
		{
			return JsonConvert.SerializeObject(value, (Formatting)(pretty ? 1 : 0), Settings);
		}

		public static T FromJson<T>(string json)
		{
			return JsonConvert.DeserializeObject<T>(json, Settings);
		}
	}
	public static class GrillItem
	{
		public static Item Prefab;

		private static GameObject storage;

		public static bool Is(Item item)
		{
			if ((Object)(object)item != (Object)null && item.ID == 247)
			{
				return (Object)(object)((Component)item).GetComponent<PortableGrillVisual>() != (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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Expected O, but got Unknown
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Expected O, but got Unknown
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_0494: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: 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(247))
			{
				throw new Exception("Portable Grill item ID 247 is already in use.");
			}
			Item? obj = (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)obj == (Object)null)
			{
				throw new Exception("No compatible base item prefab was found.");
			}
			storage = new GameObject("Portable Grill prefab storage");
			storage.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)storage);
			Item val = Object.Instantiate<Item>(obj, storage.transform);
			((Object)val).name = "Portable Grill";
			AccessTools.Field(typeof(Item), "_id").SetValue(val, (byte)247);
			AccessTools.Field(typeof(Item), "_cost").SetValue(val, 2500);
			AccessTools.Field(typeof(Item), "_worth").SetValue(val, 1250);
			AccessTools.Field(typeof(Item), "_ignoredBySeagulls").SetValue(val, true);
			AccessTools.Field(typeof(Item), "_ignoredByMoneyNPC").SetValue(val, false);
			AccessTools.Field(typeof(Item), "_ignoredByCloseDots").SetValue(val, false);
			AccessTools.Field(typeof(Item), "_heldPos").SetValue(val, (object)new Vector3(0.2f, -0.48f, 0.78f));
			AccessTools.Field(typeof(Item), "_heldRot").SetValue(val, (object)new Vector3(8f, 12f, 0f));
			Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<Renderer>(true);
			for (int num = 0; num < componentsInChildren.Length; num++)
			{
				componentsInChildren[num].enabled = false;
			}
			Collider[] componentsInChildren2 = ((Component)val).GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren2)
			{
				if (!val2.isTrigger)
				{
					val2.enabled = false;
				}
			}
			GameObject val3 = new GameObject("PortableGrillBodyCollider");
			val3.transform.SetParent(((Component)val).transform, false);
			BoxCollider val4 = val3.AddComponent<BoxCollider>();
			val4.center = new Vector3(0f, 0.23f, 0f);
			val4.size = new Vector3(1.16f, 0.48f, 1.02f);
			AccessTools.Field(typeof(Item), "_worldColliders").SetValue(val, new Collider[1] { (Collider)val4 });
			Collider val5 = (Collider)AccessTools.Field(typeof(Item), "_pickUpCollider").GetValue(val);
			if ((Object)(object)val5 != (Object)null)
			{
				val5.isTrigger = true;
			}
			if (val5 is SphereCollider)
			{
				SphereCollider val6 = (SphereCollider)val5;
				val6.radius = 0.72f;
				val6.center = new Vector3(0f, 0.28f, 0f);
			}
			else if (val5 is BoxCollider)
			{
				BoxCollider val7 = (BoxCollider)val5;
				val7.size = new Vector3(1.42f, 0.88f, 1.25f);
				val7.center = new Vector3(0f, 0.28f, 0f);
			}
			AccessTools.Field(typeof(Item), "_outOfHandHolder").SetValue(val, null);
			AccessTools.Field(typeof(Item), "_inHandHolder").SetValue(val, null);
			PortableGrillVisual portableGrillVisual = ((Component)val).gameObject.AddComponent<PortableGrillVisual>();
			portableGrillVisual.Build();
			AccessTools.Field(typeof(Item), "_mesh").SetValue(val, portableGrillVisual.InventoryMesh());
			AccessTools.Field(typeof(Item), "_inventoryMeshScale").SetValue(val, 0.58f);
			AccessTools.Field(typeof(Item), "_inventoryMeshPos").SetValue(val, (object)new Vector3(0f, -0.12f, 0f));
			AccessTools.Field(typeof(Item), "_inventoryMeshRot").SetValue(val, (object)new Vector3(20f, 35f, 0f));
			AccessTools.Field(typeof(Item), "_renderers").SetValue(val, (from r in ((Component)portableGrillVisual).GetComponentsInChildren<Renderer>(true)
				where r.enabled
				select r).ToList());
			NetworkObject component = ((Component)val).GetComponent<NetworkObject>();
			component.SetIsSpawnable(true);
			PrefabObjects prefabObjects = InstanceFinder.NetworkManager.GetPrefabObjects<SinglePrefabObjects>((ushort)42423, true);
			if (prefabObjects.GetObjectCount() != 0)
			{
				throw new Exception("Portable Grill network prefab collection 42423 is occupied.");
			}
			prefabObjects.AddObject(component, false, true);
			dictionary.Add(247, val);
			((Dictionary<byte, Item>)AccessTools.Field(typeof(GameInfo), "_allItems").GetValue(null)).Add(247, val);
			((Dictionary<string, Item>)AccessTools.Field(typeof(GameInfo), "_nameToSpawnable").GetValue(null)).Add("portablegrillmod", val);
			Prefab = val;
			Plugin.Log("Registered Portable Grill item and network prefab.");
		}
	}
	public sealed class PortableGrillVisual : MonoBehaviour
	{
		private static Material stone;

		private static Material metal;

		private static Material wood;

		private static Material ember;

		private Mesh inventoryMesh;

		private PortableGrillCooker cooker;

		private bool lastActive;

		public Mesh InventoryMesh()
		{
			return inventoryMesh;
		}

		private void Awake()
		{
			cooker = ((Component)this).GetComponent<PortableGrillCooker>();
		}

		private static Material Make(Color color, float metallic = 0f)
		{
			//IL_0018: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			Material val = new Material(Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"))
			{
				color = color
			};
			if (val.HasProperty("_Metallic"))
			{
				val.SetFloat("_Metallic", metallic);
			}
			if (val.HasProperty("_Smoothness"))
			{
				val.SetFloat("_Smoothness", metallic * 0.45f);
			}
			return val;
		}

		public void Build()
		{
			//IL_00ba: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: 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_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			//IL_041f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0424: Unknown result type (might be due to invalid IL or missing references)
			//IL_0453: Unknown result type (might be due to invalid IL or missing references)
			//IL_046d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Component)this).transform.Find("PortableGrillModel") != (Object)null)
			{
				return;
			}
			if ((Object)(object)stone == (Object)null)
			{
				stone = Make(new Color(0.16f, 0.18f, 0.21f));
				metal = Make(new Color(0.055f, 0.06f, 0.07f), 0.75f);
				wood = Make(new Color(0.31f, 0.12f, 0.045f));
				ember = Make(new Color(1f, 0.2f, 0.015f));
			}
			Transform transform = new GameObject("PortableGrillModel").transform;
			transform.SetParent(((Component)this).transform, false);
			transform.localPosition = new Vector3(0f, -0.05f, 0f);
			transform.localScale = Vector3.one * 0.8f;
			for (int i = 0; i < 10; i++)
			{
				float num = (float)i * (float)Math.PI * 2f / 10f;
				Transform val = Part("RingStone", transform, (PrimitiveType)0, new Vector3(Mathf.Cos(num) * 0.57f, 0.13f, Mathf.Sin(num) * 0.5f), new Vector3(0.38f, 0.27f, 0.34f), stone, Quaternion.Euler(12f, (float)i * 36f, 8f));
				if ((Object)(object)inventoryMesh == (Object)null)
				{
					inventoryMesh = ((Component)val).GetComponent<MeshFilter>().sharedMesh;
				}
			}
			Part("LogA", transform, (PrimitiveType)2, new Vector3(0f, 0.23f, 0f), new Vector3(0.1f, 0.43f, 0.1f), wood, Quaternion.Euler(90f, 42f, 0f));
			Part("LogB", transform, (PrimitiveType)2, new Vector3(0f, 0.25f, 0f), new Vector3(0.1f, 0.43f, 0.1f), wood, Quaternion.Euler(90f, -42f, 0f));
			Part("EmberCore", transform, (PrimitiveType)0, new Vector3(0f, 0.27f, 0f), new Vector3(0.38f, 0.13f, 0.31f), ember, Quaternion.identity);
			float num2 = 0.49f;
			Part("GrateLeft", transform, (PrimitiveType)2, new Vector3(-0.53f, num2, 0f), new Vector3(0.032f, 0.43f, 0.032f), metal, Quaternion.Euler(90f, 0f, 0f));
			Part("GrateRight", transform, (PrimitiveType)2, new Vector3(0.53f, num2, 0f), new Vector3(0.032f, 0.43f, 0.032f), metal, Quaternion.Euler(90f, 0f, 0f));
			Part("GrateFront", transform, (PrimitiveType)2, new Vector3(0f, num2, -0.42f), new Vector3(0.032f, 0.53f, 0.032f), metal, Quaternion.Euler(0f, 0f, 90f));
			Part("GrateBack", transform, (PrimitiveType)2, new Vector3(0f, num2, 0.42f), new Vector3(0.032f, 0.53f, 0.032f), metal, Quaternion.Euler(0f, 0f, 90f));
			for (int j = -3; j <= 3; j++)
			{
				Part("GrateBar", transform, (PrimitiveType)2, new Vector3((float)j * 0.145f, num2 + 0.008f, 0f), new Vector3(0.024f, 0.41f, 0.024f), metal, Quaternion.Euler(90f, 0f, 0f));
			}
			GameObject val2 = new GameObject("CookingTrigger");
			val2.transform.SetParent(((Component)this).transform, false);
			BoxCollider val3 = val2.AddComponent<BoxCollider>();
			((Collider)val3).isTrigger = true;
			val3.center = new Vector3(0f, 0.8f, 0f);
			val3.size = new Vector3(0.88f, 1.1f, 0.68f);
			((Collider)val3).enabled = false;
			cooker = ((Component)this).gameObject.AddComponent<PortableGrillCooker>();
			cooker.Configure(((Component)this).GetComponent<Item>(), (Collider)(object)val3);
		}

		public static Transform Part(string name, Transform parent, PrimitiveType primitive, Vector3 pos, Vector3 scale, Material material, Quaternion rotation)
		{
			//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)
			//IL_0039: 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.localRotation = rotation;
			obj.transform.localScale = scale;
			Object.DestroyImmediate((Object)(object)obj.GetComponent<Collider>());
			obj.GetComponent<Renderer>().sharedMaterial = material;
			return obj.transform;
		}

		private void LateUpdate()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Plugin.Instance == (Object)null))
			{
				Item component = ((Component)this).GetComponent<Item>();
				GrillData grillData = Plugin.Instance.Find(GrillItem.Serial(component));
				bool flag = grillData != null && grillData.deployed && (Object)(object)component != (Object)null && (Object)(object)component.SyncedHolder == (Object)null;
				if (flag)
				{
					((Component)this).transform.SetPositionAndRotation(grillData.position, grillData.Rotation);
				}
				if ((Object)(object)cooker == (Object)null)
				{
					cooker = ((Component)this).GetComponent<PortableGrillCooker>();
				}
				if ((Object)(object)cooker != (Object)null && (flag != lastActive || flag))
				{
					cooker.SetDeployed(flag);
				}
				lastActive = flag;
			}
		}
	}
	public sealed class PortableGrillCooker : MonoBehaviour
	{
		private Item grill;

		private Collider cookingTrigger;

		private readonly List<Item> items = new List<Item>();

		private bool deployed;

		private bool effectsReady;

		private bool lit;

		private bool subscribed;

		private float nextEffectsSearch;

		private float sizzleVolume;

		private float cookPerTick = 0.022499999f;

		private Transform effectsRoot;

		private ParticleSystem smoke;

		private ParticleSystem flame;

		private AudioSource fireSource;

		private AudioSource sizzleSource;

		private void Awake()
		{
			grill = ((Component)this).GetComponent<Item>();
			Transform val = ((Component)this).transform.Find("CookingTrigger");
			cookingTrigger = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent<Collider>());
			Subscribe();
		}

		private void Subscribe()
		{
			if (!subscribed)
			{
				NPCManager.OnUnlockedGrill += OnUnlocked;
				subscribed = true;
			}
		}

		public void Configure(Item owner, Collider trigger)
		{
			grill = owner;
			cookingTrigger = trigger;
			Subscribe();
		}

		private void OnDisable()
		{
			deployed = false;
			items.Clear();
			sizzleVolume = 0f;
			if ((Object)(object)sizzleSource != (Object)null)
			{
				sizzleSource.Stop();
			}
			StopEffects();
		}

		private void OnDestroy()
		{
			if (subscribed)
			{
				NPCManager.OnUnlockedGrill -= OnUnlocked;
			}
		}

		private bool Unlocked()
		{
			if ((Object)(object)NPCManager.Instance != (Object)null)
			{
				return NPCManager.Instance.GrillUnlocked;
			}
			return false;
		}

		private void OnUnlocked()
		{
			RefreshLit();
		}

		public void SetDeployed(bool value)
		{
			deployed = value;
			if ((Object)(object)cookingTrigger != (Object)null)
			{
				cookingTrigger.enabled = value;
			}
			if (!value)
			{
				items.Clear();
				sizzleVolume = 0f;
				if ((Object)(object)sizzleSource != (Object)null)
				{
					sizzleSource.Stop();
				}
				StopEffects();
			}
			else
			{
				RefreshLit();
			}
		}

		private void Update()
		{
			if (!deployed)
			{
				return;
			}
			if (!effectsReady && Time.unscaledTime >= nextEffectsSearch)
			{
				nextEffectsSearch = Time.unscaledTime + 1f;
				EnsureEffects();
			}
			RefreshLit();
			float num = ((lit && items.Count > 0) ? 0.25f : 0f);
			sizzleVolume = Mathf.MoveTowards(sizzleVolume, num, Time.deltaTime * 0.55f);
			if ((Object)(object)sizzleSource != (Object)null)
			{
				sizzleSource.volume = sizzleVolume;
				if (sizzleVolume > 0.002f && !sizzleSource.isPlaying)
				{
					sizzleSource.Play();
				}
				else if (sizzleVolume <= 0.002f && sizzleSource.isPlaying)
				{
					sizzleSource.Stop();
				}
			}
		}

		private void FixedUpdate()
		{
			if (!deployed || !Unlocked())
			{
				return;
			}
			for (int num = items.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)items[num] == (Object)null || !((Component)items[num]).gameObject.activeInHierarchy || ((Object)(object)items[num].Creature != (Object)null && (Object)(object)((Item)items[num].Creature).BirdHolder != (Object)null))
				{
					items.RemoveAt(num);
				}
			}
			if (!InstanceFinder.IsServerStarted)
			{
				return;
			}
			foreach (Item item in items)
			{
				if ((Object)(object)item != (Object)null && (Object)(object)item != (Object)(object)grill)
				{
					item.CookItem(cookPerTick);
				}
			}
		}

		private void OnTriggerStay(Collider other)
		{
			if (deployed && Unlocked())
			{
				Item val = ItemManager.Get(other);
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)grill && !items.Contains(val))
				{
					items.Add(val);
				}
			}
		}

		private void OnTriggerExit(Collider other)
		{
			Item val = ItemManager.Get(other);
			if ((Object)(object)val != (Object)null)
			{
				items.Remove(val);
			}
		}

		private void EnsureEffects()
		{
			//IL_0065: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Expected O, but got Unknown
			if (effectsReady)
			{
				return;
			}
			GrillBox val = Object.FindObjectsByType<GrillBox>((FindObjectsInactive)0).FirstOrDefault();
			if (!((Object)(object)val == (Object)null))
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(GrillBox), "_cookPerTick");
				if (fieldInfo != null)
				{
					cookPerTick = Mathf.Max(0.0001f, (float)fieldInfo.GetValue(val) * 0.9f);
				}
				effectsRoot = new GameObject("Portable Grill Vanilla Effects").transform;
				effectsRoot.SetParent(((Component)this).transform, false);
				effectsRoot.localPosition = new Vector3(0f, 0.2f, 0f);
				effectsRoot.localScale = Vector3.one * 0.8f;
				smoke = CloneParticle((ParticleSystem)AccessTools.Field(typeof(GrillBox), "_smokeParticles").GetValue(val), "Smoke");
				flame = CloneParticle((ParticleSystem)AccessTools.Field(typeof(GrillBox), "_grillParticles").GetValue(val), "Flame");
				fireSource = CloneAudio((AudioSource)AccessTools.Field(typeof(GrillBox), "_fireSource").GetValue(val), "Fire");
				sizzleSource = CloneAudio((AudioSource)AccessTools.Field(typeof(GrillBox), "_sizzlingSource").GetValue(val), "Sizzle");
				if ((Object)(object)sizzleSource != (Object)null)
				{
					sizzleSource.volume = 0f;
					sizzleSource.loop = true;
				}
				effectsReady = (Object)(object)smoke != (Object)null || (Object)(object)flame != (Object)null || (Object)(object)fireSource != (Object)null || (Object)(object)sizzleSource != (Object)null;
				if (effectsReady && deployed && Unlocked())
				{
					StartEffects();
				}
			}
		}

		private ParticleSystem CloneParticle(ParticleSystem source, string name)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_0076: 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_00a2: 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_00c4: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: 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_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("Portable Grill " + name);
			val.transform.SetParent(effectsRoot, false);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = ((Component)source).transform.localRotation;
			val.transform.localScale = ((name == "Flame") ? new Vector3(0.78f, 0.3f, 0.78f) : new Vector3(0.58f, 0.48f, 0.58f));
			ParticleSystem obj = val.AddComponent<ParticleSystem>();
			MainModule main = source.main;
			MainModule main2 = obj.main;
			((MainModule)(ref main2)).duration = ((MainModule)(ref main)).duration;
			((MainModule)(ref main2)).loop = true;
			((MainModule)(ref main2)).startLifetime = ((MainModule)(ref main)).startLifetime;
			((MainModule)(ref main2)).startSpeed = ((MainModule)(ref main)).startSpeed;
			((MainModule)(ref main2)).startSize = ((MainModule)(ref main)).startSize;
			((MainModule)(ref main2)).startColor = ((MainModule)(ref main)).startColor;
			((MainModule)(ref main2)).gravityModifier = ((MainModule)(ref main)).gravityModifier;
			((MainModule)(ref main2)).simulationSpace = (ParticleSystemSimulationSpace)0;
			((MainModule)(ref main2)).scalingMode = (ParticleSystemScalingMode)0;
			((MainModule)(ref main2)).maxParticles = ((MainModule)(ref main)).maxParticles;
			if (name == "Flame")
			{
				((MainModule)(ref main2)).startSpeedMultiplier = ((MainModule)(ref main2)).startSpeedMultiplier * 0.24f;
				((MainModule)(ref main2)).startLifetimeMultiplier = ((MainModule)(ref main2)).startLifetimeMultiplier * 0.58f;
				((MainModule)(ref main2)).startSizeMultiplier = ((MainModule)(ref main2)).startSizeMultiplier * 0.72f;
			}
			EmissionModule emission = source.emission;
			EmissionModule emission2 = obj.emission;
			((EmissionModule)(ref emission2)).enabled = ((EmissionModule)(ref emission)).enabled;
			((EmissionModule)(ref emission2)).rateOverTime = ((EmissionModule)(ref emission)).rateOverTime;
			ShapeModule shape = source.shape;
			ShapeModule shape2 = obj.shape;
			((ShapeModule)(ref shape2)).enabled = true;
			if (name == "Flame")
			{
				((ShapeModule)(ref shape2)).shapeType = (ParticleSystemShapeType)0;
				((ShapeModule)(ref shape2)).radius = 0.34f;
			}
			else
			{
				((ShapeModule)(ref shape2)).shapeType = ((ShapeModule)(ref shape)).shapeType;
				((ShapeModule)(ref shape2)).radius = Mathf.Min(((ShapeModule)(ref shape)).radius, 0.24f);
				((ShapeModule)(ref shape2)).angle = ((ShapeModule)(ref shape)).angle;
			}
			ParticleSystemRenderer component = ((Component)source).GetComponent<ParticleSystemRenderer>();
			ParticleSystemRenderer component2 = val.GetComponent<ParticleSystemRenderer>();
			if ((Object)(object)component != (Object)null)
			{
				((Renderer)component2).sharedMaterial = ((Renderer)component).sharedMaterial;
				component2.renderMode = component.renderMode;
				component2.mesh = component.mesh;
				component2.sortingFudge = component.sortingFudge;
			}
			obj.Stop(true, (ParticleSystemStopBehavior)0);
			return obj;
		}

		private AudioSource CloneAudio(AudioSource source, string name)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("Portable Grill " + name);
			val.transform.SetParent(effectsRoot, false);
			AudioSource obj = val.AddComponent<AudioSource>();
			obj.clip = source.clip;
			obj.loop = source.loop;
			obj.playOnAwake = false;
			obj.spatialBlend = 1f;
			obj.rolloffMode = source.rolloffMode;
			obj.minDistance = Mathf.Min(source.minDistance, 1.5f);
			obj.maxDistance = Mathf.Min(source.maxDistance, 14f);
			obj.pitch = source.pitch;
			obj.volume = source.volume;
			return obj;
		}

		private void RefreshLit()
		{
			bool flag = deployed && Unlocked();
			if (flag == lit)
			{
				if (flag && effectsReady)
				{
					StartEffects();
				}
				return;
			}
			lit = flag;
			if (lit)
			{
				EnsureEffects();
				StartEffects();
			}
			else
			{
				StopEffects();
			}
		}

		private void StartEffects()
		{
			if ((Object)(object)smoke != (Object)null && !smoke.isPlaying)
			{
				smoke.Play();
			}
			if ((Object)(object)flame != (Object)null && !flame.isPlaying)
			{
				flame.Play();
			}
			if ((Object)(object)fireSource != (Object)null && !fireSource.isPlaying)
			{
				fireSource.Play();
			}
		}

		private void StopEffects()
		{
			lit = false;
			if ((Object)(object)smoke != (Object)null)
			{
				smoke.Stop(true, (ParticleSystemStopBehavior)0);
			}
			if ((Object)(object)flame != (Object)null)
			{
				flame.Stop(true, (ParticleSystemStopBehavior)0);
			}
			if ((Object)(object)fireSource != (Object)null)
			{
				fireSource.Stop();
			}
		}
	}
	[BepInPlugin("ponyfisher.howtofish.portablegrillmod", "Portable Grill Mod", "0.1.2")]
	[DefaultExecutionOrder(29300)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "ponyfisher.howtofish.portablegrillmod";

		public static Plugin Instance;

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

		public int Selected;

		public string Status = "Unlock the vanilla grill, then purchase a Portable Grill from any money vendor.";

		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 bool nearMoneyVendor;

		private Component hoveredInteractable;

		private float nextTick;

		private float nextSave;

		private float nextState;

		private float nextVendorScan;

		private float nextIconRefresh;

		private float nextHello;

		private float statusUntil;

		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> grills = new Dictionary<int, Item>();

		private float useStarted;

		private Item activeTarget;

		private bool holdFired;

		private GUIStyle hintStyle;

		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, "PortableGrillMod-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 = "Portable Grill save data could not be read; actions are paused.";
				((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.portablegrillmod");
			harmony.PatchAll(typeof(Plugin).Assembly);
			Log("Portable Grill Mod 0.1.2 loaded. Unlock the vanilla grill, then press 7 at a money vendor.");
		}

		private void Update()
		{
			//IL_00f8: 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_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
			UpdateInteraction();
			if ((Object)(object)manager != (Object)(object)InstanceFinder.NetworkManager)
			{
				RegisterNetwork();
			}
			if (!registrationFailed && (Object)(object)GrillItem.Prefab == (Object)null)
			{
				try
				{
					GrillItem.Register();
				}
				catch (Exception ex)
				{
					registrationFailed = true;
					Status = "Portable Grill registration failed; see the BepInEx log.";
					((BaseUnityPlugin)this).Logger.LogError((object)ex);
				}
			}
			if ((Object)(object)GrillItem.Prefab != (Object)null && !catalogReady)
			{
				catalogReady = true;
				Log("Portable Grill catalog ready.");
			}
			if (catalogReady && Time.unscaledTime >= nextVendorScan)
			{
				nextVendorScan = Time.unscaledTime + 0.15f;
				nearMoneyVendor = (Object)(object)FocusedMoneyVendor(Player.LocalPlayer, 5f) != (Object)null;
			}
			Keyboard current = Keyboard.current;
			if (catalogReady && nearMoneyVendor && GrillUnlocked() && current != null && ((ButtonControl)current.digit7Key).wasPressedThisFrame)
			{
				Send("buy");
			}
			if (catalogReady && Time.unscaledTime >= nextIconRefresh)
			{
				nextIconRefresh = Time.unscaledTime + 0.15f;
				PortableGrillInventoryIcon.RefreshAll();
			}
			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.grills;
					grills.Clear();
					lastSequence.Clear();
					rateLimit.Clear();
				}
				if (Time.unscaledTime >= nextTick)
				{
					nextTick = Time.unscaledTime + 0.2f;
					AuditWorld();
				}
				if (Time.unscaledTime >= nextState)
				{
					nextState = Time.unscaledTime + 0.35f;
					Broadcast();
				}
				if (Time.unscaledTime >= nextSave)
				{
					nextSave = Time.unscaledTime + 8f;
					Persist();
				}
			}
			else if (!InstanceFinder.IsClientStarted)
			{
				world = null;
				Current = new List<GrillData>();
				grills.Clear();
			}
			if (InstanceFinder.IsClientStarted && !InstanceFinder.IsServerStarted && Time.unscaledTime >= nextHello)
			{
				nextHello = Time.unscaledTime + 3f;
				Send("hello");
			}
		}

		public static bool GrillUnlocked()
		{
			if ((Object)(object)NPCManager.Instance != (Object)null)
			{
				return NPCManager.Instance.GrillUnlocked;
			}
			return false;
		}

		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);
			}
		}

		public GrillData Find(int serial)
		{
			return Current.FirstOrDefault((GrillData g) => g.serial == serial);
		}

		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 = "Portable Grill Mod could not save; actions are paused.";
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		public void Send(string action, Vector3 position = default(Vector3), Vector3 normal = default(Vector3), int serial = 0)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.LocalPlayer == (Object)null)
			{
				SetStatus("Load into a game first.");
				return;
			}
			Command command = new Command
			{
				action = action,
				serial = ((serial > 0) ? serial : Selected),
				position = position,
				normal = normal,
				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")
				{
					SetStatus("Waiting for the host...");
				}
			}
		}

		private void Receive(NetworkConnection connection, RequestMessage message, Channel channel)
		{
			if (!InstanceFinder.IsServerStarted || message.json == null || message.json.Length > 2048)
			{
				return;
			}
			try
			{
				Command command = Codec.FromJson<Command>(message.json);
				if (command != null && command.protocol == 1 && command.sequence > 0 && (!lastSequence.TryGetValue(connection.ClientId, out var value) || command.sequence > value) && (!rateLimit.TryGetValue(connection.ClientId, out var value2) || !(Time.unscaledTime - value2 < 0.1f)))
				{
					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 Portable Grill request: " + ex.Message));
			}
		}

		private void SetStatus(string message)
		{
			Status = message;
			statusUntil = Time.unscaledTime + 4f;
		}

		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)
			{
				SetStatus(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);
			if (reply != null)
			{
				SetStatus(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 <= 250000)
			{
				Snapshot snapshot = Codec.FromJson<Snapshot>(message.json);
				if (snapshot != null && snapshot.protocol == 1 && snapshot.grills != null)
				{
					Current = snapshot.grills;
				}
			}
		}

		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,
						grills = Current
					})
				}, true, (Channel)0);
			}
		}

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

		private Item FindGrill(int serial)
		{
			if (grills.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 i) => GrillItem.Is(i) && ((NetworkBehaviour)i).IsSpawned && !((NetworkBehaviour)i).IsDeinitializing && GrillItem.Serial(i) == serial));
			if ((Object)(object)value != (Object)null)
			{
				grills[serial] = value;
			}
			return value;
		}

		private void AuditWorld()
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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)
			ScanGrills();
			foreach (KeyValuePair<int, Item> grill in grills)
			{
				Item value = grill.Value;
				GrillData grillData = Find(grill.Key);
				if (grillData == null)
				{
					Player syncedHolder = value.SyncedHolder;
					grillData = new GrillData
					{
						serial = grill.Key,
						owner = (((Object)(object)syncedHolder == (Object)null) ? 0 : syncedHolder.SteamID),
						ownerName = (((Object)(object)syncedHolder == (Object)null) ? null : syncedHolder.SteamName)
					};
					Current.Add(grillData);
					save.nextSerial = Math.Max(save.nextSerial, grill.Key + 1);
				}
				grillData.available = true;
				if ((Object)(object)value.SyncedHolder != (Object)null)
				{
					grillData.deployed = false;
				}
				else if (grillData.deployed)
				{
					value.RigidbodySync.SetKinematic(true);
					if (Vector3.Distance(((Component)value).transform.position, grillData.position) > 0.05f)
					{
						value.RigidbodySync.TeleportToPosRot(grillData.position, grillData.Rotation, (float[])null, (Quaternion[])null);
					}
				}
			}
			foreach (GrillData item in Current)
			{
				item.available = grills.ContainsKey(item.serial);
			}
		}

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

		private Item SpawnGrill(Player player, int slot, int serial)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			Item val = Object.Instantiate<Item>(GrillItem.Prefab, ((Component)player).transform.position + Vector3.up, Quaternion.identity, Server.Instance.DynamicObjectsHolder);
			val.LoadFromSave(new SavedItem
			{
				Exists = true,
				ItemID = 247,
				BettingMultiplier = serial,
				Weight = 1f,
				KillScoreMultiplier = 1f
			});
			InstanceFinder.ServerManager.Spawn(((Component)val).gameObject, (NetworkConnection)null, default(Scene));
			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("Inventory did not accept the Portable Grill.");
			}
			return val;
		}

		private bool Ground(Player player, Command cmd, Item grill, out RaycastHit hit)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			hit = default(RaycastHit);
			if (!Rules.Finite(cmd.position.x) || !Rules.Finite(cmd.position.y) || !Rules.Finite(cmd.position.z) || !Rules.SurfaceAllowed(cmd.normal.y) || Vector3.Distance(cmd.position, player.CamObject.position) > 8.35f)
			{
				return false;
			}
			Vector3 normalized = ((Vector3)(ref cmd.normal)).normalized;
			foreach (RaycastHit item in from h in Physics.RaycastAll(cmd.position + normalized * 0.35f, -normalized, 0.8f, -1, (QueryTriggerInteraction)1)
				orderby ((RaycastHit)(ref h)).distance
				select h)
			{
				RaycastHit current = item;
				if (((Component)((RaycastHit)(ref current)).collider).gameObject.layer != LayerMask.NameToLayer("Water") && !((Object)(object)((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<Player>() != (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<Item>() != (Object)null) && Rules.SurfaceAllowed(((RaycastHit)(ref current)).normal.y) && !(Vector3.Dot(((RaycastHit)(ref current)).normal, normalized) < 0.5f))
				{
					hit = current;
					return true;
				}
			}
			return false;
		}

		private float Distance(Player player, Item item)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			return Mathf.Min(Vector3.Distance(((Component)player).transform.position, ((Component)item).transform.position), ((Object)(object)player.CamObject == (Object)null) ? float.MaxValue : Vector3.Distance(player.CamObject.position, ((Component)item).transform.position));
		}

		private void Execute(Player player, Command cmd, NetworkConnection connection)
		{
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: 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_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			if (cmd.action == "hello")
			{
				Broadcast();
				return;
			}
			if (!persistenceReady || world == null || (Object)(object)GrillItem.Prefab == (Object)null || player.Dying.IsDead)
			{
				Respond(cmd, connection, "Portable Grill Mod is not ready on the host.");
				return;
			}
			ScanGrills();
			try
			{
				if (cmd.action == "buy")
				{
					if (!GrillUnlocked())
					{
						Respond(cmd, connection, "Complete the vanilla grill unlock before purchasing a Portable Grill.");
						return;
					}
					if ((Object)(object)FocusedMoneyVendor(player, 5f) == (Object)null)
					{
						Respond(cmd, connection, "Move close to and look at a money vendor to buy a Portable Grill.");
						return;
					}
					int num = OpenSlot(player);
					if (num < 0)
					{
						Respond(cmd, connection, "Free an inventory slot before buying a Portable Grill.");
						return;
					}
					if (!Wallet.Charge(player, 2500))
					{
						Respond(cmd, connection, "You need $" + 2500.ToString("N0") + " to buy a Portable Grill.");
						return;
					}
					int num2 = save.nextSerial++;
					try
					{
						SpawnGrill(player, num, num2);
					}
					catch
					{
						Wallet.Credit(player, 2500);
						throw;
					}
					Current.Add(new GrillData
					{
						serial = num2,
						owner = player.SteamID,
						ownerName = player.SteamName
					});
					Persist();
					Broadcast();
					Respond(cmd, connection, "Portable Grill purchased and added to your inventory.", num2);
					return;
				}
				GrillData grillData = Find(cmd.serial);
				Item val = FindGrill(cmd.serial);
				if (grillData == null || (Object)(object)val == (Object)null)
				{
					Respond(cmd, connection, "That Portable Grill is unavailable.");
					return;
				}
				bool flag = (Object)(object)val.SyncedHolder == (Object)(object)player;
				if (!flag && Distance(player, val) > 5.35f)
				{
					Respond(cmd, connection, "Move within " + 5f.ToString("0") + " metres of the Portable Grill.");
					return;
				}
				if (cmd.action == "deploy")
				{
					if (!flag || grillData.deployed)
					{
						Respond(cmd, connection, "Hold that Portable Grill before deploying it.");
						return;
					}
					if (!Ground(player, cmd, val, out var hit))
					{
						Respond(cmd, connection, "Look at an upward-facing surface within 8 metres.");
						return;
					}
					val.SpawnFromInventory();
					player.Inventory.RemoveItem(val);
					if ((Object)(object)val.Holder != (Object)null)
					{
						val.Drop(false, default(Vector3), default(Vector3));
					}
					val.SetSyncedHolder((Player)null, true);
					val.ReconcileLocalHolderWithSyncedHolder();
					if ((Object)(object)player.Holding.HeldItem == (Object)(object)val)
					{
						player.Hands.DropItem(false, val);
						player.Holding.DropItem(false, val);
						player.Holding.SetHeldItem((Item)null);
					}
					if ((Object)(object)player.Holding.UninitializedHeldItem == (Object)(object)val)
					{
						player.Holding.SetUninitializedHeldItem((Item)null);
					}
					grillData.position = ((RaycastHit)(ref hit)).point + ((RaycastHit)(ref hit)).normal * 0.015f;
					grillData.surfaceNormal = ((RaycastHit)(ref hit)).normal;
					Quaternion curPlayerRot = player.CurPlayerRot;
					grillData.yaw = ((Quaternion)(ref curPlayerRot)).eulerAngles.y;
					grillData.deployed = true;
					val.RigidbodySync.ServerSetSyncedSimulator(((NetworkBehaviour)Server.Instance).Owner);
					val.RigidbodySync.TeleportToPosRot(grillData.position, grillData.Rotation, (float[])null, (Quaternion[])null);
					val.RigidbodySync.SetKinematic(true);
					Respond(cmd, connection, "Portable Grill deployed and ready to cook.", grillData.serial);
				}
				else
				{
					if (!(cmd.action == "pickup"))
					{
						return;
					}
					if (flag)
					{
						Respond(cmd, connection, "The Portable Grill is already in your inventory.");
						return;
					}
					int num3 = 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.CanPickUp(num3 >= 0, emptyHands))
					{
						Respond(cmd, connection, "Free an inventory slot or empty your hands first.");
						return;
					}
					grillData.deployed = false;
					val.RigidbodySync.SetKinematic(false);
					int value = player.Inventory._syncedCurSlot.Value;
					val.SetSyncedHolder(player, true);
					if (num3 >= 0)
					{
						player.Inventory.AddItem((byte)num3, val);
					}
					val.ReconcileLocalHolderWithSyncedHolder();
					if (num3 >= 0)
					{
						player.Inventory.ServerSetSyncedCurSlot(value);
					}
					Respond(cmd, connection, "Portable Grill picked up.", grillData.serial);
				}
				Persist();
				Broadcast();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
				Respond(cmd, connection, "Portable Grill Mod could not complete that action. Check the BepInEx log.");
			}
		}

		public static bool IsMoneyVendor(NPC npc)
		{
			if ((Object)(object)npc == (Object)null)
			{
				return false;
			}
			FieldInfo fieldInfo = AccessTools.Field(typeof(NPC), "_quests");
			return ((fieldInfo == null) ? null : (fieldInfo.GetValue(npc) as IEnumerable<NPCQuest>))?.Any((NPCQuest q) => (Object)(object)q != (Object)null && (int)q.Type == 1) ?? false;
		}

		public void SetHoveredInteractable(Component value, bool active)
		{
			if (active)
			{
				hoveredInteractable = value;
			}
			else if ((Object)(object)hoveredInteractable == (Object)(object)value)
			{
				hoveredInteractable = null;
			}
		}

		private static NPC VendorFrom(Component component)
		{
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			NPC componentInParent = component.GetComponentInParent<NPC>();
			if (!((Object)(object)componentInParent != (Object)null))
			{
				return component.GetComponentInChildren<NPC>(true);
			}
			return componentInParent;
		}

		public NPC FocusedMoneyVendor(Player player, float range)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)player.CamObject == (Object)null)
			{
				return null;
			}
			if ((Object)(object)player == (Object)(object)Player.LocalPlayer && (Object)(object)hoveredInteractable != (Object)null)
			{
				NPC val = VendorFrom(hoveredInteractable);
				if (IsMoneyVendor(val) && Vector3.Distance(((Component)player).transform.position, ((Component)val).transform.position) <= range + 0.35f)
				{
					return val;
				}
			}
			foreach (RaycastHit item in from h in Physics.RaycastAll(player.CamObject.position, player.CamObject.forward, range, -1, (QueryTriggerInteraction)2)
				orderby ((RaycastHit)(ref h)).distance
				select h)
			{
				RaycastHit current = item;
				if (!((Object)(object)((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<Player>() == (Object)(object)player))
				{
					NPC componentInParent = ((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<NPC>();
					if (IsMoneyVendor(componentInParent))
					{
						return componentInParent;
					}
					if (!((RaycastHit)(ref current)).collider.isTrigger)
					{
						break;
					}
				}
			}
			NPC result = null;
			float num = 0.72f;
			RaycastHit val3 = default(RaycastHit);
			foreach (NPC item2 in Object.FindObjectsByType<NPC>().Where(IsMoneyVendor))
			{
				Vector3 val2 = (((Object)(object)item2.MouthPosForItems != (Object)null) ? item2.MouthPosForItems.position : (((Component)item2).transform.position + Vector3.up)) - player.CamObject.position;
				float magnitude = ((Vector3)(ref val2)).magnitude;
				if (!(magnitude <= 0.01f))
				{
					float num2 = Vector3.Dot(player.CamObject.forward, val2 / magnitude);
					if (Rules.CanUseVendor(magnitude, num2) && !(num2 < num) && Physics.Raycast(player.CamObject.position, val2 / magnitude, ref val3, magnitude + 0.5f, -1, (QueryTriggerInteraction)2) && !((Object)(object)((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<NPC>() != (Object)(object)item2))
					{
						result = item2;
						num = num2;
					}
				}
			}
			return result;
		}

		public void CompleteSale(Item item)
		{
			if (!InstanceFinder.IsServerStarted || (Object)(object)item == (Object)null)
			{
				return;
			}
			int num = GrillItem.Serial(item);
			GrillData grillData = Find(num);
			if (grillData != null)
			{
				Current.Remove(grillData);
				grills.Remove(num);
				if (Selected == num)
				{
					Selected = 0;
				}
				SetStatus("Portable Grill sold for $" + 1250.ToString("N0") + ".");
				Persist();
				Broadcast();
			}
		}

		private void OnDestroy()
		{
			Persist();
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Instance = null;
		}

		private void DrawVendorPrompt()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			if (catalogReady && nearMoneyVendor && GrillUnlocked() && !((Object)(object)Player.LocalPlayer == (Object)null))
			{
				GUIStyle val = new GUIStyle(GUI.skin.box)
				{
					alignment = (TextAnchor)4,
					fontSize = 18,
					fontStyle = (FontStyle)1
				};
				val.normal.textColor = (Color)((Wallet.Balance(Player.LocalPlayer) >= 2500) ? Color.white : new Color(1f, 0.45f, 0.35f));
				float num = 470f;
				float num2 = ((float)Screen.width - num) * 0.5f;
				float num3 = (float)Screen.height * 0.67f;
				if (Chainloader.PluginInfos.ContainsKey("ponyfisher.howtofish.coolermod") || Chainloader.PluginInfos.ContainsKey("ponyfisher.howtofish.waterwalkingboots"))
				{
					num3 -= 46f;
				}
				GUI.Box(new Rect(num2, num3, num, 38f), "[7] Buy Portable Grill - $" + 2500.ToString("N0"), val);
				if (Time.unscaledTime < statusUntil)
				{
					GUIStyle val2 = new GUIStyle(GUI.skin.box)
					{
						alignment = (TextAnchor)4,
						fontSize = 14,
						fontStyle = (FontStyle)1
					};
					val2.normal.textColor = Color.white;
					GUI.Box(new Rect(num2 + 20f, num3 + 42f, num - 40f, 30f), Status, val2);
				}
			}
		}

		private void OnGUI()
		{
			DrawInteractionHint();
			DrawVendorPrompt();
		}

		public static bool IsDeployed(Item item)
		{
			if ((Object)(object)Instance != (Object)null && GrillItem.Is(item) && (Object)(object)item.SyncedHolder == (Object)null)
			{
				return Instance.Find(GrillItem.Serial(item))?.deployed ?? false;
			}
			return false;
		}

		private Item RayGrill(float range)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			Player localPlayer = Player.LocalPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer.CamObject == (Object)null)
			{
				return null;
			}
			foreach (RaycastHit item in from h in Physics.RaycastAll(localPlayer.CamObject.position, localPlayer.CamObject.forward, range, -1, (QueryTriggerInteraction)2)
				orderby ((RaycastHit)(ref h)).distance
				select h)
			{
				RaycastHit current = item;
				if ((Object)(object)((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<Player>() == (Object)(object)localPlayer)
				{
					continue;
				}
				Item componentInParent = ((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<Item>();
				if (!((Object)(object)componentInParent != (Object)null) || !((Object)(object)componentInParent.SyncedHolder == (Object)(object)localPlayer))
				{
					if (GrillItem.Is(componentInParent) && IsDeployed(componentInParent))
					{
						return componentInParent;
					}
					if (!((RaycastHit)(ref current)).collider.isTrigger)
					{
						return null;
					}
				}
			}
			return null;
		}

		private Item InteractionTarget()
		{
			Player localPlayer = Player.LocalPlayer;
			if ((Object)(object)localPlayer == (Object)null || localPlayer.BlockInputs || localPlayer.Dying.IsDead)
			{
				return null;
			}
			Item heldItem = localPlayer.Holding.HeldItem;
			if (GrillItem.Is(heldItem))
			{
				return heldItem;
			}
			return RayGrill(5f);
		}

		public bool CapturesInteract()
		{
			if (!((Object)(object)InteractionTarget() != (Object)null))
			{
				return (Object)(object)activeTarget != (Object)null;
			}
			return true;
		}

		private bool CrosshairSurface(Item held, out RaycastHit surface)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			surface = default(RaycastHit);
			Player localPlayer = Player.LocalPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer.CamObject == (Object)null)
			{
				return false;
			}
			foreach (RaycastHit item in from h in Physics.RaycastAll(localPlayer.CamObject.position, localPlayer.CamObject.forward, 8f, -1, (QueryTriggerInteraction)1)
				orderby ((RaycastHit)(ref h)).distance
				select h)
			{
				RaycastHit current = item;
				if (!((Object)(object)((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<Player>() == (Object)(object)localPlayer) && !((Object)(object)((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<Item>() == (Object)(object)held))
				{
					if (((Component)((RaycastHit)(ref current)).collider).gameObject.layer == LayerMask.NameToLayer("Water") || !Rules.SurfaceAllowed(((RaycastHit)(ref current)).normal.y))
					{
						return false;
					}
					surface = current;
					return true;
				}
			}
			return false;
		}

		private void FireHeldAction(Item target)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			Selected = GrillItem.Serial(target);
			if ((Object)(object)target.SyncedHolder == (Object)(object)Player.LocalPlayer)
			{
				if (!CrosshairSurface(target, out var surface))
				{
					SetStatus("Look at an upward-facing surface within 8 metres.");
				}
				else
				{
					Send("deploy", ((RaycastHit)(ref surface)).point, ((RaycastHit)(ref surface)).normal);
				}
			}
			else
			{
				Send("pickup");
			}
		}

		private void UpdateInteraction()
		{
			Keyboard current = Keyboard.current;
			if (current != null)
			{
				if (((ButtonControl)current.eKey).wasPressedThisFrame)
				{
					activeTarget = InteractionTarget();
					useStarted = Time.unscaledTime;
					holdFired = false;
				}
				if ((Object)(object)activeTarget != (Object)null && ((ButtonControl)current.eKey).isPressed && !holdFired && Time.unscaledTime - useStarted >= 1f)
				{
					holdFired = true;
					FireHeldAction(activeTarget);
				}
				if (((ButtonControl)current.eKey).wasReleasedThisFrame)
				{
					activeTarget = null;
					holdFired = false;
				}
				if (!((ButtonControl)current.eKey).isPressed && !((ButtonControl)current.eKey).wasReleasedThisFrame && (Object)(object)activeTarget != (Object)null && Time.unscaledTime - useStarted > 2f)
				{
					activeTarget = null;
					holdFired = false;
				}
			}
		}

		private void DrawInteractionHint()
		{
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_00c3: Expected O, but got Unknown
			Item val = activeTarget ?? InteractionTarget();
			if (!((Object)(object)val == (Object)null))
			{
				string text = (((Object)(object)val.SyncedHolder == (Object)(object)Player.LocalPlayer) ? "Hold E to deploy Portable Grill" : "Hold E to pick up Portable Grill");
				if ((Object)(object)activeTarget != (Object)null && Keyboard.current != null && ((ButtonControl)Keyboard.current.eKey).isPressed)
				{
					text = text + "   " + Mathf.Clamp01((Time.unscaledTime - useStarted) / 1f).ToString("P0");
				}
				if (hintStyle == null)
				{
					hintStyle = new GUIStyle(GUI.skin.box)
					{
						fontSize = 15,
						fontStyle = (FontStyle)1,
						alignment = (TextAnchor)4
					};
				}
				GUI.Box(new Rect((float)Screen.width / 2f - 270f, (float)Screen.height * 0.73f, 540f, 42f), text, hintStyle);
			}
		}
	}
	internal static class Wallet
	{
		private static Type WalletType => Type.GetType("NoSharedMoney.Wallets, NoSharedMoney", throwOnError: false);

		public static int Balance(Player player)
		{
			Type walletType = WalletType;
			if (walletType != null)
			{
				return (int)AccessTools.Method(walletType, "Get", new Type[1] { typeof(Player) }, (Type[])null).Invoke(null, new object[1] { player });
			}
			return MoneyManager.Money;
		}

		public static bool Charge(Player player, int cost)
		{
			Type walletType = WalletType;
			if (walletType != null)
			{
				MethodInfo methodInfo = AccessTools.Method(walletType, "Get", new Type[1] { typeof(Player) }, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(walletType, "Remove", new Type[2]
				{
					typeof(Player),
					typeof(int)
				}, (Type[])null);
				if ((int)methodInfo.Invoke(null, new object[1] { player }) < cost)
				{
					return false;
				}
				methodInfo2.Invoke(null, new object[2] { player, cost });
				return true;
			}
			if ((Object)(object)MoneyManager.Instance == (Object)null || !MoneyManager.CanAfford(cost))
			{
				return false;
			}
			MoneyManager.RemoveMoney(cost, player);
			return true;
		}

		public static void Credit(Player player, int amount)
		{
			Type walletType = WalletType;
			if (walletType != null)
			{
				AccessTools.Method(walletType, "Add", new Type[2]
				{
					typeof(Player),
					typeof(int)
				}, (Type[])null).Invoke(null, new object[2] { player, amount });
			}
			else
			{
				MoneyManager.AddMoney(amount, player);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerHolding), "PickUpInput")]
	internal static class PortableGrillCaptureInteract
	{
		private static bool Prefix()
		{
			if (!((Object)(object)Plugin.Instance == (Object)null))
			{
				return !Plugin.Instance.CapturesInteract();
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(GameInfo), "Awake")]
	internal static class RegisterPortableGrill
	{
		private static void Postfix()
		{
			try
			{
				GrillItem.Register();
			}
			catch (Exception ex)
			{
				Plugin.Log("Portable Grill registration deferred: " + ex.Message);
			}
		}
	}
	[HarmonyPatch(typeof(Interactable), "Hover")]
	internal static class PortableGrillVendorHoverStart
	{
		private static void Postfix(Interactable __instance)
		{
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				Plugin.Instance.SetHoveredInteractable((Component)(object)__instance, active: true);
			}
		}
	}
	[HarmonyPatch(typeof(Interactable), "UnHover")]
	internal static class PortableGrillVendorHoverStop
	{
		private static void Postfix(Interactable __instance)
		{
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				Plugin.Instance.SetHoveredInteractable((Component)(object)__instance, active: false);
			}
		}
	}
	[HarmonyPatch(typeof(Item), "GetName")]
	internal static class PortableGrillName
	{
		private static bool Prefix(Item __instance, ref string __result)
		{
			if (!GrillItem.Is(__instance))
			{
				return true;
			}
			__result = "Portable Grill";
			return false;
		}
	}
	[HarmonyPatch(typeof(MoneyManager), "SellItem")]
	internal static class PortableGrillSale
	{
		private static void Postfix(Item item)
		{
			if (GrillItem.Is(item) && (Object)(object)Plugin.Instance != (Object)null)
			{
				Plugin.Instance.CompleteSale(item);
			}
		}
	}
	[HarmonyPatch(typeof(Item), "SetSyncedHolder")]
	internal static class PortableGrillHolder
	{
		private static void Postfix(Item __instance)
		{
			if (GrillItem.Is(__instance) && !((Object)(object)__instance.SyncedHolder == (Object)null) && !((Object)(object)Plugin.Instance == (Object)null))
			{
				GrillData grillData = Plugin.Instance.Find(GrillItem.Serial(__instance));
				if (grillData != null)
				{
					grillData.deployed = false;
				}
			}
		}
	}
	[HarmonyPatch(typeof(SaveManager), "SaveServer")]
	internal static class SavePortableGrills
	{
		private static void Postfix()
		{
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				Plugin.Instance.Persist();
			}
		}
	}
	[HarmonyPatch(typeof(SaveManager), "GetWorldItemSavePriority")]
	internal static class PortableGrillSavePriority
	{
		private static bool Prefix(Item item, ref int __result)
		{
			if (!GrillItem.Is(item))
			{
				return true;
			}
			__result = 0;
			return false;
		}
	}
	[HarmonyPatch(typeof(ItemManager), "RemoveItemsFarAwar")]
	internal static class KeepPortableGrills
	{
		private static void Prefix(List<Item> toRemove)
		{
			toRemove.RemoveAll(GrillItem.Is);
		}
	}
	[HarmonyPatch(typeof(Item), "PickUp")]
	internal static class NoDirectPortableGrillPickup
	{
		private static bool Prefix(Item __instance, bool calledFromLocal, bool sendToServer)
		{
			if (calledFromLocal || sendToServer)
			{
				return !Plugin.IsDeployed(__instance);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Item), "get_CanPickUp")]
	internal static class PortableGrillPickupPrompt
	{
		private static void Postfix(Item __instance, ref bool __result)
		{
			if (Plugin.IsDeployed(__instance))
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Item), "DestroyItem")]
	internal static class ProtectPortableGrill
	{
		private static bool Prefix(Item __instance)
		{
			return !Plugin.IsDeployed(__instance);
		}
	}
	[HarmonyPatch(typeof(RigidbodySync), "SetKinematic")]
	internal static class AnchorPortableGrill
	{
		private static void Prefix(RigidbodySync __instance, ref bool kinematic)
		{
			if (Plugin.IsDeployed(((Component)__instance).GetComponent<Item>()))
			{
				kinematic = true;
			}
		}
	}
	[HarmonyPatch(typeof(RigidbodySync), "StartSimulateLocal")]
	internal static class PreventPortableGrillExplosion
	{
		private static bool Prefix(RigidbodySync __instance)
		{
			return !Plugin.IsDeployed(((Component)__instance).GetComponent<Item>());
		}
	}
	[HarmonyPatch(typeof(Item), "UpdateLayer")]
	internal static class SolidPortableGrill
	{
		private static void Prefix(Item __instance, ref bool ____disablePlayerColOnGround)
		{
			if (Plugin.IsDeployed(__instance))
			{
				____disablePlayerColOnGround = false;
			}
		}
	}
	public sealed class PortableGrillSlotIcon : MonoBehaviour
	{
		private InventorySlot slot;

		private Renderer previewRenderer;

		private MeshFilter filter;

		private GameObject overlay;

		private bool previousRenderer;

		private bool applied;

		private static Texture2D icon;

		private static void Load()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			if ((Object)(object)icon != (Object)null)
			{
				return;
			}
			using Stream stream = typeof(PortableGrillSlotIcon).Assembly.GetManifestResourceStream("PortableGrillMod.portable-grill-icon.png");
			if (stream == null)
			{
				return;
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			icon = new Texture2D(2, 2, (TextureFormat)4, false);
			ImageConversion.LoadImage(icon, memoryStream.ToArray());
			((Texture)icon).wrapMode = (TextureWrapMode)1;
		}

		private void CreateOverlay(RawImage nativeImage)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_006e: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)overlay != (Object)null))
			{
				overlay = new GameObject("Portable Grill Mod Icon", new Type[3]
				{
					typeof(RectTransform),
					typeof(CanvasRenderer),
					typeof(RawImage)
				});
				overlay.transform.SetParent(((Component)nativeImage).transform, false);
				RectTransform val = (RectTransform)overlay.transform;
				val.anchorMin = Vector2.zero;
				val.anchorMax = Vector2.one;
				val.offsetMin = Vector2.zero;
				val.offsetMax = Vector2.zero;
				((Transform)val).localScale = Vector3.one;
				RawImage component = overlay.GetComponent<RawImage>();
				component.texture = (Texture)(object)icon;
				component.uvRect = new Rect(0f, 0f, 1f, 1f);
				((Graphic)component).color = Color.white;
				((Graphic)component).raycastTarget = false;
			}
		}

		public void Apply(InventorySlot target)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			slot = target;
			if (!GrillItem.Is(slot.Item))
			{
				return;
			}
			Load();
			if ((Object)(object)icon == (Object)null)
			{
				return;
			}
			RawImage val = (RawImage)AccessTools.Field(typeof(InventorySlot), "_itemImage").GetValue(slot);
			previewRenderer = (Renderer)AccessTools.Field(typeof(InventorySlot), "_renderer").GetValue(slot);
			filter = (MeshFilter)AccessTools.Field(typeof(InventorySlot), "_filter").GetValue(slot);
			if (!((Object)(object)val == (Object)null))
			{
				CreateOverlay(val);
				if (!applied)
				{
					previousRenderer = (Object)(object)previewRenderer == (Object)null || previewRenderer.enabled;
					applied = true;
				}
				if ((Object)(object)previewRenderer != (Object)null)
				{
					previewRenderer.enabled = false;
				}
				overlay.SetActive(true);
			}
		}

		public void Restore()
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if (!applied)
			{
				return;
			}
			InventorySlot val = slot;
			Item val2 = (((Object)(object)val == (Object)null) ? null : val.Item);
			if ((Object)(object)overlay != (Object)null)
			{
				overlay.SetActive(false);
			}
			applied = false;
			if ((Object)(object)val2 != (Object)null && !GrillItem.Is(val2) && (Object)(object)filter != (Object)null)
			{
				filter.mesh = val2.Mesh;
				((Component)filter).transform.localPosition = val2.InventoryMeshPos;
				((Component)filter).transform.localEulerAngles = val2.InventoryMeshRot;
				((Component)filter).transform.localScale = Vector3.one * val2.InventoryMeshScale;
				if ((Object)(object)previewRenderer != (Object)null)
				{
					previewRenderer.enabled = true;
				}
				try
				{
					AccessTools.Method(typeof(InventorySlot), "ApplyCookness", (Type[])null, (Type[])null).Invoke(val, new object[1] { val2 });
					AccessTools.Method(typeof(InventorySlot), "ApplySkin", (Type[])null, (Type[])null).Invoke(val, new object[1] { val2 });
				}
				catch
				{
				}
			}
			else if ((Object)(object)previewRenderer != (Object)null)
			{
				previewRenderer.enabled = previousRenderer;
			}
			slot = null;
		}

		private void Update()
		{
			if (applied && ((Object)(object)slot == (Object)null || !GrillItem.Is(slot.Item)))
			{
				Restore();
			}
		}

		private void OnDestroy()
		{
			Restore();
		}
	}
	[HarmonyPatch(typeof(InventorySlot), "SetItem")]
	internal static class PortableGrillInventoryIcon
	{
		public static void RefreshAll()
		{
			InventorySlot[] array = Object.FindObjectsByType<InventorySlot>((FindObjectsInactive)1);
			foreach (InventorySlot val in array)
			{
				PortableGrillSlotIcon portableGrillSlotIcon = ((Component)val).GetComponent<PortableGrillSlotIcon>();
				if (GrillItem.Is(val.Item))
				{
					if ((Object)(object)portableGrillSlotIcon == (Object)null)
					{
						portableGrillSlotIcon = ((Component)val).gameObject.AddComponent<PortableGrillSlotIcon>();
					}
					portableGrillSlotIcon.Apply(val);
				}
				else if ((Object)(object)portableGrillSlotIcon != (Object)null)
				{
					portableGrillSlotIcon.Restore();
				}
			}
		}

		private static void Prefix(InventorySlot __instance, Item item)
		{
			if ((Object)(object)__instance.Item != (Object)(object)item)
			{
				((Component)__instance).GetComponent<PortableGrillSlotIcon>()?.Restore();
			}
		}

		private static void Postfix(InventorySlot __instance)
		{
			if (GrillItem.Is(__instance.Item))
			{
				(((Component)__instance).GetComponent<PortableGrillSlotIcon>() ?? ((Component)__instance).gameObject.AddComponent<PortableGrillSlotIcon>()).Apply(__instance);
			}
		}
	}
}