Decompiled source of StvirisGeorgianCuisine v0.3.3

plugins/StvirisGeorgianCuisine/StvirisGeorgianCuisine.dll

Decompiled 5 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Newtonsoft.Json;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace StvirisGeorgianCuisine;

[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
[BepInPlugin("private.khinkali.food", "StvirisGeorgianCuisine", "0.3.3")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class Plugin : BaseUnityPlugin
{
	[Serializable]
	public class AssetManifest
	{
		public AssetEntry[] assets;
	}

	[Serializable]
	public class AssetEntry
	{
		public string name;

		public AssetPart[] parts;

		public AssetAnchor[] anchors;
	}

	[Serializable]
	public class AssetPart
	{
		public string name;

		public string mesh;

		public string texture;

		public float metallic;

		public float roughness;

		public float emission;
	}

	[Serializable]
	public class AssetAnchor
	{
		public string name;

		public float[] position;
	}

	[Serializable]
	private class MeshData
	{
		public string name;

		public float[] positions;

		public float[] normals;

		public float[] uv;

		public int[] triangles;
	}

	public const string Guid = "private.khinkali.food";

	public const string Version = "0.3.3";

	private string assetDirectory;

	private static bool HasGraphics => (int)SystemInfo.graphicsDeviceType != 4;

	private void ProtectAllFoodLODs()
	{
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		if (!HasGraphics)
		{
			return;
		}
		string[] array = new string[8] { "KhinkaliMod_Khinkali", "KhinkaliMod_MincedMeat", "SGC_MtsvadiRaw", "SGC_Mtsvadi", "SGC_ShotiStarterMix", "SGC_ShotiStarter", "SGC_ShotiDough", "SGC_Shoti" };
		foreach (string text in array)
		{
			GameObject itemPrefab = ItemManager.Instance.GetItem(text).ItemPrefab;
			if (!Object.op_Implicit((Object)(object)itemPrefab.GetComponentInChildren<LODGroup>(true)))
			{
				Transform val = itemPrefab.transform.Find("attach");
				GameObject val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).gameObject : itemPrefab);
				Renderer[] array2 = (from r in val2.GetComponentsInChildren<MeshRenderer>(true)
					where ((Renderer)r).enabled && ((Component)r).gameObject.activeSelf
					select r).Cast<Renderer>().ToArray();
				if (array2.Length == 0)
				{
					throw new InvalidOperationException("No dropped food renderer: " + text);
				}
				LODGroup val3 = val2.AddComponent<LODGroup>();
				val3.SetLODs((LOD[])(object)new LOD[1]
				{
					new LOD(0.001f, array2)
				});
				val3.RecalculateBounds();
			}
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Verified authored/native LOD protection for all eight food and ingredient items.");
	}

	private void RegisterMakali()
	{
		AssetManifest manifest = JsonConvert.DeserializeObject<AssetManifest>(File.ReadAllText(Path.Combine(assetDirectory, "Makali_Mtsvadi.assets.json")));
		CustomItem val = CreateSkewer(cooked: false, manifest);
		CustomItem val2 = CreateSkewer(cooked: true, manifest);
		CustomPiece val3 = CreateMakali(val.ItemDrop, val2.ItemDrop, manifest);
		try
		{
			if (!ItemManager.Instance.AddItem(val) || !ItemManager.Instance.AddItem(val2) || !PieceManager.Instance.AddPiece(val3))
			{
				throw new InvalidOperationException("Could not register Makali recipe chain.");
			}
		}
		catch
		{
			PieceManager.Instance.RemovePiece(val3);
			ItemManager.Instance.RemoveItem(val);
			ItemManager.Instance.RemoveItem(val2);
			throw;
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Registered Makali (six slots, coal) and raw/cooked Mtsvadi.");
	}

	private CustomItem CreateSkewer(bool cooked, AssetManifest manifest)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Expected O, but got Unknown
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Expected O, but got Unknown
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Expected O, but got Unknown
		//IL_00ff: 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_02d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f8: 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_030b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0319: Unknown result type (might be due to invalid IL or missing references)
		string id = (cooked ? "SGC_Mtsvadi" : "SGC_MtsvadiRaw");
		ItemConfig val = new ItemConfig();
		val.Name = (cooked ? "Mtsvadi" : "Mtsvadi (raw)");
		val.Description = (cooked ? "Juicy pork, marinated with onion and grilled slowly over charcoal." : "Five hand-cut pieces of marinated pork. Ready for the Makali.");
		val.StackSize = 20;
		val.Weight = 1f;
		val.Amount = 1;
		val.CraftingStation = (cooked ? null : "piece_preptable");
		val.MinStationLevel = 1;
		val.Requirements = (RequirementConfig[])(object)(cooked ? new RequirementConfig[0] : new RequirementConfig[2]
		{
			new RequirementConfig("RawMeat", 1, 0, true),
			new RequirementConfig("Onion", 1, 0, true)
		});
		ItemConfig val2 = val;
		CustomItem val3 = new CustomItem(id, "RawMeat", val2);
		GameObject itemPrefab = val3.ItemPrefab;
		ItemData itemData = val3.ItemDrop.m_itemData;
		SharedData shared = itemData.m_shared;
		shared.m_itemType = (ItemType)((!cooked) ? 1 : 2);
		shared.m_food = (cooked ? 65 : 0);
		shared.m_foodStamina = (cooked ? 40 : 0);
		shared.m_foodEitr = 0f;
		shared.m_foodBurnTime = (cooked ? 1500 : 0);
		shared.m_foodRegen = (cooked ? 4 : 0);
		shared.m_maxStackSize = 20;
		shared.m_weight = 1f;
		shared.m_teleportable = true;
		shared.m_maxQuality = 1;
		shared.m_isDrink = false;
		shared.m_consumeStatusEffect = null;
		shared.m_appendToolTip = null;
		shared.m_useDurability = false;
		shared.m_value = 0;
		itemData.m_stack = 1;
		itemData.m_quality = 1;
		LODGroup[] componentsInChildren = itemPrefab.GetComponentsInChildren<LODGroup>(true);
		foreach (LODGroup val4 in componentsInChildren)
		{
			Object.DestroyImmediate((Object)(object)val4);
		}
		MeshRenderer[] componentsInChildren2 = itemPrefab.GetComponentsInChildren<MeshRenderer>(true);
		foreach (MeshRenderer val5 in componentsInChildren2)
		{
			((Renderer)val5).enabled = false;
		}
		SkinnedMeshRenderer[] componentsInChildren3 = itemPrefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val6 in componentsInChildren3)
		{
			((Renderer)val6).enabled = false;
		}
		Collider[] componentsInChildren4 = itemPrefab.GetComponentsInChildren<Collider>(true);
		foreach (Collider val7 in componentsInChildren4)
		{
			val7.enabled = false;
		}
		string[] array = new string[2] { "attach", "attach_cook" };
		foreach (string text in array)
		{
			Transform val8 = itemPrefab.transform.Find(text);
			if (Object.op_Implicit((Object)(object)val8))
			{
				((Object)val8).name = "unused_" + text;
			}
		}
		itemPrefab.transform.localScale = Vector3.one;
		GameObject parent = Child(itemPrefab, "attach", Vector3.zero);
		Bounds val9 = BuildModel(parent, manifest.assets.First((AssetEntry a) => a.name == id));
		BoxCollider val10 = itemPrefab.AddComponent<BoxCollider>();
		val10.center = ((Bounds)(ref val9)).center;
		val10.size = ((Bounds)(ref val9)).size;
		Rigidbody component = itemPrefab.GetComponent<Rigidbody>();
		if (Object.op_Implicit((Object)(object)component))
		{
			component.mass = 1f;
		}
		if (HasGraphics)
		{
			shared.m_icons = (Sprite[])(object)new Sprite[1] { LoadIcon(id) };
		}
		return val3;
	}

	private CustomPiece CreateMakali(ItemDrop raw, ItemDrop cooked, AssetManifest manifest)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007f: Expected O, but got Unknown
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Expected O, but got Unknown
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Expected O, but got Unknown
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b9: Expected O, but got Unknown
		//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02eb: 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_03a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_0598: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_05de: Unknown result type (might be due to invalid IL or missing references)
		//IL_05fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0611: Unknown result type (might be due to invalid IL or missing references)
		//IL_041d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0422: Unknown result type (might be due to invalid IL or missing references)
		//IL_0430: Unknown result type (might be due to invalid IL or missing references)
		//IL_0446: 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_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_0491: Unknown result type (might be due to invalid IL or missing references)
		//IL_0496: Unknown result type (might be due to invalid IL or missing references)
		//IL_049f: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_067b: Unknown result type (might be due to invalid IL or missing references)
		//IL_068f: Unknown result type (might be due to invalid IL or missing references)
		GameObject prefab = PrefabManager.Instance.GetPrefab("piece_cookingstation_iron");
		CookingStation component = prefab.GetComponent<CookingStation>();
		PieceConfig val = new PieceConfig();
		val.Name = "Makali";
		val.Description = "A charcoal brazier for six Mtsvadi skewers. Load coal on the left.";
		val.PieceTable = "Hammer";
		val.Category = "Crafting";
		val.CraftingStation = "forge";
		val.Requirements = (RequirementConfig[])(object)new RequirementConfig[2]
		{
			new RequirementConfig("Iron", 4, 0, true),
			new RequirementConfig("Silver", 8, 0, true)
		};
		CustomPiece val2 = new CustomPiece("SGC_Makali", "piece_cookingstation_iron", val);
		GameObject piecePrefab = val2.PiecePrefab;
		piecePrefab.transform.localScale = Vector3.one;
		LODGroup[] componentsInChildren = piecePrefab.GetComponentsInChildren<LODGroup>(true);
		foreach (LODGroup val3 in componentsInChildren)
		{
			Object.DestroyImmediate((Object)(object)val3);
		}
		Transform[] array = ((IEnumerable)piecePrefab.transform).Cast<Transform>().ToArray();
		foreach (Transform val4 in array)
		{
			Object.DestroyImmediate((Object)(object)((Component)val4).gameObject);
		}
		CookingStation component2 = piecePrefab.GetComponent<CookingStation>();
		component2.m_name = "Makali";
		component2.m_requireFire = false;
		component2.m_useFuel = true;
		component2.m_useFueldWhileEmpty = false;
		component2.m_fuelItem = PrefabManager.Instance.GetPrefab("Coal").GetComponent<ItemDrop>();
		component2.m_overCookedItem = component2.m_fuelItem;
		component2.m_maxFuel = 10;
		component2.m_secPerFuel = 180;
		component2.m_canOvercookItems = true;
		component2.m_canGiveBonusYield = false;
		component2.m_moveObjectWhileCooking = false;
		component2.m_fireCheckPoints = (Transform[])(object)new Transform[0];
		List<ItemConversion> list = new List<ItemConversion>();
		ItemConversion val5 = new ItemConversion();
		val5.m_from = raw;
		val5.m_to = cooked;
		val5.m_cookTime = 45f;
		list.Add(val5);
		component2.m_conversion = list;
		component2.m_incompatibleItems = new List<ItemMessage>();
		component2.m_donePS = (ParticleSystem[])(object)new ParticleSystem[0];
		component2.m_burntPS = (ParticleSystem[])(object)new ParticleSystem[0];
		component2.m_addEffect = SoundEffects(component.m_addEffect);
		component2.m_doneEffect = SoundEffects(component.m_doneEffect);
		component2.m_overcookedEffect = SoundEffects(component.m_overcookedEffect);
		component2.m_pickEffector = SoundEffects(component.m_pickEffector);
		component2.m_fuelAddedEffects = SoundEffects(PrefabManager.Instance.GetPrefab("smelter").GetComponent<Smelter>().m_fuelAddedEffects);
		component2.m_haveFireObject = null;
		component2.m_cookingObject = null;
		component2.m_addItemTooltip = "Place raw Mtsvadi";
		component2.m_fullyCookedTooltip = "Collect Mtsvadi";
		component2.m_noCookableItemsMessage = "You have no raw Mtsvadi";
		GameObject val6 = Child(piecePrefab, "model", Vector3.zero);
		AssetEntry asset = manifest.assets.First((AssetEntry a) => a.name == "SGC_Makali");
		BuildModel(val6, asset);
		component2.m_haveFuelObject = ((Component)val6.transform.Find("Makali_EmberGlow")).gameObject;
		component2.m_haveFuelObject.SetActive(false);
		component2.m_spawnPoint = Child(piecePrefab, "output", Anchor(asset, "output")).transform;
		component2.m_spawnForce = 1f;
		component2.m_slots = (Transform[])(object)new Transform[6];
		for (int num = 0; num < 6; num++)
		{
			GameObject val7 = Object.Instantiate<GameObject>(((Component)component.m_slots[0]).gameObject, piecePrefab.transform, false);
			((Object)val7).name = "slot_" + (num + 1);
			val7.transform.localPosition = Anchor(asset, ((Object)val7).name);
			val7.transform.localRotation = Quaternion.identity;
			val7.transform.localScale = Vector3.one;
			Transform[] array2 = ((IEnumerable)val7.transform).Cast<Transform>().ToArray();
			foreach (Transform val8 in array2)
			{
				Object.DestroyImmediate((Object)(object)((Component)val8).gameObject);
			}
			ParticleSystem component3 = val7.GetComponent<ParticleSystem>();
			component3.Stop(true, (ParticleSystemStopBehavior)0);
			MainModule main = component3.main;
			((MainModule)(ref main)).startSize = new MinMaxCurve(0.06f, 0.13f);
			((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.6f, 1.3f);
			((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0.12f);
			((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.65f, 0.65f, 0.65f, 0.12f));
			((MainModule)(ref main)).maxParticles = 12;
			EmissionModule emission = component3.emission;
			((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(1.5f);
			((EmissionModule)(ref emission)).enabled = false;
			ShapeModule shape = component3.shape;
			((ShapeModule)(ref shape)).radius = 0.05f;
			AudioSource component4 = val7.GetComponent<AudioSource>();
			component4.volume = 0.18f;
			component4.spatialBlend = 1f;
			component4.minDistance = 1.5f;
			component4.maxDistance = 12f;
			component4.mute = true;
			component4.rolloffMode = (AudioRolloffMode)0;
			((Behaviour)component4).enabled = true;
			component4.loop = true;
			component4.playOnAwake = false;
			AudioClip val9 = ((IEnumerable<AudioClip>)Resources.FindObjectsOfTypeAll<AudioClip>()).FirstOrDefault((Func<AudioClip, bool>)((AudioClip a) => ((Object)a).name == "Sizzle_FleshBurning_Loop"));
			if (Object.op_Implicit((Object)(object)val9))
			{
				component4.clip = val9;
			}
			component2.m_slots[num] = val7.transform;
		}
		component2.m_addFoodSwitch = MakeSwitch(piecePrefab, "add_skewers", new Vector3(0f, 0.87f, 0f), new Vector3(1.34f, 0.16f, 0.7f));
		component2.m_addFuelSwitch = MakeSwitch(piecePrefab, "add_coal_left", Anchor(asset, "fuel_left"), new Vector3(0.3f, 0.24f, 0.47f));
		AddBox(piecePrefab, new Vector3(0f, 0.735f, 0f), new Vector3(1.42f, 0.26f, 0.68f));
		float[] array3 = new float[2] { -0.63f, 0.63f };
		foreach (float num4 in array3)
		{
			float[] array4 = new float[2] { -0.27f, 0.27f };
			foreach (float num6 in array4)
			{
				AddBox(piecePrefab, new Vector3(num4, 0.33f, num6), new Vector3(0.08f, 0.61f, 0.08f));
			}
		}
		WearNTear component5 = piecePrefab.GetComponent<WearNTear>();
		component5.m_new = val6;
		component5.m_worn = val6;
		component5.m_broken = val6;
		component5.m_wet = null;
		component5.m_fragmentRoots = (GameObject[])(object)new GameObject[1] { val6 };
		component5.m_autoCreateFragments = true;
		component5.m_noRoofWear = false;
		component5.m_health = 500f;
		piecePrefab.AddComponent<Makali>();
		if (HasGraphics)
		{
			val2.Piece.m_icon = LoadIcon("SGC_Makali");
		}
		return val2;
	}

	private static EffectList SoundEffects(EffectList source)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		EffectList val = new EffectList();
		val.m_effectPrefabs = source.m_effectPrefabs.Where((EffectData e) => Object.op_Implicit((Object)(object)e.m_prefab) && (Object.op_Implicit((Object)(object)e.m_prefab.GetComponentInChildren<ZSFX>(true)) || Object.op_Implicit((Object)(object)e.m_prefab.GetComponentInChildren<AudioSource>(true)))).ToArray();
		return val;
	}

	private Sprite LoadIcon(string id)
	{
		//IL_002c: 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)
		Texture2D val = LoadTexture(id + ".png", mipmaps: false);
		return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
	}

	private static GameObject Child(GameObject parent, string name, Vector3 position)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject(name);
		val.layer = parent.layer;
		val.transform.SetParent(parent.transform, false);
		val.transform.localPosition = position;
		return val;
	}

	private static void AddBox(GameObject go, Vector3 center, Vector3 size)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		BoxCollider val = go.AddComponent<BoxCollider>();
		val.center = center;
		val.size = size;
	}

	private static Switch MakeSwitch(GameObject parent, string name, Vector3 position, Vector3 size)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Child(parent, name, position);
		AddBox(val, Vector3.zero, size);
		return val.AddComponent<Switch>();
	}

	private static Vector3 Anchor(AssetEntry asset, string name)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		float[] position = asset.anchors.First((AssetAnchor a) => a.name == name).position;
		return new Vector3(position[0], position[1], position[2]);
	}

	private Bounds BuildModel(GameObject parent, AssetEntry asset)
	{
		//IL_0002: 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_00a5: 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_02e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Expected O, but got Unknown
		//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cd: 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_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_0230: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		Bounds result = default(Bounds);
		bool flag = true;
		Material val = (HasGraphics ? ((Renderer)PrefabManager.Instance.GetPrefab("RawMeat").GetComponentsInChildren<MeshRenderer>(true).First((MeshRenderer r) => Object.op_Implicit((Object)(object)((Renderer)r).sharedMaterial))).sharedMaterial : null);
		AssetPart[] parts = asset.parts;
		foreach (AssetPart assetPart in parts)
		{
			GameObject val2 = Child(parent, assetPart.name, Vector3.zero);
			Mesh val3 = LoadMesh(Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(assetPart.mesh)));
			if (flag)
			{
				result = val3.bounds;
				flag = false;
			}
			else
			{
				((Bounds)(ref result)).Encapsulate(val3.bounds);
			}
			if (!HasGraphics)
			{
				continue;
			}
			val2.AddComponent<MeshFilter>().sharedMesh = val3;
			Material val4 = new Material(val);
			((Object)val4).name = assetPart.name + "_Material";
			Texture2D val5 = LoadTexture(assetPart.texture, mipmaps: true);
			((Texture)val5).wrapMode = (TextureWrapMode)(!(asset.name == "SGC_Makali"));
			val4.mainTexture = (Texture)(object)val5;
			val4.mainTextureScale = Vector2.one;
			val4.mainTextureOffset = Vector2.zero;
			if (val4.HasProperty("_Color"))
			{
				val4.SetColor("_Color", Color.white);
			}
			if (val4.HasProperty("_BumpMap"))
			{
				val4.SetTexture("_BumpMap", (Texture)null);
			}
			if (val4.HasProperty("_MetallicGlossMap"))
			{
				val4.SetTexture("_MetallicGlossMap", (Texture)null);
			}
			if (val4.HasProperty("_Metallic"))
			{
				val4.SetFloat("_Metallic", assetPart.metallic);
			}
			if (val4.HasProperty("_Glossiness"))
			{
				val4.SetFloat("_Glossiness", 1f - assetPart.roughness);
			}
			val4.DisableKeyword("_NORMALMAP");
			val4.DisableKeyword("_METALLICGLOSSMAP");
			if (assetPart.emission > 0f)
			{
				val4.EnableKeyword("_EMISSION");
				if (val4.HasProperty("_EmissionMap"))
				{
					val4.SetTexture("_EmissionMap", (Texture)(object)val5);
				}
				if (val4.HasProperty("_EmissionColor"))
				{
					val4.SetColor("_EmissionColor", Color.white * assetPart.emission);
				}
			}
			((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterial = val4;
		}
		if (HasGraphics)
		{
			Renderer[] array = (from r in parent.GetComponentsInChildren<MeshRenderer>(true)
				where ((Renderer)r).enabled
				select r).Cast<Renderer>().ToArray();
			if (array.Length > 0)
			{
				LODGroup val6 = parent.AddComponent<LODGroup>();
				val6.SetLODs((LOD[])(object)new LOD[1]
				{
					new LOD(0.001f, array)
				});
				val6.RecalculateBounds();
			}
		}
		return result;
	}

	private void Awake()
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		assetDirectory = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Assets");
		new Harmony("private.khinkali.food").PatchAll(typeof(Plugin).Assembly);
		PrefabManager.OnVanillaPrefabsAvailable += RegisterItems;
	}

	private void OnDestroy()
	{
		PrefabManager.OnVanillaPrefabsAvailable -= RegisterItems;
	}

	private void RegisterItems()
	{
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Expected O, but got Unknown
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Expected O, but got Unknown
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Expected O, but got Unknown
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Expected O, but got Unknown
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Expected O, but got Unknown
		PrefabManager.OnVanillaPrefabsAvailable -= RegisterItems;
		try
		{
			string[] array = new string[7] { "RawMeat", "DeerMeat", "LoxMeat", "BarleyFlour", "Cloudberry", "piece_preptable", "piece_cauldron" };
			foreach (string text in array)
			{
				if (!Object.op_Implicit((Object)(object)PrefabManager.Instance.GetPrefab(text)))
				{
					throw new InvalidOperationException("Required vanilla prefab missing: " + text);
				}
			}
			CustomItem val = CreateItem("KhinkaliMod_MincedMeat", "Minced meat", "Deer, boar and lox, finely chopped for a hearty filling.", food: false, "piece_preptable", 1, (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig("DeerMeat", 1, 0, false),
				new RequirementConfig("RawMeat", 1, 0, false),
				new RequirementConfig("LoxMeat", 1, 0, false)
			});
			CustomItem val2 = CreateItem("KhinkaliMod_Khinkali", "Khinkali", "A pleated dumpling filled with rich meat and broth. Hold it by the knot.", food: true, "piece_cauldron", 4, (RequirementConfig[])(object)new RequirementConfig[2]
			{
				new RequirementConfig("KhinkaliMod_MincedMeat", 1, 0, false),
				new RequirementConfig("BarleyFlour", 2, 0, false)
			});
			if (!ItemManager.Instance.AddItem(val))
			{
				throw new InvalidOperationException("Could not register minced meat.");
			}
			if (!ItemManager.Instance.AddItem(val2))
			{
				ItemManager.Instance.RemoveItem(val);
				throw new InvalidOperationException("Could not register Khinkali.");
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Registered minced meat and Khinkali: 80 health, 35 stamina, 1500 seconds, 5 regeneration. Recipes: prep table 1, cauldron 4.");
			RegisterMakali();
			RegisterShoti();
			ProtectAllFoodLODs();
			RegisterServingTrayFoods();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("StvirisGeorgianCuisine registration failed. " + ex));
		}
	}

	private CustomItem CreateItem(string id, string displayName, string description, bool food, string station, int level, RequirementConfig[] requirements)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Expected O, but got Unknown
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0298: Unknown result type (might be due to invalid IL or missing references)
		//IL_029f: Expected O, but got Unknown
		//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_031f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0324: Unknown result type (might be due to invalid IL or missing references)
		//IL_0328: Unknown result type (might be due to invalid IL or missing references)
		//IL_0338: Unknown result type (might be due to invalid IL or missing references)
		//IL_034a: Unknown result type (might be due to invalid IL or missing references)
		//IL_034f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0353: Unknown result type (might be due to invalid IL or missing references)
		//IL_0363: Unknown result type (might be due to invalid IL or missing references)
		//IL_0405: Unknown result type (might be due to invalid IL or missing references)
		//IL_040c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0422: Unknown result type (might be due to invalid IL or missing references)
		//IL_0427: Unknown result type (might be due to invalid IL or missing references)
		//IL_042b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0432: Unknown result type (might be due to invalid IL or missing references)
		//IL_0440: Unknown result type (might be due to invalid IL or missing references)
		//IL_0445: Unknown result type (might be due to invalid IL or missing references)
		//IL_0449: Unknown result type (might be due to invalid IL or missing references)
		//IL_0450: Unknown result type (might be due to invalid IL or missing references)
		//IL_0478: Unknown result type (might be due to invalid IL or missing references)
		//IL_047e: Invalid comparison between Unknown and I4
		//IL_04a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ae: Expected O, but got Unknown
		//IL_04e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0513: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0602: Unknown result type (might be due to invalid IL or missing references)
		ItemConfig val = new ItemConfig();
		val.Name = displayName;
		val.Description = description;
		val.Amount = 1;
		val.Enabled = true;
		val.CraftingStation = station;
		val.MinStationLevel = level;
		val.RequireOnlyOneIngredient = false;
		val.StackSize = 20;
		val.Weight = (food ? 0.5f : 1f);
		val.Requirements = requirements;
		ItemConfig val2 = val;
		CustomItem val3 = new CustomItem(id, "RawMeat", val2);
		GameObject itemPrefab = val3.ItemPrefab;
		SharedData shared = val3.ItemDrop.m_itemData.m_shared;
		shared.m_itemType = (ItemType)((!food) ? 1 : 2);
		shared.m_maxStackSize = 20;
		shared.m_maxQuality = 1;
		shared.m_weight = (food ? 0.5f : 1f);
		shared.m_teleportable = true;
		shared.m_food = (food ? 80f : 0f);
		shared.m_foodStamina = (food ? 35f : 0f);
		shared.m_foodEitr = 0f;
		shared.m_foodBurnTime = (food ? 1500f : 0f);
		shared.m_foodRegen = (food ? 5f : 0f);
		shared.m_isDrink = false;
		shared.m_consumeStatusEffect = null;
		shared.m_appendToolTip = null;
		shared.m_useDurability = false;
		shared.m_value = 0;
		val3.ItemDrop.m_itemData.m_stack = 1;
		val3.ItemDrop.m_itemData.m_quality = 1;
		Material val4 = (from r in itemPrefab.GetComponentsInChildren<MeshRenderer>(true)
			select ((Renderer)r).sharedMaterial).FirstOrDefault((Func<Material, bool>)((Material m) => (Object)(object)m != (Object)null));
		LODGroup[] componentsInChildren = itemPrefab.GetComponentsInChildren<LODGroup>(true);
		foreach (LODGroup val5 in componentsInChildren)
		{
			Object.DestroyImmediate((Object)(object)val5);
		}
		MeshRenderer[] componentsInChildren2 = itemPrefab.GetComponentsInChildren<MeshRenderer>(true);
		foreach (MeshRenderer val6 in componentsInChildren2)
		{
			((Renderer)val6).enabled = false;
		}
		SkinnedMeshRenderer[] componentsInChildren3 = itemPrefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val7 in componentsInChildren3)
		{
			((Renderer)val7).enabled = false;
		}
		Collider[] componentsInChildren4 = itemPrefab.GetComponentsInChildren<Collider>(true);
		foreach (Collider val8 in componentsInChildren4)
		{
			val8.enabled = false;
		}
		Transform val9 = itemPrefab.transform.Find("attach");
		if (Object.op_Implicit((Object)(object)val9))
		{
			((Object)val9).name = "vanilla_attach_disabled";
		}
		GameObject val10 = new GameObject("attach");
		val10.layer = itemPrefab.layer;
		val10.transform.SetParent(itemPrefab.transform, false);
		Mesh val11 = LoadMesh(id);
		string text = (food ? "Cloudberry" : "RawMeat");
		Bounds worldMeshBounds = GetWorldMeshBounds(PrefabManager.Instance.GetPrefab(text));
		float num5 = Mathf.Max(((Bounds)(ref worldMeshBounds)).size.x, ((Bounds)(ref worldMeshBounds)).size.z) * (food ? 0.85f : 1f);
		Bounds bounds = val11.bounds;
		float num6 = ((Bounds)(ref bounds)).size.x * Mathf.Abs(itemPrefab.transform.lossyScale.x);
		Bounds bounds2 = val11.bounds;
		float num7 = Mathf.Max(num6, ((Bounds)(ref bounds2)).size.z * Mathf.Abs(itemPrefab.transform.lossyScale.z));
		if (num5 <= 0f || num7 <= 0f)
		{
			throw new InvalidOperationException("Invalid food display bounds.");
		}
		float num8 = num5 / num7;
		((BaseUnityPlugin)this).Logger.LogInfo((object)(id + " ground width: " + num5.ToString("F3") + " m; scale " + num8.ToString("F2") + "; reference " + text));
		val10.transform.localScale = Vector3.one * num8;
		BoxCollider val12 = itemPrefab.AddComponent<BoxCollider>();
		Bounds bounds3 = val11.bounds;
		val12.center = ((Bounds)(ref bounds3)).center * num8;
		Bounds bounds4 = val11.bounds;
		val12.size = ((Bounds)(ref bounds4)).size * num8;
		Rigidbody component = itemPrefab.GetComponent<Rigidbody>();
		if (Object.op_Implicit((Object)(object)component))
		{
			component.mass = shared.m_weight;
		}
		if ((int)SystemInfo.graphicsDeviceType != 4)
		{
			if (!Object.op_Implicit((Object)(object)val4))
			{
				throw new InvalidOperationException("RawMeat has no mesh material to clone.");
			}
			val10.AddComponent<MeshFilter>().sharedMesh = val11;
			Material val13 = new Material(val4);
			((Object)val13).name = id + "_Material";
			string filename = (food ? "Khinkali_BaseColor.png" : "MincedMeat_BaseColor.png");
			Texture2D mainTexture = LoadTexture(filename, mipmaps: true);
			val13.mainTexture = (Texture)(object)mainTexture;
			val13.mainTextureScale = Vector2.one;
			val13.mainTextureOffset = Vector2.zero;
			if (val13.HasProperty("_Color"))
			{
				val13.SetColor("_Color", Color.white);
			}
			if (val13.HasProperty("_BumpMap"))
			{
				val13.SetTexture("_BumpMap", (Texture)null);
			}
			if (val13.HasProperty("_MetallicGlossMap"))
			{
				val13.SetTexture("_MetallicGlossMap", (Texture)null);
			}
			if (val13.HasProperty("_Metallic"))
			{
				val13.SetFloat("_Metallic", 0f);
			}
			if (val13.HasProperty("_Glossiness"))
			{
				val13.SetFloat("_Glossiness", 0.12f);
			}
			val13.DisableKeyword("_NORMALMAP");
			val13.DisableKeyword("_METALLICGLOSSMAP");
			((Renderer)val10.AddComponent<MeshRenderer>()).sharedMaterial = val13;
			Texture2D val14 = LoadTexture(id + ".png", mipmaps: false);
			shared.m_icons = (Sprite[])(object)new Sprite[1] { Sprite.Create(val14, new Rect(0f, 0f, (float)((Texture)val14).width, (float)((Texture)val14).height), new Vector2(0.5f, 0.5f)) };
		}
		return val3;
	}

	private static Bounds GetWorldMeshBounds(GameObject prefab)
	{
		//IL_0002: 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_0054: 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_0062: 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_008f: 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_0099: 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_00a6: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: 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_00b4: 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)
		Bounds result = default(Bounds);
		bool flag = false;
		MeshFilter[] componentsInChildren = prefab.GetComponentsInChildren<MeshFilter>(true);
		foreach (MeshFilter val in componentsInChildren)
		{
			if (!Object.op_Implicit((Object)(object)val.sharedMesh))
			{
				continue;
			}
			MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>();
			if (!Object.op_Implicit((Object)(object)component) || !((Renderer)component).enabled)
			{
				continue;
			}
			Bounds bounds = val.sharedMesh.bounds;
			for (int j = 0; j < 8; j++)
			{
				Vector3 val2 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1))));
				Vector3 val3 = ((Component)val).transform.TransformPoint(val2);
				if (!flag)
				{
					result = new Bounds(val3, Vector3.zero);
					flag = true;
				}
				else
				{
					((Bounds)(ref result)).Encapsulate(val3);
				}
			}
		}
		if (!flag)
		{
			throw new InvalidOperationException("No visible mesh bounds for " + ((Object)prefab).name);
		}
		return result;
	}

	private Texture2D LoadTexture(string filename, bool mipmaps)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: Expected O, but got Unknown
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, mipmaps);
		if (!ImageConversion.LoadImage(val, File.ReadAllBytes(Path.Combine(assetDirectory, filename))))
		{
			throw new InvalidDataException("Invalid PNG: " + filename);
		}
		((Object)val).name = filename;
		((Texture)val).filterMode = (FilterMode)(!mipmaps);
		((Texture)val).wrapMode = (TextureWrapMode)1;
		return val;
	}

	private Mesh LoadMesh(string id)
	{
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: 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_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c2: Expected O, but got Unknown
		MeshData meshData = JsonUtility.FromJson<MeshData>(File.ReadAllText(Path.Combine(assetDirectory, id + ".mesh.json")));
		if (meshData == null || meshData.positions == null || meshData.positions.Length == 0 || meshData.positions.Length % 3 != 0)
		{
			throw new InvalidDataException("Invalid vertex data: " + id);
		}
		int count = meshData.positions.Length / 3;
		if (meshData.normals == null || meshData.normals.Length != count * 3 || meshData.uv == null || meshData.uv.Length != count * 2 || meshData.triangles == null || meshData.triangles.Length % 3 != 0 || meshData.triangles.Any((int i) => i < 0 || i >= count))
		{
			throw new InvalidDataException("Invalid topology/UVs: " + id);
		}
		Vector3[] array = (Vector3[])(object)new Vector3[count];
		Vector3[] array2 = (Vector3[])(object)new Vector3[count];
		Vector2[] array3 = (Vector2[])(object)new Vector2[count];
		for (int num = 0; num < count; num++)
		{
			ref Vector3 reference = ref array[num];
			reference = new Vector3(meshData.positions[num * 3], meshData.positions[num * 3 + 1], meshData.positions[num * 3 + 2]);
			ref Vector3 reference2 = ref array2[num];
			reference2 = new Vector3(meshData.normals[num * 3], meshData.normals[num * 3 + 1], meshData.normals[num * 3 + 2]);
			ref Vector2 reference3 = ref array3[num];
			reference3 = new Vector2(meshData.uv[num * 2], meshData.uv[num * 2 + 1]);
		}
		Mesh val = new Mesh();
		((Object)val).name = id;
		val.vertices = array;
		val.normals = array2;
		val.uv = array3;
		val.triangles = meshData.triangles;
		Mesh val2 = val;
		val2.RecalculateBounds();
		return val2;
	}

	private void RegisterServingTrayFoods()
	{
		GameObject prefab = PrefabManager.Instance.GetPrefab("Bread");
		PieceTable buildPieces = PrefabManager.Instance.GetPrefab("Feaster").GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces;
		string[] array = new string[3] { "KhinkaliMod_Khinkali", "SGC_Mtsvadi", "SGC_Shoti" };
		foreach (string text in array)
		{
			GameObject itemPrefab = ItemManager.Instance.GetItem(text).ItemPrefab;
			ItemDrop item = itemPrefab.GetComponent<ItemDrop>();
			SharedData shared = item.m_itemData.m_shared;
			GameObject gameObject = ((Component)itemPrefab.transform.Find("attach")).gameObject;
			foreach (Collider item2 in from c in itemPrefab.GetComponentsInChildren<Collider>(true)
				where !c.enabled
				select c)
			{
				Object.DestroyImmediate((Object)(object)item2);
			}
			Piece val = itemPrefab.GetComponent<Piece>() ?? itemPrefab.AddComponent<Piece>();
			WearNTear val2 = itemPrefab.GetComponent<WearNTear>() ?? itemPrefab.AddComponent<WearNTear>();
			CopyServingFields<Piece>(prefab.GetComponent<Piece>(), val);
			CopyServingFields<WearNTear>(prefab.GetComponent<WearNTear>(), val2);
			val.m_name = shared.m_name;
			val.m_description = shared.m_description;
			val.m_icon = shared.m_icons.FirstOrDefault();
			val.m_resources = prefab.GetComponent<Piece>().m_resources.Select(delegate(Requirement r)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Expected O, but got Unknown
				Requirement val4 = new Requirement();
				CopyServingFields<Requirement>(r, val4);
				val4.m_resItem = item;
				return val4;
			}).ToArray();
			val2.m_new = gameObject;
			val2.m_worn = gameObject;
			val2.m_broken = gameObject;
			val2.m_fragmentRoots = (GameObject[])(object)new GameObject[1] { gameObject };
			val2.m_nonSolidRenderers = new List<Renderer>();
			if (!Object.op_Implicit((Object)(object)itemPrefab.GetComponent<ServingTrayFood>()))
			{
				itemPrefab.AddComponent<ServingTrayFood>();
			}
			if (!Object.op_Implicit((Object)(object)item.m_pieceDisabledObj))
			{
				Transform val3 = ((IEnumerable<Transform>)itemPrefab.GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform p) => ((Object)p).name.IndexOf("ItemSparkles", StringComparison.OrdinalIgnoreCase) >= 0));
				if (Object.op_Implicit((Object)(object)val3))
				{
					item.m_pieceDisabledObj = ((Component)val3).gameObject;
				}
			}
			if (!buildPieces.m_pieces.Contains(itemPrefab))
			{
				buildPieces.m_pieces.Add(itemPrefab);
			}
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Registered Khinkali, Mtsvadi and Shoti in the serving tray.");
	}

	private static void CopyServingFields<T>(T source, T target)
	{
		FieldInfo[] fields = typeof(T).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (!typeof(Delegate).IsAssignableFrom(fieldInfo.FieldType))
			{
				fieldInfo.SetValue(target, fieldInfo.GetValue(source));
			}
		}
	}

	private void RegisterShoti()
	{
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Expected O, but got Unknown
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Expected O, but got Unknown
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Expected O, but got Unknown
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Expected O, but got Unknown
		//IL_0252: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Expected O, but got Unknown
		Recipe val = Resources.FindObjectsOfTypeAll<Recipe>().First((Recipe r) => Object.op_Implicit((Object)(object)r.m_item) && ((Object)r.m_item).name == "BreadDough");
		CookingStation component = PrefabManager.Instance.GetPrefab("piece_oven").GetComponent<CookingStation>();
		ItemConversion val2 = component.m_conversion.First((ItemConversion c) => Object.op_Implicit((Object)(object)c.m_from) && ((Object)c.m_from).name == "BreadDough" && ((Object)c.m_to).name == "Bread");
		Fermenter component2 = PrefabManager.Instance.GetPrefab("fermenter").GetComponent<Fermenter>();
		AssetManifest manifest = JsonConvert.DeserializeObject<AssetManifest>(File.ReadAllText(Path.Combine(assetDirectory, "Shoti.assets.json")));
		int minStationLevel = val.m_minStationLevel;
		CustomItem mix = CreateShotiItem("SGC_ShotiStarterMix", "Shoti starter mix", "Flour and water, stirred together. Ferment for ten minutes to yield three Shoti starters.", "RawMeat", minStationLevel, (RequirementConfig[])(object)new RequirementConfig[1]
		{
			new RequirementConfig("BarleyFlour", 6, 0, false)
		}, manifest);
		CustomItem val3 = CreateShotiItem("SGC_ShotiStarter", "Shoti starter", "A lively, bubbly bread starter, ready to raise Shoti dough.", "RawMeat", minStationLevel, (RequirementConfig[])(object)new RequirementConfig[0], manifest);
		CustomItem dough = CreateShotiItem("SGC_ShotiDough", "Shoti dough", "Leavened barley dough. Bake it in a stone oven.", "BreadDough", minStationLevel, (RequirementConfig[])(object)new RequirementConfig[2]
		{
			new RequirementConfig("BarleyFlour", 10, 0, false),
			new RequirementConfig("SGC_ShotiStarter", 1, 0, false)
		}, null);
		CustomItem val4 = CreateShotiItem("SGC_Shoti", "Shoti", "A long Georgian loaf with a crisp, toasted crust and a soft heart.", "Bread", minStationLevel, (RequirementConfig[])(object)new RequirementConfig[0], manifest);
		CustomItem[] array = (CustomItem[])(object)new CustomItem[4] { mix, val3, dough, val4 };
		List<CustomItem> list = new List<CustomItem>();
		try
		{
			CustomItem[] array2 = array;
			foreach (CustomItem val5 in array2)
			{
				if (!ItemManager.Instance.AddItem(val5))
				{
					throw new InvalidOperationException("Could not register " + ((Object)val5.ItemPrefab).name);
				}
				list.Add(val5);
			}
			List<ItemConversion> conversion = component2.m_conversion;
			ItemConversion val6 = new ItemConversion();
			val6.m_from = mix.ItemDrop;
			val6.m_to = val3.ItemDrop;
			val6.m_producedItems = 3;
			conversion.Add(val6);
			List<ItemConversion> conversion2 = component.m_conversion;
			ItemConversion val7 = new ItemConversion();
			val7.m_from = dough.ItemDrop;
			val7.m_to = val4.ItemDrop;
			val7.m_cookTime = val2.m_cookTime;
			conversion2.Add(val7);
		}
		catch
		{
			component2.m_conversion.RemoveAll((ItemConversion c) => (Object)(object)c.m_from == (Object)(object)mix.ItemDrop);
			component.m_conversion.RemoveAll((ItemConversion c) => (Object)(object)c.m_from == (Object)(object)dough.ItemDrop);
			foreach (CustomItem item in list)
			{
				ItemManager.Instance.RemoveItem(item);
			}
			throw;
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Registered Shoti: preparation level " + minStationLevel + ", 600-second fermentation yielding 3 starters, vanilla bread baking time " + val2.m_cookTime + " seconds."));
	}

	private CustomItem CreateShotiItem(string id, string name, string description, string template, int level, RequirementConfig[] requirements, AssetManifest manifest)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Expected O, but got Unknown
		//IL_00ba: 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_02af: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0317: Unknown result type (might be due to invalid IL or missing references)
		//IL_031c: 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_0331: Unknown result type (might be due to invalid IL or missing references)
		//IL_0342: 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_0388: Unknown result type (might be due to invalid IL or missing references)
		//IL_038f: Unknown result type (might be due to invalid IL or missing references)
		bool flag = id == "SGC_Shoti";
		string text = id;
		ItemConfig val = new ItemConfig();
		val.Name = name;
		val.Description = description;
		val.StackSize = 20;
		val.Weight = 1f;
		val.Amount = 1;
		val.Enabled = true;
		val.CraftingStation = ((requirements.Length > 0) ? "piece_preptable" : null);
		val.MinStationLevel = level;
		val.Requirements = requirements;
		CustomItem val2 = new CustomItem(text, template, val);
		GameObject itemPrefab = val2.ItemPrefab;
		ItemData itemData = val2.ItemDrop.m_itemData;
		SharedData shared = itemData.m_shared;
		shared.m_itemType = (ItemType)((!flag) ? 1 : 2);
		shared.m_food = (flag ? 25 : 0);
		shared.m_foodStamina = (flag ? 80 : 0);
		shared.m_foodEitr = 0f;
		shared.m_foodBurnTime = (flag ? 1200 : 0);
		shared.m_foodRegen = (flag ? 5 : 0);
		shared.m_maxStackSize = 20;
		shared.m_weight = 1f;
		shared.m_teleportable = true;
		shared.m_maxQuality = 1;
		shared.m_isDrink = false;
		shared.m_consumeStatusEffect = null;
		shared.m_appendToolTip = null;
		shared.m_useDurability = false;
		shared.m_value = 0;
		itemData.m_stack = 1;
		itemData.m_quality = 1;
		Rigidbody component = itemPrefab.GetComponent<Rigidbody>();
		if (Object.op_Implicit((Object)(object)component))
		{
			component.mass = 1f;
		}
		if (manifest == null)
		{
			return val2;
		}
		LODGroup[] componentsInChildren = itemPrefab.GetComponentsInChildren<LODGroup>(true);
		foreach (LODGroup val3 in componentsInChildren)
		{
			Object.DestroyImmediate((Object)(object)val3);
		}
		MeshRenderer[] componentsInChildren2 = itemPrefab.GetComponentsInChildren<MeshRenderer>(true);
		foreach (MeshRenderer val4 in componentsInChildren2)
		{
			((Renderer)val4).enabled = false;
		}
		SkinnedMeshRenderer[] componentsInChildren3 = itemPrefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val5 in componentsInChildren3)
		{
			((Renderer)val5).enabled = false;
		}
		Collider[] componentsInChildren4 = itemPrefab.GetComponentsInChildren<Collider>(true);
		foreach (Collider val6 in componentsInChildren4)
		{
			val6.enabled = false;
		}
		string[] array = new string[2] { "attach", "attach_cook" };
		foreach (string text2 in array)
		{
			Transform val7 = itemPrefab.transform.Find(text2);
			if (Object.op_Implicit((Object)(object)val7))
			{
				((Object)val7).name = "unused_" + text2;
			}
		}
		itemPrefab.transform.localScale = Vector3.one;
		GameObject val8 = Child(itemPrefab, "attach", Vector3.zero);
		Bounds val9 = BuildModel(val8, manifest.assets.First((AssetEntry a) => a.name == id));
		BoxCollider val10 = itemPrefab.AddComponent<BoxCollider>();
		val10.center = ((Bounds)(ref val9)).center;
		val10.size = ((Bounds)(ref val9)).size;
		if (flag)
		{
			Bounds worldMeshBounds = GetWorldMeshBounds(PrefabManager.Instance.GetPrefab("Bread"));
			float num = Mathf.Min(1f, Mathf.Max(((Bounds)(ref worldMeshBounds)).size.x, ((Bounds)(ref worldMeshBounds)).size.z) / Mathf.Max(((Bounds)(ref val9)).size.x, ((Bounds)(ref val9)).size.z));
			GameObject val11 = Object.Instantiate<GameObject>(val8, itemPrefab.transform, false);
			((Object)val11).name = "attach_cook";
			val11.transform.localScale = Vector3.one * num;
			LODGroup[] componentsInChildren5 = val11.GetComponentsInChildren<LODGroup>(true);
			foreach (LODGroup val12 in componentsInChildren5)
			{
				val12.enabled = false;
			}
			Renderer[] componentsInChildren6 = val11.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val13 in componentsInChildren6)
			{
				val13.enabled = false;
			}
			val11.AddComponent<ShotiCookVisual>();
		}
		if (HasGraphics)
		{
			shared.m_icons = (Sprite[])(object)new Sprite[1] { LoadIcon(id) };
		}
		return val2;
	}
}
public sealed class Makali : MonoBehaviour
{
	[HarmonyPatch(typeof(CookingStation), "UpdateCooking")]
	private static class CookingPatch
	{
		private static bool Prefix(CookingStation __instance)
		{
			Makali component = ((Component)__instance).GetComponent<Makali>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return true;
			}
			component.Tick();
			return false;
		}
	}

	[HarmonyPatch(typeof(CookingStation), "SetSlotVisual")]
	private static class SmokePatch
	{
		private static void Prefix(CookingStation __instance, string item, ref bool fireLit)
		{
			if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<Makali>()))
			{
				fireLit = fireLit && item == "SGC_MtsvadiRaw";
			}
		}
	}

	[HarmonyPatch(typeof(CookingStation), "HoverText")]
	private static class HoverPatch
	{
		private static void Postfix(CookingStation __instance, ref string __result)
		{
			Makali component = ((Component)__instance).GetComponent<Makali>();
			if (Object.op_Implicit((Object)(object)component))
			{
				__result += component.StatusText();
			}
		}
	}

	[HarmonyPatch]
	private static class MutationPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(CookingStation), "RPC_AddFuel", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(CookingStation), "RPC_AddItem", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(CookingStation), "RPC_RemoveDoneItem", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(CookingStation), "DropAllItems", (Type[])null, (Type[])null);
		}

		private static bool Prefix(CookingStation __instance, MethodBase __originalMethod, object[] __args)
		{
			Makali component = ((Component)__instance).GetComponent<Makali>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return true;
			}
			if (!component.Owner)
			{
				return false;
			}
			component.Tick();
			if (__originalMethod.Name == "RPC_AddFuel" && component.Fuel > 9f)
			{
				component.Refund("Coal");
				return false;
			}
			if (__originalMethod.Name == "RPC_AddItem")
			{
				if ((string)__args[1] != "SGC_MtsvadiRaw")
				{
					return false;
				}
				bool flag = false;
				for (int i = 0; i < 6; i++)
				{
					if (component.View.GetZDO().GetString("slot" + i, "") == "")
					{
						flag = true;
					}
				}
				if (!flag)
				{
					component.Refund("SGC_MtsvadiRaw");
					return false;
				}
			}
			return true;
		}
	}

	private static readonly MethodInfo Delta = AccessTools.Method(typeof(CookingStation), "GetDeltaTime", (Type[])null, (Type[])null);

	private static readonly MethodInfo FuelGet = AccessTools.Method(typeof(CookingStation), "GetFuel", (Type[])null, (Type[])null);

	private static readonly MethodInfo FuelSet = AccessTools.Method(typeof(CookingStation), "SetFuel", (Type[])null, (Type[])null);

	private static readonly MethodInfo Visual = AccessTools.Method(typeof(CookingStation), "UpdateVisual", (Type[])null, (Type[])null);

	private static readonly MethodInfo Hover = AccessTools.Method(typeof(CookingStation), "HoverText", (Type[])null, (Type[])null);

	private CookingStation station;

	private ZNetView view;

	public float Fuel => (float)FuelGet.Invoke(Station, null);

	private CookingStation Station
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)station))
			{
				return station = ((Component)this).GetComponent<CookingStation>();
			}
			return station;
		}
	}

	private ZNetView View
	{
		get
		{
			if (!Object.op_Implicit((Object)(object)view))
			{
				return view = ((Component)this).GetComponent<ZNetView>();
			}
			return view;
		}
	}

	public bool Owner
	{
		get
		{
			if (Object.op_Implicit((Object)(object)View) && View.IsValid())
			{
				return View.IsOwner();
			}
			return false;
		}
	}

	public void Tick()
	{
		//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_01ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_020c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0212: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)View) || !View.IsValid())
		{
			return;
		}
		CookingStation val = Station;
		ZDO zDO = View.GetZDO();
		if (Owner)
		{
			float elapsed = (float)Delta.Invoke(val, null);
			string[] array = new string[6];
			float[] array2 = new float[6];
			for (int i = 0; i < 6; i++)
			{
				array[i] = zDO.GetString("slot" + i, "");
				array2[i] = zDO.GetFloat("slot" + i, 0f);
			}
			float coal = Fuel;
			float num = MakaliTiming.Advance(elapsed, ref coal, array, array2);
			if (num > 0f)
			{
				FuelSet.Invoke(val, new object[1] { coal });
				for (int j = 0; j < 6; j++)
				{
					string text = zDO.GetString("slot" + j, "");
					zDO.Set("slot" + j, array[j]);
					zDO.Set("slot" + j, array2[j]);
					zDO.Set("slotstatus" + j, (array[j] == "Coal") ? 2 : ((array[j] == "SGC_Mtsvadi") ? 1 : 0));
					if (text != array[j])
					{
						if (array[j] == "SGC_Mtsvadi")
						{
							val.m_doneEffect.Create(val.m_slots[j].position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
						}
						else if (array[j] == "Coal")
						{
							val.m_overcookedEffect.Create(val.m_slots[j].position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
						}
					}
				}
			}
		}
		Visual.Invoke(val, new object[1] { Fuel > 0f });
		for (int k = 0; k < val.m_slots.Length; k++)
		{
			AudioSource component = ((Component)val.m_slots[k]).GetComponent<AudioSource>();
			if (Object.op_Implicit((Object)(object)component) && ((Behaviour)component).isActiveAndEnabled)
			{
				bool flag = Fuel > 0f && zDO.GetString("slot" + k, "") == "SGC_MtsvadiRaw";
				component.mute = !flag;
				if (flag && !component.isPlaying)
				{
					component.Play();
				}
				else if (!flag && component.isPlaying)
				{
					component.Stop();
				}
			}
		}
		if (Object.op_Implicit((Object)(object)val.m_addFoodSwitch))
		{
			val.m_addFoodSwitch.m_hoverText = (string)Hover.Invoke(val, null);
		}
	}

	public string StatusText()
	{
		if (!Object.op_Implicit((Object)(object)View) || !View.IsValid())
		{
			return "";
		}
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		for (int i = 0; i < 6; i++)
		{
			switch (View.GetZDO().GetString("slot" + i, ""))
			{
			case "SGC_MtsvadiRaw":
				num++;
				break;
			case "SGC_Mtsvadi":
				num2++;
				break;
			case "Coal":
				num3++;
				break;
			}
		}
		return "\nSkewers: " + (num + num2 + num3) + "/6 | Ready: " + num2 + ((num3 > 0) ? (" | Burnt: " + num3) : "") + "\nCoal: " + Fuel.ToString("0.0") + "/10" + ((Fuel <= 0f && num + num2 > 0) ? " — paused; add coal on the left" : "");
	}

	public void Refund(string id)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		GameObject prefab = ZNetScene.instance.GetPrefab(id);
		if (Object.op_Implicit((Object)(object)prefab))
		{
			Object.Instantiate<GameObject>(prefab, Station.m_spawnPoint.position, Quaternion.identity);
		}
	}
}
public static class MakaliTiming
{
	public const string Raw = "SGC_MtsvadiRaw";

	public const string Cooked = "SGC_Mtsvadi";

	public const float CookSeconds = 45f;

	public const float BurnSeconds = 90f;

	public const float SecondsPerCoal = 180f;

	public static float Advance(float elapsed, ref float coal, string[] items, float[] progress)
	{
		float num = 0f;
		for (int i = 0; i < items.Length; i++)
		{
			if (items[i] == "SGC_MtsvadiRaw" || items[i] == "SGC_Mtsvadi")
			{
				num = Math.Max(num, 90f - progress[i]);
			}
		}
		float num2 = Math.Max(0f, Math.Min(Math.Max(0f, elapsed), Math.Min(Math.Max(0f, coal) * 180f, num)));
		coal = Math.Max(0f, coal - num2 / 180f);
		for (int j = 0; j < items.Length; j++)
		{
			if (!(items[j] != "SGC_MtsvadiRaw") || !(items[j] != "SGC_Mtsvadi"))
			{
				progress[j] = Math.Min(90f, progress[j] + num2);
				if (progress[j] >= 90f)
				{
					items[j] = "Coal";
				}
				else if (progress[j] >= 45f)
				{
					items[j] = "SGC_Mtsvadi";
				}
			}
		}
		return num2;
	}
}
public sealed class ServingTrayFood : MonoBehaviour
{
	[HarmonyPatch(typeof(ItemDrop), "MakePiece")]
	private static class PlacedParticles
	{
		private static void Postfix(ItemDrop __instance)
		{
			if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<ServingTrayFood>()))
			{
				ParticleSystemRenderer component = ((Component)__instance).GetComponent<ParticleSystemRenderer>();
				if (Object.op_Implicit((Object)(object)component))
				{
					((Renderer)component).enabled = false;
				}
			}
		}
	}
}
public sealed class ShotiCookVisual : MonoBehaviour
{
	private void Awake()
	{
		bool enabled = !Object.op_Implicit((Object)(object)((Component)this).GetComponentInParent<ItemDrop>());
		LODGroup[] componentsInChildren = ((Component)this).GetComponentsInChildren<LODGroup>(true);
		foreach (LODGroup val in componentsInChildren)
		{
			val.enabled = enabled;
		}
		Renderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val2 in componentsInChildren2)
		{
			val2.enabled = enabled;
		}
	}
}
public static class Shoti
{
	[HarmonyPatch(typeof(CookingStation), "OnInteract")]
	private static class YieldPatch
	{
		private static void Prefix(CookingStation __instance, out bool __state)
		{
			__state = __instance.m_canGiveBonusYield;
			if (NextReadyIsShoti(__instance))
			{
				__instance.m_canGiveBonusYield = false;
			}
		}

		private static void Finalizer(CookingStation __instance, bool __state)
		{
			__instance.m_canGiveBonusYield = __state;
		}
	}

	[HarmonyPatch(typeof(CookingStation), "RPC_RemoveDoneItem")]
	private static class OwnerYieldPatch
	{
		private static void Prefix(CookingStation __instance, ref int __2)
		{
			if (NextReadyIsShoti(__instance))
			{
				__2 = 1;
			}
		}
	}

	[HarmonyPatch(typeof(Fermenter), "GetStatus")]
	private static class DurationPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			FieldInfo field = AccessTools.Field(typeof(Fermenter), "m_fermentationDuration");
			MethodInfo method = AccessTools.Method(typeof(Shoti), "FermentationDuration", (Type[])null, (Type[])null);
			bool patched = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Ldfld && object.Equals(instruction.operand, field))
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = method;
					patched = true;
				}
				yield return instruction;
			}
			if (!patched)
			{
				throw new InvalidOperationException("Valheim fermenter duration lookup changed; Shoti timing patch could not be applied.");
			}
		}
	}

	public const string Mix = "SGC_ShotiStarterMix";

	public const string Starter = "SGC_ShotiStarter";

	public const string Dough = "SGC_ShotiDough";

	public const string Bread = "SGC_Shoti";

	public static float FermentationDuration(Fermenter station)
	{
		ZNetView component = ((Component)station).GetComponent<ZNetView>();
		if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || component.GetZDO().GetInt(ZDOVars.s_content, 0) != StringExtensionMethods.GetStableHashCode("SGC_ShotiStarterMix"))
		{
			return station.m_fermentationDuration;
		}
		return 600f;
	}

	public static bool NextReadyIsShoti(CookingStation station)
	{
		ZNetView component = ((Component)station).GetComponent<ZNetView>();
		if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
		{
			return false;
		}
		for (int i = 0; i < station.m_slots.Length; i++)
		{
			string text = component.GetZDO().GetString("slot" + i, "");
			if (!(text == ""))
			{
				int num = component.GetZDO().GetInt("slotstatus" + i, 0);
				if (num == 1 || num == 2)
				{
					return text == "SGC_Shoti";
				}
			}
		}
		return false;
	}
}