Decompiled source of FoodTweaks v1.0.0

FoodTweaks.dll

Decompiled 3 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ModHub;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("FoodTweaks")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FoodTweaks")]
[assembly: AssemblyTitle("FoodTweaks")]
[assembly: AssemblyVersion("1.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 FoodTweaks
{
	internal static class FoodApplier
	{
		internal class FoodOrig
		{
			public float Health;

			public float Stamina;

			public float Eitr;

			public float Duration;

			public float Regen;
		}

		public static readonly string[] SeFields = new string[9] { "m_healthUpFront", "m_healthOverTime", "m_staminaUpFront", "m_staminaOverTime", "m_eitrUpFront", "m_eitrOverTime", "m_healthRegenMultiplier", "m_staminaRegenMultiplier", "m_eitrRegenMultiplier" };

		private static readonly Dictionary<string, FoodOrig> _foodOrig = new Dictionary<string, FoodOrig>();

		private static readonly Dictionary<string, Dictionary<string, float>> _meadOrig = new Dictionary<string, Dictionary<string, float>>();

		private static readonly Dictionary<string, FieldInfo> _fieldCache = new Dictionary<string, FieldInfo>();

		public static readonly List<ItemDrop> FoodItems = new List<ItemDrop>();

		public static readonly List<ItemDrop> MeadItems = new List<ItemDrop>();

		public static FoodOrig GetFoodOrig(string prefab)
		{
			FoodOrig value;
			return _foodOrig.TryGetValue(prefab, out value) ? value : null;
		}

		public static Dictionary<string, float> GetMeadOrig(string prefab)
		{
			Dictionary<string, float> value;
			return _meadOrig.TryGetValue(prefab, out value) ? value : null;
		}

		private static void Collect(ObjectDB db)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Invalid comparison between Unknown and I4
			FoodItems.Clear();
			MeadItems.Clear();
			foreach (GameObject item in db.m_items)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ItemDrop component = item.GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null || component.m_itemData?.m_shared == null)
				{
					continue;
				}
				SharedData shared = component.m_itemData.m_shared;
				if ((int)shared.m_itemType != 2)
				{
					continue;
				}
				string name = ((Object)item).name;
				if (!_foodOrig.ContainsKey(name) && !_meadOrig.ContainsKey(name))
				{
					if (shared.m_food > 0f || shared.m_foodStamina > 0f || shared.m_foodEitr > 0f)
					{
						_foodOrig[name] = new FoodOrig
						{
							Health = shared.m_food,
							Stamina = shared.m_foodStamina,
							Eitr = shared.m_foodEitr,
							Duration = shared.m_foodBurnTime,
							Regen = shared.m_foodRegen
						};
					}
					else if ((Object)(object)shared.m_consumeStatusEffect != (Object)null)
					{
						StatusEffect consumeStatusEffect = shared.m_consumeStatusEffect;
						Dictionary<string, float> dictionary = new Dictionary<string, float> { ["ttl"] = consumeStatusEffect.m_ttl };
						string[] seFields = SeFields;
						foreach (string text in seFields)
						{
							FieldInfo fieldInfo = Field(((object)consumeStatusEffect).GetType(), text);
							if (fieldInfo != null)
							{
								dictionary[text] = (float)fieldInfo.GetValue(consumeStatusEffect);
							}
						}
						_meadOrig[name] = dictionary;
					}
				}
				if (_foodOrig.ContainsKey(name))
				{
					FoodItems.Add(component);
				}
				else if (_meadOrig.ContainsKey(name))
				{
					MeadItems.Add(component);
				}
			}
		}

		private static FieldInfo Field(Type t, string name)
		{
			string key = t.FullName + "." + name;
			if (_fieldCache.TryGetValue(key, out var value))
			{
				return value;
			}
			value = AccessTools.Field(t, name);
			if (value != null && value.FieldType != typeof(float))
			{
				value = null;
			}
			_fieldCache[key] = value;
			return value;
		}

		public static bool MeadHasField(ItemDrop drop, string field)
		{
			StatusEffect consumeStatusEffect = drop.m_itemData.m_shared.m_consumeStatusEffect;
			return (Object)(object)consumeStatusEffect != (Object)null && (field == "ttl" || Field(((object)consumeStatusEffect).GetType(), field) != null);
		}

		public static void ApplyAll()
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || instance.m_items == null || instance.m_items.Count == 0)
			{
				return;
			}
			try
			{
				Collect(instance);
				FoodData active = FoodTweaksPlugin.Active;
				foreach (ItemDrop foodItem in FoodItems)
				{
					string name = ((Object)((Component)foodItem).gameObject).name;
					SharedData shared = foodItem.m_itemData.m_shared;
					FoodOrig foodOrig = _foodOrig[name];
					shared.m_food = Mathf.Max(0f, (FoodData.Get(active.Food, name, "health") ?? foodOrig.Health) * active.HealthMult);
					shared.m_foodStamina = Mathf.Max(0f, (FoodData.Get(active.Food, name, "stamina") ?? foodOrig.Stamina) * active.StaminaMult);
					shared.m_foodEitr = Mathf.Max(0f, (FoodData.Get(active.Food, name, "eitr") ?? foodOrig.Eitr) * active.EitrMult);
					shared.m_foodBurnTime = Mathf.Max(1f, (FoodData.Get(active.Food, name, "duration") ?? foodOrig.Duration) * active.DurationMult);
					shared.m_foodRegen = Mathf.Max(0f, (FoodData.Get(active.Food, name, "regen") ?? foodOrig.Regen) * active.RegenMult);
				}
				foreach (ItemDrop meadItem in MeadItems)
				{
					string name2 = ((Object)((Component)meadItem).gameObject).name;
					StatusEffect consumeStatusEffect = meadItem.m_itemData.m_shared.m_consumeStatusEffect;
					if ((Object)(object)consumeStatusEffect == (Object)null)
					{
						continue;
					}
					Dictionary<string, float> dictionary = _meadOrig[name2];
					float num = FoodData.Get(active.Mead, name2, "ttl") ?? dictionary["ttl"];
					consumeStatusEffect.m_ttl = Mathf.Max(0f, num * active.MeadDurationMult);
					foreach (KeyValuePair<string, float> item in dictionary)
					{
						if (!(item.Key == "ttl"))
						{
							FieldInfo fieldInfo = Field(((object)consumeStatusEffect).GetType(), item.Key);
							if (!(fieldInfo == null))
							{
								fieldInfo.SetValue(consumeStatusEffect, FoodData.Get(active.Mead, name2, item.Key) ?? item.Value);
							}
						}
					}
				}
				FoodTweaksPlugin.Log.LogInfo((object)$"Applied: {FoodItems.Count} foods, {MeadItems.Count} meads");
			}
			catch (Exception ex)
			{
				FoodTweaksPlugin.Log.LogError((object)("Apply failed: " + ex));
			}
		}

		public static float FoodFinal(FoodData d, string prefab, string field)
		{
			FoodOrig foodOrig = GetFoodOrig(prefab);
			if (foodOrig == null)
			{
				return 0f;
			}
			return field switch
			{
				"health" => (FoodData.Get(d.Food, prefab, field) ?? foodOrig.Health) * d.HealthMult, 
				"stamina" => (FoodData.Get(d.Food, prefab, field) ?? foodOrig.Stamina) * d.StaminaMult, 
				"eitr" => (FoodData.Get(d.Food, prefab, field) ?? foodOrig.Eitr) * d.EitrMult, 
				"duration" => (FoodData.Get(d.Food, prefab, field) ?? foodOrig.Duration) * d.DurationMult, 
				"regen" => (FoodData.Get(d.Food, prefab, field) ?? foodOrig.Regen) * d.RegenMult, 
				_ => 0f, 
			};
		}

		public static float FoodVanilla(string prefab, string field)
		{
			FoodOrig foodOrig = GetFoodOrig(prefab);
			if (foodOrig == null)
			{
				return 0f;
			}
			return field switch
			{
				"health" => foodOrig.Health, 
				"stamina" => foodOrig.Stamina, 
				"eitr" => foodOrig.Eitr, 
				"duration" => foodOrig.Duration, 
				"regen" => foodOrig.Regen, 
				_ => 0f, 
			};
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class Patch_ObjectDB_Awake
	{
		[HarmonyPriority(0)]
		private static void Postfix()
		{
			FoodApplier.ApplyAll();
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	internal static class Patch_ObjectDB_CopyOtherDB
	{
		[HarmonyPriority(0)]
		private static void Postfix()
		{
			FoodApplier.ApplyAll();
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class Patch_Player_OnSpawned
	{
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				FoodApplier.ApplyAll();
			}
		}
	}
	[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
	internal static class Patch_Player_GetTotalFoodValue
	{
		private static void Prefix(Player __instance)
		{
			if (!FoodTweaksPlugin.Active.NoDegradation)
			{
				return;
			}
			List<Food> foods = __instance.GetFoods();
			if (foods == null)
			{
				return;
			}
			foreach (Food item in foods)
			{
				SharedData val = item?.m_item?.m_shared;
				if (val != null)
				{
					item.m_health = val.m_food;
					item.m_stamina = val.m_foodStamina;
					item.m_eitr = val.m_foodEitr;
				}
			}
		}
	}
	internal class FoodData
	{
		public const string FHealth = "health";

		public const string FStamina = "stamina";

		public const string FEitr = "eitr";

		public const string FDuration = "duration";

		public const string FRegen = "regen";

		public const string MTtl = "ttl";

		public bool NoDegradation;

		public float HealthMult = 1f;

		public float StaminaMult = 1f;

		public float EitrMult = 1f;

		public float DurationMult = 1f;

		public float RegenMult = 1f;

		public float MeadDurationMult = 1f;

		public readonly Dictionary<string, Dictionary<string, float>> Food = new Dictionary<string, Dictionary<string, float>>();

		public readonly Dictionary<string, Dictionary<string, float>> Mead = new Dictionary<string, Dictionary<string, float>>();

		public bool HasGlobalChanges => NoDegradation || HealthMult != 1f || StaminaMult != 1f || EitrMult != 1f || DurationMult != 1f || RegenMult != 1f || MeadDurationMult != 1f;

		public static float? Get(Dictionary<string, Dictionary<string, float>> d, string prefab, string field)
		{
			Dictionary<string, float> value;
			float value2;
			return (d.TryGetValue(prefab, out value) && value.TryGetValue(field, out value2)) ? new float?(value2) : ((float?)null);
		}

		public static void Set(Dictionary<string, Dictionary<string, float>> d, string prefab, string field, float? value)
		{
			if (!value.HasValue)
			{
				if (d.TryGetValue(prefab, out var value2))
				{
					value2.Remove(field);
					if (value2.Count == 0)
					{
						d.Remove(prefab);
					}
				}
			}
			else
			{
				if (!d.TryGetValue(prefab, out var value3))
				{
					value3 = (d[prefab] = new Dictionary<string, float>());
				}
				value3[field] = value.Value;
			}
		}

		public static bool Has(Dictionary<string, Dictionary<string, float>> d, string prefab)
		{
			Dictionary<string, float> value;
			return d.TryGetValue(prefab, out value) && value.Count > 0;
		}

		public FoodData Clone()
		{
			return Parse(Serialize());
		}

		private static string F(float v)
		{
			return v.ToString("R", CultureInfo.InvariantCulture);
		}

		public string Serialize()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("v1\n");
			stringBuilder.Append("nodegrade=").Append(NoDegradation ? "1" : "0").Append('\n');
			stringBuilder.Append("mult.health=").Append(F(HealthMult)).Append('\n');
			stringBuilder.Append("mult.stamina=").Append(F(StaminaMult)).Append('\n');
			stringBuilder.Append("mult.eitr=").Append(F(EitrMult)).Append('\n');
			stringBuilder.Append("mult.duration=").Append(F(DurationMult)).Append('\n');
			stringBuilder.Append("mult.regen=").Append(F(RegenMult)).Append('\n');
			stringBuilder.Append("mult.meadduration=").Append(F(MeadDurationMult)).Append('\n');
			Write(stringBuilder, "food", Food);
			Write(stringBuilder, "mead", Mead);
			return stringBuilder.ToString();
		}

		private static void Write(StringBuilder sb, string kind, Dictionary<string, Dictionary<string, float>> d)
		{
			foreach (KeyValuePair<string, Dictionary<string, float>> item in d.OrderBy((KeyValuePair<string, Dictionary<string, float>> k) => k.Key))
			{
				foreach (KeyValuePair<string, float> item2 in item.Value.OrderBy((KeyValuePair<string, float> k) => k.Key))
				{
					sb.Append(kind).Append('|').Append(item.Key)
						.Append('|')
						.Append(item2.Key)
						.Append('=')
						.Append(F(item2.Value))
						.Append('\n');
				}
			}
		}

		public static FoodData Parse(string text)
		{
			FoodData foodData = new FoodData();
			if (string.IsNullOrEmpty(text))
			{
				return foodData;
			}
			string[] array = text.Split(new char[1] { '\n' });
			foreach (string text2 in array)
			{
				string text3 = text2.Trim();
				if (text3.Length == 0 || text3.StartsWith("#") || text3 == "v1")
				{
					continue;
				}
				int num = text3.IndexOf('=');
				if (num <= 0)
				{
					continue;
				}
				string text4 = text3.Substring(0, num).Trim();
				string s = text3.Substring(num + 1).Trim();
				if (!float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					continue;
				}
				switch (text4)
				{
				case "nodegrade":
					foodData.NoDegradation = result != 0f;
					continue;
				case "mult.health":
					foodData.HealthMult = result;
					continue;
				case "mult.stamina":
					foodData.StaminaMult = result;
					continue;
				case "mult.eitr":
					foodData.EitrMult = result;
					continue;
				case "mult.duration":
					foodData.DurationMult = result;
					continue;
				case "mult.regen":
					foodData.RegenMult = result;
					continue;
				case "mult.meadduration":
					foodData.MeadDurationMult = result;
					continue;
				}
				string[] array2 = text4.Split(new char[1] { '|' });
				if (array2.Length == 3)
				{
					if (array2[0] == "food")
					{
						Set(foodData.Food, array2[1], array2[2], result);
					}
					else if (array2[0] == "mead")
					{
						Set(foodData.Mead, array2[1], array2[2], result);
					}
				}
			}
			return foodData;
		}
	}
	internal static class FoodMenu
	{
		private enum Kind
		{
			Food,
			Mead
		}

		private class Entry
		{
			public ItemDrop Drop;

			public string Prefab;

			public string Name;

			public Kind Kind;
		}

		private const string Id = "foodtweaks";

		private const float W = 1000f;

		private const float Pad = 40f;

		private const float ListW = 320f;

		private const float RowH = 46f;

		private const float FieldH = 32f;

		private const float Gap = 10f;

		private static FoodData _draft = new FoodData();

		private static bool _dirty;

		private static int _loadedVersion = -1;

		private static Kind _tab = Kind.Food;

		private static Entry _selected;

		private static string _search = "";

		private static bool _showAllMeadFields;

		private static Vector2 _listScroll;

		private static Vector2 _rightScroll;

		private static float _rightContentH = 400f;

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

		private static List<Entry> _foods = new List<Entry>();

		private static List<Entry> _meads = new List<Entry>();

		private static string _status;

		private static float _statusUntil;

		private static GUIStyle _rowLabel;

		private static GUIStyle _rowLabelSel;

		private static readonly Dictionary<string, string> MeadLabels = new Dictionary<string, string>
		{
			{ "ttl", "Длительность, сек" },
			{ "m_healthUpFront", "Здоровье сразу" },
			{ "m_healthOverTime", "Здоровье за действие" },
			{ "m_staminaUpFront", "Выносливость сразу" },
			{ "m_staminaOverTime", "Выносливость за действие" },
			{ "m_eitrUpFront", "Эйтр сразу" },
			{ "m_eitrOverTime", "Эйтр за действие" },
			{ "m_healthRegenMultiplier", "Реген здоровья, ×" },
			{ "m_staminaRegenMultiplier", "Реген выносливости, ×" },
			{ "m_eitrRegenMultiplier", "Реген эйтра, ×" }
		};

		private static readonly (string key, string label)[] FoodFields = new(string, string)[5]
		{
			("health", "Здоровье"),
			("stamina", "Выносливость"),
			("eitr", "Эйтр"),
			("duration", "Длительность, сек"),
			("regen", "Регенерация")
		};

		public static bool IsOpen { get; private set; }

		public static void Open()
		{
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				if (FoodApplier.FoodItems.Count == 0)
				{
					FoodApplier.ApplyAll();
				}
				BuildLists();
				LoadDraft();
				IsOpen = true;
				ModHubAPI.SetInputBlock("foodtweaks", true);
			}
		}

		public static void Close()
		{
			IsOpen = false;
			_edit.Clear();
			ModHubAPI.SetInputBlock("foodtweaks", false);
		}

		public static void Update()
		{
			if (IsOpen)
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					Close();
				}
				else if (Input.GetKeyDown((KeyCode)27))
				{
					Close();
				}
			}
		}

		private static void LoadDraft()
		{
			_draft = FoodTweaksPlugin.Active.Clone();
			_dirty = false;
			_loadedVersion = FoodTweaksPlugin.DataVersion;
			_edit.Clear();
		}

		private static void BuildLists()
		{
			_foods = Make(FoodApplier.FoodItems, Kind.Food);
			_meads = Make(FoodApplier.MeadItems, Kind.Mead);
			if (_selected != null && (Object)(object)_selected.Drop == (Object)null)
			{
				_selected = null;
			}
		}

		private static List<Entry> Make(List<ItemDrop> items, Kind kind)
		{
			List<Entry> list = new List<Entry>();
			foreach (ItemDrop item in items)
			{
				if (!((Object)(object)item == (Object)null))
				{
					string name = item.m_itemData.m_shared.m_name;
					string name2 = ((Localization.instance != null) ? Localization.instance.Localize(name) : name);
					list.Add(new Entry
					{
						Drop = item,
						Prefab = ((Object)((Component)item).gameObject).name,
						Name = name2,
						Kind = kind
					});
				}
			}
			list.Sort((Entry a, Entry b) => string.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase));
			return list;
		}

		private static List<Entry> Filtered()
		{
			List<Entry> list = ((_tab == Kind.Food) ? _foods : _meads);
			if (string.IsNullOrEmpty(_search))
			{
				return list;
			}
			string q = _search.Trim();
			return list.FindAll((Entry e) => e.Name.IndexOf(q, StringComparison.CurrentCultureIgnoreCase) >= 0 || e.Prefab.IndexOf(q, StringComparison.OrdinalIgnoreCase) >= 0);
		}

		public static void Draw()
		{
			//IL_0032: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOpen)
			{
				return;
			}
			if (!_dirty && _loadedVersion != FoodTweaksPlugin.DataVersion)
			{
				LoadDraft();
			}
			Vector2 screen = HubUI.BeginScaled();
			try
			{
				DrawWindow(screen);
			}
			finally
			{
				HubUI.EndScaled();
			}
		}

		private static void DrawWindow(Vector2 screen)
		{
			//IL_0055: 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_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_0081: 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_003a: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			if (_rowLabel == null)
			{
				_rowLabel = HubUI.NoWrap(HubUI.LabelStyle);
				_rowLabel.clipping = (TextClipping)1;
				_rowLabelSel = new GUIStyle(_rowLabel);
				_rowLabelSel.normal.textColor = HubUI.GoldBright;
			}
			float num = Mathf.Min(780f, screen.y - 40f);
			Rect val = HubUI.Centered(screen, 1000f, num);
			HubUI.Window(val, "Food", false);
			if (HubUI.CloseButton(val))
			{
				Close();
				return;
			}
			if (GUI.Button(new Rect(((Rect)(ref val)).x + 22f, ((Rect)(ref val)).y + 22f, 30f, 30f), "<", HubUI.ButtonStyle))
			{
				Close();
				ModHubAPI.OpenHub();
				return;
			}
			bool canEdit = FoodTweaksPlugin.CanEdit;
			float num2 = ((Rect)(ref val)).y + 88f;
			float num3 = ((Rect)(ref val)).yMax - 110f;
			DrawLeft(((Rect)(ref val)).x + 40f, num2, num3);
			float num4 = ((Rect)(ref val)).x + 40f + 320f + 30f;
			float num5 = ((Rect)(ref val)).xMax - 40f - num4;
			DrawRight(new Rect(num4, num2, num5, num3 - num2), canEdit);
			DrawBottom(val, canEdit);
		}

		private static void DrawLeft(float x, float y, float bottom)
		{
			//IL_000d: 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_00a7: 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_00ff: 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)
			//IL_00e4: 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_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: 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_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: 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_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_037c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			if (TabButton(new Rect(x, y, 320f, 36f), "Общие настройки", _selected == null))
			{
				_selected = null;
				_edit.Clear();
			}
			y += 46f;
			float num = 155f;
			if (TabButton(new Rect(x, y, num, 34f), $"Еда ({_foods.Count})", _tab == Kind.Food))
			{
				_tab = Kind.Food;
				_listScroll = Vector2.zero;
			}
			if (TabButton(new Rect(x + num + 10f, y, num, 34f), $"Медовуха ({_meads.Count})", _tab == Kind.Mead))
			{
				_tab = Kind.Mead;
				_listScroll = Vector2.zero;
			}
			y += 44f;
			_search = HubUI.TextField(new Rect(x, y, 320f, 32f), _search);
			if (string.IsNullOrEmpty(_search))
			{
				GUI.Label(new Rect(x + 10f, y, 300f, 32f), "поиск...", HubUI.LabelDimStyle);
			}
			y += 42f;
			List<Entry> list = Filtered();
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(x, y, 320f, bottom - y);
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(0f, 0f, 316f, Mathf.Max((float)list.Count * 46f, ((Rect)(ref val)).height));
			Dictionary<string, Dictionary<string, float>> d = ((_tab == Kind.Food) ? _draft.Food : _draft.Mead);
			_listScroll = GUI.BeginScrollView(val, _listScroll, val2, false, false, GUIStyle.none, GUIStyle.none);
			if (list.Count == 0)
			{
				GUI.Label(new Rect(0f, 0f, 316f, 40f), "Ничего не найдено", HubUI.LabelCenterStyle);
			}
			Rect val3 = default(Rect);
			for (int i = 0; i < list.Count; i++)
			{
				Entry entry = list[i];
				((Rect)(ref val3))..ctor(0f, (float)i * 46f, 316f, 40f);
				if (!(((Rect)(ref val3)).yMax < _listScroll.y) && !(((Rect)(ref val3)).y > _listScroll.y + ((Rect)(ref val)).height))
				{
					bool flag = _selected == entry;
					bool flag2 = ((Rect)(ref val3)).Contains(Event.current.mousePosition);
					HubUI.Slot(val3, flag2, flag);
					Sprite icon = entry.Drop.m_itemData.GetIcon();
					HubUI.DrawSprite(new Rect(((Rect)(ref val3)).x + 6f, ((Rect)(ref val3)).y + 4f, 32f, 32f), icon);
					GUI.Label(new Rect(((Rect)(ref val3)).x + 46f, ((Rect)(ref val3)).y, ((Rect)(ref val3)).width - 100f, ((Rect)(ref val3)).height), entry.Name, flag ? _rowLabelSel : _rowLabel);
					if (FoodData.Has(d, entry.Prefab))
					{
						GUI.Label(new Rect(((Rect)(ref val3)).xMax - 52f, ((Rect)(ref val3)).y, 46f, ((Rect)(ref val3)).height), "<color=#E8C36A>изм.</color>", HubUI.LabelCenterStyle);
					}
					if (GUI.Button(val3, GUIContent.none, GUIStyle.none))
					{
						_selected = entry;
						_edit.Clear();
						_rightScroll = Vector2.zero;
					}
				}
			}
			GUI.EndScrollView();
		}

		private static bool TabButton(Rect r, string text, bool active)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (!active)
			{
				return GUI.Button(r, text, HubUI.ButtonStyle);
			}
			HubUI.Slot(r, false, true);
			GUI.Label(r, text, HubUI.TileLabelHoverStyle);
			return false;
		}

		private static void DrawRight(Rect view, bool canEdit)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(0f, 0f, ((Rect)(ref view)).width - 4f, Mathf.Max(_rightContentH, ((Rect)(ref view)).height));
			_rightScroll = GUI.BeginScrollView(view, _rightScroll, val, false, false, GUIStyle.none, GUIStyle.none);
			float w = ((Rect)(ref view)).width - 4f;
			float y = 0f;
			bool enabled = GUI.enabled;
			if (_selected == null)
			{
				DrawGlobal(w, ref y, canEdit);
			}
			else if (_selected.Kind == Kind.Food)
			{
				DrawFood(_selected, w, ref y, canEdit);
			}
			else
			{
				DrawMead(_selected, w, ref y, canEdit);
			}
			GUI.enabled = enabled;
			_rightContentH = y + 10f;
			GUI.EndScrollView();
		}

		private static void WhoLine(float w, ref float y)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			string text = (HubNet.IsServer ? "Ты хост — изменения действуют для всех игроков." : ((!FoodTweaksPlugin.HasServerData) ? "На сервере нет FoodTweaks — меняются только твои настройки." : (FoodTweaksPlugin.IsAdminOnServer ? "Ты админ — изменения уйдут на сервер всем игрокам." : "<color=#B03A34>Настройки сервера. Менять может только админ.</color>")));
			GUI.Label(new Rect(0f, y, w, 24f), text, HubUI.LabelDimStyle);
			y += 34f;
		}

		private static void DrawGlobal(float w, ref float y, bool canEdit)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: 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_01da: Unknown result type (might be due to invalid IL or missing references)
			HubUI.Header(new Rect(0f, y, w, 30f), "Общие настройки");
			y += 34f;
			WhoLine(w, ref y);
			GUI.enabled = canEdit;
			bool flag = HubUI.Toggle(new Rect(0f, y, w, 30f), _draft.NoDegradation, "Еда не теряет силу со временем");
			if (flag != _draft.NoDegradation)
			{
				_draft.NoDegradation = flag;
				_dirty = true;
			}
			y += 30f;
			GUI.Label(new Rect(32f, y, w - 32f, 40f), "Здоровье, выносливость и эйтр от еды держатся полными до самого конца действия.", HubUI.LabelDimStyle);
			y += 54f;
			HubUI.Header(new Rect(0f, y, w, 28f), "Множители для всей еды");
			y += 32f;
			Mult(w, ref y, "Здоровье", ref _draft.HealthMult);
			Mult(w, ref y, "Выносливость", ref _draft.StaminaMult);
			Mult(w, ref y, "Эйтр", ref _draft.EitrMult);
			Mult(w, ref y, "Длительность", ref _draft.DurationMult);
			Mult(w, ref y, "Регенерация", ref _draft.RegenMult);
			y += 10f;
			HubUI.Header(new Rect(0f, y, w, 28f), "Медовухи");
			y += 32f;
			Mult(w, ref y, "Длительность", ref _draft.MeadDurationMult);
			y += 10f;
			int count = _draft.Food.Count;
			int count2 = _draft.Mead.Count;
			GUI.Label(new Rect(0f, y, w, 44f), $"Отдельно изменено: еды — {count}, медовух — {count2}.\nМножители действуют поверх, в том числе на изменённые предметы.", HubUI.LabelDimStyle);
			y += 48f;
		}

		private static void Mult(float w, ref float y, string label, ref float value)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			float num = HubUI.SliderText(new Rect(0f, y, w, 30f), label, value, 0.1f, 5f, $"x{value:0.##}", "0.##", -1f);
			num = Mathf.Round(num * 20f) / 20f;
			if (!Mathf.Approximately(num, value))
			{
				value = num;
				_dirty = true;
			}
			y += 40f;
		}

		private static void ItemHeader(Entry e, float w, ref float y)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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)
			HubUI.Slot(new Rect(0f, y, 72f, 72f), false, false);
			HubUI.DrawSprite(new Rect(6f, y + 6f, 60f, 60f), e.Drop.m_itemData.GetIcon());
			GUI.Label(new Rect(86f, y + 6f, w - 86f, 32f), e.Name, HubUI.HeaderStyle);
			GUI.Label(new Rect(86f, y + 38f, w - 86f, 24f), e.Prefab, HubUI.LabelDimStyle);
			y += 82f;
		}

		private static void DrawFood(Entry e, float w, ref float y, bool canEdit)
		{
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			ItemHeader(e, w, ref y);
			WhoLine(w, ref y);
			GUI.enabled = canEdit;
			(string, string)[] foodFields = FoodFields;
			for (int i = 0; i < foodFields.Length; i++)
			{
				(string, string) tuple = foodFields[i];
				string key = tuple.Item1;
				string item = tuple.Item2;
				float num = FoodApplier.FoodVanilla(e.Prefab, key);
				float? overrideValue = FoodData.Get(_draft.Food, e.Prefab, key);
				string vanillaText = ((key == "duration") ? $"ваниль: {num:0} ({num / 60f:0.#} мин)" : $"ваниль: {num:0.##}");
				FieldRow(w, ref y, "food:" + key, item, overrideValue, num, vanillaText, delegate(float? v)
				{
					FoodData.Set(_draft.Food, e.Prefab, key, v);
				});
			}
			y += 10f;
			float num2 = FoodApplier.FoodFinal(_draft, e.Prefab, "health");
			float num3 = FoodApplier.FoodFinal(_draft, e.Prefab, "stamina");
			float num4 = FoodApplier.FoodFinal(_draft, e.Prefab, "eitr");
			float num5 = FoodApplier.FoodFinal(_draft, e.Prefab, "duration");
			float num6 = FoodApplier.FoodFinal(_draft, e.Prefab, "regen");
			GUI.Label(new Rect(0f, y, w, 44f), $"В игре (с общими множителями): здоровье {num2:0.#} · выносливость {num3:0.#} · эйтр {num4:0.#} · {num5 / 60f:0.#} мин · реген {num6:0.#}", HubUI.LabelDimStyle);
			y += 48f;
			if (FoodData.Has(_draft.Food, e.Prefab))
			{
				if (HubUI.Button(new Rect(0f, y, 240f, 36f), "Сбросить этот предмет"))
				{
					_draft.Food.Remove(e.Prefab);
					_edit.Clear();
					_dirty = true;
				}
				y += 46f;
			}
		}

		private static void DrawMead(Entry e, float w, ref float y, bool canEdit)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: 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)
			ItemHeader(e, w, ref y);
			WhoLine(w, ref y);
			Dictionary<string, float> meadOrig = FoodApplier.GetMeadOrig(e.Prefab);
			if (meadOrig == null)
			{
				GUI.Label(new Rect(0f, y, w, 30f), "Нет данных об эффекте.", HubUI.LabelDimStyle);
				y += 34f;
				return;
			}
			GUI.enabled = true;
			bool flag = HubUI.Toggle(new Rect(0f, y, w, 28f), _showAllMeadFields, "Показать все поля");
			if (flag != _showAllMeadFields)
			{
				_showAllMeadFields = flag;
				_edit.Clear();
			}
			y += 38f;
			GUI.enabled = canEdit;
			int num = 0;
			foreach (KeyValuePair<string, string> meadLabel in MeadLabels)
			{
				string key = meadLabel.Key;
				if (!meadOrig.TryGetValue(key, out var value))
				{
					continue;
				}
				float? overrideValue = FoodData.Get(_draft.Mead, e.Prefab, key);
				bool flag2 = key.EndsWith("Multiplier");
				bool flag3 = key == "ttl" || (flag2 ? (!Mathf.Approximately(value, 1f)) : (!Mathf.Approximately(value, 0f)));
				if (_showAllMeadFields || flag3 || overrideValue.HasValue)
				{
					string vanillaText = ((key == "ttl") ? $"ваниль: {value:0} ({value / 60f:0.#} мин)" : $"ваниль: {value:0.##}");
					FieldRow(w, ref y, "mead:" + key, meadLabel.Value, overrideValue, value, vanillaText, delegate(float? v)
					{
						FoodData.Set(_draft.Mead, e.Prefab, key, v);
					});
					num++;
				}
			}
			if (num <= 1 && !_showAllMeadFields)
			{
				GUI.Label(new Rect(0f, y, w, 40f), "У этой медовухи другой эффект (например, сопротивление) — меняется только длительность. Включи «Показать все поля», чтобы добавить ей восстановление.", HubUI.LabelDimStyle);
				y += 44f;
			}
			y += 10f;
			GUI.Label(new Rect(0f, y, w, 44f), $"Длительность — это и кулдаун: пока эффект действует, такую же медовуху выпить нельзя. Общий множитель длительности медовух: x{_draft.MeadDurationMult:0.##}.", HubUI.LabelDimStyle);
			y += 48f;
			if (FoodData.Has(_draft.Mead, e.Prefab))
			{
				if (HubUI.Button(new Rect(0f, y, 240f, 36f), "Сбросить этот предмет"))
				{
					_draft.Mead.Remove(e.Prefab);
					_edit.Clear();
					_dirty = true;
				}
				y += 46f;
			}
		}

		private static void FieldRow(float w, ref float y, string key, string label, float? overrideValue, float vanilla, string vanillaText, Action<float?> set)
		{
			//IL_001e: 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_00e9: 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)
			float num = w * 0.34f;
			float num2 = w * 0.2f;
			GUI.Label(new Rect(0f, y, num, 32f), label, HubUI.LabelStyle);
			float num3 = overrideValue ?? vanilla;
			float? num4 = NumberField(new Rect(num, y, num2, 32f), key, num3);
			if (num4.HasValue && !Mathf.Approximately(num4.Value, num3))
			{
				set(Mathf.Approximately(num4.Value, vanilla) ? ((float?)null) : new float?(Mathf.Max(0f, num4.Value)));
				_dirty = true;
			}
			string text = (overrideValue.HasValue ? ("<color=#E8C36A>изм.</color>  " + vanillaText) : vanillaText);
			GUI.Label(new Rect(num + num2 + 12f, y, w - num - num2 - 96f, 32f), text, HubUI.LabelDimStyle);
			if (overrideValue.HasValue && GUI.Button(new Rect(w - 80f, y, 78f, 32f), "сброс", HubUI.ButtonStyle))
			{
				set(null);
				_edit.Remove(key);
				_dirty = true;
			}
			y += 42f;
		}

		private static float? NumberField(Rect r, string key, float current)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			string text = "ft_" + key;
			if (!_edit.TryGetValue(key, out var value))
			{
				value = current.ToString("0.###", CultureInfo.InvariantCulture);
			}
			GUI.SetNextControlName(text);
			string text2 = GUI.TextField(r, value, HubUI.TextFieldStyle);
			if (text2 != value)
			{
				_edit[key] = text2;
				if (float.TryParse(text2.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
				{
					return result;
				}
			}
			else if (GUI.GetNameOfFocusedControl() != text)
			{
				_edit.Remove(key);
			}
			return null;
		}

		private static void DrawBottom(Rect win, bool canEdit)
		{
			//IL_0048: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			bool enabled = GUI.enabled;
			float num = 190f;
			float num2 = ((Rect)(ref win)).yMax - 96f;
			float num3 = ((Rect)(ref win)).xMax - 40f - num * 3f - 20f;
			GUI.enabled = enabled && canEdit;
			if (HubUI.Button(new Rect(num3, num2, num, 40f), "Всё как в ванилле"))
			{
				_draft = new FoodData();
				_edit.Clear();
				_dirty = true;
			}
			GUI.enabled = enabled && _dirty;
			if (HubUI.Button(new Rect(num3 + num + 10f, num2, num, 40f), "Отменить"))
			{
				LoadDraft();
			}
			GUI.enabled = enabled && canEdit && _dirty;
			if (HubUI.Button(new Rect(num3 + (num + 10f) * 2f, num2, num, 40f), _dirty ? "Применить *" : "Применить"))
			{
				Apply();
			}
			GUI.enabled = enabled;
			string text = ((Time.unscaledTime < _statusUntil) ? _status : (_dirty ? "Есть несохранённые изменения" : "Esc — закрыть"));
			GUI.Label(new Rect(((Rect)(ref win)).x + 40f, num2, num3 - ((Rect)(ref win)).x - 40f - 10f, 40f), text, HubUI.LabelDimStyle);
		}

		private static void Apply()
		{
			FoodData data = _draft.Clone();
			if (HubNet.IsServer || !FoodTweaksPlugin.HasServerData)
			{
				FoodTweaksPlugin.SaveLocal(data);
				SetStatus("Сохранено и применено");
			}
			else
			{
				if (!FoodSync.SendToServer(data))
				{
					SetStatus("Нет связи с сервером");
					return;
				}
				SetStatus("Отправлено на сервер");
			}
			_dirty = false;
			_loadedVersion = FoodTweaksPlugin.DataVersion;
		}

		private static void SetStatus(string text)
		{
			_status = text;
			_statusUntil = Time.unscaledTime + 3f;
		}
	}
	[HarmonyPatch(typeof(TextInput), "IsVisible")]
	internal static class Patch_TextInput_IsVisible
	{
		private static void Postfix(ref bool __result)
		{
			if (FoodMenu.IsOpen)
			{
				__result = true;
			}
		}
	}
	internal static class FoodSync
	{
		public const string RPC = "FoodTweaks_Sync";

		public const string RPC_SET = "FoodTweaks_Set";

		private const int ProtocolVersion = 1;

		internal static ZPackage Build(bool receiverIsAdmin)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(receiverIsAdmin);
			val.Write(FoodTweaksPlugin.Local.Serialize());
			return val;
		}

		public static void Receive(ZRpc rpc, ZPackage p)
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer())
			{
				int num = p.ReadInt();
				if (num != 1)
				{
					FoodTweaksPlugin.Log.LogWarning((object)$"Server FoodTweaks protocol {num} != {1}. Update the mod on both sides.");
					return;
				}
				FoodTweaksPlugin.IsAdminOnServer = p.ReadBool();
				FoodTweaksPlugin.Server = FoodData.Parse(p.ReadString());
				FoodTweaksPlugin.Log.LogInfo((object)"Received FoodTweaks settings from server");
				FoodTweaksPlugin.Changed();
			}
		}

		public static void BroadcastIfServer()
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer())
			{
				return;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer != null)
				{
					ZRpc rpc = peer.m_rpc;
					if (rpc != null)
					{
						rpc.Invoke("FoodTweaks_Sync", new object[1] { Build(HubNet.IsAdmin(peer)) });
					}
				}
			}
		}

		public static bool SendToServer(FoodData data)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			ZRpc val = HubNet.ServerRpc();
			if (val == null)
			{
				return false;
			}
			ZPackage val2 = new ZPackage();
			val2.Write(1);
			val2.Write(data.Serialize());
			val.Invoke("FoodTweaks_Set", new object[1] { val2 });
			return true;
		}

		public static void ReceiveSet(ZRpc rpc, ZPackage p)
		{
			if (HubNet.IsServer)
			{
				ZNetPeer val = HubNet.FindPeer(rpc);
				if (!HubNet.IsAdmin(val))
				{
					FoodTweaksPlugin.Log.LogWarning((object)("Ignored FoodTweaks settings from non-admin " + (val?.m_playerName ?? "?")));
				}
				else if (p.ReadInt() == 1)
				{
					FoodTweaksPlugin.SaveLocal(FoodData.Parse(p.ReadString()));
					FoodTweaksPlugin.Log.LogInfo((object)("FoodTweaks settings changed by admin " + val.m_playerName));
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
	internal static class Patch_ZNet_OnNewConnection
	{
		private static void Postfix(ZNetPeer peer)
		{
			if (peer != null)
			{
				ZRpc rpc = peer.m_rpc;
				if (rpc != null)
				{
					rpc.Register<ZPackage>("FoodTweaks_Sync", (Action<ZRpc, ZPackage>)FoodSync.Receive);
				}
			}
			if (peer != null)
			{
				ZRpc rpc2 = peer.m_rpc;
				if (rpc2 != null)
				{
					rpc2.Register<ZPackage>("FoodTweaks_Set", (Action<ZRpc, ZPackage>)FoodSync.ReceiveSet);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
	internal static class Patch_ZNet_RPC_PeerInfo
	{
		private static void Postfix(ZNet __instance, ZRpc rpc)
		{
			if (__instance.IsServer() && rpc != null)
			{
				rpc.Invoke("FoodTweaks_Sync", new object[1] { FoodSync.Build(HubNet.IsAdmin(HubNet.FindPeer(rpc))) });
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnDestroy")]
	internal static class Patch_ZNet_OnDestroy
	{
		private static void Postfix()
		{
			bool flag = FoodTweaksPlugin.Server != null;
			FoodTweaksPlugin.Server = null;
			FoodTweaksPlugin.IsAdminOnServer = false;
			if (flag)
			{
				FoodTweaksPlugin.Changed();
			}
		}
	}
	[BepInPlugin("brat.foodtweaks", "FoodTweaks", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class FoodTweaksPlugin : BaseUnityPlugin
	{
		public const string GUID = "brat.foodtweaks";

		public const string NAME = "FoodTweaks";

		public const string VERSION = "1.0.0";

		internal static ManualLogSource Log;

		internal static FoodData Local = new FoodData();

		internal static FoodData Server;

		internal static bool IsAdminOnServer;

		internal static int DataVersion;

		internal static FoodData Active => Server ?? Local;

		internal static bool HasServerData => Server != null;

		internal static bool CanEdit => HubNet.IsServer || Server == null || IsAdminOnServer;

		internal static string DataPath => Path.Combine(Paths.ConfigPath, "brat.foodtweaks.txt");

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			LoadLocal();
			new Harmony("brat.foodtweaks").PatchAll(typeof(FoodTweaksPlugin).Assembly);
			Action action = FoodMenu.Open;
			Action action2 = FoodMenu.Close;
			ModHubAPI.Register("foodtweaks", "Food", action, "MeadHealthMinor", (Sprite)null, (Color?)null, "Характеристики еды и медовух", 50, (Func<bool>)null, action2, (Func<bool>)(() => FoodMenu.IsOpen));
			Log.LogInfo((object)"FoodTweaks 1.0.0 loaded");
		}

		private void Update()
		{
			FoodMenu.Update();
		}

		private void OnGUI()
		{
			FoodMenu.Draw();
		}

		private static void LoadLocal()
		{
			try
			{
				if (File.Exists(DataPath))
				{
					Local = FoodData.Parse(File.ReadAllText(DataPath));
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to read " + DataPath + ": " + ex.Message));
			}
		}

		internal static void SaveLocal(FoodData data)
		{
			Local = data;
			try
			{
				File.WriteAllText(DataPath, data.Serialize(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to save " + DataPath + ": " + ex.Message));
			}
			Changed();
			FoodSync.BroadcastIfServer();
		}

		internal static void Changed()
		{
			DataVersion++;
			FoodApplier.ApplyAll();
		}
	}
}