Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of FoodTweaks v1.0.0
FoodTweaks.dll
Decompiled 3 hours agousing 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(); } } }