using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using I2.Loc;
using PerfectRandom.Sulfur.Core;
using PerfectRandom.Sulfur.Core.Items;
using PerfectRandom.Sulfur.Core.Stats;
using PerfectRandom.Sulfur.Core.UI.ItemDescription;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("net.mizle.SulfurRecipeBook")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0")]
[assembly: AssemblyProduct("SulfurRecipeBook")]
[assembly: AssemblyTitle("net.mizle.SulfurRecipeBook")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.0")]
[module: UnverifiableCode]
namespace SulfurRecipeBook;
[BepInPlugin("net.mizle.SulfurRecipeBook", "SulfurRecipeBook", "2.0.0")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Logger;
public static ConfigEntry<bool> ConfigShowHealPerSlot;
private void Awake()
{
Logger = ((BaseUnityPlugin)this).Logger;
Logger.LogInfo((object)"Plugin net.mizle.SulfurRecipeBook is loaded!");
ConfigShowHealPerSlot = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowHealPerSlot", false, "Show heal per slot in item description");
Harmony.CreateAndPatchAll(typeof(RecipeBook), (string)null);
Harmony.CreateAndPatchAll(typeof(ReversePatch), (string)null);
}
}
internal class IngredientRange
{
public int Min { get; set; } = int.MaxValue;
public int Max { get; set; }
}
public static class RecipeAnalyzer
{
public static Dictionary<string, string> AnalyzeRecipes(List<CraftingRecipe> recipes)
{
Dictionary<string, List<(Dictionary<string, int>, string, int, CraftingRecipe)>> dictionary = new Dictionary<string, List<(Dictionary<string, int>, string, int, CraftingRecipe)>>();
foreach (CraftingRecipe recipe in recipes)
{
IOrderedEnumerable<string> values = from i in recipe.itemsNeeded
select i.item.identifier into name
orderby name
select name;
string key = string.Join("+", values);
Dictionary<string, int> item = recipe.itemsNeeded.ToDictionary((IngredientDefinition ing) => ing.item.identifier, (IngredientDefinition ing) => ing.quantity);
if (!dictionary.ContainsKey(key))
{
dictionary[key] = new List<(Dictionary<string, int>, string, int, CraftingRecipe)>();
}
dictionary[key].Add((item, recipe.createsItem.identifier, recipe.quantityCreated, recipe));
}
Dictionary<string, string> dictionary2 = new Dictionary<string, string>();
foreach (KeyValuePair<string, List<(Dictionary<string, int>, string, int, CraftingRecipe)>> item5 in dictionary)
{
item5.Deconstruct(out var key2, out var value);
string key3 = key2;
List<(Dictionary<string, int> Ingredients, string Result, int Quantity, CraftingRecipe Recipe)> recipesList = value;
Dictionary<string, IngredientRange> dictionary3 = new Dictionary<string, IngredientRange>();
Dictionary<string, (IngredientRange, List<CraftingRecipe>)> dictionary4 = new Dictionary<string, (IngredientRange, List<CraftingRecipe>)>();
foreach (var (dictionary5, key4, val, item2) in recipesList)
{
foreach (KeyValuePair<string, int> item6 in dictionary5)
{
item6.Deconstruct(out key2, out var value2);
string key5 = key2;
int val2 = value2;
if (!dictionary3.ContainsKey(key5))
{
dictionary3[key5] = new IngredientRange();
}
dictionary3[key5].Min = Math.Min(dictionary3[key5].Min, val2);
dictionary3[key5].Max = Math.Max(dictionary3[key5].Max, val2);
}
if (!dictionary4.ContainsKey(key4))
{
dictionary4[key4] = (new IngredientRange(), new List<CraftingRecipe>());
}
dictionary4[key4].Item1.Min = Math.Min(dictionary4[key4].Item1.Min, val);
dictionary4[key4].Item1.Max = Math.Max(dictionary4[key4].Item1.Max, val);
dictionary4[key4].Item2.Add(item2);
}
List<string> values2 = dictionary3.Select((KeyValuePair<string, IngredientRange> kvp) => FormatRange(GetDisplayName(recipesList[0].Recipe, kvp.Key), kvp.Value)).ToList();
foreach (KeyValuePair<string, (IngredientRange, List<CraftingRecipe>)> item7 in dictionary4)
{
item7.Deconstruct(out key2, out var value3);
(IngredientRange, List<CraftingRecipe>) tuple2 = value3;
string identifier = key2;
IngredientRange item3 = tuple2.Item1;
List<CraftingRecipe> item4 = tuple2.Item2;
float num = CalculateHealPerSlot(item4[0].createsItem);
string text = FormatRange(GetDisplayName(item4[0], identifier), item3);
if (Plugin.ConfigShowHealPerSlot.Value && num > 0f)
{
text += $"<size=-1> [{num:F2}]</size>";
}
string value4 = string.Join("<size=-1><color=#6D8791> + </color></size>", values2) + "<size=-1><color=#6D8791> = </color></size>" + text;
dictionary2[key3] = value4;
}
}
return dictionary2;
}
private static string GetDisplayName(CraftingRecipe recipe, string identifier)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
if (identifier == recipe.createsItem.identifier)
{
return recipe.createsItem.LocalizedDisplayName;
}
return ((IEnumerable<IngredientDefinition>)recipe.itemsNeeded).FirstOrDefault((Func<IngredientDefinition, bool>)((IngredientDefinition i) => i.item.identifier == identifier)).item.LocalizedDisplayName ?? identifier;
}
public static float CalculateHealPerSlot(ItemDefinition item)
{
int num = ((Vector2Int)(ref item.inventorySize)).x * ((Vector2Int)(ref item.inventorySize)).y;
BuffDefinition? obj = item.buffsOnConsume.Find((BuffDefinition buff) => (int)buff.attributeNew.id == 54);
if (obj == null)
{
return 0f;
}
return obj.totalValueOverride / (float)num;
}
private static string FormatRange(string itemName, IngredientRange range)
{
if (range.Min == range.Max)
{
return $"{itemName}<size=-1><color=#6D8791>x{range.Min}</color></size>";
}
return $"{itemName}<size=-1><color=#6D8791>x({range.Min}~{range.Max})</color></size>";
}
}
[HarmonyPatch]
internal class ReversePatch
{
[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
[HarmonyPatch(typeof(ItemDescription), "AddAttribute", new Type[] { typeof(string) })]
public static void AddTextLineAsAttribute(object instance, string key)
{
throw new NotImplementedException("It's a stub");
}
[HarmonyReversePatch(/*Could not decode attribute arguments.*/)]
[HarmonyPatch(typeof(ItemDescription), "AddDescriptionText", new Type[] { typeof(string) })]
public static void AddTextLineAsDescription(object instance, string descriptionText)
{
throw new NotImplementedException("It's a stub");
}
}
[HarmonyPatch]
internal class RecipeBook
{
private static readonly List<CraftingRecipe> AllRecipe = ((Func<List<CraftingRecipe>>)delegate
{
CraftingManager instance = StaticInstance<CraftingManager>.Instance;
return (from r in instance.genericRecipes.Concat(instance.cookingRecipes)
where r.canBeCrafted
select r).ToList();
})();
private static bool _fontAtlasPopulationModeUpdated;
private static List<CraftingRecipe> FindRecipe(InventoryItem targetItem)
{
return AllRecipe.Where((CraftingRecipe recipe) => recipe.itemsNeeded.Any((IngredientDefinition ingredient) => ingredient.item.identifier == targetItem.itemDefinition.identifier)).ToList();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ItemDescription), "Setup")]
private static void DescriptionSetupPostfix(ItemDescription __instance, InventoryItem inventoryItem)
{
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Expected O, but got Unknown
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
List<CraftingRecipe> list = FindRecipe(inventoryItem);
if (list.Count == 0)
{
return;
}
ReversePatch.AddTextLineAsAttribute(__instance, "Recipes:");
Dictionary<string, string> dictionary = RecipeAnalyzer.AnalyzeRecipes(list);
foreach (string value in dictionary.Values)
{
ReversePatch.AddTextLineAsDescription(__instance, value);
UpdateLatestHorizontalLayoutGroupPadding(__instance, new RectOffset(8, 2, 2, 0));
}
if (!_fontAtlasPopulationModeUpdated)
{
UpdateLatestDescriptionFontAtlasPopulationMode(__instance);
_fontAtlasPopulationModeUpdated = true;
}
int num = ((dictionary.Count > 20) ? 500 : 350);
((Component)__instance).gameObject.GetComponent<RectTransform>().sizeDelta = new Vector2((float)num, 100f);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(ItemDescription), "AddDescriptionText")]
private static void AddDescriptionTextPostfix(ItemDescription __instance, string descriptionText)
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Invalid comparison between Unknown and I4
if (!Plugin.ConfigShowHealPerSlot.Value)
{
return;
}
InventoryItem value = Traverse.Create((object)__instance).Field("inventoryRepresentation").GetValue<InventoryItem>();
if (value.itemDefinition.buffsOnConsume.Find((BuffDefinition b) => (int)b.attributeNew.id == 54) == null)
{
return;
}
foreach (BuffDefinition item in value.itemDefinition.buffsOnConsume)
{
if ((int)item.attributeNew.id != 54 || LocalizationManager.GetTranslation("ItemDescriptions/DynamicString_HealthConsumable", true, 0, true, false, (GameObject)null, (string)null, true).Replace("VALUE_X", item.totalValueOverride.ToString()).Replace("DURATION_X", item.duration.ToString()) != descriptionText)
{
break;
}
float num = RecipeAnalyzer.CalculateHealPerSlot(value.itemDefinition);
string newDescription = $"{descriptionText} [Heal per Slot: {num}]";
UpdateLatestDescription(__instance, newDescription);
}
}
private static void UpdateLatestHorizontalLayoutGroupPadding(ItemDescription instance, RectOffset padding)
{
Transform child = ((Component)instance).transform.GetChild(0);
HorizontalLayoutGroup componentInChildren = ((Component)child.GetChild(child.childCount - 1)).GetComponentInChildren<HorizontalLayoutGroup>();
if ((Object)(object)componentInChildren == (Object)null)
{
Plugin.Logger.LogInfo((object)"No HorizontalLayoutGroup found.");
}
else
{
((LayoutGroup)componentInChildren).padding = padding;
}
}
private static void UpdateLatestDescription(ItemDescription instance, string newDescription)
{
Transform child = ((Component)instance).transform.GetChild(0);
TextMeshProUGUI componentInChildren = ((Component)child.GetChild(child.childCount - 1)).GetComponentInChildren<TextMeshProUGUI>();
if ((Object)(object)componentInChildren == (Object)null)
{
Plugin.Logger.LogInfo((object)"No TextMeshProUGUI found.");
}
else
{
((TMP_Text)componentInChildren).text = newDescription;
}
}
private static void UpdateLatestDescriptionFontAtlasPopulationMode(ItemDescription instance)
{
Transform child = ((Component)instance).transform.GetChild(0);
TextMeshProUGUI componentInChildren = ((Component)child.GetChild(child.childCount - 1)).GetComponentInChildren<TextMeshProUGUI>();
if ((Object)(object)componentInChildren == (Object)null)
{
Plugin.Logger.LogInfo((object)"No TextMeshProUGUI found.");
return;
}
Plugin.Logger.LogInfo((object)("Updating font settings: " + ((Object)componentInChildren).name));
((TMP_Text)componentInChildren).font.atlasPopulationMode = (AtlasPopulationMode)0;
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "net.mizle.SulfurRecipeBook";
public const string PLUGIN_NAME = "SulfurRecipeBook";
public const string PLUGIN_VERSION = "2.0.0";
}