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 CraftingBrowser v1.0.0
CraftingBrowser.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("CraftingBrowser")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+901b84ab23f2f10926b13865f9b40bb283490874")] [assembly: AssemblyProduct("CraftingBrowser")] [assembly: AssemblyTitle("CraftingBrowser")] [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 CraftingBrowser { public class BrowserGUI : MonoBehaviour { private bool m_open; private bool m_isFullscreen; private int m_tabIndex; private int m_subIndex; private string m_search = ""; private VisibilityMode m_mode; private readonly List<RecipeEntry> m_visible = new List<RecipeEntry>(); private readonly Dictionary<int, int> m_subCounts = new Dictionary<int, int>(); private readonly List<ItemData> m_ownedCopies = new List<ItemData>(); private RecipeEntry m_selected; private int m_selectedCopy; private Vector2 m_sidebarScroll; private Vector2 m_detailsScroll; private int m_gridRow; private int m_gridCols = 8; private float m_lastClickTime; private int m_lastClickedIndex = -1; private string m_status = ""; private float m_statusTimer; private bool m_wasCrafting; private string m_pendingCraftName; private string m_recentlyCrafted; private Texture2D m_whiteTex; private static readonly Color ColBackdrop = new Color(0f, 0f, 0f, 0.8f); private static readonly Color ColWindowBg = new Color(0.08f, 0.1f, 0.14f, 0.99f); private static readonly Color ColWindowBorder = new Color(0.74f, 0.58f, 0.28f, 1f); private static readonly Color ColWindowBorderInner = new Color(0.18f, 0.23f, 0.32f, 0.85f); private static readonly Color ColCardBg = new Color(0.09f, 0.11f, 0.16f, 0.96f); private static readonly Color ColCardBorder = new Color(0.22f, 0.28f, 0.38f, 0.85f); private static readonly Color ColCardHeaderBg = new Color(0.12f, 0.16f, 0.22f, 1f); private static readonly Color ColGoldText = new Color(1f, 0.84f, 0.38f, 1f); private static readonly Color ColWhiteText = new Color(0.92f, 0.95f, 0.98f, 1f); private static readonly Color ColMutedText = new Color(0.6f, 0.66f, 0.75f, 1f); private static readonly Color ColCyanText = new Color(0.4f, 0.8f, 1f, 1f); private static readonly Color ColGreenText = new Color(0.38f, 0.88f, 0.48f, 1f); private static readonly Color ColRedText = new Color(0.95f, 0.38f, 0.38f, 1f); private static readonly Color ColSlotEmptyBg = new Color(0.06f, 0.07f, 0.1f, 0.9f); private static readonly Color ColSlotEmptyBorder = new Color(0.2f, 0.24f, 0.32f, 0.9f); private static readonly Color ColSlotHoverBorder = new Color(0.45f, 0.8f, 1f, 1f); private static readonly Color ColSlotSelectedBorder = new Color(1f, 0.84f, 0.38f, 1f); private static readonly Dictionary<string, GUIStyle> s_styleCache = new Dictionary<string, GUIStyle>(); private static GUIStyle s_textFieldStyle; private static readonly Color ColScrollbar = new Color(0.2f, 0.25f, 0.35f, 0.8f); private float m_lastGridHeight = 400f; private float m_lastCell = 54f; public static BrowserGUI Instance { get; private set; } public static bool IsOpen { get { if ((Object)(object)Instance != (Object)null) { return Instance.m_open; } return false; } } private void Awake() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) Instance = this; m_whiteTex = new Texture2D(1, 1); m_whiteTex.SetPixel(0, 0, Color.white); m_whiteTex.Apply(); } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } public void Open() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { if (!RecipeIndex.Built) { RecipeIndex.Build(localPlayer); } if (!RecipeIndex.Built) { m_status = "No recipes loaded yet. Open a crafting station again in a moment."; m_statusTimer = 5f; } Refilter(); m_open = true; m_wasCrafting = false; Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } } public void Close() { if (m_open) { m_open = false; m_selected = null; Cursor.visible = false; Cursor.lockState = (CursorLockMode)1; } } private void Update() { if (m_statusTimer > 0f) { m_statusTimer -= Time.deltaTime; } if (!m_open) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead()) { Close(); return; } float progress; if (Input.GetKeyDown((KeyCode)27)) { if (CraftingBridge.IsCrafting(out progress)) { CraftingBridge.Cancel(); SetStatus("Craft cancelled."); } else { Close(); } } bool flag = CraftingBridge.IsCrafting(out progress); if (m_wasCrafting && !flag) { m_wasCrafting = false; if (m_pendingCraftName != null) { m_recentlyCrafted = m_pendingCraftName; m_pendingCraftName = null; } } m_wasCrafting = flag; RecipeIndex.Refresh(localPlayer); } private void Refilter() { RecipeIndex.Filter(m_visible, m_search, m_tabIndex, m_subIndex, m_mode); if (m_selected != null && !m_visible.Contains(m_selected)) { m_selected = null; m_selectedCopy = 0; } ClampGridScroll(); } private void ClampGridScroll() { int num = RowCount(); int num2 = Mathf.Max(1, GridVisibleRows()); m_gridRow = Mathf.Clamp(m_gridRow, 0, Mathf.Max(0, num - num2)); } private int RowCount() { return Mathf.CeilToInt((float)m_visible.Count / (float)Mathf.Max(1, m_gridCols)); } private void SetStatus(string text, float seconds = 4f) { m_status = text; m_statusTimer = seconds; } private void OnGUI() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) if (m_open) { DrawRect(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), ColBackdrop); float num = (m_isFullscreen ? ((float)Screen.width - 24f) : Mathf.Min(1180f, (float)Screen.width - 32f)); float num2 = (m_isFullscreen ? ((float)Screen.height - 24f) : Mathf.Min(700f, (float)Screen.height - 32f)); Rect r = default(Rect); ((Rect)(ref r))..ctor(((float)Screen.width - num) * 0.5f, ((float)Screen.height - num2) * 0.5f, num, num2); DrawBox(r, ColWindowBg, ColWindowBorder, 2f); DrawBorder(Shrink(r, 3f), ColWindowBorderInner); float num3 = ((Rect)(ref r)).y + 8f; float num4 = 10f; float num5 = ((Rect)(ref r)).width - num4 * 2f; Rect r2 = default(Rect); ((Rect)(ref r2))..ctor(((Rect)(ref r)).x + num4, num3, num5, 46f); DrawHeader(r2); num3 = ((Rect)(ref r2)).yMax + 8f; Rect r3 = default(Rect); ((Rect)(ref r3))..ctor(((Rect)(ref r)).x + num4, num3, num5, 32f); DrawTopTabs(r3); num3 = ((Rect)(ref r3)).yMax + 8f; Rect r4 = default(Rect); ((Rect)(ref r4))..ctor(((Rect)(ref r)).x + num4, num3, num5, ((Rect)(ref r)).yMax - num3 - 40f); DrawBody(r4); DrawFooter(new Rect(((Rect)(ref r)).x + num4, ((Rect)(ref r)).yMax - 34f, num5, 26f)); } } private void DrawHeader(Rect r) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: 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_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: Unknown result type (might be due to invalid IL or missing references) DrawBox(r, ColCardHeaderBg, ColCardBorder); string text = RecipeIndex.CurrentStationName(Player.m_localPlayer); string text2 = (CraftingBridge.Ready ? "craft engine: bound" : "craft engine: UNAVAILABLE"); GUI.Label(new Rect(((Rect)(ref r)).x + 14f, ((Rect)(ref r)).y + 5f, 380f, 22f), "? CRAFTING BROWSER", GetTextStyle(15, bold: true, (TextAnchor)3, ColGoldText)); GUI.Label(new Rect(((Rect)(ref r)).x + 14f, ((Rect)(ref r)).y + 25f, 460f, 16f), "Station: <color=#FFD760>" + text + "</color> \ufffd " + text2, GetTextStyle(11, bold: false, (TextAnchor)3, CraftingBridge.Ready ? ColMutedText : ColRedText)); Rect r2 = default(Rect); ((Rect)(ref r2))..ctor(((Rect)(ref r)).x + 360f, ((Rect)(ref r)).y + 9f, 250f, 28f); DrawBox(r2, new Color(0.04f, 0.05f, 0.08f, 1f), ColCardBorder); string text3 = GUI.TextField(Shrink(r2, 5f), m_search, GetTextFieldStyle()); if (text3 != m_search) { m_search = text3; Refilter(); } if (CustomButton(new Rect(((Rect)(ref r2)).xMax + 4f, ((Rect)(ref r2)).y, 26f, 28f), "?", new Color(0.24f, 0.12f, 0.12f, 0.9f), new Color(0.55f, 0.15f, 0.15f, 1f), ColWhiteText, 11, bold: true, ColRedText)) { m_search = ""; Refilter(); } float num = 128f; float num2 = ((Rect)(ref r)).xMax - 36f - num; string text4 = ((m_mode == VisibilityMode.Unlocked) ? "Unlocked" : ((m_mode == VisibilityMode.CraftableHere) ? "Craftable here" : "All recipes")); if (CustomButton(new Rect(num2, ((Rect)(ref r)).y + 9f, num, 28f), text4, (m_mode == VisibilityMode.All) ? new Color(0.24f, 0.2f, 0.1f, 0.95f) : new Color(0.12f, 0.16f, 0.24f, 0.95f), new Color(0.2f, 0.28f, 0.4f, 1f), ColGoldText, 11, bold: true, ColWindowBorder)) { m_mode = ((m_mode == VisibilityMode.Unlocked) ? VisibilityMode.CraftableHere : ((m_mode == VisibilityMode.CraftableHere) ? VisibilityMode.All : VisibilityMode.Unlocked)); Refilter(); } if (CustomButton(new Rect(num2 - 34f, ((Rect)(ref r)).y + 9f, 30f, 28f), m_isFullscreen ? "?" : "?", new Color(0.12f, 0.15f, 0.2f, 0.9f), new Color(0.2f, 0.26f, 0.34f, 1f), ColWhiteText, 13)) { m_isFullscreen = !m_isFullscreen; } if (CustomButton(new Rect(((Rect)(ref r)).xMax - 36f, ((Rect)(ref r)).y + 9f, 30f, 28f), "?", new Color(0.24f, 0.12f, 0.12f, 0.9f), new Color(0.55f, 0.15f, 0.15f, 1f), ColWhiteText, 13, bold: true, ColRedText)) { Close(); } } private void DrawTopTabs(Rect r) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) CategoryTable table = CraftingCategories.Table; if (table == null) { return; } int count = table.tabs.Count; float num = (((Rect)(ref r)).width - (float)(count - 1) * 4f) / (float)count; Rect r2 = default(Rect); for (int i = 0; i < count; i++) { ((Rect)(ref r2))..ctor(((Rect)(ref r)).x + (float)i * (num + 4f), ((Rect)(ref r)).y, num, ((Rect)(ref r)).height); bool flag = m_tabIndex == i; Color val = (flag ? new Color(0.22f, 0.28f, 0.38f, 1f) : new Color(0.1f, 0.13f, 0.18f, 0.85f)); Color value = (flag ? ColWindowBorder : ColCardBorder); Color textColor = (flag ? ColGoldText : ColWhiteText); if (CustomButton(r2, table.tabs[i].label, val, (Color)(flag ? val : new Color(0.16f, 0.21f, 0.29f, 0.95f)), textColor, 11, bold: true, value)) { m_tabIndex = i; m_subIndex = 0; m_gridRow = 0; m_sidebarScroll = Vector2.zero; Refilter(); } } } private void DrawBody(Rect r) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) float num = 8f; float num2 = Mathf.Clamp(((Rect)(ref r)).width * 0.16f, 130f, 190f); float num3 = Mathf.Clamp(((Rect)(ref r)).width * 0.3f, 250f, 340f); float num4 = ((Rect)(ref r)).width - num2 - num3 - num * 2f; Rect r2 = default(Rect); ((Rect)(ref r2))..ctor(((Rect)(ref r)).x, ((Rect)(ref r)).y, num2, ((Rect)(ref r)).height); Rect r3 = default(Rect); ((Rect)(ref r3))..ctor(((Rect)(ref r2)).xMax + num, ((Rect)(ref r)).y, num4, ((Rect)(ref r)).height); Rect r4 = default(Rect); ((Rect)(ref r4))..ctor(((Rect)(ref r3)).xMax + num, ((Rect)(ref r)).y, num3, ((Rect)(ref r)).height); DrawSidebar(r2); DrawGrid(r3); DrawDetails(r4); } private void DrawSidebar(Rect r) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) DrawCard(r, "CATEGORIES", (m_tabIndex > 0) ? null : "all"); Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref r)).x + 6f, ((Rect)(ref r)).y + 34f, ((Rect)(ref r)).width - 12f, ((Rect)(ref r)).height - 42f); if (m_tabIndex <= 0) { GUI.Label(val, "Every recipe the player has discovered, newest categories included.\n\nPick a top tab to narrow by subcategory.", GetTextStyle(11, bold: false, (TextAnchor)0, ColMutedText)); return; } RecipeIndex.CountBySubcategory(m_tabIndex, m_mode, m_subCounts); int num = CraftingCategories.Table.SubCount(m_tabIndex); float num2 = 30f; Color backgroundColor = GUI.backgroundColor; GUI.backgroundColor = ColScrollbar; m_sidebarScroll = GUI.BeginScrollView(val, m_sidebarScroll, new Rect(0f, 0f, ((Rect)(ref val)).width - 16f, (float)num * (num2 + 2f))); GUI.backgroundColor = backgroundColor; Rect r2 = default(Rect); for (int i = 0; i < num; i++) { ((Rect)(ref r2))..ctor(0f, (float)i * (num2 + 2f), ((Rect)(ref val)).width - 18f, num2); bool flag = m_subIndex == i; m_subCounts.TryGetValue(i, out var value); string text = $"{CraftingCategories.Table.SubLabel(m_tabIndex, i)} ({value})"; if (CustomButton(r2, text, flag ? new Color(0.24f, 0.2f, 0.1f, 0.98f) : new Color(0.1f, 0.13f, 0.18f, 0.7f), flag ? new Color(0.3f, 0.25f, 0.12f, 1f) : new Color(0.16f, 0.21f, 0.29f, 0.9f), flag ? ColGoldText : ColWhiteText, 11, bold: true, flag ? ColWindowBorder : ColCardBorder)) { m_subIndex = i; m_gridRow = 0; Refilter(); } } GUI.EndScrollView(); } private int GridVisibleRows() { return Mathf.Max(1, (int)(m_lastGridHeight / (m_lastCell + 4f))); } private void DrawGrid(Rect r) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Invalid comparison between Unknown and I4 //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) DrawCard(r, "RECIPES", $"{m_visible.Count} shown"); Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref r)).x + 6f, ((Rect)(ref r)).y + 34f, ((Rect)(ref r)).width - 12f, ((Rect)(ref r)).height - 42f); if (m_visible.Count == 0) { GUI.Label(val, (m_mode == VisibilityMode.Unlocked) ? "Nothing here yet. Switch the header toggle to All recipes to see everything, including what you have not discovered." : "No recipe matches that search.", GetTextStyle(11, bold: false, (TextAnchor)0, ColMutedText)); return; } if ((int)Event.current.type == 6 && ((Rect)(ref val)).Contains(Event.current.mousePosition)) { m_gridRow += ((Event.current.delta.y > 0f) ? 1 : (-1)); ClampGridScroll(); Event.current.Use(); } float num = 4f; float num2 = Mathf.Floor((((Rect)(ref val)).width - (float)(m_gridCols - 1) * num) / (float)m_gridCols); num2 = (m_lastCell = Mathf.Clamp(num2, 34f, m_isFullscreen ? 66f : 56f)); m_lastGridHeight = ((Rect)(ref val)).height; m_gridCols = Mathf.Max(1, (int)((((Rect)(ref val)).width + num) / (num2 + num))); num2 = (m_lastCell = Mathf.Floor((((Rect)(ref val)).width - (float)(m_gridCols - 1) * num) / (float)m_gridCols)); int num3 = RowCount(); ClampGridScroll(); int num4 = m_gridRow * m_gridCols; int num5 = Mathf.Min(m_visible.Count, num4 + m_gridCols * (num3 - m_gridRow)); int num6 = 0; Rect cell = default(Rect); for (int i = num4; i < num5; i++) { int num7 = num6 % m_gridCols; int num8 = num6 / m_gridCols; ((Rect)(ref cell))..ctor(((Rect)(ref val)).x + (float)num7 * (num2 + num), ((Rect)(ref val)).y + (float)num8 * (num2 + num), num2, num2); DrawRecipeCell(cell, m_visible[i], i); num6++; } if (num3 > GridVisibleRows()) { GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).yMax - 18f, ((Rect)(ref val)).width, 16f), $"Rows {m_gridRow + 1}-{Mathf.Min(num3, m_gridRow + GridVisibleRows())} of {num3}", GetTextStyle(10, bold: false, (TextAnchor)4, ColMutedText)); } } private void DrawRecipeCell(Rect cell, RecipeEntry entry, int index) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_004a: 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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) bool flag = entry == m_selected; bool flag2 = ((Rect)(ref cell)).Contains(Event.current.mousePosition); Color bg = (Color)(flag ? new Color(0.24f, 0.2f, 0.1f, 0.98f) : (entry.CanCraftNow ? new Color(0.11f, 0.16f, 0.13f, 0.95f) : (entry.Unlocked ? ColSlotEmptyBg : new Color(0.05f, 0.05f, 0.07f, 0.9f)))); Color border = (Color)(flag ? ColSlotSelectedBorder : (flag2 ? ColSlotHoverBorder : (entry.Unlocked ? ColSlotEmptyBorder : new Color(0.14f, 0.15f, 0.18f, 0.8f)))); DrawBox(cell, bg, border, flag ? 2f : 1f); float num = (entry.Unlocked ? 1f : 0.38f); DrawIcon(Shrink(cell, 4f), entry.Icon, num); if (entry.Amount > 1) { GUI.Label(new Rect(((Rect)(ref cell)).x + 2f, ((Rect)(ref cell)).yMax - 14f, ((Rect)(ref cell)).width - 4f, 12f), "x" + entry.Amount, GetTextStyle(9, bold: true, (TextAnchor)5, new Color(1f, 1f, 1f, num))); } if ((int)Event.current.type != 0 || !((Rect)(ref cell)).Contains(Event.current.mousePosition)) { return; } m_selected = entry; m_selectedCopy = 0; m_ownedCopies.Clear(); m_detailsScroll = Vector2.zero; Event.current.Use(); if (Event.current.button == 0) { float unscaledTime = Time.unscaledTime; if (m_lastClickedIndex == index && unscaledTime - m_lastClickTime < 0.35f) { TryCraft(); m_lastClickTime = 0f; m_lastClickedIndex = -1; } else { m_lastClickTime = unscaledTime; m_lastClickedIndex = index; } } } private void DrawDetails(Rect r) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) DrawCard(r, "DETAILS", (m_selected != null) ? m_selected.StationName : null); Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref r)).x + 8f, ((Rect)(ref r)).y + 34f, ((Rect)(ref r)).width - 16f, ((Rect)(ref r)).height - 42f); Color backgroundColor = GUI.backgroundColor; GUI.backgroundColor = ColScrollbar; m_detailsScroll = GUI.BeginScrollView(val, m_detailsScroll, new Rect(0f, 0f, ((Rect)(ref val)).width - 16f, Mathf.Max(((Rect)(ref val)).height, 420f))); GUI.backgroundColor = backgroundColor; if (m_selected == null) { GUI.Label(new Rect(0f, 0f, ((Rect)(ref val)).width - 16f, 60f), "Pick a recipe to see its ingredients and craft it.", GetTextStyle(11, bold: false, (TextAnchor)0, ColMutedText)); GUI.EndScrollView(); return; } float num = 0f; float num2 = ((Rect)(ref val)).width - 16f; DrawIcon(new Rect(0f, num, 40f, 40f), m_selected.Icon, 1f); GUI.Label(new Rect(46f, num, num2 - 46f, 20f), m_selected.DisplayName, GetTextStyle(13, bold: true, (TextAnchor)3, ColGoldText)); GUI.Label(new Rect(46f, num + 19f, num2 - 46f, 18f), (m_selected.Amount > 1) ? $"Produces {m_selected.Amount} \ufffd {m_selected.StationName}" : m_selected.StationName, GetTextStyle(10, bold: false, (TextAnchor)3, ColMutedText)); num += 46f; string text = ((!m_selected.Unlocked) ? "<color=#F26262>Not yet discovered</color>" : ((!m_selected.StationOk) ? ("<color=#F2B262>Needs a " + m_selected.StationName + "</color>") : (m_selected.CanCraftNow ? $"<color=#63E07A>You can craft {m_selected.MaxCraftable}</color>" : "<color=#E0C063>Missing materials</color>"))); GUI.Label(new Rect(0f, num, num2, 18f), text, GetTextStyle(11, bold: true, (TextAnchor)3, ColWhiteText)); num += 24f; num = DrawRequirementList(0f, num, num2); num = DrawUpgradeStrip(0f, num, num2); num = DrawCraftButton(0f, num, num2); GUI.EndScrollView(); } private float DrawRequirementList(float x, float y, float w) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) Requirement[] resources = m_selected.Recipe.m_resources; if (resources == null || resources.Length == 0) { GUI.Label(new Rect(x, y, w, 18f), "No materials required.", GetTextStyle(11, bold: false, (TextAnchor)3, ColMutedText)); return y + 24f; } if (m_selected.Recipe.m_requireOnlyOneIngredient) { GUI.Label(new Rect(x, y, w, 16f), "Only one ingredient set is needed.", GetTextStyle(10, bold: false, (TextAnchor)3, ColCyanText)); y += 18f; } Player localPlayer = Player.m_localPlayer; Inventory val = (((Object)(object)localPlayer != (Object)null) ? ((Humanoid)localPlayer).GetInventory() : null); Rect r = default(Rect); foreach (Requirement val2 in resources) { if (val2 != null && !((Object)(object)val2.m_resItem == (Object)null) && val2.m_resItem.m_itemData != null) { SharedData shared = val2.m_resItem.m_itemData.m_shared; int num = Mathf.Max(1, val2.GetAmount(1)); int num2 = ((val != null) ? val.CountItems(shared.m_name, -1, true) : 0); bool flag = num2 >= num; ((Rect)(ref r))..ctor(x, y, w, 24f); DrawBox(r, new Color(0.06f, 0.08f, 0.11f, 0.8f), ColCardBorder); DrawIcon(new Rect(((Rect)(ref r)).x + 2f, ((Rect)(ref r)).y + 2f, 20f, 20f), val2.m_resItem.m_itemData.GetIcon(), 1f); GUI.Label(new Rect(((Rect)(ref r)).x + 26f, ((Rect)(ref r)).y, ((Rect)(ref r)).width - 90f, 24f), RecipeIndex.Localize(shared.m_name), GetTextStyle(10, bold: false, (TextAnchor)3, ColWhiteText)); GUI.Label(new Rect(((Rect)(ref r)).xMax - 62f, ((Rect)(ref r)).y, 58f, 24f), $"{num2} / {num}", GetTextStyle(11, bold: true, (TextAnchor)5, flag ? ColGreenText : ColRedText)); y += 26f; } } return y + 6f; } private float DrawUpgradeStrip(float x, float y, float w) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) SharedData shared = m_selected.Recipe.m_item.m_itemData.m_shared; if (shared.m_maxQuality <= 1) { return y; } Player localPlayer = Player.m_localPlayer; Inventory val = (((Object)(object)localPlayer != (Object)null) ? ((Humanoid)localPlayer).GetInventory() : null); if (val == null) { return y; } if (m_ownedCopies.Count == 0) { m_ownedCopies.Clear(); val.GetAllItems(shared.m_name, m_ownedCopies); if (m_selectedCopy >= m_ownedCopies.Count) { m_selectedCopy = 0; } } GUI.Label(new Rect(x, y, w, 18f), $"Upgrade target ({m_ownedCopies.Count} owned)", GetTextStyle(11, bold: true, (TextAnchor)3, ColCyanText)); y += 20f; if (m_ownedCopies.Count == 0) { GUI.Label(new Rect(x, y, w, 16f), "You do not own any to upgrade.", GetTextStyle(10, bold: false, (TextAnchor)3, ColMutedText)); return y + 22f; } float num = Mathf.Min(38f, (w - 6f) / (float)Mathf.Min(m_ownedCopies.Count, 6)); Rect r = default(Rect); for (int i = 0; i < m_ownedCopies.Count; i++) { if (i >= 6) { GUI.Label(new Rect(x + 6f * (num + 2f), y, 40f, 34f), "+" + (m_ownedCopies.Count - 6), GetTextStyle(11, bold: true, (TextAnchor)3, ColMutedText)); break; } ((Rect)(ref r))..ctor(x + (float)i * (num + 2f), y, num, 34f); bool flag = m_selectedCopy == i; DrawBox(r, (Color)(flag ? new Color(0.24f, 0.2f, 0.1f, 0.98f) : ColSlotEmptyBg), flag ? ColWindowBorder : ColSlotEmptyBorder, flag ? 2f : 1f); DrawIcon(Shrink(r, 3f), m_ownedCopies[i].m_shared.m_icons[0], 1f); GUI.Label(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).yMax - 13f, ((Rect)(ref r)).width, 12f), "?" + m_ownedCopies[i].m_quality, GetTextStyle(9, bold: true, (TextAnchor)4, ColGoldText)); if ((int)Event.current.type == 0 && ((Rect)(ref r)).Contains(Event.current.mousePosition)) { m_selectedCopy = i; Event.current.Use(); } } return y + 40f; } private float DrawCraftButton(float x, float y, float w) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: 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_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) if (CraftingBridge.IsCrafting(out var progress)) { Rect val = default(Rect); ((Rect)(ref val))..ctor(x, y + 4f, w, 16f); DrawBox(val, new Color(0.05f, 0.06f, 0.09f, 1f), ColCardBorder); DrawRect(new Rect(((Rect)(ref val)).x + 1f, ((Rect)(ref val)).y + 1f, (((Rect)(ref val)).width - 2f) * progress, ((Rect)(ref val)).height - 2f), new Color(0.35f, 0.75f, 0.45f, 0.95f)); GUI.Label(val, $"Crafting {progress * 100f:F0}%", GetTextStyle(10, bold: true, (TextAnchor)4, ColWhiteText)); if (CustomButton(new Rect(x, y + 24f, w, 30f), "Cancel", new Color(0.32f, 0.14f, 0.14f, 0.95f), new Color(0.55f, 0.18f, 0.18f, 1f), ColWhiteText, 12, bold: true, ColRedText)) { CraftingBridge.Cancel(); SetStatus("Craft cancelled."); } return y + 60f; } if (m_recentlyCrafted != null) { Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(x, y, w, 30f); DrawBox(val2, new Color(0.12f, 0.26f, 0.16f, 0.95f), ColGreenText); GUI.Label(val2, "? Crafted " + m_recentlyCrafted, GetTextStyle(12, bold: true, (TextAnchor)4, ColGreenText)); if (CustomButton(new Rect(x, y + 34f, w, 26f), "View inventory", new Color(0.12f, 0.16f, 0.24f, 0.95f), new Color(0.2f, 0.28f, 0.4f, 1f), ColWhiteText, 11, bold: true, ColCyanText)) { m_recentlyCrafted = null; Close(); } if (CustomButton(new Rect(x, y + 62f, w, 24f), "Dismiss", new Color(0.1f, 0.12f, 0.16f, 0.9f), new Color(0.16f, 0.2f, 0.26f, 1f), ColMutedText, 10, bold: false, ColCardBorder)) { m_recentlyCrafted = null; } return y + 92f; } bool ready = CraftingBridge.Ready; bool stationOk = m_selected.StationOk; bool canCraftNow = m_selected.CanCraftNow; bool flag = m_selected.Unlocked && stationOk && canCraftNow; string text = ((!ready) ? "Craft unavailable" : ((!m_selected.Unlocked) ? "Not discovered" : ((!stationOk) ? ("Needs a " + m_selected.StationName) : ((!canCraftNow) ? "Missing materials" : "Craft")))); Color bg = ((!flag || !ready) ? new Color(0.12f, 0.13f, 0.16f, 0.9f) : new Color(0.16f, 0.34f, 0.2f, 0.95f)); if (CustomButton(new Rect(x, y, w, 32f), text, bg, new Color(0.22f, 0.48f, 0.28f, 1f), (flag && ready) ? ColWhiteText : ColMutedText, 12, bold: true, (flag && ready) ? ColGreenText : ColCardBorder)) { TryCraft(); } return y + 38f; } private void TryCraft() { if (m_selected == null) { return; } if (!CraftingBridge.Ready) { SetStatus("The crafting engine is not bound on this game build; browsing still works."); return; } if (!m_selected.Unlocked) { SetStatus("You have not discovered that recipe yet."); return; } if (!m_selected.StationOk) { SetStatus("That recipe needs a different crafting station."); return; } if (!m_selected.CanCraftNow) { SetStatus("You are missing materials for that recipe."); return; } ItemData val = null; if (m_selected.Recipe.m_item.m_itemData.m_shared.m_maxQuality > 1 && m_ownedCopies.Count > 0) { val = m_ownedCopies[Mathf.Clamp(m_selectedCopy, 0, m_ownedCopies.Count - 1)]; } if (CraftingBridge.TryStartCraft(Player.m_localPlayer, m_selected.Recipe, val, out var error)) { m_pendingCraftName = m_selected.DisplayName; m_recentlyCrafted = null; SetStatus((val != null) ? ("Upgrading " + m_selected.DisplayName + "...") : ("Crafting " + m_selected.DisplayName + "...")); } else { SetStatus("Could not start: " + error); } } private void DrawFooter(Rect r) { //IL_0001: 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) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) DrawBox(r, new Color(0.06f, 0.07f, 0.1f, 0.95f), ColCardBorder); string text = ((m_statusTimer > 0f) ? m_status : BuildFooterSummary()); GUI.Label(Shrink(r, 8f), text, GetTextStyle(10, bold: false, (TextAnchor)3, (m_statusTimer > 0f) ? ColCyanText : ColMutedText)); GUI.Label(Shrink(r, 8f), "Esc close / cancel \ufffd double-click to craft", GetTextStyle(10, bold: false, (TextAnchor)5, ColMutedText)); } private string BuildFooterSummary() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append($"{RecipeIndex.All.Count} recipes indexed \ufffd "); stringBuilder.Append($"{CraftingCategories.LastTotal - CraftingCategories.LastUnmatched} categorised"); if (CraftingCategories.LastUnmatched > 0) { stringBuilder.Append($", {CraftingCategories.LastUnmatched} in Other"); } int untranslatedCount = RecipeIndex.UntranslatedCount; if (untranslatedCount > 0) { stringBuilder.Append($" \ufffd <color=#F2B262>{untranslatedCount} names untranslated</color>"); } return stringBuilder.ToString(); } private void DrawRect(Rect r, Color c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) GUI.color = c; GUI.DrawTexture(r, (Texture)(object)m_whiteTex); GUI.color = Color.white; } private void DrawBorder(Rect r, Color c, float thickness = 1f) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) GUI.color = c; GUI.DrawTexture(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y, ((Rect)(ref r)).width, thickness), (Texture)(object)m_whiteTex); GUI.DrawTexture(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).yMax - thickness, ((Rect)(ref r)).width, thickness), (Texture)(object)m_whiteTex); GUI.DrawTexture(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + thickness, thickness, ((Rect)(ref r)).height - thickness * 2f), (Texture)(object)m_whiteTex); GUI.DrawTexture(new Rect(((Rect)(ref r)).xMax - thickness, ((Rect)(ref r)).y + thickness, thickness, ((Rect)(ref r)).height - thickness * 2f), (Texture)(object)m_whiteTex); GUI.color = Color.white; } private void DrawBox(Rect r, Color bg, Color border, float thickness = 1f) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) DrawRect(r, bg); if (thickness > 0f && border.a > 0.01f) { DrawBorder(r, border, thickness); } } private void DrawCard(Rect r, string title, string badge = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) DrawBox(r, ColCardBg, ColCardBorder); Rect r2 = default(Rect); ((Rect)(ref r2))..ctor(((Rect)(ref r)).x, ((Rect)(ref r)).y, ((Rect)(ref r)).width, 28f); DrawBox(r2, ColCardHeaderBg, ColCardBorder); GUI.Label(new Rect(((Rect)(ref r2)).x + 10f, ((Rect)(ref r2)).y + 4f, ((Rect)(ref r2)).width - 20f, 20f), title, GetTextStyle(12, bold: true, (TextAnchor)3, ColGoldText)); if (!string.IsNullOrEmpty(badge)) { GUI.Label(new Rect(((Rect)(ref r2)).xMax - 170f, ((Rect)(ref r2)).y + 4f, 160f, 20f), badge, GetTextStyle(11, bold: true, (TextAnchor)5, ColCyanText)); } } private bool CustomButton(Rect r, string text, Color bg, Color hoverBg, Color textColor, int fontSize = 12, bool bold = true, Color? border = null) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0062: 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_0069: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) bool flag = ((Rect)(ref r)).Contains(Event.current.mousePosition); Color bg2 = (flag ? hoverBg : bg); Color border2 = (Color)(((??)border) ?? (flag ? new Color(0.4f, 0.75f, 1f, 0.9f) : new Color(0.24f, 0.3f, 0.4f, 0.85f))); DrawBox(r, bg2, border2); GUI.Label(r, text, GetTextStyle(fontSize, bold, (TextAnchor)4, textColor)); return GUI.Button(r, GUIContent.none, GUIStyle.none); } private static Rect Shrink(Rect r, float amount) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) return new Rect(((Rect)(ref r)).x + amount, ((Rect)(ref r)).y + amount, ((Rect)(ref r)).width - amount * 2f, ((Rect)(ref r)).height - amount * 2f); } private void DrawIcon(Rect r, Sprite sprite, float alpha) { //IL_001c: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sprite == (Object)null) { return; } Texture texture = (Texture)(object)sprite.texture; if ((Object)(object)texture == (Object)null) { return; } Rect textureRect = sprite.textureRect; float num = texture.width; float num2 = texture.height; if (num <= 0f || num2 <= 0f) { return; } Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref textureRect)).x / num, ((Rect)(ref textureRect)).y / num2, ((Rect)(ref textureRect)).width / num, ((Rect)(ref textureRect)).height / num2); Rect val2 = r; if (((Rect)(ref val)).width > 0f && ((Rect)(ref val)).height > 0f) { float num3 = ((Rect)(ref val)).width / ((Rect)(ref val)).height; if (((Rect)(ref r)).width / ((Rect)(ref r)).height > num3) { float num4 = ((Rect)(ref r)).height * num3; ((Rect)(ref val2))..ctor(((Rect)(ref r)).x + (((Rect)(ref r)).width - num4) * 0.5f, ((Rect)(ref r)).y, num4, ((Rect)(ref r)).height); } else { float num5 = ((Rect)(ref r)).width / num3; ((Rect)(ref val2))..ctor(((Rect)(ref r)).x, ((Rect)(ref r)).y + (((Rect)(ref r)).height - num5) * 0.5f, ((Rect)(ref r)).width, num5); } } Color color = GUI.color; GUI.color = new Color(1f, 1f, 1f, alpha); GUI.DrawTextureWithTexCoords(val2, texture, val, true); GUI.color = color; } private static GUIStyle GetTextStyle(int fontSize, bool bold, TextAnchor anchor, Color color) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected I4, but got Unknown //IL_002b: 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) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00af: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) string key = $"{fontSize}_{(bold ? 1 : 0)}_{(int)anchor}_{color.r:F2}_{color.g:F2}_{color.b:F2}_{color.a:F2}"; if (!s_styleCache.TryGetValue(key, out var value)) { value = new GUIStyle(GUI.skin.label) { fontSize = fontSize, fontStyle = (FontStyle)(bold ? 1 : 0), alignment = anchor, clipping = (TextClipping)1, wordWrap = true }; value.normal.textColor = color; value.hover.textColor = color; value.active.textColor = color; s_styleCache[key] = value; } return value; } private static GUIStyle GetTextFieldStyle() { //IL_0011: 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) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (s_textFieldStyle == null) { s_textFieldStyle = new GUIStyle(GUI.skin.textField) { fontSize = 12, alignment = (TextAnchor)3 }; s_textFieldStyle.normal.textColor = ColWhiteText; } return s_textFieldStyle; } } public static class CraftingBridge { private const BindingFlags AnyInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static FieldInfo f_selectedRecipe; private static FieldInfo f_selectedVariant; private static FieldInfo f_craftRecipe; private static FieldInfo f_craftUpgradeItem; private static FieldInfo f_craftVariant; private static FieldInfo f_multiCrafting; private static FieldInfo f_craftTimer; private static MethodInfo m_onCraftCancelPressed; private static ConstructorInfo c_pair; private static Type t_pair; private static readonly List<string> s_missing = new List<string>(); public static bool Ready { get; private set; } public static string MissingReport { get { if (s_missing.Count != 0) { return string.Join(", ", s_missing.ToArray()); } return "none"; } } public static Recipe CurrentCraft { get { if (f_craftRecipe == null) { return null; } try { InventoryGui instance = InventoryGui.instance; return (Recipe)(((Object)(object)instance == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/); } catch (Exception) { return null; } } } public static void Init() { s_missing.Clear(); t_pair = typeof(InventoryGui).GetNestedType("RecipeDataPair", BindingFlags.Public | BindingFlags.NonPublic); if (t_pair == null) { s_missing.Add("InventoryGui+RecipeDataPair"); } else { c_pair = t_pair.GetConstructor(new Type[4] { typeof(Recipe), typeof(ItemData), typeof(GameObject), typeof(bool) }); if (c_pair == null) { s_missing.Add("RecipeDataPair(Recipe,ItemData,GameObject,bool)"); } } f_selectedRecipe = Field("m_selectedRecipe"); f_selectedVariant = Field("m_selectedVariant"); f_craftRecipe = Field("m_craftRecipe"); f_craftUpgradeItem = Field("m_craftUpgradeItem"); f_craftVariant = Field("m_craftVariant"); f_multiCrafting = Field("m_multiCrafting"); f_craftTimer = Field("m_craftTimer"); m_onCraftCancelPressed = Method("OnCraftCancelPressed"); Ready = s_missing.Count == 0; if (Ready) { Logger.LogInfo((object)"Crafting Browser: crafting engine bound to the vanilla InventoryGui."); } else { Logger.LogError((object)("Crafting Browser: could not bind the crafting engine (" + MissingReport + "). The browser will open read-only and Craft is disabled. Run verify_patches.ps1 to see which member moved.")); } } private static FieldInfo Field(string name) { FieldInfo? field = typeof(InventoryGui).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { s_missing.Add("InventoryGui." + name); } return field; } private static MethodInfo Method(string name, params Type[] args) { MethodInfo? method = typeof(InventoryGui).GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, args, null); if (method == null) { s_missing.Add("InventoryGui." + name); } return method; } public static bool TryStartCraft(Player player, Recipe recipe, ItemData upgradeItem, out string error) { error = null; if (!Ready) { error = "crafting engine unavailable"; return false; } if ((Object)(object)player == (Object)null || (Object)(object)recipe == (Object)null) { error = "no player or recipe"; return false; } InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null) { error = "inventory panel is not open"; return false; } if (IsCrafting(out var _)) { error = "already crafting"; return false; } if (!player.HaveRequirements(recipe, false, 1, 1)) { error = "missing materials"; return false; } try { if (c_pair != null) { object value = c_pair.Invoke(new object[4] { recipe, upgradeItem, null, true }); f_selectedRecipe.SetValue(instance, value); } f_selectedVariant.SetValue(instance, 0); f_craftRecipe.SetValue(instance, recipe); f_craftUpgradeItem.SetValue(instance, upgradeItem); f_craftVariant.SetValue(instance, 0); f_multiCrafting.SetValue(instance, false); f_craftTimer.SetValue(instance, 0f); return true; } catch (Exception ex) { error = ex.GetBaseException().Message; Logger.LogError((object)("Crafting Browser: failed to arm a craft: " + ex)); return false; } } public static bool IsCrafting(out float progress) { progress = 0f; if (f_craftTimer == null) { return false; } try { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null) { return false; } if (!(f_craftTimer.GetValue(instance) is float num)) { return false; } if (num < 0f) { return false; } progress = Mathf.Clamp01(num); return true; } catch (Exception) { return false; } } public static void Cancel() { if (m_onCraftCancelPressed == null) { return; } try { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null) { m_onCraftCancelPressed.Invoke(instance, null); } } catch (Exception ex) { Logger.LogError((object)("Crafting Browser: cancel failed: " + ex)); } } } [BepInPlugin("com.dfg.craftingbrowser", "Crafting Browser", "1.0.0")] public class CraftingBrowserPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(CraftingStation), "Interact")] private static class CraftingStationInteractPatch { private static void Postfix() { if (Enabled == null || !Enabled.Value || !OpenOnStation.Value) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)localPlayer.GetCurrentCraftingStation() == (Object)null)) { s_openQueued = true; if (!s_openLogged) { s_openLogged = true; Logger.LogInfo((object)"Crafting Browser: station interaction detected, browser will open."); } } } } [HarmonyPatch(typeof(InventoryGui), "Hide")] private static class InventoryGuiHidePatch { private static bool Prefix() { return !BrowserGUI.IsOpen; } } [HarmonyPatch(typeof(PlayerController), "InInventoryEtc")] private static class InInventoryEtcPatch { private static void Postfix(ref bool __result) { if (BrowserGUI.IsOpen) { __result = true; } } } public const string PluginGUID = "com.dfg.craftingbrowser"; public const string PluginName = "Crafting Browser"; public const string PluginVersion = "1.0.0"; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> OpenOnStation; internal static ConfigEntry<KeyCode> OpenKey; internal static ConfigEntry<bool> HotReloadCategories; private Harmony m_harmony; private static bool s_openQueued; private static bool s_openLogged; private float s_nextHotReloadCheck; private void Awake() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for the crafting browser."); OpenOnStation = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "OpenOnStationInteract", true, "Open the browser when you interact with a crafting station. The vanilla inventory panel still opens underneath; the browser is drawn over it, because the game itself is what actually performs the craft."); OpenKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "OpenKey", (KeyCode)290, "Hotkey that opens the browser from anywhere, whether or not you are at a station. Crafting still requires a valid station."); HotReloadCategories = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "HotReloadCategories", true, "Re-read categories.json when it changes on disk, without a restart."); CraftingCategories.Load(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location)); CraftingBridge.Init(); m_harmony = new Harmony("com.dfg.craftingbrowser"); try { m_harmony.PatchAll(); } catch (Exception ex) { Logger.LogError((object)("Crafting Browser: Harmony patching failed: " + ex)); } ((Component)this).gameObject.AddComponent<BrowserGUI>(); Logger.LogInfo((object)"Crafting Browser 1.0.0 loading."); } private void Update() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (!Enabled.Value) { if (BrowserGUI.IsOpen) { BrowserGUI.Instance.Close(); } return; } if (s_openQueued) { s_openQueued = false; if ((Object)(object)BrowserGUI.Instance != (Object)null && !BrowserGUI.IsOpen) { BrowserGUI.Instance.Open(); } } if ((int)OpenKey.Value != 0 && Input.GetKeyDown(OpenKey.Value)) { if (BrowserGUI.IsOpen) { BrowserGUI.Instance.Close(); } else { BrowserGUI.Instance.Open(); } } if (!HotReloadCategories.Value || !(Time.unscaledTime >= s_nextHotReloadCheck)) { return; } s_nextHotReloadCheck = Time.unscaledTime + 2f; if (CraftingCategories.PollForEdit()) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && RecipeIndex.Built) { RecipeIndex.Build(localPlayer); } Logger.LogInfo((object)"Crafting Browser: categories.json changed, recipe categories rebuilt."); } } private void OnDestroy() { Harmony harmony = m_harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public sealed class CategoryDef { public string id = ""; public string label = ""; public string[] match = Array.Empty<string>(); public string[] itemTypes = Array.Empty<string>(); public bool Matches(string internalName, ItemType itemType) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (match != null) { for (int i = 0; i < match.Length; i++) { string value = match[i]; if (!string.IsNullOrEmpty(value) && internalName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } if (itemTypes != null) { for (int j = 0; j < itemTypes.Length; j++) { if (Enum.TryParse<ItemType>(itemTypes[j], ignoreCase: true, out ItemType result) && result == itemType) { return true; } } } return false; } } public sealed class TopTabDef { public string id = ""; public string label = ""; public List<CategoryDef> categories = new List<CategoryDef>(); [JsonIgnore] public int OtherSubIndex => categories.Count; } public sealed class CategoryTable { public List<TopTabDef> tabs = new List<TopTabDef>(); public const string AllTabId = "all"; public int RealTabStart => 1; public int SubCount(int tabIndex) { if (tabIndex < 0 || tabIndex >= tabs.Count) { return 0; } return tabs[tabIndex].categories.Count + 1; } public string SubLabel(int tabIndex, int subIndex) { if (tabIndex == 0) { return "All"; } TopTabDef topTabDef = tabs[tabIndex]; if (subIndex < topTabDef.categories.Count) { return topTabDef.categories[subIndex].label; } return "Other"; } public void Resolve(string internalName, ItemType itemType, out int tabIndex, out int subIndex) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) for (int i = RealTabStart; i < tabs.Count; i++) { TopTabDef topTabDef = tabs[i]; for (int j = 0; j < topTabDef.categories.Count; j++) { if (topTabDef.categories[j].Matches(internalName, itemType)) { tabIndex = i; subIndex = j; return; } } } if (tabs.Count > RealTabStart) { tabIndex = RealTabStart; subIndex = tabs[RealTabStart].OtherSubIndex; } else { tabIndex = 0; subIndex = 0; } } } public static class CraftingCategories { private static string s_path; private static DateTime s_writtenUtc = DateTime.MinValue; private static int s_lastUnmatched; private static int s_lastTotal; public static CategoryTable Table { get; private set; } public static int LastUnmatched => s_lastUnmatched; public static int LastTotal => s_lastTotal; public static void Load(string pluginDirectory) { s_path = Path.Combine(pluginDirectory ?? ".", "categories.json"); if (!File.Exists(s_path)) { Table = BuildDefault(); Save(); Logger.LogInfo((object)("Crafting Browser: no categories.json found, wrote the default table to " + s_path)); return; } try { s_writtenUtc = File.GetLastWriteTimeUtc(s_path); Table = JsonConvert.DeserializeObject<CategoryTable>(File.ReadAllText(s_path)); } catch (Exception ex) { Logger.LogWarning((object)("Crafting Browser: categories.json is unreadable (" + ex.Message + "). Rewriting the default table.")); Table = BuildDefault(); Save(); return; } if (Table == null || Table.tabs == null || Table.tabs.Count == 0) { Logger.LogWarning((object)"Crafting Browser: categories.json has no tabs. Rewriting the default table."); Table = BuildDefault(); Save(); } else if (Table.tabs[0].id != "all") { Logger.LogWarning((object)"Crafting Browser: categories.json must keep tabs[0].id = \"all\". Inserting a synthetic All tab."); Table.tabs.Insert(0, new TopTabDef { id = "all", label = "All" }); } } public static void Save() { if (s_path == null || Table == null) { return; } try { File.WriteAllText(s_path, JsonConvert.SerializeObject((object)Table, (Formatting)1)); s_writtenUtc = File.GetLastWriteTimeUtc(s_path); } catch (Exception ex) { Logger.LogWarning((object)("Crafting Browser: could not write categories.json: " + ex.Message)); } } public static bool PollForEdit() { if (s_path == null || Table == null) { return false; } try { if (!File.Exists(s_path)) { return false; } DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(s_path); if (lastWriteTimeUtc <= s_writtenUtc) { return false; } s_writtenUtc = lastWriteTimeUtc; Table = JsonConvert.DeserializeObject<CategoryTable>(File.ReadAllText(s_path)); if (Table != null && Table.tabs != null && Table.tabs.Count > 0 && Table.tabs[0].id == "all") { return true; } Logger.LogWarning((object)"Crafting Browser: edited categories.json is missing tabs, keeping the previous table."); } catch (Exception ex) { Logger.LogWarning((object)("Crafting Browser: could not re-read categories.json: " + ex.Message)); } return false; } public static void ReportMatchRate(int total, int unmatched) { s_lastTotal = total; s_lastUnmatched = unmatched; if (total > 0) { Logger.LogInfo((object)($"Crafting Browser: {total - unmatched}/{total} recipes matched a category" + ((unmatched > 0) ? $"; {unmatched} filed under Other (edit categories.json to place them)" : "."))); } } public static CategoryTable BuildDefault() { CategoryTable categoryTable = new CategoryTable(); categoryTable.tabs.Add(new TopTabDef { id = "all", label = "All" }); categoryTable.tabs.Add(new TopTabDef { id = "weapons", label = "Weapons", categories = new List<CategoryDef> { ByName("polearms", "Polearms & Spears", "poleaxe", "spear", "atgeir", "pike", "halberd", "glaive"), ByName("hammers", "Hammers & Maces", "hammer", "mace", "maul", "club", "sledge"), ByName("swords", "Swords", "sword", "blade", "sabre", "rapier", "katana", "katana_"), ByName("axes", "Axes", "axe", "hatchet"), ByName("bows", "Bows & Crossbows", "bow", "crossbow", "ballista"), ByName("shields", "Shields", "shield", "buckler"), ByName("ammo", "Ammunition", "arrow", "bolt", "ammo") } }); categoryTable.tabs.Add(new TopTabDef { id = "tools", label = "Tools", categories = new List<CategoryDef> { ByName("pickaxes", "Pickaxes", "pickaxe"), ByName("hammers", "Hammers", "hammer"), ByName("axes", "Axes", "axe"), ByName("shovels", "Shovels", "shovel"), ByName("rods", "Fishing Rods", "fishingrod", "rod") } }); categoryTable.tabs.Add(new TopTabDef { id = "armor", label = "Armor", categories = new List<CategoryDef> { ByName("helmets", "Helmets", "helmet", "hood"), ByName("body", "Body", "armor", "hauberk", "plate", "tunic", "jacket", "robe", "harness", "mail"), ByName("legs", "Legs", "pants", "trousers", "skirt", "greaves", "boots", "leggings"), ByName("hands", "Hands", "gloves", "gauntlet", "mittens", "bracer"), ByName("cloaks", "Cloaks & Capes", "cape", "cloak", "mantle", "shawl") } }); categoryTable.tabs.Add(new TopTabDef { id = "food", label = "Food & Drink", categories = new List<CategoryDef> { ByName("mead", "Meads", "mead"), ByName("drinks", "Drinks & Potions", "drink", "potion", "juice", "tea", "coffee", "ale", "wine", "sake"), ByName("fish", "Fish & Seafood", "fish", "seafood", "crab", "lobster", "shrimp", "squid", "eel"), ByName("cooked", "Cooked Food", "sausage", "stew", "soup", "pie", "cake", "bread", "pancake", "skewer"), ByItemType("food", "Raw & Basic Food", "Consumable") } }); categoryTable.tabs.Add(new TopTabDef { id = "materials", label = "Materials", categories = new List<CategoryDef> { ByItemType("trophy", "Trophies", "Trophy"), ByName("relic", "Relics & Tinkering", "relic", "tinkering", "crystal", "rune"), ByItemType("trinket", "Trinkets", "Trinket"), ByItemType("crafting", "Crafting Materials", "Material"), ByItemType("misc", "Miscellaneous", "Misc") } }); categoryTable.tabs.Add(new TopTabDef { id = "furniture", label = "Furniture", categories = new List<CategoryDef> { ByName("seating", "Seating", "chair", "stool", "bench", "throne", "bed"), ByName("tables", "Tables", "table", "shelf", "rack"), ByName("storage", "Storage", "chest", "backpack", "bag", "pouch", "bundle"), ByName("lighting", "Lighting", "candle", "torch", "lantern", "lamp", "brazier", "sconce"), ByName("decoration", "Decoration", "banner", "rug", "painting", "ornament", "sign", "carving", "loom", "weaver") } }); return categoryTable; } private static CategoryDef ByName(string id, string label, params string[] keywords) { return new CategoryDef { id = id, label = label, match = (keywords ?? Array.Empty<string>()) }; } private static CategoryDef ByItemType(string id, string label, params string[] itemTypes) { return new CategoryDef { id = id, label = label, itemTypes = (itemTypes ?? Array.Empty<string>()) }; } } public enum VisibilityMode { Unlocked, CraftableHere, All } public sealed class RecipeEntry { public Recipe Recipe; public string InternalName = ""; public string DisplayName = ""; public Sprite Icon; public int Amount = 1; public int TopTab; public int SubCategory; public string StationName = ""; public bool Unlocked; public bool StationOk; public bool CanCraftNow; public bool NameIsFallback; public int MaxCraftable; public bool MatchesSearch(string needle) { if (string.IsNullOrEmpty(needle)) { return true; } if (InternalName.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return DisplayName.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0; } } public static class RecipeIndex { public static readonly List<RecipeEntry> All = new List<RecipeEntry>(); private const float RefreshInterval = 0.35f; private static float s_nextRefresh; private static int s_lastRecipeCount = -1; private static bool s_namesDirty = true; private static bool s_watchingLanguage; private static int s_untranslated; public static bool Built { get; private set; } public static int UntranslatedCount => s_untranslated; public static void Build(Player player) { //IL_019a: Unknown result type (might be due to invalid IL or missing references) All.Clear(); Built = false; if ((Object)(object)player == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return; } List<Recipe> recipes = ObjectDB.instance.m_recipes; if (recipes == null) { return; } s_lastRecipeCount = recipes.Count; SeasonalItemGroup currentSeason = player.CurrentSeason; for (int i = 0; i < recipes.Count; i++) { Recipe val = recipes[i]; if ((Object)(object)val == (Object)null || (Object)(object)val.m_item == (Object)null) { continue; } bool flag = (Object)(object)currentSeason != (Object)null && currentSeason.Recipes != null && currentSeason.Recipes.Contains(val); if (val.m_enabled || flag) { SharedData val2 = ((val.m_item.m_itemData != null) ? val.m_item.m_itemData.m_shared : null); if (val2 != null && (string.IsNullOrEmpty(val2.m_dlc) || !((Object)(object)DLCMan.instance != (Object)null) || DLCMan.instance.IsDLCInstalled(val2.m_dlc))) { RecipeEntry recipeEntry = new RecipeEntry { Recipe = val, InternalName = val2.m_name, DisplayName = Localize(val2.m_name), Amount = Mathf.Max(1, val.m_amount), Icon = val.m_item.m_itemData.GetIcon() }; CraftingStation requiredStation = val.GetRequiredStation(1); recipeEntry.StationName = (((Object)(object)requiredStation == (Object)null) ? "Basic" : Localize(requiredStation.m_name)); CraftingCategories.Table.Resolve(recipeEntry.InternalName, val2.m_itemType, out recipeEntry.TopTab, out recipeEntry.SubCategory); All.Add(recipeEntry); } } } All.Sort((RecipeEntry a, RecipeEntry b) => string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase)); int num = 0; for (int num2 = 0; num2 < All.Count; num2++) { if (All[num2].SubCategory == CraftingCategories.Table.tabs[All[num2].TopTab].OtherSubIndex) { num++; } } CraftingCategories.ReportMatchRate(All.Count, num); WatchLanguage(); ResolveNames(); Refresh(player, force: true); Built = true; } private static void ResolveNames() { if (All.Count == 0) { return; } int num = 0; for (int i = 0; i < All.Count; i++) { RecipeEntry recipeEntry = All[i]; if ((Object)(object)recipeEntry.Recipe == (Object)null || (Object)(object)recipeEntry.Recipe.m_item == (Object)null || recipeEntry.Recipe.m_item.m_itemData == null) { continue; } SharedData shared = recipeEntry.Recipe.m_item.m_itemData.m_shared; if (shared != null) { bool flag = shared.m_name != null && shared.m_name.Length > 0 && shared.m_name[0] == '$'; recipeEntry.DisplayName = Localize(shared.m_name); recipeEntry.NameIsFallback = flag && string.Equals(recipeEntry.DisplayName, Prettify(shared.m_name), StringComparison.Ordinal); if (recipeEntry.NameIsFallback) { num++; } CraftingStation requiredStation = recipeEntry.Recipe.GetRequiredStation(1); recipeEntry.StationName = (((Object)(object)requiredStation == (Object)null) ? "Basic" : Localize(requiredStation.m_name)); } } All.Sort((RecipeEntry a, RecipeEntry b) => string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase)); s_untranslated = num; if (num > 0) { string text = ((All[0] != null) ? All[0].InternalName : "?"); Logger.LogWarning((object)($"Crafting Browser: {num}/{All.Count} names could not be localized and are " + "shown prettified from the key instead (e.g. '" + text + "'). Set language in the main menu and the names will re-resolve.")); } else { Logger.LogInfo((object)"Crafting Browser: all recipe names localized."); } } private static void WatchLanguage() { if (s_watchingLanguage) { return; } try { Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, new Action(OnLanguageChanged)); s_watchingLanguage = true; } catch (Exception ex) { Logger.LogWarning((object)("Crafting Browser: could not watch for language changes: " + ex.Message)); } } private static void OnLanguageChanged() { s_namesDirty = true; } public static string CurrentStationName(Player player) { if ((Object)(object)player == (Object)null) { return ""; } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); if (!((Object)(object)currentCraftingStation == (Object)null)) { return Localize(currentCraftingStation.m_name); } return "No station"; } public static void Refresh(Player player, bool force = false) { if (Built && !((Object)(object)player == (Object)null) && (force || !(Time.unscaledTime < s_nextRefresh))) { s_nextRefresh = Time.unscaledTime + 0.35f; if (s_namesDirty) { s_namesDirty = false; ResolveNames(); } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); bool atUpgrader = (Object)(object)currentCraftingStation != (Object)null && currentCraftingStation.m_upgrader; Inventory inventory = ((Humanoid)player).GetInventory(); for (int i = 0; i < All.Count; i++) { RecipeEntry recipeEntry = All[i]; Recipe recipe = recipeEntry.Recipe; recipeEntry.Unlocked = player.IsRecipeKnown(recipeEntry.InternalName); recipeEntry.StationOk = player.RequiredCraftingStation(recipe, 1, true); recipeEntry.CanCraftNow = player.HaveRequirements(recipe, false, 1, 1); recipeEntry.MaxCraftable = ((inventory != null) ? MaxCraftable(player, recipe, inventory, currentCraftingStation, atUpgrader) : 0); } } } private static int MaxCraftable(Player player, Recipe recipe, Inventory inventory, CraftingStation station, bool atUpgrader) { Requirement[] resources = recipe.m_resources; if (resources == null || resources.Length == 0) { return 0; } int num = int.MaxValue; foreach (Requirement val in resources) { if (val == null || (Object)(object)val.m_resItem == (Object)null || val.m_resItem.m_itemData == null || (val.m_upgraderResource && ((Object)(object)station == (Object)null || !atUpgrader))) { continue; } int num2 = Mathf.Max(1, val.GetAmount(1)); int num3 = inventory.CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true) / num2; if (recipe.m_requireOnlyOneIngredient) { if (num3 > num) { num = num3; } } else if (num3 < num) { num = num3; } } if (num == int.MaxValue) { return 0; } return Mathf.Max(0, num); } public static void Filter(List<RecipeEntry> destination, string search, int tabIndex, int subIndex, VisibilityMode mode) { destination.Clear(); if (CraftingCategories.Table == null) { return; } for (int i = 0; i < All.Count; i++) { RecipeEntry recipeEntry = All[i]; if ((mode != VisibilityMode.Unlocked || recipeEntry.Unlocked) && (mode != VisibilityMode.CraftableHere || (recipeEntry.Unlocked && recipeEntry.CanCraftNow)) && (tabIndex <= 0 || recipeEntry.TopTab == tabIndex) && (tabIndex <= 0 || recipeEntry.SubCategory == subIndex) && recipeEntry.MatchesSearch(search)) { destination.Add(recipeEntry); } } } public static void CountBySubcategory(int tabIndex, VisibilityMode mode, Dictionary<int, int> counts) { counts.Clear(); if (tabIndex <= 0) { return; } int num = CraftingCategories.Table.SubCount(tabIndex); for (int i = 0; i < num; i++) { counts[i] = 0; } for (int j = 0; j < All.Count; j++) { RecipeEntry recipeEntry = All[j]; if (recipeEntry.TopTab == tabIndex && (mode != VisibilityMode.Unlocked || recipeEntry.Unlocked) && (mode != VisibilityMode.CraftableHere || (recipeEntry.Unlocked && recipeEntry.CanCraftNow)) && counts.ContainsKey(recipeEntry.SubCategory)) { counts[recipeEntry.SubCategory]++; } } } public static string Localize(string key) { if (string.IsNullOrEmpty(key)) { return ""; } if (key[0] != '$') { return key; } string text = null; try { Localization instance = Localization.instance; if (instance != null) { text = instance.Localize(key); } } catch (Exception) { } if (!string.IsNullOrEmpty(text) && text[0] != '$') { return text; } return Prettify(key); } public static string Prettify(string key) { if (string.IsNullOrEmpty(key)) { return ""; } string text = (key.StartsWith("$") ? key.Substring(1) : key); List<string> list = new List<string>(text.Split('_')); if (list.Count > 1 && IsKeyNamespace(list[0])) { list.RemoveAt(0); } List<string> list2 = new List<string>(); foreach (string item in list) { if (!string.IsNullOrEmpty(item)) { list2.AddRange(SplitCamelCase(item)); } } if (list2.Count == 0) { return text; } StringBuilder stringBuilder = new StringBuilder(); foreach (string item2 in list2) { if (stringBuilder.Length > 0) { stringBuilder.Append(' '); } stringBuilder.Append(char.ToUpperInvariant(item2[0])); if (item2.Length > 1) { stringBuilder.Append(item2.Substring(1)); } } return stringBuilder.ToString(); } private static bool IsKeyNamespace(string segment) { switch (segment.ToLowerInvariant()) { case "item": case "misc": case "craft": case "enemy": case "piece": case "builder": case "gamenet": case "msg": case "crafting": case "recipe": return true; default: return false; } } private static IEnumerable<string> SplitCamelCase(string part) { List<string> list = new List<string>(); StringBuilder stringBuilder = new StringBuilder(); foreach (char c in part) { if (char.IsUpper(c) && stringBuilder.Length > 0) { list.Add(stringBuilder.ToString()); stringBuilder.Length = 0; } stringBuilder.Append(c); } if (stringBuilder.Length > 0) { list.Add(stringBuilder.ToString()); } return list; } } }