using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using PinThoseRecipes.Patches; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("PinThoseRecipes")] [assembly: AssemblyDescription("Middle-click recipes in a crafting station to pin them to a Subnautica-style panel under the minimap.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("PinThoseRecipes")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("7b2c4e1a-9d3f-4b6e-8a21-1c5d9f0e7a34")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [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 PinThoseRecipes { [BepInPlugin("shadymods.pinthoserecipes", "Pin Those Recipes", "1.0.0")] public sealed class PinThoseRecipesPlugin : BaseUnityPlugin { internal const string Guid = "shadymods.pinthoserecipes"; internal const string Name = "Pin Those Recipes"; internal const string Version = "1.0.0"; private static GameObject _controllerGo; private Harmony _harmony; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; PinConfig.Init(((BaseUnityPlugin)this).Config); _harmony = new Harmony("shadymods.pinthoserecipes"); try { _harmony.PatchAll(typeof(PinThoseRecipesPlugin).Assembly); } catch (Exception ex) { Log.LogError((object)("Harmony patching failed (some features may be disabled): " + ex)); } _controllerGo = new GameObject("PinThoseRecipes_Controller"); Object.DontDestroyOnLoad((Object)(object)_controllerGo); ((Object)_controllerGo).hideFlags = (HideFlags)61; _controllerGo.AddComponent(); Log.LogInfo((object)"Pin Those Recipes 1.0.0 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)_controllerGo != (Object)null) { Object.Destroy((Object)(object)_controllerGo); _controllerGo = null; } } } internal static class PinConfig { private static bool _resettingClearToggle; private static Color _satisfied = new Color(0.3f, 0.88f, 0.3f, 1f); private static Color _missing = new Color(1f, 0.42f, 0.42f, 1f); private static Color _name = Color.white; internal static ConfigEntry Enabled { get; private set; } internal static ConfigEntry PlayPinSound { get; private set; } internal static ConfigEntry MaxPinnedRecipes { get; private set; } internal static ConfigEntry PanelScale { get; private set; } internal static ConfigEntry OffsetX { get; private set; } internal static ConfigEntry ExtraOffsetBelowMinimap { get; private set; } internal static ConfigEntry InventoryOpenShiftLeft { get; private set; } internal static ConfigEntry InventoryOpenShiftDown { get; private set; } internal static ConfigEntry SatisfiedColorHex { get; private set; } internal static ConfigEntry MissingColorHex { get; private set; } internal static ConfigEntry NameColorHex { get; private set; } internal static ConfigEntry ClearActiveCharacterPins { get; private set; } internal static Color SatisfiedColor => _satisfied; internal static Color MissingColor => _missing; internal static Color NameColor => _name; internal static event Action Changed; internal static void Init(ConfigFile config) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown Enabled = config.Bind("General", "Enabled", true, "Master toggle for Pin Those Recipes. When false, no pinning UI is shown or created."); PlayPinSound = config.Bind("General", "PlayPinSound", true, "Play a soft UI sound when you pin or unpin a recipe."); MaxPinnedRecipes = config.Bind("Panel", "MaxPinnedRecipes", 8, new ConfigDescription("How many pinned recipes are shown in the side panel at once. Extra pins are kept and shown as a '+X more' row.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 30), Array.Empty())); PanelScale = config.Bind("Panel", "PanelScale", 1f, new ConfigDescription("Overall scale of the pinned-recipes panel content.", (AcceptableValueBase)(object)new AcceptableValueRange(0.5f, 2f), Array.Empty())); OffsetX = config.Bind("Panel", "OffsetX", -14f, "Horizontal offset of the panel from the top-right corner (negative moves left, in UI units)."); ExtraOffsetBelowMinimap = config.Bind("Panel", "ExtraOffsetBelowMinimap", -14f, "Additional vertical offset applied below the minimap (negative moves further down, in UI units)."); InventoryOpenShiftLeft = config.Bind("Panel", "InventoryOpenShiftLeft", 640f, "How far LEFT the panel moves while the inventory/crafting screen is open, so it clears the crafting panel on the right (otherwise the pins are hidden behind it). Higher number = further left. Set to 0 to keep it on the right. (Negative moves right.)"); InventoryOpenShiftDown = config.Bind("Panel", "InventoryOpenShiftDown", 170f, "How far DOWN the panel moves while the inventory/crafting screen is open. Higher number = further down. Default drops it below the repair button; increase it to clear other mods' inventory UI (e.g. Extra Slots by shudnal). (Negative moves up.)"); SatisfiedColorHex = config.Bind("Colors", "SatisfiedColor", "#4CE04C", "Color of a material count when you have enough."); MissingColorHex = config.Bind("Colors", "MissingColor", "#FF6B6B", "Color of a material count when you are missing some."); NameColorHex = config.Bind("Colors", "NameColor", "#FFFFFF", "Color of the pinned item name text."); ClearActiveCharacterPins = config.Bind("Maintenance", "ClearActiveCharacterPins", false, "Set to true to clear ALL pins for the currently loaded character. Resets itself to false afterwards. Useful for removing stale/unresolved pins."); ClearActiveCharacterPins.SettingChanged += OnClearPinsToggled; ReparseColors(); config.SettingChanged += OnAnySettingChanged; } private static void OnAnySettingChanged(object sender, SettingChangedEventArgs e) { ReparseColors(); PinConfig.Changed?.Invoke(); } private static void OnClearPinsToggled(object sender, EventArgs e) { if (_resettingClearToggle || ClearActiveCharacterPins == null || !ClearActiveCharacterPins.Value) { return; } PinStore.ClearActivePins(); _resettingClearToggle = true; try { ClearActiveCharacterPins.Value = false; } finally { _resettingClearToggle = false; } } private static void ReparseColors() { //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_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) _satisfied = ParseOr(SatisfiedColorHex?.Value, _satisfied); _missing = ParseOr(MissingColorHex?.Value, _missing); _name = ParseOr(NameColorHex?.Value, _name); } private static Color ParseOr(string hex, Color fallback) { //IL_0014: 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) Color result = default(Color); if (!string.IsNullOrEmpty(hex) && ColorUtility.TryParseHtmlString(hex, ref result)) { return result; } return fallback; } } internal sealed class PinStoreFile { public int Version = 1; public List Characters = new List(); } internal sealed class CharacterPinData { public string Profile; public List Pins = new List(); public List BuildPins = new List(); public List Collapsed = new List(); } internal static class PinStore { private static readonly List _activePins = new List(); private static readonly List _activeBuildPins = new List(); private static readonly HashSet _collapsed = new HashSet(); private static string _activeProfileKey; private static bool _loggedMalformed; private static string FilePath => Path.Combine(Paths.ConfigPath, "PinThoseRecipes_pins.json"); internal static bool HasActiveProfile => !string.IsNullOrEmpty(_activeProfileKey); internal static int TotalPinCount => _activePins.Count + _activeBuildPins.Count; internal static event Action PinsChanged; internal static IReadOnlyList GetPins() { return _activePins; } internal static IReadOnlyList GetBuildPins() { return _activeBuildPins; } internal static string CraftCollapseKey(string pinKey) { return pinKey; } internal static string BuildCollapseKey(string prefabName) { return "b:" + prefabName; } internal static string CraftPinKey(string prefabName) { return prefabName; } internal static string UpgradePinKey(string prefabName, int targetQuality) { return "u:" + prefabName + ":" + targetQuality; } internal static bool TryParseCraftPinKey(string pinKey, out string prefabName, out int upgradeQuality) { prefabName = null; upgradeQuality = 0; if (string.IsNullOrEmpty(pinKey)) { return false; } if (pinKey.Length > 2 && pinKey[0] == 'u' && pinKey[1] == ':') { int num = pinKey.LastIndexOf(':'); if (num <= 2 || num >= pinKey.Length - 1) { return false; } if (!int.TryParse(pinKey.Substring(num + 1), out var result) || result < 2) { return false; } prefabName = pinKey.Substring(2, num - 2); if (string.IsNullOrEmpty(prefabName)) { return false; } upgradeQuality = result; return true; } prefabName = pinKey; upgradeQuality = 0; return true; } internal static bool IsPinned(string pinKey) { if (!string.IsNullOrEmpty(pinKey)) { return _activePins.Contains(pinKey); } return false; } internal static bool IsBuildPinned(string prefabName) { if (!string.IsNullOrEmpty(prefabName)) { return _activeBuildPins.Contains(prefabName); } return false; } internal static bool IsCollapsed(string collapseKey) { if (!string.IsNullOrEmpty(collapseKey)) { return _collapsed.Contains(collapseKey); } return false; } internal static bool ToggleCollapsed(string collapseKey, bool isBuild, string prefabName) { if (string.IsNullOrEmpty(collapseKey) || !HasActiveProfile) { return true; } if (isBuild ? (!IsBuildPinned(prefabName)) : (!IsPinned(prefabName))) { return true; } bool result; if (_collapsed.Contains(collapseKey)) { _collapsed.Remove(collapseKey); result = true; } else { _collapsed.Add(collapseKey); result = false; } Save(); return result; } internal static int GetPinIndex(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return int.MaxValue; } int num = _activePins.IndexOf(prefabName); if (num >= 0) { return num; } return int.MaxValue; } internal static bool Toggle(string pinKey) { if (string.IsNullOrEmpty(pinKey) || !HasActiveProfile) { return false; } bool result; if (_activePins.Contains(pinKey)) { _activePins.Remove(pinKey); _collapsed.Remove(CraftCollapseKey(pinKey)); result = false; } else { _activePins.Add(pinKey); result = true; } Save(); PinStore.PinsChanged?.Invoke(); return result; } internal static bool ToggleBuild(string prefabName) { if (string.IsNullOrEmpty(prefabName) || !HasActiveProfile) { return false; } bool result; if (_activeBuildPins.Contains(prefabName)) { _activeBuildPins.Remove(prefabName); _collapsed.Remove(BuildCollapseKey(prefabName)); result = false; } else { _activeBuildPins.Add(prefabName); result = true; } Save(); PinStore.PinsChanged?.Invoke(); return result; } internal static void ClearActive() { bool num = _activePins.Count > 0 || _activeBuildPins.Count > 0; _activePins.Clear(); _activeBuildPins.Clear(); _collapsed.Clear(); _activeProfileKey = null; if (num) { PinStore.PinsChanged?.Invoke(); } } internal static void ClearActivePins() { if (HasActiveProfile && (_activePins.Count != 0 || _activeBuildPins.Count != 0)) { _activePins.Clear(); _activeBuildPins.Clear(); _collapsed.Clear(); Save(); PinStore.PinsChanged?.Invoke(); } } internal static void LoadForProfile(string profileKey) { profileKey = Normalize(profileKey); if (string.IsNullOrEmpty(profileKey)) { ClearActive(); } else { if (profileKey == _activeProfileKey) { return; } _activeProfileKey = profileKey; _activePins.Clear(); _activeBuildPins.Clear(); _collapsed.Clear(); CharacterPinData characterPinData = ReadFile().Characters.Find((CharacterPinData c) => c != null && Normalize(c.Profile) == profileKey); if (characterPinData?.Pins != null) { foreach (string pin in characterPinData.Pins) { if (!string.IsNullOrEmpty(pin) && !_activePins.Contains(pin)) { _activePins.Add(pin); } } } if (characterPinData?.BuildPins != null) { foreach (string buildPin in characterPinData.BuildPins) { if (!string.IsNullOrEmpty(buildPin) && !_activeBuildPins.Contains(buildPin)) { _activeBuildPins.Add(buildPin); } } } if (characterPinData?.Collapsed != null) { foreach (string item2 in characterPinData.Collapsed) { if (string.IsNullOrEmpty(item2)) { continue; } if (item2.StartsWith("b:", StringComparison.Ordinal)) { string item = item2.Substring(2); if (_activeBuildPins.Contains(item)) { _collapsed.Add(item2); } } else if (_activePins.Contains(item2)) { _collapsed.Add(item2); } } } ManualLogSource log = PinThoseRecipesPlugin.Log; if (log != null) { log.LogInfo((object)$"Loaded {_activePins.Count} craft pin(s) and {_activeBuildPins.Count} build pin(s) for profile '{profileKey}'."); } PinStore.PinsChanged?.Invoke(); } } private static void Save() { if (!HasActiveProfile) { return; } try { PinStoreFile pinStoreFile = ReadFile(); CharacterPinData characterPinData = pinStoreFile.Characters.Find((CharacterPinData c) => c != null && Normalize(c.Profile) == _activeProfileKey); if (characterPinData == null) { characterPinData = new CharacterPinData { Profile = _activeProfileKey }; pinStoreFile.Characters.Add(characterPinData); } characterPinData.Pins = new List(_activePins); characterPinData.BuildPins = new List(_activeBuildPins); characterPinData.Collapsed = new List(_collapsed); string contents = ToJson(pinStoreFile); string directoryName = Path.GetDirectoryName(FilePath); if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } string text = FilePath + ".tmp"; File.WriteAllText(text, contents); if (File.Exists(FilePath)) { File.Delete(FilePath); } File.Move(text, FilePath); } catch (Exception ex) { ManualLogSource log = PinThoseRecipesPlugin.Log; if (log != null) { log.LogError((object)("Failed to save pins: " + ex)); } } } private static PinStoreFile ReadFile() { try { if (!File.Exists(FilePath)) { return new PinStoreFile(); } string text = File.ReadAllText(FilePath); if (string.IsNullOrWhiteSpace(text)) { return new PinStoreFile(); } PinStoreFile pinStoreFile = FromJson(text); if (pinStoreFile == null) { throw new InvalidDataException("Deserialized to null."); } if (pinStoreFile.Characters == null) { pinStoreFile.Characters = new List(); } return pinStoreFile; } catch (Exception ex) { if (!_loggedMalformed) { _loggedMalformed = true; ManualLogSource log = PinThoseRecipesPlugin.Log; if (log != null) { log.LogWarning((object)("Pin data unreadable, starting fresh (a .bak backup was made): " + ex.Message)); } } TryBackupCorrupt(); return new PinStoreFile(); } } private static string ToJson(PinStoreFile file) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("{"); stringBuilder.Append(" \"Version\": ").Append(file.Version).AppendLine(","); stringBuilder.AppendLine(" \"Characters\": ["); for (int i = 0; i < file.Characters.Count; i++) { CharacterPinData characterPinData = file.Characters[i]; if (characterPinData == null) { continue; } stringBuilder.AppendLine(" {"); stringBuilder.Append(" \"Profile\": ").Append(Quote(characterPinData.Profile)).AppendLine(","); stringBuilder.Append(" \"Pins\": ["); List list = characterPinData.Pins ?? new List(); for (int j = 0; j < list.Count; j++) { if (j > 0) { stringBuilder.Append(", "); } stringBuilder.Append(Quote(list[j])); } stringBuilder.AppendLine("],"); stringBuilder.Append(" \"BuildPins\": ["); List list2 = characterPinData.BuildPins ?? new List(); for (int k = 0; k < list2.Count; k++) { if (k > 0) { stringBuilder.Append(", "); } stringBuilder.Append(Quote(list2[k])); } stringBuilder.AppendLine("],"); stringBuilder.Append(" \"Collapsed\": ["); List list3 = characterPinData.Collapsed ?? new List(); for (int l = 0; l < list3.Count; l++) { if (l > 0) { stringBuilder.Append(", "); } stringBuilder.Append(Quote(list3[l])); } stringBuilder.AppendLine("]"); stringBuilder.Append(" }"); if (i < file.Characters.Count - 1) { stringBuilder.Append(","); } stringBuilder.AppendLine(); } stringBuilder.AppendLine(" ]"); stringBuilder.Append("}"); return stringBuilder.ToString(); } private static PinStoreFile FromJson(string json) { PinStoreFile pinStoreFile = new PinStoreFile(); Match match = Regex.Match(json, "\"Version\"\\s*:\\s*(\\d+)"); if (match.Success) { int.TryParse(match.Groups[1].Value, out pinStoreFile.Version); } Match match2 = Regex.Match(json, "\"Characters\"\\s*:\\s*\\[(.*)\\]", RegexOptions.Singleline); if (!match2.Success) { return pinStoreFile; } foreach (Match item in Regex.Matches(match2.Groups[1].Value, "\\{[^{}]*\\}")) { string value = item.Value; Match match3 = Regex.Match(value, "\"Profile\"\\s*:\\s*\"((?:\\\\.|[^\"\\\\])*)\""); if (!match3.Success) { continue; } CharacterPinData characterPinData = new CharacterPinData { Profile = Unescape(match3.Groups[1].Value), Pins = new List(), BuildPins = new List(), Collapsed = new List() }; Match match4 = Regex.Match(value, "\"Pins\"\\s*:\\s*\\[(.*?)\\]", RegexOptions.Singleline); if (match4.Success) { foreach (Match item2 in Regex.Matches(match4.Groups[1].Value, "\"((?:\\\\.|[^\"\\\\])*)\"")) { string text = Unescape(item2.Groups[1].Value); if (!string.IsNullOrEmpty(text) && !characterPinData.Pins.Contains(text)) { characterPinData.Pins.Add(text); } } } Match match5 = Regex.Match(value, "\"BuildPins\"\\s*:\\s*\\[(.*?)\\]", RegexOptions.Singleline); if (match5.Success) { foreach (Match item3 in Regex.Matches(match5.Groups[1].Value, "\"((?:\\\\.|[^\"\\\\])*)\"")) { string text2 = Unescape(item3.Groups[1].Value); if (!string.IsNullOrEmpty(text2) && !characterPinData.BuildPins.Contains(text2)) { characterPinData.BuildPins.Add(text2); } } } Match match6 = Regex.Match(value, "\"Collapsed\"\\s*:\\s*\\[(.*?)\\]", RegexOptions.Singleline); if (match6.Success) { foreach (Match item4 in Regex.Matches(match6.Groups[1].Value, "\"((?:\\\\.|[^\"\\\\])*)\"")) { string text3 = Unescape(item4.Groups[1].Value); if (!string.IsNullOrEmpty(text3) && !characterPinData.Collapsed.Contains(text3)) { characterPinData.Collapsed.Add(text3); } } } pinStoreFile.Characters.Add(characterPinData); } return pinStoreFile; } private static string Quote(string s) { if (s == null) { return "\"\""; } return "\"" + s.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n") .Replace("\r", "\\r") + "\""; } private static string Unescape(string s) { return s.Replace("\\\"", "\"").Replace("\\\\", "\\").Replace("\\n", "\n") .Replace("\\r", "\r"); } private static void TryBackupCorrupt() { try { if (File.Exists(FilePath)) { string text = FilePath + ".bak"; if (File.Exists(text)) { File.Delete(text); } File.Copy(FilePath, text); } } catch { } } private static string Normalize(string key) { if (!string.IsNullOrWhiteSpace(key)) { return key.Trim(); } return null; } } internal sealed class ResolvedRequirement { public Sprite Icon; public string SharedName; public string DisplayName; public int Need; } internal sealed class ResolvedRecipe { public string PrefabName; public string ItemPrefabName; public Sprite Icon; public string DisplayName; public int OutputAmount; public bool IsBuild; public bool IsUpgrade; public int UpgradeQuality; public readonly List Requirements = new List(); } internal static class RecipeResolver { private static readonly Dictionary> _byPrefab = new Dictionary>(); private static readonly HashSet _loggedUnresolved = new HashSet(); private static ObjectDB _cachedInstance; internal static void InvalidateCache() { _byPrefab.Clear(); _loggedUnresolved.Clear(); _cachedInstance = null; } private static bool EnsureCache() { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return false; } if (instance != _cachedInstance || _byPrefab.Count == 0) { Rebuild(instance); } return true; } private static void Rebuild(ObjectDB db) { _byPrefab.Clear(); _loggedUnresolved.Clear(); _cachedInstance = db; if (db.m_recipes == null) { return; } foreach (Recipe recipe in db.m_recipes) { if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null) { continue; } string name = ((Object)((Component)recipe.m_item).gameObject).name; if (!string.IsNullOrEmpty(name)) { if (!_byPrefab.TryGetValue(name, out var value)) { value = new List(); _byPrefab[name] = value; } value.Add(recipe); } } } internal static List GetRecipes(string prefabName) { if (string.IsNullOrEmpty(prefabName) || !EnsureCache()) { return null; } if (!_byPrefab.TryGetValue(prefabName, out var value)) { return null; } return value; } internal static Recipe GetPreferredRecipe(string prefabName) { List recipes = GetRecipes(prefabName); if (recipes == null || recipes.Count == 0) { return null; } if (recipes.Count == 1) { return recipes[0]; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { List list = new List(); localPlayer.GetAvailableRecipes(ref list); foreach (Recipe item in recipes) { if (list.Contains(item)) { return item; } } foreach (Recipe item2 in recipes) { if ((Object)(object)item2.m_item != (Object)null && localPlayer.IsRecipeKnown(item2.m_item.m_itemData.m_shared.m_name)) { return item2; } } } List list2 = new List(recipes); list2.Sort(delegate(Recipe a, Recipe b) { int num = string.CompareOrdinal(((Object)a).name, ((Object)b).name); if (num != 0) { return num; } string strA = (((Object)(object)a.m_craftingStation != (Object)null) ? ((Object)a.m_craftingStation).name : ""); string strB = (((Object)(object)b.m_craftingStation != (Object)null) ? ((Object)b.m_craftingStation).name : ""); return string.CompareOrdinal(strA, strB); }); return list2[0]; } internal static ResolvedRecipe Resolve(string pinKey) { if (!PinStore.TryParseCraftPinKey(pinKey, out var prefabName, out var upgradeQuality)) { LogUnresolvedOnce(pinKey); return null; } Recipe preferredRecipe = GetPreferredRecipe(prefabName); if ((Object)(object)preferredRecipe == (Object)null || (Object)(object)preferredRecipe.m_item == (Object)null) { LogUnresolvedOnce(pinKey); return null; } bool flag = upgradeQuality >= 2; int num = ((!flag) ? 1 : upgradeQuality); string text = Localize(preferredRecipe.m_item.m_itemData.m_shared.m_name); if (flag) { text = text + " ★" + upgradeQuality; } ResolvedRecipe resolvedRecipe = new ResolvedRecipe { PrefabName = pinKey, ItemPrefabName = prefabName, Icon = preferredRecipe.m_item.m_itemData.GetIcon(), DisplayName = text, OutputAmount = (flag ? 1 : Mathf.Max(1, preferredRecipe.m_amount)), IsUpgrade = flag, UpgradeQuality = (flag ? upgradeQuality : 0) }; if (preferredRecipe.m_resources != null) { Requirement[] resources = preferredRecipe.m_resources; foreach (Requirement val in resources) { if (val != null && !((Object)(object)val.m_resItem == (Object)null)) { int amount = val.GetAmount(num); if (amount > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; resolvedRecipe.Requirements.Add(new ResolvedRequirement { Icon = val.m_resItem.m_itemData.GetIcon(), SharedName = name, DisplayName = Localize(name), Need = amount }); } } } } return resolvedRecipe; } private static void LogUnresolvedOnce(string prefabName) { if (!string.IsNullOrEmpty(prefabName) && !_loggedUnresolved.Contains(prefabName)) { _loggedUnresolved.Add(prefabName); ManualLogSource log = PinThoseRecipesPlugin.Log; if (log != null) { log.LogInfo((object)("Pinned recipe '" + prefabName + "' is not resolvable yet (missing prefab/recipe or ObjectDB not ready); kept and hidden.")); } } } private static string Localize(string token) { if (string.IsNullOrEmpty(token)) { return ""; } if (Localization.instance == null) { return token; } return Localization.instance.Localize(token); } } internal static class PieceResolver { private static readonly Dictionary _byPrefab = new Dictionary(); private static readonly HashSet _loggedUnresolved = new HashSet(); private static ZNetScene _cachedScene; internal static void InvalidateCache() { _byPrefab.Clear(); _loggedUnresolved.Clear(); _cachedScene = null; } private static void EnsureCache() { ZNetScene instance = ZNetScene.instance; if (!((Object)(object)instance == (Object)null) && (instance != _cachedScene || _byPrefab.Count == 0)) { Rebuild(instance); } } private static void Rebuild(ZNetScene scene) { _byPrefab.Clear(); _loggedUnresolved.Clear(); _cachedScene = scene; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { PieceTable val = TraverseBuildPieces(localPlayer); if ((Object)(object)val != (Object)null && val.m_pieces != null) { foreach (GameObject piece in val.m_pieces) { IndexPiece(piece); } } } foreach (string buildPin in PinStore.GetBuildPins()) { if (!_byPrefab.ContainsKey(buildPin)) { IndexPiece(scene.GetPrefab(buildPin)); } } } private static PieceTable TraverseBuildPieces(Player player) { try { object? obj = AccessTools.Field(typeof(Player), "m_buildPieces")?.GetValue(player); return (PieceTable)((obj is PieceTable) ? obj : null); } catch { return null; } } private static void IndexPiece(GameObject go) { if ((Object)(object)go == (Object)null) { return; } Piece component = go.GetComponent(); if (!((Object)(object)component == (Object)null)) { string text = Utils.GetPrefabName(go); if (string.IsNullOrEmpty(text)) { text = ((Object)go).name; } if (!_byPrefab.ContainsKey(text)) { _byPrefab[text] = component; } } } internal static Piece GetPiece(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return null; } EnsureCache(); if (_byPrefab.TryGetValue(prefabName, out var value) && (Object)(object)value != (Object)null) { return value; } ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance != (Object)null) { GameObject prefab = instance.GetPrefab(prefabName); value = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent() : null); if ((Object)(object)value != (Object)null) { _byPrefab[prefabName] = value; return value; } } return null; } internal static ResolvedRecipe Resolve(string prefabName) { Piece piece = GetPiece(prefabName); if ((Object)(object)piece == (Object)null) { if (!string.IsNullOrEmpty(prefabName) && !_loggedUnresolved.Contains(prefabName)) { _loggedUnresolved.Add(prefabName); ManualLogSource log = PinThoseRecipesPlugin.Log; if (log != null) { log.LogInfo((object)("Pinned build piece '" + prefabName + "' is not resolvable yet; kept and hidden.")); } } return null; } ResolvedRecipe resolvedRecipe = new ResolvedRecipe { PrefabName = prefabName, Icon = piece.m_icon, DisplayName = Localize(piece.m_name), OutputAmount = 1, IsBuild = true }; if (piece.m_resources != null) { Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (val != null && !((Object)(object)val.m_resItem == (Object)null)) { int amount = val.GetAmount(1); if (amount > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; resolvedRecipe.Requirements.Add(new ResolvedRequirement { Icon = val.m_resItem.m_itemData.GetIcon(), SharedName = name, DisplayName = Localize(name), Need = amount }); } } } } return resolvedRecipe; } private static string Localize(string token) { if (string.IsNullOrEmpty(token)) { return ""; } if (Localization.instance == null) { return token; } return Localization.instance.Localize(token); } } internal static class PinIcon { private const string EmbeddedName = "PinThoseRecipes.pin.png"; private static Sprite _sprite; private static Sprite _buildSprite; private static bool _resolved; internal static Sprite Sprite { get { Ensure(); return _sprite; } } internal static Sprite BuildSprite { get { Ensure(); return _buildSprite; } } internal static void Ensure() { if (_resolved) { return; } _resolved = true; try { _sprite = LoadEmbedded() ?? BuildStarFallback(); } catch (Exception ex) { ManualLogSource log = PinThoseRecipesPlugin.Log; if (log != null) { log.LogWarning((object)("PinIcon load failed, using fallback: " + ex.Message)); } try { _sprite = BuildStarFallback(); } catch { _sprite = null; } } try { _buildSprite = BuildDiamondFallback(); } catch { _buildSprite = _sprite; } } private static Sprite LoadEmbedded() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown using Stream stream = typeof(PinIcon).Assembly.GetManifestResourceStream("PinThoseRecipes.pin.png"); if (stream == null) { return null; } byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { break; } } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!LoadImageInto(val, array)) { Object.Destroy((Object)(object)val); return null; } ((Object)val).name = "PinThoseRecipes_PinEmbedded"; ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).wrapMode = (TextureWrapMode)1; return MakeSprite(val, "PinThoseRecipes_PinEmbedded"); } private static Sprite BuildStarFallback() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0043: 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_0060: 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_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0104: 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_0106: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false) { name = "PinThoseRecipes_PinFallback", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; Color32 val2 = default(Color32); ((Color32)(ref val2))..ctor((byte)0, (byte)0, (byte)0, (byte)0); Color32[] array = (Color32[])(object)new Color32[4096]; for (int i = 0; i < array.Length; i++) { array[i] = val2; } Vector2 center = new Vector2(32f, 32f); float num = 29.44f; float num2 = num * 0.42f; Vector2[] poly = BuildStar(center, num, num2); Vector2[] poly2 = BuildStar(center, num * 0.8f, num2 * 0.8f); Color32 val3 = default(Color32); ((Color32)(ref val3))..ctor(byte.MaxValue, (byte)205, (byte)60, byte.MaxValue); Color32 val4 = default(Color32); ((Color32)(ref val4))..ctor((byte)60, (byte)40, (byte)5, byte.MaxValue); Vector2 p = default(Vector2); for (int j = 0; j < 64; j++) { for (int k = 0; k < 64; k++) { ((Vector2)(ref p))..ctor((float)k + 0.5f, (float)j + 0.5f); if (PolygonContains(poly, p)) { array[j * 64 + k] = (PolygonContains(poly2, p) ? val3 : val4); } } } val.SetPixels32(array); val.Apply(false, false); return MakeSprite(val, "PinThoseRecipes_Pin"); } private static Sprite BuildDiamondFallback() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0043: 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_0082: 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_0094: 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_00a6: 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_00b8: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false) { name = "PinThoseRecipes_BuildPinFallback", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; Color32 val2 = default(Color32); ((Color32)(ref val2))..ctor((byte)0, (byte)0, (byte)0, (byte)0); Color32[] array = (Color32[])(object)new Color32[4096]; for (int i = 0; i < array.Length; i++) { array[i] = val2; } float num = 32f; float num2 = 32f; float num3 = 26.88f; float num4 = num3 * 0.72f; Vector2[] poly = (Vector2[])(object)new Vector2[4] { new Vector2(num, num2 + num3), new Vector2(num + num3, num2), new Vector2(num, num2 - num3), new Vector2(num - num3, num2) }; Vector2[] poly2 = (Vector2[])(object)new Vector2[4] { new Vector2(num, num2 + num4), new Vector2(num + num4, num2), new Vector2(num, num2 - num4), new Vector2(num - num4, num2) }; Color32 val3 = default(Color32); ((Color32)(ref val3))..ctor((byte)70, (byte)210, (byte)200, byte.MaxValue); Color32 val4 = default(Color32); ((Color32)(ref val4))..ctor((byte)10, (byte)50, (byte)55, byte.MaxValue); Vector2 p = default(Vector2); for (int j = 0; j < 64; j++) { for (int k = 0; k < 64; k++) { ((Vector2)(ref p))..ctor((float)k + 0.5f, (float)j + 0.5f); if (PolygonContains(poly, p)) { array[j * 64 + k] = (PolygonContains(poly2, p) ? val3 : val4); } } } val.SetPixels32(array); val.Apply(false, false); return MakeSprite(val, "PinThoseRecipes_BuildPin"); } private static Vector2[] BuildStar(Vector2 center, float outer, float inner) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) Vector2[] array = (Vector2[])(object)new Vector2[10]; for (int i = 0; i < 10; i++) { float num = ((i % 2 == 0) ? outer : inner); float num2 = (float)Math.PI / 2f + (float)i * (float)Math.PI / 5f; array[i] = new Vector2(center.x + Mathf.Cos(num2) * num, center.y + Mathf.Sin(num2) * num); } return array; } private static bool PolygonContains(Vector2[] poly, Vector2 p) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_0058: Unknown result type (might be due to invalid IL or missing references) bool flag = false; int num = poly.Length - 1; int num2 = 0; while (num2 < poly.Length) { if (poly[num2].y > p.y != poly[num].y > p.y && p.x < (poly[num].x - poly[num2].x) * (p.y - poly[num2].y) / (poly[num].y - poly[num2].y) + poly[num2].x) { flag = !flag; } num = num2++; } return flag; } private static bool LoadImageInto(Texture2D tex, byte[] data) { MethodInfo methodInfo = typeof(ImageConversion).GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, null) ?? typeof(ImageConversion).GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(Texture2D), typeof(byte[]) }, null); if (methodInfo == null) { return false; } object[] parameters = ((methodInfo.GetParameters().Length != 3) ? new object[2] { tex, data } : new object[3] { tex, data, false }); return (bool)methodInfo.Invoke(null, parameters); } private static Sprite MakeSprite(Texture2D tex, string name) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Sprite obj = Sprite.Create(tex, new Rect(0f, 0f, (float)((Texture)tex).width, (float)((Texture)tex).height), new Vector2(0.5f, 0.5f), 100f); ((Object)obj).name = name; return obj; } } internal static class UiUtils { private static TMP_FontAsset _cachedFont; internal static TMP_FontAsset ResolveFont() { if ((Object)(object)_cachedFont != (Object)null) { return _cachedFont; } InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.m_recipeName != (Object)null && (Object)(object)instance.m_recipeName.font != (Object)null) { _cachedFont = instance.m_recipeName.font; } return _cachedFont; } internal static RectTransform NewRect(Transform parent, string name) { //IL_0014: 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) //IL_0032: Unknown result type (might be due to invalid IL or missing references) RectTransform component = new GameObject(name, new Type[1] { typeof(RectTransform) }).GetComponent(); ((Transform)component).SetParent(parent, false); ((Transform)component).localScale = Vector3.one; component.anchoredPosition = Vector2.zero; return component; } internal static Image NewImage(Transform parent, string name, Sprite sprite = null, bool raycast = false) { Image obj = ((Component)NewRect(parent, name)).gameObject.AddComponent(); obj.sprite = sprite; ((Graphic)obj).raycastTarget = raycast; obj.preserveAspect = true; return obj; } internal static TextMeshProUGUI NewText(Transform parent, string name, float fontSize, TextAlignmentOptions align) { //IL_0030: 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_0071: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI val = ((Component)NewRect(parent, name)).gameObject.AddComponent(); TMP_FontAsset val2 = ResolveFont(); if ((Object)(object)val2 != (Object)null) { ((TMP_Text)val).font = val2; } ((TMP_Text)val).fontSize = fontSize; ((TMP_Text)val).alignment = align; ((TMP_Text)val).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)val).overflowMode = (TextOverflowModes)0; ((Graphic)val).raycastTarget = false; ((Graphic)val).color = Color.white; ((TMP_Text)val).fontStyle = (FontStyles)0; ((TMP_Text)val).outlineWidth = 0.15f; ((TMP_Text)val).outlineColor = new Color32((byte)0, (byte)0, (byte)0, (byte)200); return val; } internal static void SetAnchors(RectTransform rt, Vector2 min, Vector2 max, Vector2 pivot) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) rt.anchorMin = min; rt.anchorMax = max; rt.pivot = pivot; } } internal sealed class RecipePinInteraction : MonoBehaviour, IPointerClickHandler, IEventSystemHandler { internal string PinKey; internal Recipe Recipe; internal Image PinImage; internal InventoryGui Owner; public void OnPointerClick(PointerEventData eventData) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if (eventData != null && (int)eventData.button == 2 && ((Behaviour)this).isActiveAndEnabled && !string.IsNullOrEmpty(PinKey) && PinStore.HasActiveProfile) { PinStore.Toggle(PinKey); RefreshPinVisual(); PinSound.Play(); } } internal void RefreshPinVisual() { if (!((Object)(object)PinImage == (Object)null)) { bool flag = PinStore.IsPinned(PinKey); if (((Component)PinImage).gameObject.activeSelf != flag) { ((Component)PinImage).gameObject.SetActive(flag); } } } internal static void RefreshAllPinVisuals() { RecipePinInteraction[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null) { array[i].RefreshPinVisual(); } } } } internal static class PinSound { internal static void Play() { //IL_0047: 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) if (PinConfig.PlayPinSound == null || !PinConfig.PlayPinSound.Value) { return; } try { InventoryGui instance = InventoryGui.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance != (Object)null && (Object)(object)localPlayer != (Object)null && instance.m_moveItemEffects != null) { instance.m_moveItemEffects.Create(((Component)localPlayer).transform.position, Quaternion.identity, (Transform)null, 1f, -1); } } catch { } } } internal sealed class PinnedPanelController : MonoBehaviour { internal sealed class EntryView { public RectTransform Root; public RectTransform ReqsRoot; public TextMeshProUGUI ArrowLabel; public string PrefabName; public string CollapseKey; public bool IsBuild; public bool Expanded = true; public readonly List Reqs = new List(); public void ApplyExpanded(bool expanded) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) Expanded = expanded; if ((Object)(object)ReqsRoot != (Object)null) { ((Component)ReqsRoot).gameObject.SetActive(expanded); } if ((Object)(object)ArrowLabel != (Object)null) { ((TMP_Text)ArrowLabel).text = (expanded ? "▼" : "▶"); ((Graphic)ArrowLabel).color = new Color(0.85f, 0.85f, 0.85f, 1f); } } } internal sealed class ReqView { public string SharedName; public int Need; public TextMeshProUGUI Label; } private const float CountRefreshInterval = 0.25f; private const float ProfileSyncInterval = 0.5f; private const float UnresolvedRetryInterval = 1f; private const float ItemIconSize = 40f; private const float MatIconSize = 26f; private const float ArrowSize = 22f; private RectTransform _root; private CanvasGroup _canvasGroup; private RectTransform _content; private Transform _boundParent; private RectTransform _contextMenu; private string _contextMenuPrefab; private bool _contextMenuIsBuild; private TextMeshProUGUI _contextMenuLabel; private static string _hoverTipText; private static bool _hoverTipVisible; private readonly List _entries = new List(); private bool _dirty = true; private float _nextCountRefresh; private float _nextProfileSync; private float _nextUnresolvedRetry; private bool _hasUnresolved; private bool _wasInventoryOpen; private readonly Vector3[] _cornersParent = (Vector3[])(object)new Vector3[4]; private readonly Vector3[] _cornersMinimap = (Vector3[])(object)new Vector3[4]; private readonly Vector3[] _cornersShipHud = (Vector3[])(object)new Vector3[4]; private void Awake() { PinIcon.Ensure(); PinStore.PinsChanged += OnPinsChanged; PinConfig.Changed += OnConfigChanged; } private void OnDestroy() { PinStore.PinsChanged -= OnPinsChanged; PinConfig.Changed -= OnConfigChanged; DestroyRoot(); HideMaterialTip(); } private void OnPinsChanged() { HideContextMenu(); _dirty = true; RecipePinInteraction.RefreshAllPinVisuals(); } private void OnConfigChanged() { _dirty = true; ApplyScale(); } private void Update() { if (Time.unscaledTime >= _nextProfileSync) { _nextProfileSync = Time.unscaledTime + 0.5f; ProfileLifecyclePatches.SyncProfile(); } EnsureHudBinding(); if ((Object)(object)_root == (Object)null) { return; } bool flag = ShouldShowPanel(); _canvasGroup.alpha = (flag ? 1f : 0f); _canvasGroup.blocksRaycasts = flag; _canvasGroup.interactable = flag; if (!flag) { HideContextMenu(); HideMaterialTip(); return; } if (_dirty || (_hasUnresolved && Time.unscaledTime >= _nextUnresolvedRetry)) { HideContextMenu(); HideMaterialTip(); RebuildPanel(); } if (Time.unscaledTime >= _nextCountRefresh) { _nextCountRefresh = Time.unscaledTime + 0.25f; RefreshCounts(); } UpdatePosition(); bool flag2 = IsInventoryOpen(); if (_wasInventoryOpen && !flag2) { HideContextMenu(); } _wasInventoryOpen = flag2; if ((Object)(object)_contextMenu != (Object)null && ((Component)_contextMenu).gameObject.activeSelf && (Input.GetKeyDown((KeyCode)27) || Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(2)) && !IsPointerOverContextMenu()) { HideContextMenu(); } } private bool IsPointerOverContextMenu() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_0054: 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) if ((Object)(object)_contextMenu == (Object)null || !Object.op_Implicit((Object)(object)EventSystem.current)) { return false; } List list = new List(); PointerEventData val = new PointerEventData(EventSystem.current) { position = Vector2.op_Implicit(Input.mousePosition) }; EventSystem.current.RaycastAll(val, list); foreach (RaycastResult item in list) { RaycastResult current = item; if ((Object)(object)((RaycastResult)(ref current)).gameObject != (Object)null && ((RaycastResult)(ref current)).gameObject.transform.IsChildOf((Transform)(object)_contextMenu)) { return true; } } return false; } private Transform ResolveParent() { Minimap instance = Minimap.instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.m_smallRoot != (Object)null) { return instance.m_smallRoot.transform.parent; } return null; } private void EnsureHudBinding() { if (PinConfig.Enabled != null && !PinConfig.Enabled.Value) { DestroyRoot(); return; } Transform val = ResolveParent(); if ((!((Object)(object)val == (Object)null) || (!((Object)(object)_root == (Object)null) && !((Object)(object)_boundParent == (Object)null))) && (!((Object)(object)_root != (Object)null) || !((Object)(object)_boundParent == (Object)(object)val))) { DestroyRoot(); if (!((Object)(object)val == (Object)null)) { BuildRoot(val); } } } private void BuildRoot(Transform parent) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_005b: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0153: 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_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Expected O, but got Unknown _boundParent = parent; GameObject val = new GameObject("PinThoseRecipes_PanelRoot", new Type[2] { typeof(RectTransform), typeof(CanvasGroup) }); _root = val.GetComponent(); ((Transform)_root).SetParent(parent, false); UiUtils.SetAnchors(_root, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(1f, 1f)); _root.sizeDelta = new Vector2(0f, 0f); ((Transform)_root).localScale = Vector3.one; Canvas obj = val.AddComponent(); obj.overrideSorting = true; obj.sortingOrder = 1200; val.AddComponent(); _canvasGroup = val.GetComponent(); _canvasGroup.alpha = 0f; _canvasGroup.blocksRaycasts = false; _canvasGroup.interactable = false; _content = UiUtils.NewRect((Transform)(object)_root, "Content"); UiUtils.SetAnchors(_content, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(1f, 1f)); _content.anchoredPosition = Vector2.zero; Image obj2 = ((Component)_content).gameObject.AddComponent(); ((Graphic)obj2).color = new Color(0f, 0f, 0f, 0.55f); ((Graphic)obj2).raycastTarget = false; VerticalLayoutGroup obj3 = ((Component)_content).gameObject.AddComponent(); ((HorizontalOrVerticalLayoutGroup)obj3).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)obj3).spacing = 8f; ((LayoutGroup)obj3).padding = new RectOffset(10, 10, 8, 8); ((LayoutGroup)obj3).childAlignment = (TextAnchor)2; ContentSizeFitter obj4 = ((Component)_content).gameObject.AddComponent(); obj4.horizontalFit = (FitMode)2; obj4.verticalFit = (FitMode)2; BuildContextMenu(); ApplyScale(); _dirty = true; } private void BuildContextMenu() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_005e: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: 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_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Expected O, but got Unknown _contextMenu = UiUtils.NewRect((Transform)(object)_root, "ContextMenu"); UiUtils.SetAnchors(_contextMenu, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(0f, 1f)); _contextMenu.sizeDelta = new Vector2(150f, 42f); ((Component)_contextMenu).gameObject.SetActive(false); Image obj = ((Component)_contextMenu).gameObject.AddComponent(); ((Graphic)obj).color = new Color(0.1f, 0.09f, 0.07f, 0.96f); ((Graphic)obj).raycastTarget = true; Outline obj2 = ((Component)_contextMenu).gameObject.AddComponent(); ((Shadow)obj2).effectColor = new Color(0.85f, 0.72f, 0.35f, 1f); ((Shadow)obj2).effectDistance = new Vector2(1.5f, -1.5f); RectTransform val = UiUtils.NewRect((Transform)(object)_contextMenu, "UnpinButton"); UiUtils.SetAnchors(val, Vector2.zero, Vector2.one, new Vector2(0.5f, 0.5f)); val.offsetMin = new Vector2(3f, 3f); val.offsetMax = new Vector2(-3f, -3f); Image val2 = ((Component)val).gameObject.AddComponent(); ((Graphic)val2).color = new Color(0.18f, 0.16f, 0.12f, 1f); ((Graphic)val2).raycastTarget = true; Button obj3 = ((Component)val).gameObject.AddComponent