using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("OldMarket.CraftSupport")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OldMarket.CraftSupport")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("041278ab-957b-4957-9f70-eb09000c864e")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace OldMarket.CraftSupport;
[BepInPlugin("oldmarket.craftsupport", "Old Market Craft Support", "1.0.0")]
public class CraftSupportPlugin : BaseUnityPlugin
{
public const string PluginGuid = "oldmarket.craftsupport";
public const string PluginName = "Old Market Craft Support";
public const string PluginVersion = "1.0.0";
internal static ManualLogSource Log;
private void Awake()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Harmony val = new Harmony("oldmarket.craftsupport");
val.PatchAll();
}
internal static string GetLocaleCode()
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
try
{
Locale selectedLocale = LocalizationSettings.SelectedLocale;
object result;
if (!((Object)(object)selectedLocale != (Object)null))
{
result = null;
}
else
{
LocaleIdentifier identifier = selectedLocale.Identifier;
result = ((LocaleIdentifier)(ref identifier)).Code;
}
return (string)result;
}
catch
{
return null;
}
}
internal static bool IsJapaneseLocale()
{
string localeCode = GetLocaleCode();
return !string.IsNullOrEmpty(localeCode) && localeCode.StartsWith("ja", StringComparison.OrdinalIgnoreCase);
}
internal static string GetAmountLabel()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
try
{
if (IsJapaneseLocale())
{
return "数量";
}
return LocalizationSettings.StringDatabase.GetLocalizedString(TableReference.op_Implicit("Translations"), TableEntryReference.op_Implicit("amount"), (Locale)null, (FallbackBehavior)0, Array.Empty<object>());
}
catch
{
return "Amount";
}
}
internal static string GetWholesaleLabel()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
try
{
return LocalizationSettings.StringDatabase.GetLocalizedString(TableReference.op_Implicit("Translations"), TableEntryReference.op_Implicit("wholesale"), (Locale)null, (FallbackBehavior)0, Array.Empty<object>());
}
catch
{
return "Wholesale";
}
}
}
internal static class CraftSupportLogic
{
private static FieldInfo _panelRecipeIngredientsField;
private static void CountWorldItems(ItemSO itemSO, out int totalAmount, out int maxStackSeen)
{
totalAmount = 0;
maxStackSeen = 0;
if ((Object)(object)itemSO == (Object)null)
{
return;
}
try
{
Item[] array = Object.FindObjectsOfType<Item>();
foreach (Item val in array)
{
if ((Object)(object)val == (Object)null || (Object)(object)val.itemSO != (Object)(object)itemSO)
{
continue;
}
try
{
if (val.amount != null)
{
int value = val.amount.Value;
totalAmount += value;
if (value > maxStackSeen)
{
maxStackSeen = value;
}
}
}
catch (Exception ex)
{
ManualLogSource log = CraftSupportPlugin.Log;
if (log != null)
{
log.LogDebug((object)("[CraftSupport] Item.amount read failed for " + ((Object)itemSO).name + ": " + ex.Message));
}
}
}
}
catch (Exception arg)
{
ManualLogSource log2 = CraftSupportPlugin.Log;
if (log2 != null)
{
log2.LogError((object)$"[CraftSupport] Failed counting stock for {((Object)itemSO).name}: {arg}");
}
}
}
private static string BuildStockText(int totalAmount, int maxStackSeen)
{
string amountLabel = CraftSupportPlugin.GetAmountLabel();
bool flag = CraftSupportPlugin.IsJapaneseLocale();
if (totalAmount <= 0)
{
amountLabel = (amountLabel ?? string.Empty).ToUpperInvariant();
return amountLabel + ": 0";
}
string text;
if (maxStackSeen > 1)
{
int num = totalAmount / maxStackSeen;
text = ((num <= 0) ? totalAmount.ToString() : ((!flag) ? $"{totalAmount} (x{num})" : $"{totalAmount}(x{num})"));
}
else
{
text = totalAmount.ToString();
}
amountLabel = (amountLabel ?? string.Empty).ToUpperInvariant();
return amountLabel + ": " + text;
}
internal static string BuildRecipeInfoLine(RecipeSO recipe)
{
if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.output == (Object)null)
{
return string.Empty;
}
ItemSO output = recipe.output;
ProductSO val = (ProductSO)(object)((output is ProductSO) ? output : null);
CountWorldItems(output, out var totalAmount, out var maxStackSeen);
string text = BuildStockText(totalAmount, maxStackSeen);
string text2 = string.Empty;
if ((Object)(object)val != (Object)null)
{
try
{
GameManager instance = GameManager.Instance;
if ((Object)(object)instance != (Object)null)
{
int wholesalePrice = instance.GetWholesalePrice(val);
if (wholesalePrice > 0)
{
int num = ((recipe.amount <= 0) ? 1 : recipe.amount);
int num2 = wholesalePrice * num;
string text3 = CraftSupportPlugin.GetWholesaleLabel() ?? "Wholesale";
text3 = text3.ToUpperInvariant();
bool flag = CraftSupportPlugin.IsJapaneseLocale();
text2 = ((num <= 1) ? $"{text3}: {wholesalePrice} C" : ((!flag) ? $"{text3}: {num2} C ({wholesalePrice} C x{num})" : $"{text3}: {num2} C({wholesalePrice} C x{num})"));
}
}
}
catch (Exception arg)
{
ManualLogSource log = CraftSupportPlugin.Log;
if (log != null)
{
log.LogError((object)$"[CraftSupport] Failed calculating price for {((Object)output).name}: {arg}");
}
}
}
if (!string.IsNullOrEmpty(text2))
{
return text + "\n" + text2;
}
return text;
}
internal static string BuildIngredientInfoLine(ItemSO itemSO)
{
if ((Object)(object)itemSO == (Object)null)
{
return string.Empty;
}
CountWorldItems(itemSO, out var totalAmount, out var maxStackSeen);
return BuildStockText(totalAmount, maxStackSeen);
}
internal static void ApplyToRecipeList(UIManager ui, List<RecipeSO> recipes)
{
if ((Object)(object)ui == (Object)null || (Object)(object)ui.listRecipes == (Object)null)
{
return;
}
Transform listRecipes = ui.listRecipes;
int childCount = listRecipes.childCount;
for (int i = 0; i < childCount; i++)
{
Transform child = listRecipes.GetChild(i);
if ((Object)(object)child == (Object)null)
{
continue;
}
try
{
RecipeSO val = FindRecipeOnTile(child, recipes);
if ((Object)(object)val == (Object)null || (Object)(object)val.output == (Object)null)
{
continue;
}
TextMeshProUGUI nameLabelOnTile = GetNameLabelOnTile(child, val);
if (!((Object)(object)nameLabelOnTile == (Object)null))
{
string text = BuildRecipeInfoLine(val);
if (!string.IsNullOrEmpty(text))
{
string localizedName = val.output.GetLocalizedName();
((TMP_Text)nameLabelOnTile).richText = true;
((TMP_Text)nameLabelOnTile).text = $"<size=140%>{localizedName}</size>\n<size=120%>{text}</size>";
}
}
}
catch (Exception arg)
{
ManualLogSource log = CraftSupportPlugin.Log;
if (log != null)
{
log.LogError((object)$"[CraftSupport] ApplyToRecipeList tile {i} failed: {arg}");
}
}
}
}
internal static void ApplyToRecipeIngredients(UIManager ui, RecipeSO recipe)
{
if ((Object)(object)ui == (Object)null || (Object)(object)recipe == (Object)null)
{
return;
}
Transform recipeIngredientsParent = GetRecipeIngredientsParent(ui);
if ((Object)(object)recipeIngredientsParent == (Object)null)
{
return;
}
GameManager instance = GameManager.Instance;
if ((Object)(object)instance == (Object)null || instance.itemDatabase == null || instance.itemDatabase.Count == 0)
{
return;
}
Dictionary<string, ItemSO> dictionary = new Dictionary<string, ItemSO>();
try
{
List<ItemSO> itemDatabase = instance.itemDatabase;
for (int i = 0; i < itemDatabase.Count; i++)
{
ItemSO val = itemDatabase[i];
if (!((Object)(object)val == (Object)null))
{
string localizedName;
try
{
localizedName = val.GetLocalizedName();
}
catch
{
continue;
}
if (!string.IsNullOrEmpty(localizedName) && !dictionary.ContainsKey(localizedName))
{
dictionary.Add(localizedName, val);
}
}
}
}
catch (Exception arg)
{
ManualLogSource log = CraftSupportPlugin.Log;
if (log != null)
{
log.LogError((object)$"[CraftSupport] Build ingredient name map failed: {arg}");
}
return;
}
int childCount = recipeIngredientsParent.childCount;
for (int j = 0; j < childCount; j++)
{
Transform child = recipeIngredientsParent.GetChild(j);
if ((Object)(object)child == (Object)null)
{
continue;
}
try
{
TextMeshProUGUI componentInChildren = ((Component)child).GetComponentInChildren<TextMeshProUGUI>(true);
if ((Object)(object)componentInChildren == (Object)null)
{
continue;
}
string text = ((TMP_Text)componentInChildren).text ?? string.Empty;
int num = text.IndexOf('\n');
string text2 = ((num < 0) ? text : text.Substring(0, num));
text2 = text2.Trim();
if (string.IsNullOrEmpty(text2))
{
((TMP_Text)componentInChildren).text = text;
continue;
}
if (!dictionary.TryGetValue(text2, out var value) || (Object)(object)value == (Object)null)
{
((TMP_Text)componentInChildren).text = text2;
continue;
}
string text3 = BuildIngredientInfoLine(value);
if (string.IsNullOrEmpty(text3))
{
((TMP_Text)componentInChildren).text = text2;
continue;
}
((TMP_Text)componentInChildren).richText = true;
((TMP_Text)componentInChildren).text = $"<size=140%>{text2}</size>\n<size=120%>{text3}</size>";
}
catch (Exception arg2)
{
ManualLogSource log2 = CraftSupportPlugin.Log;
if (log2 != null)
{
log2.LogError((object)$"[CraftSupport] ApplyToRecipeIngredients tile {j} failed: {arg2}");
}
}
}
}
private static Transform GetRecipeIngredientsParent(UIManager ui)
{
if ((Object)(object)ui == (Object)null)
{
return null;
}
try
{
if (_panelRecipeIngredientsField == null)
{
_panelRecipeIngredientsField = typeof(UIManager).GetField("panelRecipeIngredients", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (_panelRecipeIngredientsField == null)
{
FieldInfo[] fields = typeof(UIManager).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
Type fieldType = fieldInfo.FieldType;
if (typeof(Transform).IsAssignableFrom(fieldType) || typeof(GameObject).IsAssignableFrom(fieldType))
{
string text = fieldInfo.Name ?? string.Empty;
string text2 = text.ToLowerInvariant();
if (text2.Contains("recipe") && text2.Contains("ingredient"))
{
_panelRecipeIngredientsField = fieldInfo;
break;
}
}
}
}
}
if (_panelRecipeIngredientsField == null)
{
ManualLogSource log = CraftSupportPlugin.Log;
if (log != null)
{
log.LogDebug((object)"[CraftSupport] Recipe ingredients panel field not found.");
}
return null;
}
object value = _panelRecipeIngredientsField.GetValue(ui);
Transform val = (Transform)((value is Transform) ? value : null);
if ((Object)(object)val != (Object)null)
{
return val;
}
GameObject val2 = (GameObject)((value is GameObject) ? value : null);
if ((Object)(object)val2 != (Object)null)
{
return val2.transform;
}
return null;
}
catch (Exception arg)
{
ManualLogSource log2 = CraftSupportPlugin.Log;
if (log2 != null)
{
log2.LogError((object)$"[CraftSupport] GetRecipeIngredientsParent failed: {arg}");
}
return null;
}
}
private static RecipeSO FindRecipeOnTile(Transform tile, List<RecipeSO> recipes)
{
if ((Object)(object)tile == (Object)null)
{
return null;
}
try
{
Component[] componentsInChildren = ((Component)tile).GetComponentsInChildren<Component>(true);
foreach (Component val in componentsInChildren)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
Type type = ((object)val).GetType();
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (FieldInfo fieldInfo in fields)
{
if (typeof(RecipeSO).IsAssignableFrom(fieldInfo.FieldType))
{
object obj = null;
try
{
obj = fieldInfo.GetValue(val);
}
catch
{
}
RecipeSO val2 = (RecipeSO)((obj is RecipeSO) ? obj : null);
if ((Object)(object)val2 != (Object)null)
{
return val2;
}
}
}
}
}
catch (Exception ex)
{
ManualLogSource log = CraftSupportPlugin.Log;
if (log != null)
{
log.LogDebug((object)("[CraftSupport] FindRecipeOnTile reflection failed: " + ex.Message));
}
}
if (recipes != null && recipes.Count > 0)
{
TextMeshProUGUI componentInChildren = ((Component)tile).GetComponentInChildren<TextMeshProUGUI>(true);
if ((Object)(object)componentInChildren != (Object)null)
{
string text = ((TMP_Text)componentInChildren).text ?? string.Empty;
int num = text.IndexOf('\n');
string text2 = ((num < 0) ? text : text.Substring(0, num));
string text3 = text2;
int num2 = text2.LastIndexOf('x');
if (num2 > 0 && text2[num2 - 1] == ' ')
{
text3 = text2.Substring(0, num2 - 1);
}
for (int k = 0; k < recipes.Count; k++)
{
RecipeSO val3 = recipes[k];
if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.output == (Object)null))
{
string localizedName = val3.output.GetLocalizedName();
if (localizedName == text3)
{
return val3;
}
}
}
}
}
return null;
}
private static TextMeshProUGUI GetNameLabelOnTile(Transform tile, RecipeSO recipe)
{
if ((Object)(object)tile == (Object)null || (Object)(object)recipe == (Object)null || (Object)(object)recipe.output == (Object)null)
{
return null;
}
string localizedName = recipe.output.GetLocalizedName();
TextMeshProUGUI[] componentsInChildren = ((Component)tile).GetComponentsInChildren<TextMeshProUGUI>(true);
TextMeshProUGUI val = null;
foreach (TextMeshProUGUI val2 in componentsInChildren)
{
if (!((Object)(object)val2 == (Object)null))
{
string text = ((TMP_Text)val2).text;
if (!string.IsNullOrEmpty(text) && text.Contains(localizedName))
{
val = val2;
break;
}
}
}
if ((Object)(object)val == (Object)null && componentsInChildren.Length != 0)
{
val = componentsInChildren[0];
}
return val;
}
}
[HarmonyPatch(typeof(UIManager))]
internal static class UIManager_OpenRecipesPanel_Patch
{
[HarmonyPostfix]
[HarmonyPatch("OpenRecipesPanel")]
private static void Postfix(UIManager __instance, List<RecipeSO> recipes)
{
CraftSupportLogic.ApplyToRecipeList(__instance, recipes);
}
}
[HarmonyPatch(typeof(UIManager))]
internal static class UIManager_UpdateRecipeIngredients_Patch
{
[HarmonyPostfix]
[HarmonyPatch("UpdateRecipeIngredients")]
private static void Postfix(UIManager __instance, RecipeSO recipeSO)
{
CraftSupportLogic.ApplyToRecipeIngredients(__instance, recipeSO);
}
}