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 HardheimHungary v1.0.3
plugins/RecipePinner.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("PinRecipe")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("PinRecipe")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("b7fff297-caca-412c-8cb0-52556a76bd3f")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace ValheimRecipePinner; public class ContainerScanner { public static List<Container> AllContainers = new List<Container>(); private static readonly HashSet<Container> _containerSet = new HashSet<Container>(); internal static readonly object ContainerLock = new object(); public Dictionary<string, int> ContainerCache = new Dictionary<string, int>(); private static readonly HashSet<int> _processedIDs = new HashSet<int>(); private readonly List<Container> _snapshotBuffer = new List<Container>(); private Vector3 _lastScanPos; private int _lastItemCount = 0; private float _scanTimer = 0f; private float _moveScanCooldown = 0f; private const float MovementThresholdSqr = 4f; private const float MinMoveScanCooldown = 1f; public void InitializeContainers() { DebugLogger.Log("Init containers"); lock (ContainerLock) { if (AllContainers.Count != 0) { return; } Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); Container[] array2 = array; foreach (Container val in array2) { if ((Object)(object)val != (Object)null && _containerSet.Add(val)) { AllContainers.Add(val); if ((Object)(object)((Component)val).GetComponent<ContainerTracker>() == (Object)null) { ContainerTracker containerTracker = ((Component)val).gameObject.AddComponent<ContainerTracker>(); containerTracker.MyContainer = val; } } } DebugLogger.Log($"Tracking {AllContainers.Count} containers"); } } public void UpdateScanning() { //IL_0045: 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) if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } _scanTimer += Time.deltaTime; _moveScanCooldown += Time.deltaTime; float num = Vector3.SqrMagnitude(((Component)Player.m_localPlayer).transform.position - _lastScanPos); bool flag = num > 4f && _moveScanCooldown >= 1f; int num2 = 0; foreach (ItemData allItem in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()) { num2 += allItem.m_stack; } bool flag2 = num2 != _lastItemCount; bool flag3 = false; if ((Object)(object)InventoryGui.instance != (Object)null) { flag3 = (Object)(object)ReflectionHelper.GetCurrentContainer(InventoryGui.instance) != (Object)null; } float num3 = (flag3 ? 0.5f : RecipePinnerPlugin.ChestScanInterval.Value); bool flag4 = _scanTimer >= num3; if (flag || flag2 || flag4) { DebugLogger.Verbose($"Scanning containers - Moved: {flag}, InvChanged: {flag2}, Interval: {flag4}"); _scanTimer = 0f; if (flag) { _moveScanCooldown = 0f; } _lastItemCount = num2; UpdateContainerCache(); } } private void UpdateContainerCache() { //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_0250: 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_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) ContainerCache.Clear(); if ((Object)(object)Player.m_localPlayer == (Object)null) { DebugLogger.Verbose("Cannot scan - player is null"); return; } Vector3 position = ((Component)Player.m_localPlayer).transform.position; float value = RecipePinnerPlugin.ChestScanRange.Value; float num = value * value; _snapshotBuffer.Clear(); lock (ContainerLock) { _snapshotBuffer.AddRange(AllContainers); } _processedIDs.Clear(); int num2 = 0; int num3 = 0; int num4 = 0; foreach (Container item in _snapshotBuffer) { if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).transform == (Object)null) { num3++; continue; } int instanceID = ((Object)item).GetInstanceID(); if (!_processedIDs.Add(instanceID)) { num3++; continue; } float num5 = Vector3.SqrMagnitude(((Component)item).transform.position - position); if (num5 > num) { num3++; continue; } bool flag = true; if (ReflectionHelper.CheckContainerAccess != null) { flag = ReflectionHelper.CheckContainerAccess(item, Player.m_localPlayer.GetPlayerID()); } if (!flag) { num4++; continue; } Inventory inventory = item.GetInventory(); if (inventory == null) { continue; } foreach (ItemData allItem in inventory.GetAllItems()) { string name = allItem.m_shared.m_name; if (ContainerCache.TryGetValue(name, out var value2)) { ContainerCache[name] = value2 + allItem.m_stack; } else { ContainerCache[name] = allItem.m_stack; } } num2++; } _lastScanPos = position; DebugLogger.Verbose($"Container scan complete - Scanned: {num2}, Skipped: {num3}, AccessDenied: {num4}, UniqueItems: {ContainerCache.Count}"); } [HarmonyPatch(typeof(Container), "Awake")] [HarmonyPostfix] public static void TrackContainerAwake(Container __instance) { if (!((Object)(object)__instance != (Object)null)) { return; } lock (ContainerLock) { if (_containerSet.Add(__instance)) { AllContainers.Add(__instance); ContainerTracker containerTracker = ((Component)__instance).gameObject.GetComponent<ContainerTracker>() ?? ((Component)__instance).gameObject.AddComponent<ContainerTracker>(); containerTracker.MyContainer = __instance; DebugLogger.Verbose($"New container tracked: {((Object)__instance).name} (Total: {AllContainers.Count})"); } } } public static void RemoveFromSet(Container c) { _containerSet.Remove(c); } } public class ContainerTracker : MonoBehaviour { public Container MyContainer; private void OnDestroy() { if (ContainerScanner.AllContainers != null && (Object)(object)MyContainer != (Object)null) { lock (ContainerScanner.ContainerLock) { ContainerScanner.AllContainers.Remove(MyContainer); ContainerScanner.RemoveFromSet(MyContainer); DebugLogger.Verbose($"Container removed: {((Object)MyContainer).name} (Remaining: {ContainerScanner.AllContainers.Count})"); } } } } public class DataPersistence { public void SavePins() { try { string savePath = GetSavePath(); if (string.IsNullOrEmpty(savePath)) { DebugLogger.Warning("Cannot save - save path is invalid"); return; } RecipeManager recipeMgr = RecipePinnerPlugin.Instance.RecipeMgr; List<string> list = new List<string>(); foreach (KeyValuePair<string, int> pinnedRecipe in recipeMgr.PinnedRecipes) { list.Add($"{pinnedRecipe.Key}:{pinnedRecipe.Value}"); } File.WriteAllLines(savePath, list); DebugLogger.Log($"Saved {list.Count} pinned recipes to: {savePath}"); } catch (Exception ex) { DebugLogger.Error("Failed to save pins", ex); } } public void LoadPins() { string savePath = GetSavePath(); if (string.IsNullOrEmpty(savePath)) { DebugLogger.Warning("Cannot load - save path is invalid"); return; } RecipeManager recipeMgr = RecipePinnerPlugin.Instance.RecipeMgr; if (!File.Exists(savePath)) { DebugLogger.Log("No save file found at: " + savePath); return; } try { recipeMgr.PinnedRecipes.Clear(); string[] array = File.ReadAllLines(savePath); int num = 0; int num2 = 0; string[] array2 = array; foreach (string text in array2) { if (string.IsNullOrWhiteSpace(text)) { continue; } int num3 = text.LastIndexOf(':'); if (num3 > 0 && num3 < text.Length - 1) { string key = text.Substring(0, num3).Trim(); string s = text.Substring(num3 + 1).Trim(); if (int.TryParse(s, out var result)) { recipeMgr.PinnedRecipes[key] = result; num++; } else { DebugLogger.Warning("Invalid count value in save file: " + text); num2++; } } else if (!recipeMgr.PinnedRecipes.ContainsKey(text)) { recipeMgr.PinnedRecipes[text] = 1; num++; } } if (recipeMgr.PinnedRecipes.Count > RecipePinnerPlugin.MaximumPins.Value) { int count = recipeMgr.PinnedRecipes.Count; Dictionary<string, int> dictionary = new Dictionary<string, int>(); int num4 = 0; foreach (KeyValuePair<string, int> pinnedRecipe in recipeMgr.PinnedRecipes) { if (num4 >= RecipePinnerPlugin.MaximumPins.Value) { break; } dictionary[pinnedRecipe.Key] = pinnedRecipe.Value; num4++; } recipeMgr.PinnedRecipes = dictionary; DebugLogger.Warning($"Exceeded max pins limit - trimmed from {count} to {recipeMgr.PinnedRecipes.Count}"); } DebugLogger.Log($"Loaded {num} recipes from: {savePath} (Errors: {num2})"); } catch (Exception ex) { DebugLogger.Error("Failed to load pins", ex); } } private string GetSavePath() { if ((Object)(object)Player.m_localPlayer == (Object)null) { DebugLogger.Verbose("Cannot get save path - local player is null"); return null; } string playerName = Player.m_localPlayer.GetPlayerName(); if (string.IsNullOrWhiteSpace(playerName)) { DebugLogger.Warning("Cannot get save path - player name is empty"); return null; } string text = Path.Combine(Paths.ConfigPath, "RecipePinner_Data"); if (!Directory.Exists(text)) { try { Directory.CreateDirectory(text); DebugLogger.Log("Created save directory: " + text); } catch (Exception ex) { DebugLogger.Error("Failed to create save directory: " + text, ex); return null; } } string text2 = playerName; char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { text2 = text2.Replace(oldChar, '_'); } string text3 = Path.Combine(text, text2 + ".txt"); DebugLogger.Verbose("Save path: " + text3); return text3; } } public static class DebugLogger { private const string Prefix = "[RecipePinner]"; public static void Log(string message) { if (IsDebugEnabled()) { Debug.Log((object)("[RecipePinner] " + message)); } } public static void Warning(string message) { Debug.LogWarning((object)("[RecipePinner] " + message)); } public static void Error(string message) { Debug.LogError((object)("[RecipePinner] " + message)); } public static void Error(string message, Exception ex) { Debug.LogError((object)("[RecipePinner] " + message + "\nException: " + ex.Message + "\nStackTrace: " + ex.StackTrace)); } public static void Verbose(string message) { if (IsDebugEnabled()) { Debug.Log((object)("[RecipePinner] [VERBOSE] " + message)); } } private static bool IsDebugEnabled() { return (Object)(object)RecipePinnerPlugin.Instance != (Object)null && RecipePinnerPlugin.EnableDebugLogging != null && RecipePinnerPlugin.EnableDebugLogging.Value; } } public class LocalizationManager { private readonly RecipePinnerPlugin _plugin; private readonly Dictionary<string, string> _localizedText = new Dictionary<string, string>(); private static readonly Dictionary<string, string> _defaultEnglish = new Dictionary<string, string> { { "pinned", "Recipe Pinned!" }, { "unpinned", "Pin Removed" }, { "list_full", "List Full!" }, { "added_more", "Added More: {0}x" }, { "decreased", "Decreased: {0}x" }, { "cleared", "Pinned Recipes Cleared" }, { "max_level", "Max Level Reached" }, { "no_upgrade_cost", "No upgrade cost found" }, { "gathering_title", "GATHERING LIST" }, { "gathering_opened", "Gathering List Opened" }, { "gathering_closed", "Gathering List Closed" }, { "gathering_empty", "No Recipes Pinned" }, { "gathering_hint", "Open/Close: {0}" } }; public LocalizationManager(RecipePinnerPlugin plugin) { _plugin = plugin; DebugLogger.Log("LocalizationManager init"); } public void LoadTranslations() { _localizedText.Clear(); string text = RecipePinnerPlugin.LanguageOverride.Value.Trim(); if (string.IsNullOrEmpty(text) || text.ToLower() == "auto") { text = ((Localization.instance == null) ? "English" : Localization.instance.GetSelectedLanguage()); DebugLogger.Log("Auto-detected language: " + text); } else { DebugLogger.Log("Using forced language: " + text); } string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)_plugin).Info.Location); string text2 = Path.Combine(directoryName, "RecipePinner_languages", text + ".json"); if (!File.Exists(text2)) { DebugLogger.Log("Language file not found: " + text2 + " - Using default English"); return; } try { string text3 = File.ReadAllText(text2); int num = 0; string[] array = text3.Split(new char[1] { '\n' }); foreach (string text4 in array) { string text5 = text4.Trim(); if (string.IsNullOrEmpty(text5) || text5 == "{" || text5 == "}" || !text5.Contains(":")) { continue; } string[] array2 = text5.Split(new char[1] { ':' }, 2); if (array2.Length == 2) { string text6 = array2[0].Trim(',', '"', ' ', '\t', '\r'); string value = array2[1].Trim(',', '"', ' ', '\t', '\r'); if (!string.IsNullOrEmpty(text6) && !string.IsNullOrEmpty(value)) { _localizedText[text6] = value; num++; } } } DebugLogger.Log($"Loaded {num} translations from: {text}.json"); } catch (Exception ex) { DebugLogger.Error("Failed to load language file: " + text2, ex); } } public string GetText(string key) { if (_localizedText.TryGetValue(key, out var value)) { DebugLogger.Verbose("Translation found for '" + key + "': " + value); return value; } if (_defaultEnglish.TryGetValue(key, out var value2)) { DebugLogger.Verbose("Using default English for '" + key + "': " + value2); return value2; } DebugLogger.Warning("No translation found for key: " + key); return key; } } public class PinnedRecipeData { public Recipe RecipeRef; public string RawName; public string CachedHeader; public string CachedShadowHeader; public Sprite Icon; public int StackCount; public List<PinnedResData> Resources = new List<PinnedResData>(); public bool IsDirty = true; } public class PinnedResData { public string ItemName; public string CachedName; public string CachedShadowName; public Sprite Icon; public int RequiredAmount; public int LastKnownAmount; public int LastKnownInvAmount; public string CachedAmountString; } public class RecipeManager { public Dictionary<string, int> PinnedRecipes = new Dictionary<string, int>(); public List<PinnedRecipeData> CachedPins = new List<PinnedRecipeData>(); private readonly Dictionary<string, Recipe> _fakeRecipeCache = new Dictionary<string, Recipe>(); private static readonly Regex CleanNameRegex = new Regex("<.*?>", RegexOptions.Compiled); private static readonly Regex ShadowCleanRegex = new Regex("<color=.*?>|</color>", RegexOptions.Compiled); private static readonly Regex AmountSuffixRegex = new Regex("\\s*[xX]?\\s*\\d+$", RegexOptions.Compiled); private static readonly Regex UpgradeStarRegex = new Regex("\\s*★(\\d+)$", RegexOptions.Compiled); private static readonly Dictionary<Type, FieldInfo> _cachedRecipeFields = new Dictionary<Type, FieldInfo>(); private static readonly Dictionary<Type, PropertyInfo> _cachedRecipeProps = new Dictionary<Type, PropertyInfo>(); private static readonly Dictionary<Type, FieldInfo> _cachedItemFields = new Dictionary<Type, FieldInfo>(); private static readonly Dictionary<Type, PropertyInfo> _cachedItemProps = new Dictionary<Type, PropertyInfo>(); public void Cleanup() { DebugLogger.Log("RecipeManager cleanup"); int count = _fakeRecipeCache.Count; foreach (Recipe value in _fakeRecipeCache.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } _fakeRecipeCache.Clear(); DebugLogger.Log($"Cleaned {count} fake recipes"); _cachedRecipeFields.Clear(); _cachedRecipeProps.Clear(); _cachedItemFields.Clear(); _cachedItemProps.Clear(); } public void RefreshRecipeCache() { DebugLogger.Verbose("Refreshing cache"); CachedPins.Clear(); if ((Object)(object)ObjectDB.instance == (Object)null) { DebugLogger.Warning("ObjectDB null, can't refresh"); return; } int num = 0; int num2 = 0; foreach (KeyValuePair<string, int> pinnedRecipe in PinnedRecipes) { string key = pinnedRecipe.Key; int value = pinnedRecipe.Value; Recipe recipeByName = GetRecipeByName(key); if ((Object)(object)recipeByName != (Object)null) { PinnedRecipeData pinnedRecipeData = new PinnedRecipeData { IsDirty = true, RecipeRef = recipeByName, StackCount = value }; if ((Object)(object)recipeByName.m_item != (Object)null) { pinnedRecipeData.Icon = recipeByName.m_item.m_itemData.GetIcon(); pinnedRecipeData.RawName = recipeByName.m_item.m_itemData.m_shared.m_name; } else { ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(((Object)recipeByName).name) : null); if ((Object)(object)val != (Object)null) { Piece component = val.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { pinnedRecipeData.Icon = component.m_icon; pinnedRecipeData.RawName = component.m_name; } } } if (string.IsNullOrEmpty(pinnedRecipeData.RawName)) { pinnedRecipeData.RawName = ((Object)recipeByName).name; } string text = pinnedRecipeData.RawName; if (Localization.instance != null) { Match match = UpgradeStarRegex.Match(key); if (match.Success) { string text2 = pinnedRecipeData.RawName; if (Localization.instance != null) { text2 = Localization.instance.Localize(pinnedRecipeData.RawName); } text = text2 + match.Value; } else { text = Localization.instance.Localize(pinnedRecipeData.RawName); } } text = text.Replace("\r", "").Replace("\n", ""); if (recipeByName.m_amount > 1) { text += $" (x{recipeByName.m_amount})"; } if (value > 1) { text = $"{value}x {text}"; } pinnedRecipeData.CachedHeader = text; pinnedRecipeData.CachedShadowHeader = text; Requirement[] resources = recipeByName.m_resources; foreach (Requirement val2 in resources) { if (val2 != null && !((Object)(object)val2.m_resItem == (Object)null) && val2.m_amount > 0) { PinnedResData pinnedResData = new PinnedResData { ItemName = val2.m_resItem.m_itemData.m_shared.m_name, Icon = val2.m_resItem.m_itemData.GetIcon(), RequiredAmount = val2.m_amount * value, LastKnownAmount = -1, LastKnownInvAmount = -1 }; string text3 = pinnedResData.ItemName; if (Localization.instance != null) { text3 = Localization.instance.Localize(pinnedResData.ItemName); } text3 = (pinnedResData.CachedName = text3.Replace("\r", "").Replace("\n", "")); pinnedResData.CachedShadowName = ShadowCleanRegex.Replace(text3, string.Empty); pinnedRecipeData.Resources.Add(pinnedResData); } } CachedPins.Add(pinnedRecipeData); num++; } else { DebugLogger.Warning("Recipe not found: " + key); num2++; } } DebugLogger.Log($"Cache refreshed: {num} ok, {num2} failed"); if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)RecipePinnerPlugin.Instance != (Object)null) { RecipePinnerPlugin.Instance.UIMgr.UpdateUI(isVisible: true); } } public Recipe GetRecipeByName(string name) { if ((Object)(object)ObjectDB.instance == (Object)null) { return null; } if (_fakeRecipeCache.TryGetValue(name, out var value)) { DebugLogger.Verbose("Found cached fake recipe: " + name); return value; } Match match = UpgradeStarRegex.Match(name); if (match.Success) { string name2 = name.Substring(0, match.Index).Trim(); int targetLevel = int.Parse(match.Groups[1].Value); Recipe recipeByName = GetRecipeByName(name2); if ((Object)(object)recipeByName != (Object)null) { Recipe val = CreateFakeUpgradeRecipe(recipeByName, targetLevel, name); if ((Object)(object)val != (Object)null) { return val; } } } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name); ItemDrop val2 = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 != (Object)null) { Recipe recipe = ObjectDB.instance.GetRecipe(val2.m_itemData); if ((Object)(object)recipe != (Object)null) { DebugLogger.Verbose("Found standard recipe: " + name); return recipe; } } Recipe val3 = null; foreach (Recipe recipe2 in ObjectDB.instance.m_recipes) { if (((Object)recipe2).name == name) { val3 = recipe2; break; } } if ((Object)(object)val3 != (Object)null) { DebugLogger.Verbose("Found recipe in ObjectDB: " + name); return val3; } ZNetScene instance = ZNetScene.instance; GameObject val4 = ((instance != null) ? instance.GetPrefab(name) : null); if ((Object)(object)val4 != (Object)null) { Piece component = val4.GetComponent<Piece>(); if ((Object)(object)component != (Object)null && component.m_resources != null && component.m_resources.Length != 0) { Recipe val5 = ScriptableObject.CreateInstance<Recipe>(); ((Object)val5).hideFlags = (HideFlags)61; ((Object)val5).name = name; val5.m_item = val4.GetComponent<ItemDrop>(); val5.m_resources = (Requirement[])component.m_resources.Clone(); _fakeRecipeCache[name] = val5; DebugLogger.Verbose("Created fake recipe for piece: " + name); return val5; } } DebugLogger.Warning("Recipe not found anywhere: " + name); return null; } private Recipe CreateFakeUpgradeRecipe(Recipe baseRecipe, int targetLevel, string customName) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown if ((Object)(object)baseRecipe == (Object)null) { return null; } Recipe val = ScriptableObject.CreateInstance<Recipe>(); ((Object)val).hideFlags = (HideFlags)61; ((Object)val).name = customName; val.m_item = baseRecipe.m_item; val.m_amount = 1; int num = Mathf.Max(1, targetLevel - 1); List<Requirement> list = new List<Requirement>(); Requirement[] resources = baseRecipe.m_resources; foreach (Requirement val2 in resources) { if (val2.m_amountPerLevel > 0) { Requirement item = new Requirement { m_resItem = val2.m_resItem, m_amount = val2.m_amountPerLevel * num, m_amountPerLevel = 0, m_recover = val2.m_recover }; list.Add(item); } } if (list.Count == 0) { Object.Destroy((Object)(object)val); return null; } val.m_resources = list.ToArray(); _fakeRecipeCache[customName] = val; DebugLogger.Verbose("Created fake upgrade recipe: " + customName); return val; } public void ValidateAndCleanPins() { if ((Object)(object)ObjectDB.instance == (Object)null) { DebugLogger.Warning("Cannot validate pins - ObjectDB.instance is null"); return; } DebugLogger.Log("Validating pins"); List<string> list = new List<string>(); foreach (string key in PinnedRecipes.Keys) { if ((Object)(object)GetRecipeByName(key) == (Object)null) { list.Add(key); } } if (list.Count > 0) { foreach (string item in list) { PinnedRecipes.Remove(item); DebugLogger.Warning("Removed invalid recipe: " + item); } RecipePinnerPlugin.Instance?.DataMgr.SavePins(); DebugLogger.Log($"Removed {list.Count} invalid pins"); } else { DebugLogger.Log("All pins valid"); } } public void TryPinHoveredRecipe(InventoryGui gui) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown DebugLogger.Verbose("Attempting to pin hovered recipe..."); Transform recipeListRoot = ReflectionHelper.GetRecipeListRoot(gui); if (!(ReflectionHelper.GetAvailableRecipes(gui) is IList list) || (Object)(object)recipeListRoot == (Object)null) { DebugLogger.Verbose("Cannot pin - listRoot or availableRecipes is null"); return; } ScrollRect componentInParent = ((Component)recipeListRoot).GetComponentInParent<ScrollRect>(); bool flag = !((Selectable)gui.m_tabUpgrade).interactable; foreach (Transform item in recipeListRoot) { Transform val = item; if (!((Component)val).gameObject.activeInHierarchy) { continue; } RectTransform val2 = (RectTransform)(object)((val is RectTransform) ? val : null); if ((Object)(object)val2 == (Object)null || !IsVisibleInScroll(val2, componentInParent) || !InputHelper.IsMouseOverRect(val2)) { continue; } string text = ExtractTextFromUI(val); if (string.IsNullOrEmpty(text)) { continue; } string text2 = CleanNameRegex.Replace(text, string.Empty).Trim(); text2 = text2.Replace("\r", "").Replace("\n", ""); string text3 = AmountSuffixRegex.Replace(text2, "").Trim(); DebugLogger.Verbose($"Hovered: '{text3}' (UpgradeTab: {flag})"); foreach (object item2 in list) { Recipe recipeFromObject = GetRecipeFromObject(item2); if (!((Object)(object)recipeFromObject != (Object)null)) { continue; } string rawRecipeName = GetRawRecipeName(recipeFromObject); if (string.IsNullOrEmpty(rawRecipeName)) { continue; } string text4 = rawRecipeName; if (Localization.instance != null) { text4 = Localization.instance.Localize(rawRecipeName); } text4 = text4.Replace("\r", "").Replace("\n", ""); if (!text4.Equals(text3, StringComparison.OrdinalIgnoreCase) && !text4.Equals(text2, StringComparison.OrdinalIgnoreCase)) { continue; } if (flag) { ItemData val3 = GetItemDataFromObject(item2) ?? ReflectionHelper.GetCraftUpgradeItem(gui); if (val3 != null) { int quality = val3.m_quality; int num = quality + 1; int maxQuality = val3.m_shared.m_maxQuality; if (quality >= maxQuality) { string text5 = RecipePinnerPlugin.Instance.LocalizationMgr.GetText("max_level"); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, text5, 0, (Sprite)null); } return; } string name = ((Object)recipeFromObject.m_item).name; string text6 = $"{name} ★{num}"; DebugLogger.Log("Attempting to pin upgrade: " + text6 + " (Base: " + name + ")"); if ((Object)(object)GetRecipeByName(text6) != (Object)null) { TogglePin(text6); return; } string text7 = RecipePinnerPlugin.Instance.LocalizationMgr.GetText("no_upgrade_cost"); Player localPlayer2 = Player.m_localPlayer; if (localPlayer2 != null) { ((Character)localPlayer2).Message((MessageType)2, text7, 0, (Sprite)null); } } else { DebugLogger.Warning("Matched name but could not get ItemData for upgrade."); } } else { DebugLogger.Log("Matched recipe: " + ((Object)recipeFromObject).name); TogglePin(((Object)recipeFromObject).name); } return; } } } public void TryPinHoveredPiece() { DebugLogger.Verbose("Attempting to pin hovered piece..."); if (!((Object)(object)Hud.instance == (Object)null)) { Piece hoveredPiece = ReflectionHelper.GetHoveredPiece(Hud.instance); if ((Object)(object)hoveredPiece != (Object)null && hoveredPiece.m_resources != null && hoveredPiece.m_resources.Length != 0) { DebugLogger.Log("Pinning piece: " + ((Object)hoveredPiece).name); TogglePin(((Object)hoveredPiece).name); } else { DebugLogger.Verbose("No valid piece to pin (Mouse must be over a recipe icon)"); } } } private void TogglePin(string recipeName) { bool flag = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); LocalizationManager localizationMgr = RecipePinnerPlugin.Instance.LocalizationMgr; if (PinnedRecipes.TryGetValue(recipeName, out var value)) { if (flag) { value--; if (value <= 0) { PinnedRecipes.Remove(recipeName); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, localizationMgr.GetText("unpinned"), 0, (Sprite)null); } DebugLogger.Log("Unpinned: " + recipeName); } else { PinnedRecipes[recipeName] = value; string text = string.Format(localizationMgr.GetText("decreased"), value); Player localPlayer2 = Player.m_localPlayer; if (localPlayer2 != null) { ((Character)localPlayer2).Message((MessageType)2, text, 0, (Sprite)null); } DebugLogger.Log($"Decreased pin count: {recipeName} = {value}"); } } else { value++; PinnedRecipes[recipeName] = value; string text2 = string.Format(localizationMgr.GetText("added_more"), value); Player localPlayer3 = Player.m_localPlayer; if (localPlayer3 != null) { ((Character)localPlayer3).Message((MessageType)2, text2, 0, (Sprite)null); } DebugLogger.Log($"Increased pin count: {recipeName} = {value}"); } } else { if (flag) { return; } if (PinnedRecipes.Count < RecipePinnerPlugin.MaximumPins.Value) { PinnedRecipes.Add(recipeName, 1); Player localPlayer4 = Player.m_localPlayer; if (localPlayer4 != null) { ((Character)localPlayer4).Message((MessageType)2, localizationMgr.GetText("pinned"), 0, (Sprite)null); } DebugLogger.Log("Pinned new recipe: " + recipeName); } else { Player localPlayer5 = Player.m_localPlayer; if (localPlayer5 != null) { ((Character)localPlayer5).Message((MessageType)2, localizationMgr.GetText("list_full"), 0, (Sprite)null); } DebugLogger.Warning($"Cannot pin {recipeName} - max pins reached ({RecipePinnerPlugin.MaximumPins.Value})"); } } RefreshRecipeCache(); } private Recipe GetRecipeFromObject(object data) { if (data == null) { return null; } Recipe val = (Recipe)((data is Recipe) ? data : null); if (val != null) { return val; } Type type = data.GetType(); if (_cachedRecipeFields.TryGetValue(type, out var value)) { object? value2 = value.GetValue(data); return (Recipe)((value2 is Recipe) ? value2 : null); } if (_cachedRecipeProps.TryGetValue(type, out var value3)) { object? value4 = value3.GetValue(data, null); return (Recipe)((value4 is Recipe) ? value4 : null); } PropertyInfo property = type.GetProperty("Key"); if (property != null) { object? value5 = property.GetValue(data, null); Recipe val2 = (Recipe)((value5 is Recipe) ? value5 : null); if (val2 != null) { _cachedRecipeProps[type] = property; return val2; } } FieldInfo field = type.GetField("m_recipe", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object? value6 = field.GetValue(data); Recipe val3 = (Recipe)((value6 is Recipe) ? value6 : null); if (val3 != null) { _cachedRecipeFields[type] = field; return val3; } } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(Recipe)) { _cachedRecipeFields[type] = fieldInfo; object? value7 = fieldInfo.GetValue(data); return (Recipe)((value7 is Recipe) ? value7 : null); } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.PropertyType == typeof(Recipe) && propertyInfo.CanRead) { _cachedRecipeProps[type] = propertyInfo; object? value8 = propertyInfo.GetValue(data, null); return (Recipe)((value8 is Recipe) ? value8 : null); } } return null; } private ItemData GetItemDataFromObject(object data) { if (data == null) { return null; } Type type = data.GetType(); if (_cachedItemFields.TryGetValue(type, out var value)) { object? value2 = value.GetValue(data); return (ItemData)((value2 is ItemData) ? value2 : null); } if (_cachedItemProps.TryGetValue(type, out var value3)) { object? value4 = value3.GetValue(data, null); return (ItemData)((value4 is ItemData) ? value4 : null); } PropertyInfo property = type.GetProperty("Value"); if (property != null) { object? value5 = property.GetValue(data, null); ItemData val = (ItemData)((value5 is ItemData) ? value5 : null); if (val != null) { _cachedItemProps[type] = property; return val; } } PropertyInfo property2 = type.GetProperty("Item2"); if (property2 != null) { object? value6 = property2.GetValue(data, null); ItemData val2 = (ItemData)((value6 is ItemData) ? value6 : null); if (val2 != null) { _cachedItemProps[type] = property2; return val2; } } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(ItemData)) { _cachedItemFields[type] = fieldInfo; object? value7 = fieldInfo.GetValue(data); return (ItemData)((value7 is ItemData) ? value7 : null); } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.PropertyType == typeof(ItemData) && propertyInfo.CanRead) { _cachedItemProps[type] = propertyInfo; object? value8 = propertyInfo.GetValue(data, null); return (ItemData)((value8 is ItemData) ? value8 : null); } } return null; } private string ExtractTextFromUI(Transform child) { Text componentInChildren = ((Component)child).GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null) { return componentInChildren.text; } Component[] componentsInChildren = ((Component)child).GetComponentsInChildren<Component>(true); Component[] array = componentsInChildren; foreach (Component val in array) { if (!((object)val).GetType().Name.Contains("TextMeshPro") && !((object)val).GetType().Name.Contains("TMP_Text")) { continue; } PropertyInfo property = ((object)val).GetType().GetProperty("text"); if (property != null) { string text = property.GetValue(val, null) as string; if (!string.IsNullOrEmpty(text)) { return text; } } } return null; } private string GetRawRecipeName(Recipe r) { if ((Object)(object)r.m_item != (Object)null && r.m_item.m_itemData != null) { return r.m_item.m_itemData.m_shared.m_name; } ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.GetPrefab(((Object)r).name) : null); if ((Object)(object)val != (Object)null) { ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component != (Object)null) { return component.m_itemData.m_shared.m_name; } Piece component2 = val.GetComponent<Piece>(); if ((Object)(object)component2 != (Object)null) { return component2.m_name; } } return null; } private bool IsVisibleInScroll(RectTransform item, ScrollRect scrollRect) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: 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_00e3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)item == (Object)null || !((Component)item).gameObject.activeInHierarchy) { return false; } if ((Object)(object)scrollRect == (Object)null || (Object)(object)scrollRect.viewport == (Object)null) { return true; } Vector3[] array = (Vector3[])(object)new Vector3[4]; scrollRect.viewport.GetWorldCorners(array); Rect val = default(Rect); ((Rect)(ref val))..ctor(array[0].x, array[0].y, array[2].x - array[0].x, array[2].y - array[0].y); Vector3[] array2 = (Vector3[])(object)new Vector3[4]; item.GetWorldCorners(array2); Vector3 val2 = (array2[0] + array2[2]) / 2f; return ((Rect)(ref val)).Contains(val2); } } [BepInPlugin("com.Kadrio.RecipePinner", "Recipe Pinner", "1.2.1")] public class RecipePinnerPlugin : BaseUnityPlugin { public enum PinLayoutMode { AutoDetect, ForceVertical, ForceHorizontal, ForceBottomRightHorizontal } public class ConfigurationManagerAttributes { public bool? ShowRangeAsPercent; public Action<ConfigEntryBase> CustomDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func<object, string> ObjToStr; public Func<string, object> StrToObj; } public static RecipePinnerPlugin Instance; public static ConfigEntry<bool> EnableMod; public static ConfigEntry<string> LanguageOverride; public static ConfigEntry<PinLayoutMode> LayoutModeConfig; public static ConfigEntry<int> MaximumPins; public static ConfigEntry<int> PinsPerPage; public static ConfigEntry<bool> AutoUnpinAfterCrafting; public static ConfigEntry<bool> EnableGatheringList; public static ConfigEntry<bool> AutoOpenGatheringList; public static ConfigEntry<KeyCode> HotkeyPin; public static ConfigEntry<KeyCode> HotkeyClearAll; public static ConfigEntry<KeyCode> HotkeyToggleVisibility; public static ConfigEntry<KeyCode> HotkeyPageSwitch; public static ConfigEntry<KeyCode> HotkeyGatheringList; public static ConfigEntry<bool> EnableChestScanning; public static ConfigEntry<float> ChestScanRange; public static ConfigEntry<float> ChestScanInterval; public static ConfigEntry<float> UIScale; public static ConfigEntry<int> FontSizeRecipeName; public static ConfigEntry<int> FontSizeMaterials; public static ConfigEntry<float> BackgroundOpacity; public static ConfigEntry<Color> ColorHeader; public static ConfigEntry<Color> ColorEnoughInInventory; public static ConfigEntry<Color> ColorEnoughWithChests; public static ConfigEntry<Color> ColorMissing; public static ConfigEntry<Color> ColorPaginationActive; public static ConfigEntry<float> PaginationInactiveOpacity; public static ConfigEntry<int> PaginationDotSize; public static ConfigEntry<int> PaginationDotSpacing; public static ConfigEntry<bool> EnableCraftReadiness; public static ConfigEntry<Color> ColorCraftReady; public static ConfigEntry<Color> ColorCraftNotReady; public static ConfigEntry<int> GatheringListFontSizeTitle; public static ConfigEntry<int> GatheringListFontSizeMaterials; public static ConfigEntry<float> VerticalListWidth; public static ConfigEntry<float> VerticalPinSpacing; public static ConfigEntry<Vector2> VerticalPosition; public static ConfigEntry<float> HorizontalColumnWidth; public static ConfigEntry<float> HorizontalPinSpacing; public static ConfigEntry<Vector2> HorizontalPosition; public static ConfigEntry<float> BottomRightColumnWidth; public static ConfigEntry<float> BottomRightPinSpacing; public static ConfigEntry<Vector2> BottomRightPosition; public static ConfigEntry<bool> EnableDebugLogging; public static ConfigEntry<Vector2> InventoryGatheringListPosition; public LocalizationManager LocalizationMgr; public RecipeManager RecipeMgr; public ContainerScanner ContainerMgr; public UIManager UIMgr; public DataPersistence DataMgr; internal bool _mluiMapListEnabled = false; internal bool _mluiNoMapListEnabled = false; internal bool _mluiInstalled = false; private bool _startupInitialized = false; private string _lastLanguage = ""; private string _currentSessionPlayer = null; private static bool _isUiVisible = true; public bool IsHorizontalMode { get { if (LayoutModeConfig.Value == PinLayoutMode.ForceBottomRightHorizontal) { return true; } if (LayoutModeConfig.Value == PinLayoutMode.ForceHorizontal) { return true; } if (LayoutModeConfig.Value == PinLayoutMode.ForceVertical) { return false; } if (!_mluiInstalled) { return false; } if (Game.m_noMap) { return _mluiNoMapListEnabled; } return _mluiMapListEnabled; } } private void Awake() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown Instance = this; BindConfigs(); DebugLogger.Log("Plugin init"); LocalizationMgr = new LocalizationManager(this); RecipeMgr = new RecipeManager(); ContainerMgr = new ContainerScanner(); UIMgr = new UIManager(); DataMgr = new DataPersistence(); DebugLogger.Log("Managers ready"); Harmony val = new Harmony("com.Kadrio.RecipePinner"); val.PatchAll(typeof(RecipePinnerPlugin)); val.PatchAll(typeof(ContainerScanner)); DebugLogger.Log("Patches applied"); } private void BindConfigs() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Expected O, but got Unknown //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Expected O, but got Unknown //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Expected O, but got Unknown //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Expected O, but got Unknown //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Expected O, but got Unknown //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Expected O, but got Unknown //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Expected O, but got Unknown //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Expected O, but got Unknown //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_03f7: Expected O, but got Unknown //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Expected O, but got Unknown //IL_0498: Unknown result type (might be due to invalid IL or missing references) //IL_04a2: Expected O, but got Unknown //IL_04eb: Unknown result type (might be due to invalid IL or missing references) //IL_04f5: Expected O, but got Unknown //IL_053e: Unknown result type (might be due to invalid IL or missing references) //IL_0548: Expected O, but got Unknown //IL_05a8: Unknown result type (might be due to invalid IL or missing references) //IL_05b2: Expected O, but got Unknown //IL_05ea: Unknown result type (might be due to invalid IL or missing references) //IL_05f4: Expected O, but got Unknown //IL_0643: Unknown result type (might be due to invalid IL or missing references) //IL_064d: Expected O, but got Unknown //IL_069c: Unknown result type (might be due to invalid IL or missing references) //IL_06a6: Expected O, but got Unknown //IL_06f5: Unknown result type (might be due to invalid IL or missing references) //IL_06ff: Expected O, but got Unknown //IL_074d: Unknown result type (might be due to invalid IL or missing references) //IL_0757: Expected O, but got Unknown //IL_0797: Unknown result type (might be due to invalid IL or missing references) //IL_07bd: Unknown result type (might be due to invalid IL or missing references) //IL_07c7: Expected O, but got Unknown //IL_0807: Unknown result type (might be due to invalid IL or missing references) //IL_082d: Unknown result type (might be due to invalid IL or missing references) //IL_0837: Expected O, but got Unknown //IL_0877: Unknown result type (might be due to invalid IL or missing references) //IL_089d: Unknown result type (might be due to invalid IL or missing references) //IL_08a7: Expected O, but got Unknown //IL_08e7: Unknown result type (might be due to invalid IL or missing references) //IL_090d: Unknown result type (might be due to invalid IL or missing references) //IL_0917: Expected O, but got Unknown //IL_0957: Unknown result type (might be due to invalid IL or missing references) //IL_097d: Unknown result type (might be due to invalid IL or missing references) //IL_0987: Expected O, but got Unknown //IL_09c7: Unknown result type (might be due to invalid IL or missing references) //IL_09ed: Unknown result type (might be due to invalid IL or missing references) //IL_09f7: Expected O, but got Unknown //IL_0a37: Unknown result type (might be due to invalid IL or missing references) //IL_0a5d: Unknown result type (might be due to invalid IL or missing references) //IL_0a67: Expected O, but got Unknown //IL_0ac7: Unknown result type (might be due to invalid IL or missing references) //IL_0ad1: Expected O, but got Unknown //IL_0b27: Unknown result type (might be due to invalid IL or missing references) //IL_0b31: Expected O, but got Unknown //IL_0b86: Unknown result type (might be due to invalid IL or missing references) //IL_0b90: Expected O, but got Unknown //IL_0be2: Unknown result type (might be due to invalid IL or missing references) //IL_0bec: Expected O, but got Unknown //IL_0c27: Unknown result type (might be due to invalid IL or missing references) //IL_0c31: Expected O, but got Unknown //IL_0c50: Unknown result type (might be due to invalid IL or missing references) //IL_0c76: Unknown result type (might be due to invalid IL or missing references) //IL_0c80: Expected O, but got Unknown //IL_0cbb: Unknown result type (might be due to invalid IL or missing references) //IL_0cc5: Expected O, but got Unknown //IL_0d00: Unknown result type (might be due to invalid IL or missing references) //IL_0d0a: Expected O, but got Unknown //IL_0d29: Unknown result type (might be due to invalid IL or missing references) //IL_0d4f: Unknown result type (might be due to invalid IL or missing references) //IL_0d59: Expected O, but got Unknown //IL_0d94: Unknown result type (might be due to invalid IL or missing references) //IL_0d9e: Expected O, but got Unknown //IL_0dd9: Unknown result type (might be due to invalid IL or missing references) //IL_0de3: Expected O, but got Unknown //IL_0e02: Unknown result type (might be due to invalid IL or missing references) //IL_0e28: Unknown result type (might be due to invalid IL or missing references) //IL_0e32: Expected O, but got Unknown //IL_0e51: Unknown result type (might be due to invalid IL or missing references) //IL_0e77: Unknown result type (might be due to invalid IL or missing references) //IL_0e81: Expected O, but got Unknown //IL_0eb8: Unknown result type (might be due to invalid IL or missing references) //IL_0ec2: Expected O, but got Unknown EnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "EnableMod", true, new ConfigDescription("Enable or disable the mod completely.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); EnableMod.SettingChanged += delegate { if (!EnableMod.Value) { UIMgr?.DestroyUI(); } }; LanguageOverride = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "LanguageOverride", "Auto", new ConfigDescription("Force a specific language (e.g., 'German', 'Turkish').", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 98 } })); LanguageOverride.SettingChanged += delegate { LocalizationMgr?.LoadTranslations(); RecipeMgr?.RefreshRecipeCache(); UIMgr?.DestroyUI(); }; LayoutModeConfig = ((BaseUnityPlugin)this).Config.Bind<PinLayoutMode>("1 - General", "LayoutMode", PinLayoutMode.AutoDetect, new ConfigDescription("Choose layout position.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 97 } })); LayoutModeConfig.SettingChanged += delegate { UIMgr?.DestroyUI(); }; MaximumPins = ((BaseUnityPlugin)this).Config.Bind<int>("1 - General", "MaximumPins", 10, new ConfigDescription("Max pins allowed.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), new object[1] { new ConfigurationManagerAttributes { Order = 96 } })); MaximumPins.SettingChanged += delegate { UIMgr?.DestroyUI(); }; PinsPerPage = ((BaseUnityPlugin)this).Config.Bind<int>("1 - General", "PinsPerPage", 5, new ConfigDescription("How many pins to show per page.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), new object[1] { new ConfigurationManagerAttributes { Order = 95 } })); PinsPerPage.SettingChanged += delegate { UIMgr?.ResetPage(); UIMgr?.DestroyUI(); }; AutoUnpinAfterCrafting = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "AutoUnpinAfterCrafting", true, new ConfigDescription("Unpin after crafting.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 94 } })); EnableGatheringList = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "EnableGatheringList", true, new ConfigDescription("Enable the gathering list feature.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 93 } })); EnableGatheringList.SettingChanged += delegate { UIMgr?.DestroyUI(); }; AutoOpenGatheringList = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "AutoOpenGatheringList", true, new ConfigDescription("Automatically open gathering list when 2+ recipes are pinned.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 92 } })); HotkeyPin = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("2 - Controls", "HotkeyPin", (KeyCode)325, new ConfigDescription("Key to pin recipe.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); HotkeyToggleVisibility = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("2 - Controls", "HotkeyToggleVisibility", (KeyCode)288, new ConfigDescription("Key to toggle overlay.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 98 } })); HotkeyGatheringList = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("2 - Controls", "HotkeyGatheringList", (KeyCode)289, new ConfigDescription("Key to toggle gathering list panel.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 97 } })); HotkeyPageSwitch = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("2 - Controls", "HotkeyPageSwitch", (KeyCode)308, new ConfigDescription("Key to cycle through pin pages.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 96 } })); HotkeyClearAll = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("2 - Controls", "HotkeyClearAll", (KeyCode)112, new ConfigDescription("Key to clear all pins.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 95 } })); EnableChestScanning = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Chest Scanner", "EnableChestScanning", false, new ConfigDescription("Count materials in nearby chests.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); EnableChestScanning.SettingChanged += delegate { RecipeMgr?.RefreshRecipeCache(); }; ChestScanRange = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Chest Scanner", "ChestScanRange", 20f, new ConfigDescription("Scan radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), new object[1] { new ConfigurationManagerAttributes { Order = 98 } })); ChestScanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Chest Scanner", "ChestScanInterval", 3f, new ConfigDescription("Scan frequency (seconds).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), new object[1] { new ConfigurationManagerAttributes { Order = 97 } })); UIScale = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Appearance", "UIScale", 0.75f, new ConfigDescription("Global UI scale.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); UIScale.SettingChanged += delegate { UIMgr?.DestroyUI(); }; BackgroundOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Appearance", "BackgroundOpacity", 0.5f, new ConfigDescription("Background opacity.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { new ConfigurationManagerAttributes { Order = 98 } })); FontSizeRecipeName = ((BaseUnityPlugin)this).Config.Bind<int>("4 - Appearance", "FontSizeRecipeName", 16, new ConfigDescription("Recipe name font size.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 97 } })); FontSizeRecipeName.SettingChanged += delegate { RecipeMgr?.RefreshRecipeCache(); }; FontSizeMaterials = ((BaseUnityPlugin)this).Config.Bind<int>("4 - Appearance", "FontSizeMaterials", 15, new ConfigDescription("Material font size.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 96 } })); FontSizeMaterials.SettingChanged += delegate { RecipeMgr?.RefreshRecipeCache(); }; GatheringListFontSizeTitle = ((BaseUnityPlugin)this).Config.Bind<int>("4 - Appearance", "GatheringListFontSizeTitle", 20, new ConfigDescription("Gathering list title font size.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 95 } })); GatheringListFontSizeTitle.SettingChanged += delegate { UIMgr?.DestroyUI(); }; GatheringListFontSizeMaterials = ((BaseUnityPlugin)this).Config.Bind<int>("4 - Appearance", "GatheringListFontSizeMaterials", 15, new ConfigDescription("Gathering list material font size.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 94 } })); GatheringListFontSizeMaterials.SettingChanged += delegate { UIMgr?.DestroyUI(); }; EnableCraftReadiness = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Appearance", "EnableCraftReadiness", true, new ConfigDescription("Show a colored accent bar indicating craft readiness.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 93 } })); EnableCraftReadiness.SettingChanged += delegate { RecipeMgr?.RefreshRecipeCache(); }; ColorHeader = ((BaseUnityPlugin)this).Config.Bind<Color>("5 - Colors", "ColorHeader", new Color(1f, 0.717f, 0.368f, 1f), new ConfigDescription("Recipe title color.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); ColorHeader.SettingChanged += delegate { RecipeMgr?.RefreshRecipeCache(); }; ColorEnoughInInventory = ((BaseUnityPlugin)this).Config.Bind<Color>("5 - Colors", "ColorEnoughInInventory", new Color(0f, 1f, 0f, 1f), new ConfigDescription("Color: Enough in inventory.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 98 } })); ColorEnoughInInventory.SettingChanged += delegate { RecipeMgr?.RefreshRecipeCache(); }; ColorEnoughWithChests = ((BaseUnityPlugin)this).Config.Bind<Color>("5 - Colors", "ColorEnoughWithChests", new Color(1f, 1f, 0f, 1f), new ConfigDescription("Color: Enough with chests.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 97 } })); ColorEnoughWithChests.SettingChanged += delegate { RecipeMgr?.RefreshRecipeCache(); }; ColorMissing = ((BaseUnityPlugin)this).Config.Bind<Color>("5 - Colors", "ColorMissing", new Color(1f, 0.33f, 0.33f, 1f), new ConfigDescription("Color: Missing materials.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 96 } })); ColorMissing.SettingChanged += delegate { RecipeMgr?.RefreshRecipeCache(); }; ColorCraftReady = ((BaseUnityPlugin)this).Config.Bind<Color>("5 - Colors", "ColorCraftReady", new Color(0.2f, 0.9f, 0.3f, 0.85f), new ConfigDescription("Accent bar color when all materials are available.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 95 } })); ColorCraftReady.SettingChanged += delegate { RecipeMgr?.RefreshRecipeCache(); }; ColorCraftNotReady = ((BaseUnityPlugin)this).Config.Bind<Color>("5 - Colors", "ColorCraftNotReady", new Color(0.9f, 0.25f, 0.25f, 0.5f), new ConfigDescription("Accent bar color when materials are missing.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 94 } })); ColorCraftNotReady.SettingChanged += delegate { RecipeMgr?.RefreshRecipeCache(); }; ColorPaginationActive = ((BaseUnityPlugin)this).Config.Bind<Color>("6 - Pagination", "ColorPaginationActive", new Color(1f, 0.717f, 0.368f, 1f), new ConfigDescription("Active page dot color.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); ColorPaginationActive.SettingChanged += delegate { UIMgr?.UpdateUI(isVisible: true); }; PaginationInactiveOpacity = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Pagination", "PaginationInactiveOpacity", 0.3f, new ConfigDescription("Opacity of inactive page dots.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), new object[1] { new ConfigurationManagerAttributes { Order = 98 } })); PaginationInactiveOpacity.SettingChanged += delegate { UIMgr?.UpdateUI(isVisible: true); }; PaginationDotSize = ((BaseUnityPlugin)this).Config.Bind<int>("6 - Pagination", "PaginationDotSize", 10, new ConfigDescription("Size of the pagination squares.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 20), new object[1] { new ConfigurationManagerAttributes { Order = 97 } })); PaginationDotSize.SettingChanged += delegate { UIMgr?.UpdateUI(isVisible: true); }; PaginationDotSpacing = ((BaseUnityPlugin)this).Config.Bind<int>("6 - Pagination", "PaginationDotSpacing", 8, new ConfigDescription("Space between pagination squares.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 20), new object[1] { new ConfigurationManagerAttributes { Order = 96 } })); PaginationDotSpacing.SettingChanged += delegate { UIMgr?.UpdateUI(isVisible: true); }; VerticalListWidth = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Layout (Vertical Mode)", "ListWidth", 265f, new ConfigDescription("List width.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); VerticalPinSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Layout (Vertical Mode)", "PinSpacing", 10f, new ConfigDescription("Spacing between pins.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 98 } })); VerticalPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("7 - Layout (Vertical Mode)", "Position", new Vector2(-40f, -250f), new ConfigDescription("Position (X, Y).", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 97 } })); HorizontalColumnWidth = ((BaseUnityPlugin)this).Config.Bind<float>("8 - Layout (Horizontal - Map Side)", "ColumnWidth", 265f, new ConfigDescription("Column width.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); HorizontalPinSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("8 - Layout (Horizontal - Map Side)", "PinSpacing", 10f, new ConfigDescription("Spacing between pins.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 98 } })); HorizontalPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("8 - Layout (Horizontal - Map Side)", "Position", new Vector2(-250f, -40f), new ConfigDescription("Position (X, Y).", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 97 } })); BottomRightColumnWidth = ((BaseUnityPlugin)this).Config.Bind<float>("9 - Layout (Horizontal - Bottom Right)", "ColumnWidth", 265f, new ConfigDescription("Column width.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); BottomRightPinSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("9 - Layout (Horizontal - Bottom Right)", "PinSpacing", 10f, new ConfigDescription("Spacing between pins.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 98 } })); BottomRightPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("9 - Layout (Horizontal - Bottom Right)", "Position", new Vector2(-40f, 40f), new ConfigDescription("Position (X, Y).", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 97 } })); InventoryGatheringListPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("1 - General", "InventoryGatheringListPosition", new Vector2(-1680f, 1150f), new ConfigDescription("Gathering list position offset (X, Y) when inventory/chest is open.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 91 } })); EnableDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("10 - Debug", "EnableDebugLogging", false, new ConfigDescription("Enable debug logs.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 99 } })); DebugLogger.Log("Config loaded"); } private void Start() { DebugLogger.Log("Start()"); LocalizationMgr.LoadTranslations(); ReadMyLittleUIConfig(); ContainerMgr.InitializeContainers(); DebugLogger.Log("Start done"); } private void OnDestroy() { DebugLogger.Log("OnDestroy"); if ((Object)(object)Player.m_localPlayer != (Object)null) { DataMgr.SavePins(); } RecipeMgr.Cleanup(); } private void Update() { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) if (!EnableMod.Value) { return; } ReflectionHelper.UpdateGuiScale(); if (!_startupInitialized && (Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_recipes.Count > 0) { DebugLogger.Log("First init"); _lastLanguage = Localization.instance.GetSelectedLanguage(); DataMgr.LoadPins(); RecipeMgr.ValidateAndCleanPins(); RecipeMgr.RefreshRecipeCache(); _startupInitialized = true; DebugLogger.Log($"Init done - {RecipeMgr.PinnedRecipes.Count} pins loaded"); } if (EnableChestScanning.Value && (Object)(object)Player.m_localPlayer != (Object)null && RecipeMgr.CachedPins.Count > 0) { ContainerMgr.UpdateScanning(); } if (Input.GetKeyDown(HotkeyToggleVisibility.Value) && !InputHelper.IsInputBlocked()) { _isUiVisible = !_isUiVisible; DebugLogger.Log($"UI visibility toggled: {_isUiVisible}"); } if ((Object)(object)Player.m_localPlayer != (Object)null) { UpdatePlayerSession(); } if (Input.GetKeyDown(HotkeyPin.Value)) { if ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible()) { RecipeMgr.TryPinHoveredRecipe(InventoryGui.instance); } else if ((Object)(object)Hud.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null && ((Character)Player.m_localPlayer).InPlaceMode()) { RecipeMgr.TryPinHoveredPiece(); } } if (Input.GetKeyDown(HotkeyClearAll.Value) && !InputHelper.IsInputBlocked() && RecipeMgr.PinnedRecipes.Count > 0) { int count = RecipeMgr.PinnedRecipes.Count; RecipeMgr.PinnedRecipes.Clear(); RecipeMgr.RefreshRecipeCache(); UIMgr.CloseGatheringList(); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, LocalizationMgr.GetText("cleared"), 0, (Sprite)null); } DebugLogger.Log($"Cleared {count} pinned recipes"); } if (Localization.instance != null) { string selectedLanguage = Localization.instance.GetSelectedLanguage(); if (_lastLanguage != selectedLanguage) { DebugLogger.Log("Language changed from " + _lastLanguage + " to " + selectedLanguage); _lastLanguage = selectedLanguage; LocalizationMgr.LoadTranslations(); if ((Object)(object)ObjectDB.instance != (Object)null) { RecipeMgr.RefreshRecipeCache(); } UIMgr?.DestroyUI(); } } if (Input.GetKeyDown(HotkeyPageSwitch.Value) && _isUiVisible && !InputHelper.IsInputBlocked()) { UIMgr?.CyclePage(); } if (Input.GetKeyDown(HotkeyGatheringList.Value) && !InputHelper.IsInputBlocked() && EnableGatheringList.Value) { UIMgr?.ToggleGatheringList(); } } private void UpdatePlayerSession() { if ((Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).IsDead()) { return; } string playerName = Player.m_localPlayer.GetPlayerName(); if (string.IsNullOrEmpty(playerName)) { return; } if (_currentSessionPlayer != playerName) { DebugLogger.Log("Player session changed from '" + _currentSessionPlayer + "' to '" + playerName + "'"); RecipeMgr.PinnedRecipes.Clear(); RecipeMgr.CachedPins.Clear(); UIMgr.DestroyUI(); _currentSessionPlayer = playerName; if (!string.IsNullOrEmpty(playerName)) { DataMgr.LoadPins(); RecipeMgr.RefreshRecipeCache(); } } UIMgr.UpdateUI(_isUiVisible); } private void ReadMyLittleUIConfig() { if (!Chainloader.PluginInfos.ContainsKey("shudnal.MyLittleUI")) { _mluiInstalled = false; DebugLogger.Log("MyLittleUI not detected"); return; } _mluiInstalled = true; _mluiMapListEnabled = true; _mluiNoMapListEnabled = true; string path = Path.Combine(Paths.ConfigPath, "shudnal.MyLittleUI.cfg"); if (!File.Exists(path)) { DebugLogger.Log("MyLittleUI installed but config not found"); return; } try { string[] array = File.ReadAllLines(path); string text = ""; string[] array2 = array; foreach (string text2 in array2) { string text3 = text2.Trim(); if (text3.StartsWith("[") && text3.EndsWith("]")) { text = text3; } else if (text3.StartsWith("Enable")) { bool flag = text3.ToLower().Contains("true"); if (text == "[Status effects - Map - List]") { _mluiMapListEnabled = flag; } else if (text == "[Status effects - Nomap - List]") { _mluiNoMapListEnabled = flag; } } } DebugLogger.Log($"MyLittleUI Config: MapList={_mluiMapListEnabled}, NoMapList={_mluiNoMapListEnabled}"); } catch (Exception ex) { Debug.LogWarning((object)("[RecipePinner] Error reading MyLittleUI config: " + ex.Message)); } } [HarmonyPatch(typeof(Game), "SavePlayerProfile")] [HarmonyPostfix] public static void AutoSavePinsHook() { if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)Instance != (Object)null) { DebugLogger.Log("Auto-saving pins"); Instance.DataMgr.SavePins(); } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] [HarmonyPostfix] public static void AutoUnpinHook(InventoryGui __instance) { if (!EnableMod.Value || !AutoUnpinAfterCrafting.Value || (Object)(object)Instance == (Object)null) { return; } Recipe craftRecipe = ReflectionHelper.GetCraftRecipe(__instance); if (!((Object)(object)craftRecipe != (Object)null)) { return; } string text = null; if (!((Selectable)__instance.m_tabUpgrade).interactable) { ItemData craftUpgradeItem = ReflectionHelper.GetCraftUpgradeItem(__instance); if (craftUpgradeItem != null) { string name = ((Object)craftRecipe.m_item).name; int quality = craftUpgradeItem.m_quality; int num = quality + 1; text = $"{name} ★{num}"; DebugLogger.Log($"Upgrade crafted: Unpinning target {text} (Base Level: {quality})"); } } else { text = ((Object)craftRecipe).name; } if (text != null && Instance.RecipeMgr.PinnedRecipes.TryGetValue(text, out var value)) { value--; DebugLogger.Log($"Auto-unpin: {text}, remaining count: {value}"); if (value <= 0) { Instance.RecipeMgr.PinnedRecipes.Remove(text); DebugLogger.Log("Recipe " + text + " fully unpinned"); } else { Instance.RecipeMgr.PinnedRecipes[text] = value; } Instance.RecipeMgr.RefreshRecipeCache(); if (Instance.RecipeMgr.PinnedRecipes.Count < 2) { Instance.UIMgr.CloseGatheringList(); } } } [HarmonyPatch(typeof(Player), "ConsumeResources")] [HarmonyPostfix] public static void AutoUnpinBuildHook() { if ((Object)(object)Instance == (Object)null || !EnableMod.Value || !AutoUnpinAfterCrafting.Value) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } PieceTable pieceTable = ReflectionHelper.GetPieceTable(localPlayer); if ((Object)(object)pieceTable == (Object)null) { return; } Piece selectedPiece = pieceTable.GetSelectedPiece(); if ((Object)(object)selectedPiece == (Object)null) { return; } string text = ((Object)selectedPiece).name.Replace("(Clone)", "").Trim(); if (Instance.RecipeMgr.PinnedRecipes.TryGetValue(text, out var value)) { value--; DebugLogger.Log($"Auto-unpin (Build): {text}, remaining count: {value}"); if (value <= 0) { Instance.RecipeMgr.PinnedRecipes.Remove(text); DebugLogger.Log("Build recipe " + text + " fully unpinned"); } else { Instance.RecipeMgr.PinnedRecipes[text] = value; } Instance.RecipeMgr.RefreshRecipeCache(); if (Instance.RecipeMgr.PinnedRecipes.Count < 2) { Instance.UIMgr.CloseGatheringList(); } } } } public static class ReflectionHelper { private static Func<float> _getGuiScale; private static Func<InventoryGui, Transform> _getRecipeListRoot; private static Func<InventoryGui, object> _getAvailableRecipes; private static Func<InventoryGui, Container> _getCurrentContainer; private static Func<InventoryGui, Recipe> _getCraftRecipe; private static Func<InventoryGui, ItemData> _getCraftUpgradeItem; private static Func<Hud, Piece> _getHoveredPiece; public static Func<Container, long, bool> CheckContainerAccess; private static FieldInfo _f_buildPieces; public static float currentGuiScaleValue; static ReflectionHelper() { currentGuiScaleValue = 1f; InitializeReflection(); } public static void InitializeReflection() { DebugLogger.Log("Reflection init"); int num = 0; int num2 = 0; try { FieldInfo fieldInfo = AccessTools.Field(typeof(GuiScaler), "m_largeGuiScale"); if (fieldInfo != null && fieldInfo.IsStatic) { _getGuiScale = Expression.Lambda<Func<float>>(Expression.Field(null, fieldInfo), Array.Empty<ParameterExpression>()).Compile(); num++; DebugLogger.Verbose("✓ GuiScaler.m_largeGuiScale"); } else { num2++; DebugLogger.Warning("✗ GuiScaler.m_largeGuiScale not found"); } FieldInfo fieldInfo2 = AccessTools.Field(typeof(InventoryGui), "m_recipeListRoot"); if (fieldInfo2 != null) { ParameterExpression parameterExpression = Expression.Parameter(typeof(InventoryGui), "arg"); _getRecipeListRoot = Expression.Lambda<Func<InventoryGui, Transform>>(Expression.Field(parameterExpression, fieldInfo2), new ParameterExpression[1] { parameterExpression }).Compile(); num++; DebugLogger.Verbose("✓ InventoryGui.m_recipeListRoot"); } else { num2++; DebugLogger.Warning("✗ InventoryGui.m_recipeListRoot not found"); } FieldInfo fieldInfo3 = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes"); if (fieldInfo3 != null) { ParameterExpression parameterExpression2 = Expression.Parameter(typeof(InventoryGui), "arg"); _getAvailableRecipes = Expression.Lambda<Func<InventoryGui, object>>(Expression.Field(parameterExpression2, fieldInfo3), new ParameterExpression[1] { parameterExpression2 }).Compile(); num++; DebugLogger.Verbose("✓ InventoryGui.m_availableRecipes"); } else { num2++; DebugLogger.Warning("✗ InventoryGui.m_availableRecipes not found"); } FieldInfo fieldInfo4 = AccessTools.Field(typeof(InventoryGui), "m_currentContainer"); if (fieldInfo4 != null) { ParameterExpression parameterExpression3 = Expression.Parameter(typeof(InventoryGui), "arg"); _getCurrentContainer = Expression.Lambda<Func<InventoryGui, Container>>(Expression.Field(parameterExpression3, fieldInfo4), new ParameterExpression[1] { parameterExpression3 }).Compile(); num++; DebugLogger.Verbose("✓ InventoryGui.m_currentContainer"); } else { num2++; DebugLogger.Warning("✗ InventoryGui.m_currentContainer not found"); } FieldInfo fieldInfo5 = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe"); if (fieldInfo5 != null) { ParameterExpression parameterExpression4 = Expression.Parameter(typeof(InventoryGui), "arg"); _getCraftRecipe = Expression.Lambda<Func<InventoryGui, Recipe>>(Expression.Field(parameterExpression4, fieldInfo5), new ParameterExpression[1] { parameterExpression4 }).Compile(); num++; DebugLogger.Verbose("✓ InventoryGui.m_craftRecipe"); } else { num2++; DebugLogger.Warning("✗ InventoryGui.m_craftRecipe not found"); } FieldInfo fieldInfo6 = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem"); if (fieldInfo6 != null) { ParameterExpression parameterExpression5 = Expression.Parameter(typeof(InventoryGui), "arg"); _getCraftUpgradeItem = Expression.Lambda<Func<InventoryGui, ItemData>>(Expression.Field(parameterExpression5, fieldInfo6), new ParameterExpression[1] { parameterExpression5 }).Compile(); num++; DebugLogger.Verbose("✓ InventoryGui.m_craftUpgradeItem"); } else { num2++; DebugLogger.Warning("✗ InventoryGui.m_craftUpgradeItem not found"); } FieldInfo fieldInfo7 = AccessTools.Field(typeof(Hud), "m_hoveredPiece"); if (fieldInfo7 != null) { ParameterExpression parameterExpression6 = Expression.Parameter(typeof(Hud), "arg"); _getHoveredPiece = Expression.Lambda<Func<Hud, Piece>>(Expression.Field(parameterExpression6, fieldInfo7), new ParameterExpression[1] { parameterExpression6 }).Compile(); num++; DebugLogger.Verbose("✓ Hud.m_hoveredPiece"); } else { num2++; DebugLogger.Warning("✗ Hud.m_hoveredPiece not found"); } MethodInfo methodInfo = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); if (methodInfo != null) { CheckContainerAccess = AccessTools.MethodDelegate<Func<Container, long, bool>>(methodInfo, (object)null, true); num++; DebugLogger.Verbose("✓ Container.CheckAccess"); } else { num2++; DebugLogger.Warning("✗ Container.CheckAccess not found"); } DebugLogger.Log($"Reflection done: {num} ok, {num2} failed"); if (num2 > 0) { DebugLogger.Warning("Some reflection targets failed"); } _f_buildPieces = AccessTools.Field(typeof(Player), "m_buildPieces"); if (_f_buildPieces != null) { num++; DebugLogger.Verbose("✓ Player.m_buildPieces"); } else { num2++; DebugLogger.Warning("✗ Player.m_buildPieces not found"); } } catch (Exception ex) { DebugLogger.Error("Reflection init failed", ex); } } public static void UpdateGuiScale() { if (_getGuiScale != null) { currentGuiScaleValue = _getGuiScale(); } else { currentGuiScaleValue = 1f; } } public static Transform GetRecipeListRoot(InventoryGui gui) { if (_getRecipeListRoot == null) { DebugLogger.Warning("GetRecipeListRoot delegate is null"); return null; } return _getRecipeListRoot(gui); } public static object GetAvailableRecipes(InventoryGui gui) { if (_getAvailableRecipes == null) { DebugLogger.Warning("GetAvailableRecipes delegate is null"); return null; } return _getAvailableRecipes(gui); } public static Container GetCurrentContainer(InventoryGui gui) { if (_getCurrentContainer == null) { DebugLogger.Verbose("GetCurrentContainer delegate is null"); return null; } return _getCurrentContainer(gui); } public static Recipe GetCraftRecipe(InventoryGui gui) { if (_getCraftRecipe == null) { DebugLogger.Warning("GetCraftRecipe delegate is null"); return null; } return _getCraftRecipe(gui); } public static ItemData GetCraftUpgradeItem(InventoryGui gui) { return _getCraftUpgradeItem?.Invoke(gui); } public static Piece GetHoveredPiece(Hud hud) { if (_getHoveredPiece == null) { DebugLogger.Verbose("GetHoveredPiece delegate is null"); return null; } return _getHoveredPiece(hud); } public static PieceTable GetPieceTable(Player player) { if (_f_buildPieces == null || (Object)(object)player == (Object)null) { return null; } object? value = _f_buildPieces.GetValue(player); return (PieceTable)((value is PieceTable) ? value : null); } } public static class InputHelper { public static bool IsInputBlocked() { if (Console.IsVisible()) { return true; } if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return true; } if (TextInput.IsVisible()) { DebugLogger.Verbose("Input blocked: TextInput is visible"); return true; } return false; } public static bool IsMouseOverRect(RectTransform rect) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)rect == (Object)null) { DebugLogger.Verbose("IsMouseOverRect: rect is null"); return false; } bool flag = RectTransformUtility.RectangleContainsScreenPoint(rect, Vector2.op_Implicit(Input.mousePosition)); if (flag) { DebugLogger.Verbose("Mouse over rect: " + ((Object)((Component)rect).gameObject).name); } return flag; } } public class GatheringItemUI : MonoBehaviour { public Image Icon; public Text AmountText; public void SetActive(bool active) { ((Component)this).gameObject.SetActive(active); } } public class GatheringListUI : MonoBehaviour { [CompilerGenerated] private sealed class <FixLayout>d__10 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public GatheringListUI <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FixLayout>d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)<>4__this.ItemListRoot != (Object)null) { Transform itemListRoot = <>4__this.ItemListRoot; LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((itemListRoot is RectTransform) ? itemListRoot : null)); } if ((Object)(object)<>4__this.PanelRect != (Object)null) { LayoutRebuilder.ForceRebuildLayoutImmediate(<>4__this.PanelRect); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public RectTransform PanelRect; public Image BgImage; public Text TitleText; public Transform ItemListRoot; public Text HintText; public List<GatheringItemUI> ItemSlots = new List<GatheringItemUI>(); private Coroutine _layoutCoroutine; public void SetActive(bool active) { ((Component)this).gameObject.SetActive(active); } public void RefreshLayout() { if (((Component)this).gameObject.activeInHierarchy) { if (_layoutCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_layoutCoroutine); } _layoutCoroutine = ((MonoBehaviour)this).StartCoroutine(FixLayout()); } } private void OnDisable() { _layoutCoroutine = null; } [IteratorStateMachine(typeof(<FixLayout>d__10))] private IEnumerator FixLayout() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FixLayout>d__10(0) { <>4__this = this }; } } public class GatheringItemData { public string ItemName; public string DisplayName; public Sprite Icon; public int TotalRequired; public int TotalHave; public bool IsComplete; } public static class UIBuilder { private static Color ValheimOrange = new Color(1f, 0.77f, 0.31f, 1f); private static Color DividerColor = new Color(1f, 1f, 1f, 0.1f); private static Sprite _cachedUiSprite; private static bool _spriteSearchDone = false; private static Sprite GetBackgroundSprite() { if ((Object)(object)_cachedUiSprite != (Object)null) { return _cachedUiSprite; } if (_spriteSearchDone) { return null; } Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>(); Sprite val = null; Sprite[] array2 = array; foreach (Sprite val2 in array2) { if (!((Object)(object)val2 == (Object)null)) { if (((Object)val2).name == "UISprite") { _cachedUiSprite = val2; break; } if ((Object)(object)val == (Object)null && ((Object)val2).name == "Knob") { val = val2; } } } if ((Object)(object)_cachedUiSprite == (Object)null) { _cachedUiSprite = val; } _spriteSearchDone = true; if ((Object)(object)_cachedUiSprite != (Object)null) { DebugLogger.Verbose("Found background sprite: " + ((Object)_cachedUiSprite).name); } else { DebugLogger.Warning("No suitable background sprite found"); } return _cachedUiSprite; } public static PinSlotUI CreatePinSlot(Transform parent, Font font) { //IL_0019: 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_0027: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Expected O, but got Unknown //IL_0133: 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_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Expected O, but got Unknown //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Expected O, but got Unknown //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Expected O, but got Unknown //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Expected O, but got Unknown //IL_03f2: Unknown result type (might be due to invalid IL or missing references) //IL_0440: Unknown result type (might be due to invalid IL or missing references) //IL_0445: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Expected O, but got Unknown //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_0488: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_050d: Unknown result type (might be due to invalid IL or missing references) //IL_0512: Unknown result type (might be due to invalid IL or missing references) //IL_051c: Expected O, but got Unknown GameObject val = new GameObject("PinSlot", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val.transform.SetParent(parent, false); PinSlotUI pinSlotUI = val.AddComponent<PinSlotUI>(); pinSlotUI.Rect = val.GetComponent<RectTransform>(); Image val2 = val.AddComponent<Image>(); Sprite val3 = (val2.sprite = GetBackgroundSprite()); if ((Object)(object)val3 != (Object)null && val3.border != Vector4.zero) { val2.type = (Type)1; } else { val2.type = (Type)0; } float num = ((RecipePinnerPlugin.BackgroundOpacity != null) ? RecipePinnerPlugin.BackgroundOpacity.Value : 0.45f); ((Graphic)val2).color = new Color(0f, 0f, 0f, num); ((Graphic)val2).raycastTarget = false; GameObject val4 = new GameObject("AccentBar", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val4.transform.SetParent(val.transform, false); Image val5 = val4.AddComponent<Image>(); ((Graphic)val5).raycastTarget = false; ((Graphic)val5).color = new Color(0.9f, 0.25f, 0.25f, 0.5f); RectTransform component = val4.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 0f); component.anchorMax = new Vector2(0f, 1f); component.pivot = new Vector2(0f, 0.5f); component.sizeDelta = new Vector2(4f, 0f); component.anchoredPosition = Vector2.zero; LayoutElement val6 = val4.AddComponent<LayoutElement>(); val6.ignoreLayout = true; pinSlotUI.AccentBar = val5; VerticalLayoutGroup val7 = val.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)val7).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val7).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val7).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val7).spacing = 5f; ((LayoutGroup)val7).padding = new RectOffset(14, 8, 8, 8); ContentSizeFitter val8 = val.AddComponent<ContentSizeFitter>(); val8.horizontalFit = (FitMode)0; val8.verticalFit = (FitMode)2; GameObject val9 = new GameObject("HeaderRow", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val9.transform.SetParent(val.transform, false); HorizontalLayoutGroup val10 = val9.AddComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)val10).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val10).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val10).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val10).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)val10).spacing = 8f; LayoutElement val11 = val9.AddComponent<LayoutElement>(); val11.minHeight = 30f; val11.flexibleHeight = 0f; val11.flexibleWidth = 1f; GameObject val12 = new GameObject("Icon", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val12.transform.SetParent(val9.transform, false); Image val13 = val12.AddComponent<Image>(); ((Graphic)val13).raycastTarget = false; val13.preserveAspect = true; pinSlotUI.IconImage = val13; LayoutElement val14 = val12.AddComponent<LayoutElement>(); val14.minWidth = 28f; val14.minHeight = 28f; val14.preferredWidth = 28f; val14.preferredHeight = 28f; val14.flexibleWidth = 0f; GameObject val15 = new GameObject("Title", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val15.transform.SetParent(val9.transform, false); Text val16 = val15.AddComponent<Text>(); ((Graphic)val16).raycastTarget = false; val16.font = font; val16.fontSize = 18; val16.alignment = (TextAnchor)3; val16.horizontalOverflow = (HorizontalWrapMode)0; val16.verticalOverflow = (VerticalWrapMode)1; ((Graphic)val16).color = ValheimOrange; pinSlotUI.HeaderText = val16; LayoutElement val17 = val15.AddComponent<LayoutElement>(); val17.minHeight = 24f; val17.flexibleWidth = 1f; GameObject val18 = new GameObject("Divider", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val18.transform.SetParent(val.transform, false); Image val19 = val18.AddComponent<Image>(); val19.sprite = GetBackgroundSprite(); if ((Object)(object)val3 != (Object)null && val3.border != Vector4.zero) { val19.type = (Type)1; } else { val19.type = (Type)0; } ((Graphic)val19).color = DividerColor; ((Graphic)val19).raycastTarget = false; LayoutElement val20 = val18.AddComponent<LayoutElement>(); val20.minHeight = 2f; val20.preferredHeight = 2f; val20.flexibleWidth = 1f; GameObject val21 = new GameObject("ResourceList", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val21.transform.SetParent(val.transform, false); VerticalLayoutGroup val22 = val21.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)val22).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val22).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val22).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val22).spacing = 3f; ContentSizeFitter val23 = val21.AddComponent<ContentSizeFitter>(); val23.verticalFit = (FitMode)2; pinSlotUI.ResourceListRoot = val21.transform; DebugLogger.Verbose("Created pin slot UI"); return pinSlotUI; } public static ResourceSlotUI CreateResourceSlot(Transform parent, Font font) { //IL_0019: 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_0027: Expected O, but got Unknown //IL_00ae: 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_00bd: Expected O, but got Unknown //IL_015a: 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_0169: Expected O, but got Unknown //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Expected O, but got Unknown GameObject val = new GameObject("ResSlot", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val.transform.SetParent(parent, false); ResourceSlotUI resourceSlotUI = val.AddComponent<ResourceSlotUI>(); HorizontalLayoutGroup val2 = val.AddComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)val2).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)val2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)val2).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val2).childForceExpandWidth = false; ((LayoutGroup)val2).childAlignment = (TextAnchor)3; ((HorizontalOrVerticalLayoutGroup)val2).spacing = 6f; LayoutElement val3 = val.AddComponent<LayoutElement>(); val3.minHeight = 22f; val3.flexibleHeight = 0f; GameObject val4 = new GameObject("Icon", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val4.transform.SetParent(val.transform, false); resourceSlotUI.ResIcon = val4.AddComponent<Image>(); ((Graphic)resourceSlotUI.ResIcon).raycastTarget = false; resourceSlotUI.ResIcon.preserveAspect = true; LayoutElement val5 = val4.AddComponent<LayoutElement>(); val5.minWidth = 20f; val5.minHeight = 20f; val5.preferredWidth = 20f; val5.preferredHeight = 20f; val5.flexibleWidth = 0f; GameObject val6 = new GameObject("Name", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val6.transform.SetParent(val.transform, false); resourceSlotUI.ResName = val6.AddComponent<Text>(); ((Graphic)resourceSlotUI.ResName).raycastTarget = false; resourceSlotUI.ResName.font = font; resourceSlotUI.ResName.fontSize = 15; resourceSlotUI.ResName.alignment = (TextAnchor)3; resourceSlotUI.ResName.horizontalOverflow = (HorizontalWrapMode)0; ((Graphic)resourceSlotUI.ResName).color = new Color(0.9f, 0.9f, 0.9f, 1f); LayoutElement val7 = val6.AddComponent<LayoutElement>(); val7.flexibleWidth = 1f; GameObject val8 = new GameObject("Amount", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val8.transform.SetParent(val.transform, false); resourceSlotUI.ResAmount = val8.AddComponent<Text>(); ((Graphic)resourceSlotUI.ResAmount).raycastTarget = false; resourceSlotUI.ResAmount.font = font; resourceSlotUI.ResAmount.fontSize = 15; resourceSlotUI.ResAmount.alignment = (TextAnchor)5; LayoutElement val9 = val8.AddComponent<LayoutElement>(); val9.minWidth = 40f; DebugLogger.Verbose("Created resource slot UI"); return resourceSlotUI; } public static GameObject CreatePaginationContainer(Transform parent) { //IL_0019: 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_0027: Expected O, but got Unknown GameObject val = new GameObject("PaginationDots", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val.transform.SetParent(parent, false); LayoutElement val2 = val.AddComponent<LayoutElement>(); val2.ignoreLayout = true; HorizontalLayoutGroup val3 = val.AddComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)val3).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)val3).childControlWidth = false; ((HorizontalOrVerticalLayoutGroup)val3).childForceExpandHeight = false; ((HorizontalOrVerticalLayoutGroup)val3).childForceExpandWidth = false; ((HorizontalOrVerticalLayoutGroup)val3).spacing = RecipePinnerPlugin.PaginationDotSpacing.Value; ((LayoutGroup)val3).childAlignment = (TextAnchor)4; ContentSizeFitter val4 = val.AddComponent<ContentSizeFitter>(); val4.horizontalFit = (FitMode)2; val4.verticalFit = (FitMode)2; return val; } public static Image CreatePageDot(Transform parent) { //IL_0019: 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_0027: Expected O, but got Unknown //IL_0063: 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) GameObject val = new GameObject("PageDot", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val.transform.SetParent(parent, false); Image val2 = val.AddComponent<Image>(); val2.type = (Type)0; ((Graphic)val2).raycastTarget = false; int value = RecipePinnerPlugin.PaginationDotSize.Value; RectTransform component = val.GetComponent<RectTransform>(); component.sizeDelta = new Vector2((float)value, (float)value); ((Transform)component).localRotation = Quaternion.Euler(0f, 0f, 45f); return val2; } public static GatheringListUI CreateGatheringListPanel(Transform parent, Font font, string title) { //IL_0019: 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_0027: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Expected O, but got Unknown //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Expected O, but got Unknown //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0385: 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_0394: Expected O, but got Unknown //IL_03ec: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("GatheringListPanel", new Type[1] { typeof(RectTransform) }) { layer = 5 }; val.transform.SetParent(parent, false); GatheringListUI gatheringListUI = val.AddComponent<GatheringListUI>(); gatheringListUI.PanelRect = val.GetComponent<RectTransform>(); Image val2 = val.AddComponent<Image>(); Sprite val3 = (val2.sprite = GetBackgroundSprite()); if ((Object)(object)val3 != (Object)null && val3.border != Vector4.zero) { val2.type = (Type)1; } else { val2.type = (Type)0; } float num = ((RecipePinnerPlugin.BackgroundOpacity != null) ? RecipePinnerPlugin.BackgroundOpacity.Value : 0.45f); ((Graphic)val2).color = new Color(0f, 0f,
plugins/ZenCompass.dll
Decompiled 3 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; using Zen; using Zen.Lib; using Zen.Lib.Config; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("ZenCompass")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+541c404549c74eba4197ed2d6e167f13f23acf30")] [assembly: AssemblyProduct("ZenCompass")] [assembly: AssemblyTitle("ZenCompass")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 ZenCompass { internal class Compass { private CompassConstants.ViewMode _viewMode = SmallOrLarge; private float _lastInvLookup; private const float InvLookupFrequency = 0.5f; private ItemData? _inventoryItem; private readonly GameObject _root; private readonly GameObject _needle; private readonly GameObject _center; private readonly GameObject _heading; private readonly GameObject _looking; private readonly GameObject _glass; private readonly GameObject _mask; private readonly GameObject _ship; private readonly GameObject _ring; private readonly Sprite _ringSun; private readonly Image _lookingImage; private readonly Image _ringImage; private readonly Image _shipIndicatorUnder; private readonly Image _shipIndicatorOver; private readonly Transform _windRing; private readonly Image _windIcon; private readonly Transform? _originalPinRootParent; private float _radarEmptyTimestamp; private bool _isRadarEmptyForDuration; private bool _isRadarExpanded; private bool _isRadarShrunk; private int _radarPinCount; private bool _isDarkMode; private const float _malfunctionCheckFrequency = 2f; private float _lastMalfunctionCheckTime; private bool _isMalfunction; private Coroutine? _malfunctionDelayCoroutine; private readonly Dictionary<Biome, EnvSetup[]?> _malfunctionConditions = new Dictionary<Biome, EnvSetup[]>(); public Vector3 North { get; private set; } public Vector3 Looking { get; private set; } public Vector3 Heading { get; private set; } internal Transform transform => _root.transform; private static Transform SmallMap => Minimap.instance.m_mapSmall.transform; private static bool InDungeon => ((Character)Player.m_localPlayer).InInterior(); private static CompassConstants.ViewMode SmallOrLarge { get { if (!Configs.ShrinkWhenEmpty.Value) { return CompassConstants.ViewMode.Large; } return CompassConstants.ViewMode.Small; } } internal Compass() { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: 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_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014c: 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) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) Minimap instance = Minimap.instance; ((Component)instance.m_smallMarker).gameObject.SetActive(false); ((Component)instance.m_windMarker).gameObject.SetActive(false); ((Component)instance.m_biomeNameSmall).gameObject.SetActive(false); ((Behaviour)((Component)instance.m_smallShipMarker).GetComponent<Image>()).enabled = false; ((Component)instance.m_pinNameRootSmall).gameObject.SetActive(false); ((Component)instance.m_smallRoot.transform.Find("Key tip")).gameObject.SetActive(false); ((Behaviour)instance.m_mapSmall.GetComponent<RectMask2D>()).enabled = false; ((Behaviour)instance.m_smallRoot.GetComponent<Image>()).enabled = false; ((Behaviour)instance.m_mapImageSmall).enabled = false; instance.m_mapSmall.transform.localScale = Vector2.op_Implicit(Vector2.one * 1.4f); instance.m_mapSmall.transform.localPosition = Vector2.op_Implicit(CompassConstants.PositionInit); _root = new GameObject("ZenCompass_Root"); _root.transform.SetParent(SmallMap, false); _root.transform.SetAsFirstSibling(); _root.transform.localScale = Vector3.one * 2f; _ship = Object.Instantiate<GameObject>(((Component)Minimap.instance.m_smallShipMarker).gameObject, _root.transform); _ship.transform.localScale = Vector3.one * 2f; _ship.SetActive(true); _looking = LoadCompassImage("compass_looking.png", _root); _center = LoadCompassImage("compass_center.png", _root); _needle = LoadCompassImage("compass_needle.png", _root); _heading = LoadCompassImage("compass_heading.png", _root); _glass = LoadCompassImage("compass_glass.png", _root); _mask = LoadCompassImage("compass_mask.png", _root); _ring = LoadCompassImage("compass_ring.png", _root); _ringSun = AssetIO.LoadSpriteFromResource((BaseUnityPlugin)(object)ZenMod<Plugin>.Instance, "compass_ring_time.png"); _ringImage = _ring.GetComponent<Image>(); _lookingImage = _looking.GetComponent<Image>(); _mask.AddComponent<Mask>().showMaskGraphic = false; _originalPinRootParent = ((Transform)Minimap.instance.m_pinRootSmall).parent; ((Transform)Minimap.instance.m_pinRootSmall).SetParent(_mask.transform); _shipIndicatorUnder = _ship.GetComponent<Image>(); _shipIndicatorOver = ((Component)((Transform)Hud.instance.m_shipWindIndicatorRoot).Find("Ship")).gameObject.GetComponent<Image>(); _windRing = ((Transform)Hud.instance.m_shipWindIndicatorRoot).Find("Circle"); ((Component)_windRing).gameObject.SetActive(false); _windIcon = Hud.instance.m_shipWindIcon; ((Component)_windIcon).transform.localScale = Vector3.one / 2f; Hud.instance.m_shipHudRoot.transform.SetAsLastSibling(); Configs.MalfunctionConditions.SettingChanged += delegate { ParseMalfunctionConditions(); }; ParseMalfunctionConditions(); } public void Destroy() { //IL_0023: 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) Logging<Plugin>.Info((object)"Unloading", 0); if (Object.op_Implicit((Object)(object)Minimap.instance)) { _root.transform.localScale = Vector3.one * 2f; ((Component)Minimap.instance.m_pinRootSmall).gameObject.SetActive(true); ((Transform)Minimap.instance.m_pinRootSmall).SetParent(_originalPinRootParent); Object.Destroy((Object)(object)_root); } } internal void Update() { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { bool flag = PlayerExt.IsShipCaptain(Player.m_localPlayer); bool flag2 = ((Character)Player.m_localPlayer).IsAttachedToShip(); bool flag3 = ((Character)Player.m_localPlayer).IsRiding(); InventoryCheck(); MalfunctionCheck(); UpdateRadar(); UpdateConfigScale(); CheckViewMode(flag || flag2 || flag3); UpdateViewScale(); UpdateRotation(flag); UpdateStatusEffectsPosition(); UpdateShipIndicator(flag); UpdateWindVisibility(flag); UpdateTimeOfDay(); } } private void InventoryCheck() { if ((Configs.CraftToUse.Value || Configs.EquipToUse.Value) && Time.time > _lastInvLookup + 0.5f) { _inventoryItem = CompassItem.FindInInventory(); _lastInvLookup = Time.time; } } private void MalfunctionCheck() { //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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) bool flag = Player.m_localPlayer.m_teleporting || Player.m_localPlayer.m_teleportCooldown < 2f; if (Time.time < _lastMalfunctionCheckTime + 2f && !flag) { return; } _lastMalfunctionCheckTime = Time.time; Dictionary<Biome, EnvSetup[]?> conditions = _malfunctionConditions; Biome currentBiome = Player.m_localPlayer.GetCurrentBiome(); EnvSetup currentEnv = EnvMan.instance.GetCurrentEnvironment(); bool flag2 = conditions.Keys.Any((Biome biome) => ((Enum)biome).HasFlag((Enum)(object)currentBiome)); bool flag3 = CheckEnv((Biome)895) || CheckEnv(currentBiome); bool malfunction = flag2 && flag3 && !((Character)Player.m_localPlayer).InGodMode(); Logging<Plugin>.Debug((object)$"Malfunction? {malfunction} Biome: {currentBiome} Env: {currentEnv.m_name} InBiome: {flag2} InEnv: {flag3}", 0); if (malfunction != _isMalfunction && _malfunctionDelayCoroutine == null) { _malfunctionDelayCoroutine = Timing.Delay((MonoBehaviour)(object)ZenMod<Plugin>.Instance, Configs.MalfunctionTransitionDelay.Value, (Action)delegate { _isMalfunction = malfunction; _malfunctionDelayCoroutine = null; }); } bool CheckEnv(Biome biome) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (conditions.TryGetValue(biome, out EnvSetup[] value)) { return value?.Any((EnvSetup env) => env.m_name == currentEnv?.m_name) ?? true; } return false; } } private void ParseMalfunctionConditions() { //IL_006c: 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) //IL_0086: 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) List<EnvSetup> environments = EnvMan.instance.m_environments; _malfunctionConditions.Clear(); foreach (var (text, text2) in IEnumerableExt.AsTuple<string, string>(Configs.MalfunctionConditions.Value.ToDictionary(':'))) { try { Biome key = (Biome)Enum.Parse(typeof(Biome), text); if (text2 == "All") { _malfunctionConditions[key] = null; continue; } string[] weatherNames = text2.Split(new char[1] { '|' }); if (!weatherNames.All((string w) => environments.Any((EnvSetup e) => e.m_name == w))) { throw new Exception("Invalid weather"); } _malfunctionConditions[key] = environments.FindAll((EnvSetup e) => weatherNames.Contains(e.m_name)).ToArray(); } catch (Exception ex) { Logging<Plugin>.Error((object)("Malformed config for malfunction condition: " + text + "=" + text2 + " " + ex.Message), (ushort)0); } } } private void CheckViewMode(bool isShipOrMount) { if (((Character)Player.m_localPlayer).IsDead()) { _viewMode = CompassConstants.ViewMode.None; return; } if (Configs.CraftToUse.Value) { if (_inventoryItem == null) { _viewMode = CompassConstants.ViewMode.None; return; } if (Configs.EquipToUse.Value && !_inventoryItem.IsEquipped()) { _viewMode = CompassConstants.ViewMode.None; return; } } if (InDungeon) { _viewMode = (Configs.AllowInDungeon.Value ? SmallOrLarge : CompassConstants.ViewMode.None); return; } if (Minimap.IsOpen()) { _viewMode = CompassConstants.ViewMode.Small; return; } int num = ((isShipOrMount && Plugin.IsZenMapLoaded) ? 1 : 0); if (_radarPinCount <= num) { if (_isRadarEmptyForDuration) { if (Time.time - _radarEmptyTimestamp > 5f) { _viewMode = SmallOrLarge; } } else { _isRadarEmptyForDuration = true; _radarEmptyTimestamp = Time.time; } } else { _isRadarEmptyForDuration = false; _viewMode = CompassConstants.ViewMode.Large; } } private void UpdateRotation(bool isShipCaptain) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0118: 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_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: 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_0158: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: 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_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: 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_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) CompassConstants.Orientation orientation = (Configs.RotatingCompass.Value ? CompassConstants.Orientation.Rotating : CompassConstants.Orientation.Fixed); if (Configs.CraftToUse.Value) { orientation = ((!Configs.EquipToUse.Value) ? ((!_inventoryItem.IsCompass() || Configs.RotatingCompass.Value) ? CompassConstants.Orientation.Rotating : CompassConstants.Orientation.Fixed) : ((!_inventoryItem.IsEquipped() || !_inventoryItem.IsCompass() || Configs.RotatingCompass.Value) ? CompassConstants.Orientation.Rotating : CompassConstants.Orientation.Fixed)); } Minimap instance = Minimap.instance; instance.m_minZoom = 0.005f * (float)Configs.RadarRangePercent.Value / 100f; instance.m_smallZoom = Minimap.instance.m_minZoom; Quaternion rotation = ((Component)Camera.current).transform.rotation; Vector3 eulerAngles = ((Quaternion)(ref rotation)).eulerAngles; rotation = ((Component)Player.m_localPlayer).transform.rotation; Vector3 eulerAngles2 = ((Quaternion)(ref rotation)).eulerAngles; switch (isShipCaptain ? CompassConstants.Orientation.Rotating : orientation) { case CompassConstants.Orientation.Fixed: North = Vector3.forward; Looking = Vector3.forward * (0f - eulerAngles.y); Heading = Vector3.forward * (0f - eulerAngles2.y); break; case CompassConstants.Orientation.Rotating: North = Vector3.forward * eulerAngles.y; Looking = Vector3.forward; Heading = Vector3.forward * (eulerAngles.y - eulerAngles2.y); break; default: throw new ArgumentOutOfRangeException("orientation", orientation, "Orientation unknown"); } SmallMap.eulerAngles = North; _needle.transform.eulerAngles = (_isMalfunction ? (Vector3.forward * (Mathf.Sin(Time.time / 2f) * Mathf.Sin(Time.time) * 200f)) : North); _heading.transform.eulerAngles = (_isMalfunction ? (Vector3.forward * (Mathf.Cos(Time.time) * 400f)) : Heading); _looking.transform.eulerAngles = Looking; _ship.transform.eulerAngles = Heading; _looking.SetActive(!_isMalfunction); } private void UpdateTimeOfDay() { //IL_0023: 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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_0089: Unknown result type (might be due to invalid IL or missing references) if (Configs.TrackTimeDay.Value && !((Character)Player.m_localPlayer).InInterior()) { _ring.transform.eulerAngles = Vector3.forward * ((EnvMan.instance.GetDayFraction() - 0.25f) * 360f); _ringImage.overrideSprite = _ringSun; } else { _ringImage.overrideSprite = null; } if (_isDarkMode && EnvMan.IsDaylight() && !((Character)Player.m_localPlayer).InInterior()) { Color white = Color.white; AdjustAmbiance(white); _isDarkMode = false; } if ((!_isDarkMode && !EnvMan.IsDaylight()) || ((Character)Player.m_localPlayer).InInterior()) { Color32 val = default(Color32); ((Color32)(ref val))..ctor((byte)0, (byte)127, byte.MaxValue, byte.MaxValue); AdjustAmbiance(Color32.op_Implicit(val)); _isDarkMode = true; } void AdjustAmbiance(Color targetColor) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) Logging<Plugin>.Info((object)"Adjusting ambiance", 0); float transitionDuration = EnvMan.instance.m_transitionDuration; ((Graphic)_ringImage).CrossFadeColor(targetColor, transitionDuration, false, false); ((Graphic)_lookingImage).CrossFadeColor(targetColor, transitionDuration, false, false); } } private void UpdateWindVisibility(bool isShipCaptain) { ((Behaviour)_windIcon).enabled = (Configs.TrackWind.Value && _viewMode != 0 && !InDungeon && !_isMalfunction) || isShipCaptain; ((Component)_windRing).gameObject.SetActive(isShipCaptain); _ring.gameObject.SetActive(!isShipCaptain); } private void UpdateStatusEffectsPosition() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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) //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (Configs.RepositionStatusEffects.Value) { float num = 84f * UI.ScaleFactor; float num2 = 70f * UI.ScaleFactor; Transform val = _root.transform; RectTransform statusEffectListRoot = Hud.instance.m_statusEffectListRoot; Vector3 position = ((Transform)statusEffectListRoot).position; position.x = val.position.x - val.localScale.x * num - num2; ((Transform)statusEffectListRoot).position = position; } } private void UpdateShipIndicator(bool isShipCaptain) { ((Behaviour)_shipIndicatorOver).enabled = isShipCaptain && _viewMode == CompassConstants.ViewMode.None; ((Behaviour)_shipIndicatorUnder).enabled = isShipCaptain && !((Behaviour)_shipIndicatorOver).enabled; Hud.instance.m_shipControlsRoot.SetActive(isShipCaptain); } private void UpdateRadar() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) RectTransform pinRootSmall = Minimap.instance.m_pinRootSmall; bool flag = Configs.RadarRangePercent.Value > 0 && !_isMalfunction && !InDungeon; _radarPinCount = 0; ((Component)pinRootSmall).gameObject.SetActive(flag); if (!flag) { return; } foreach (Transform item in (Transform)pinRootSmall) { item.localScale = Vector3.one * 1f; item.rotation = Quaternion.identity; Vector2 val2 = Vector2.op_Implicit(item.localPosition); if (((Vector2)(ref val2)).magnitude < 84f) { _radarPinCount++; } } } private static void UpdateConfigScale() { //IL_000f: 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_0037: 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_005f: 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) Minimap.instance.m_smallRoot.transform.localScale = Vector3.one * Configs.DisplayScale.Value; Hud.instance.m_shipHudRoot.transform.localScale = Vector3.one * Configs.DisplayScale.Value; Hud.instance.m_shipControlsRoot.transform.localScale = Vector3.one / Configs.DisplayScale.Value; } private void UpdateViewScale() { switch (_viewMode) { case CompassConstants.ViewMode.None: SetVisible(isVisible: false); ShrinkCompass(1f); break; case CompassConstants.ViewMode.Small: SetVisible(isVisible: true); ShrinkCompass(1f); break; case CompassConstants.ViewMode.Large: SetVisible(isVisible: true); ExpandCompass(2f); break; default: throw new ArgumentOutOfRangeException("_viewMode", _viewMode, "ViewMode Unknown"); } } private void ShrinkCompass(float scale) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_004b: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) Vector3 localScale = _root.transform.localScale; _isRadarShrunk = localScale.x <= scale + 0.005f; if (!_isRadarShrunk) { SmallMap.localPosition = SmallMap.localPosition.SmoothMove(Vector2.op_Implicit(CompassConstants.PositionShrink)); _root.transform.localScale = localScale.SmoothScale(scale); Transform obj = ((Component)_windIcon).transform; obj.localScale = obj.localScale.SmoothScale(scale - 0.3f); } } private void ExpandCompass(float scale) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_004b: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) Vector3 localScale = _root.transform.localScale; _isRadarExpanded = localScale.x >= scale - 0.005f; if (!_isRadarExpanded) { SmallMap.localPosition = SmallMap.localPosition.SmoothMove(Vector2.op_Implicit(CompassConstants.PositionInit)); _root.transform.localScale = localScale.SmoothScale(scale); Transform obj = ((Component)_windIcon).transform; obj.localScale = obj.localScale.SmoothScale(1f / scale); } } private void SetVisible(bool isVisible) { Minimap.instance.m_smallRoot.SetActive(isVisible); if (!isVisible) { return; } if (Configs.CraftToUse.Value) { bool flag = _inventoryItem.IsEquipped(); bool flag2 = _inventoryItem.IsCompass(); if (Configs.EquipToUse.Value) { AdjustParts(flag2 && flag); } else { AdjustParts(flag2); } } else { AdjustParts(Configs.ShowNorthArrow.Value); } void AdjustParts(bool isCompass) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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) bool active = (isCompass ? Configs.ShowHeadingCompass.Value : Configs.ShowHeadingSunstone.Value); _heading.SetActive(active); _needle.SetActive(isCompass); _heading.transform.localScale = (isCompass ? Vector3.one : (Vector3.one * 1.3f)); } } private static GameObject LoadCompassImage(string resourceName, GameObject parent) { //IL_0010: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown GameObject val = new GameObject(resourceName.Replace(".png", "")); val.transform.SetParent(parent.transform, false); val.AddComponent<Image>().sprite = AssetIO.LoadSpriteFromResource((BaseUnityPlugin)(object)ZenMod<Plugin>.Instance, resourceName); return val; } } internal static class CompassConstants { internal enum ViewMode { None, Small, Large } internal enum Orientation { Fixed, Rotating } internal const float AnimTime = 0.05f; internal const float AnimErrMargin = 0.005f; internal const float ShrinkScale = 1f; internal const float ShrinkDelayWhenEmpty = 5f; internal static readonly Vector2 PositionInit = Vector2.one * -138.59999f; internal static readonly Vector2 PositionShrink = PositionInit * 0.39999998f; private const float Margin = 15f; internal const float StatusEffectHudOffset = 70f; internal const float RenderScale = 1.4f; internal const float CompassScale = 2f; internal const float PinScale = 1f; internal const float RadarRange = 0.005f; internal const float ScanRadius = 84f; } internal static class CompassItem { public const string PrefabCompass = "ZenCompass"; public const string PrefabSunstone = "ZenSunstone"; private static readonly string[] PrefabNames = new string[2] { "ZenCompass", "ZenSunstone" }; private const string ItemAttachName = "compass"; public static bool IsEquipped(this ItemData? item) { return item?.m_equipped ?? false; } public static bool IsCompass(this ItemData? item) { return ((item != null) ? ItemDataExt.GetPrefabName(item) : null) == "ZenCompass"; } public static bool IsSunstone(this ItemData? item) { return ((item != null) ? ItemDataExt.GetPrefabName(item) : null) == "ZenSunstone"; } public static bool IsNavItem(this ItemData? item) { if (item != null) { return PrefabNames.Contains(ItemDataExt.GetPrefabName(item)); } return false; } internal static Action AddCraftingItems() { //IL_00bc: 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_00d5: Unknown result type (might be due to invalid IL or missing references) Sprite val = AssetIO.LoadSpriteFromResource((BaseUnityPlugin)(object)ZenMod<Plugin>.Instance, "compass_icon2.png"); Sprite icon = ItemDataExt.GetIcon(PrefabManager.Instance.GetPrefab("FlametalOre").GetComponent<ItemDrop>()); CustomItem craftingItem; CustomItem craftingItem2; List<Action> configSync = new List<Action> { AddCraftingItem("ZenCompass", "ShieldFlametal", val, "$item_compass", "$item_compass_description", 0.3f, Configs.CraftingStationCompass, Configs.CraftingStationLevelCompass, Configs.CraftingMaterialsCompass, Configs.CraftingEnabledCompass, out craftingItem), AddCraftingItem("ZenSunstone", "FlametalOre", icon, "$item_sunstone", "$item_sunstone_description", 0.3f, Configs.CraftingStationSunstone, Configs.CraftingStationLevelSunstone, Configs.CraftingMaterialsSunstone, Configs.CraftingEnabledSunstone, out craftingItem2) }; CustomItemExt.ApplyTextureToPrefab(craftingItem, val.texture, 0.25f, Vector2.one * 2f, new Vector2(0.1f, -0.85f), "compass", true, (Color?)null); InitPrefabItem(craftingItem2, 0.25f); return delegate { CollectionExtensions.Do<Action>((IEnumerable<Action>)configSync, (Action<Action>)delegate(Action sync) { sync(); }); }; } private static void InitPrefabItem(CustomItem item, float scale3D) { //IL_002c: 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) ((Object)item.ItemPrefab.transform.GetChild(0)).name = "compass"; Transform transform = ((Component)item.ItemPrefab.GetComponentInChildren<MeshRenderer>()).transform; transform.localScale *= scale3D; SharedData shared = item.ItemDrop.m_itemData.m_shared; shared.m_movementModifier = 0f; shared.m_useDurability = false; shared.m_canBeReparied = false; shared.m_maxQuality = 1; shared.m_value = 0; } private static Action AddCraftingItem(string prefabName, string basePrefabName, Sprite? icon, string label, string description, float weight, ConfigEntry<string> station, ConfigEntry<int> stationLevel, ConfigEntry<StringList> materials, ConfigEntry<bool> isEnabled, out CustomItem craftingItem) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown ConfigEntry<bool> isEnabled2 = isEnabled; string prefabName2 = prefabName; string basePrefabName2 = basePrefabName; ConfigEntry<string> station2 = station; ConfigEntry<int> stationLevel2 = stationLevel; ConfigEntry<StringList> materials2 = materials; Logging<Plugin>.Info((object)("Add crafting item: " + prefabName2 + ", based on " + basePrefabName2), 0); string text = prefabName2; string text2 = basePrefabName2; ItemConfig val = new ItemConfig(); val.Name = label; val.Description = description; val.CraftingStation = station2.Value; val.MinStationLevel = stationLevel2.Value; val.Requirements = materials2.Value.ToRequirementConfigs(':'); val.Icons = (Sprite[])(object)((!Object.op_Implicit((Object)(object)icon)) ? null : new Sprite[1] { icon }); val.StackSize = 1; val.Weight = weight; craftingItem = new CustomItem(text, text2, val); SharedData shared = craftingItem.ItemDrop.m_itemData.m_shared; SetPrefabItemType(shared); ItemManager.Instance.AddItem(craftingItem); shared.m_variants = 0; shared.m_teleportable = true; CustomRecipe customRecipe = craftingItem.Recipe; return ConfigSync; void ConfigSync() { SetPrefabItemType(shared); if (Configs.CraftToUse.Value && isEnabled2.Value) { Logging<Plugin>.Info((object)("Update recipe: " + prefabName2 + ", based on " + basePrefabName2), 0); Recipe recipe = customRecipe.Recipe; recipe.m_craftingStation = PrefabManagerExt.GetCraftingStation(PrefabManager.Instance, station2.Value); recipe.m_minStationLevel = stationLevel2.Value; recipe.m_resources = materials2.Value.ToRequirements(':'); } else { Logging<Plugin>.Info((object)("Remove recipe: " + prefabName2), 0); ItemManager.Instance.RemoveRecipe(customRecipe); } } } private static void SetPrefabItemType(SharedData shared) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (Configs.CraftToUse.Value && Configs.EquipToUse.Value) { shared.m_equipDuration = 1f; shared.m_itemType = (ItemType)18; } else { shared.m_equipDuration = 0f; shared.m_itemType = (ItemType)16; } } public static ItemData? FindInInventory() { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return null; } IEnumerable<ItemData> enumerable = ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems().Where(IsNavItem); ItemData val = null; foreach (ItemData item in enumerable) { if (val == null || (item.IsCompass() && !val.m_equipped)) { val = item; } if (item.m_equipped) { val = item; } } return val; } } internal static class Configs { internal enum DeathRule { Tombstone, Keep, Destroy } public static readonly ConfigEntry<float> DisplayScale; public static readonly ConfigEntry<bool> ShrinkWhenEmpty; public static readonly ConfigEntry<int> RadarRangePercent; public static readonly ConfigEntry<bool> ShowNorthArrow; public static readonly ConfigEntry<bool> ShowHeadingSunstone; public static readonly ConfigEntry<bool> ShowHeadingCompass; public static readonly ConfigEntry<bool> RotatingCompass; public static readonly ConfigEntry<bool> TrackTimeDay; public static readonly ConfigEntry<bool> TrackWind; public static readonly ConfigEntry<bool> AllowInDungeon; public static readonly ConfigEntry<bool> CraftToUse; public static readonly ConfigEntry<bool> EquipToUse; public static readonly ConfigEntry<StringList> MalfunctionConditions; public static readonly ConfigEntry<float> MalfunctionTransitionDelay; public static readonly ConfigEntry<bool> CraftingEnabledCompass; public static readonly ConfigEntry<string> CraftingStationCompass; public static readonly ConfigEntry<int> CraftingStationLevelCompass; public static readonly ConfigEntry<StringList> CraftingMaterialsCompass; public static readonly ConfigEntry<bool> CraftingEnabledSunstone; public static readonly ConfigEntry<string> CraftingStationSunstone; public static readonly ConfigEntry<int> CraftingStationLevelSunstone; public static readonly ConfigEntry<StringList> CraftingMaterialsSunstone; public static readonly ConfigEntry<DeathRule> PlayerDeath; public static readonly ConfigEntry<bool> AutoRemoveDeathPin; public static readonly ConfigEntry<KeyCode> ForceRemoveDeathPinKey; public static readonly ConfigEntry<bool> RepositionStatusEffects; public static readonly ConfigEntry<bool> RepositionShipPowerIndicator; static Configs() { //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Expected O, but got Unknown //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Expected O, but got Unknown //IL_01d0: Expected O, but got Unknown //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Expected O, but got Unknown //IL_02ce: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Expected O, but got Unknown //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Expected O, but got Unknown //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Expected O, but got Unknown //IL_02f9: Expected O, but got Unknown //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Expected O, but got Unknown //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Expected O, but got Unknown //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Expected O, but got Unknown //IL_039a: Expected O, but got Unknown DisplayScale = Config.Define<float>(false, "General", "Display Scale", 1f, Config.AcceptRange<float>(0.5f, 2f), "Adjust the display scale of the compass. It has two display modes: Small and Large.\r\nIt will be small while there are no pins on the radar and large when there are pins.\r\nSet your scale preference with both scenarios in mind.\r\nAlso this compounds with the vanilla GUI scaling options found in the Settings."); ShrinkWhenEmpty = Config.Define<bool>(false, "General", "Shrink When Empty", true, "Automatically shrink the compass when there are no pins nearby."); ShowHeadingSunstone = Config.Define<bool>(true, "General", "Show Heading Sunstone", false, "Show the sunstone facing direction gear-arrow."); ShowHeadingCompass = Config.Define<bool>(true, "General", "Show Heading Compass", true, "Show the compass facing direction gear-arrow."); ShowNorthArrow = Config.Define<bool>(true, "General", "Show North Arrow", true, "When Craft To Use is disabled this will toggle display of the north arrow on the compass."); RotatingCompass = Config.Define<bool>(true, "General", "Rotating Compass", false, "If true the compass rotates around the player axis such that up is always the direction you are looking."); TrackTimeDay = Config.Define<bool>(true, "General", "Track Time of Day", true, "Track the time of day with an indicator of the sun on the outer ring of the compass.\r\nThe sun rises in the east and sets in the west. Noon is at the top of the compass; midnight the bottom.\r\nDisabling this will make the Sunstone very difficult to use.\r\nNote: This can be confusing to interpret when used with Rotating Compass enabled at the same time."); TrackWind = Config.Define<bool>(true, "General", "Track Wind", true, "Track the wind direction with an indicator on the outer ring of the compass.\r\nDisabling this will make the Sunstone very difficult to use."); RadarRangePercent = Config.Define<int>(true, "General", "Radar Range Percent", 100, Config.AcceptRange<int>(0, 300), "How far to scan for pins, as percentage. Set to 0 to disable the radar function."); AllowInDungeon = Config.Define<bool>(true, "General", "Allow In Dungeon", false, "Does the sunstone/compass work inside dungeons? If false it will malfunction inside dungeons."); string text = GeneralExtensions.Join<Biome>(Enum.GetValues(typeof(Biome)).Cast<Biome>().Except(new <>z__ReadOnlySingleElementList<Biome>((Biome)0)), (Func<Biome, string>)null, ", "); StringList val = new StringList(); ((List<string>)val).Add("All:" + Weather.MountainBlizzard); ((List<string>)val).Add($"{(object)(Biome)512}:All"); ((List<string>)val).Add($"{(object)(Biome)256}:{Weather.ThunderStorm}|{Weather.ClearThunderStorm}"); MalfunctionConditions = Config.Define<StringList>(true, "General", "Malfunction Conditions", val, "List of Biome:Weather conditions that cause the compass to malfunction.\r\nLeave blank to disable the malfunction conditions.\r\nUse the keyword 'All' to apply to all biomes or weathers.\r\nOnly one biome per entry, but a given biome can have multiple weathers.\r\nUse | to separate multiple weathers, example:\r\nBiome:Weather1|Weather2|Weather3|...\r\nPossible biomes: [" + text + "]\r\nPossible weather: https://valheim.fandom.com/wiki/Environment#Weather"); MalfunctionTransitionDelay = Config.Define<float>(true, "General", "Malfunction Transition Delay", 15f, Config.AcceptRange<float>(0f, 60f), "How many seconds to wait before transitioning to/from malfunction state once a condition is met.\r\nSet to 0 to for instant change.\r\nWhen entering a biome or a weather condition it can be helpful to wait a few seconds before malfunctioning\r\nThat way the environment can fully transition before the compass gives out. \r\nAlso it helps when on a biome line so it doesn't keep switching between malfunction and normal states."); CraftToUse = Config.Define<bool>(true, "Crafting", "Craft To Use", true, "The item must be in your inventory before it can be used.\nFalse to make the sunstone/compass always available; no crafting required."); EquipToUse = Config.Define<bool>(true, "Crafting", "Equip To Use", true, "If true the sunstone/compass must also be equipped before it can be used.\nNOTE: " + ((ConfigEntryBase)CraftToUse).Definition.Key + " must be true for this to have any effect"); CraftingEnabledCompass = Config.Define<bool>(true, "Crafting", "Item Compass - Enabled", true, "Enable / disable crafting of the compass item.\r\n[restart required for changes to take effect]"); CraftingStationCompass = Config.Define<string>(true, "Crafting", "Item Compass - Station", "Workbench", CraftingStations.GetAcceptableValueList(), "The station required to craft the compass.\r\nNOTE: For a more challenging game you can change this to a level 1 ArtisanTable\r\nThereby requiring defeat of the Dragon before you can get a compass.\r\nThe idea is to pair this mod with ZenMap and experience the first portion of the game with no compass.\r\n[restart required for changes to take effect]"); CraftingStationLevelCompass = Config.Define<int>(true, "Crafting", "Item Compass - Station Level", 5, Config.AcceptRange<int>(1, 5), "The station level required to craft the compass.\r\nYou will need to treck into the mountains to get a small bit of obsidian to make a level 5 workbench.\r\nNote: The sunstone is available at an earlier stage of progression.\r\n[restart required for changes to take effect]"); StringList val2 = new StringList(); ((List<string>)val2).Add("ZenSunstone:1"); ((List<string>)val2).Add("FineWood:2"); ((List<string>)val2).Add("BoneFragments:4"); ((List<string>)val2).Add("IronNails:1"); CraftingMaterialsCompass = Config.Define<StringList>(true, "Crafting", "Item Compass - Materials", val2, "The materials required to craft the compass. \r\nThe default requires you to get to the swamp and get an iron nail before you can get a compass.\r\nFor an easier game: To get the compass as soon as you enter the Black Forest remove the IronNails requirement and set the workbench requirement to level 1.\r\nThe idea is to pair this mod with ZenMap and experience the first portion of the game with no compass.\r\n[restart required for changes to take effect]"); CraftingEnabledSunstone = Config.Define<bool>(true, "Crafting", "Item Sunstone - Enabled", true, "Enable / disable crafting of the sunstone item.\r\n[restart required for changes to take effect]"); CraftingStationSunstone = Config.Define<string>(true, "Crafting", "Item Sunstone - Station", "Forge", CraftingStations.GetAcceptableValueList(), "The station required to craft the sunstone.\r\n[restart required for changes to take effect]"); CraftingStationLevelSunstone = Config.Define<int>(true, "Crafting", "Item Sunstone - Station Level", 1, Config.AcceptRange<int>(1, 5), "The station level required to craft the sunstone.\r\n[restart required for changes to take effect]"); StringList val3 = new StringList(); ((List<string>)val3).Add("Ruby:1"); ((List<string>)val3).Add("Copper:3"); ((List<string>)val3).Add("Feathers:2"); CraftingMaterialsSunstone = Config.Define<StringList>(true, "Crafting", "Item Sunstone - Materials", val3, "The materials required to craft the sunstone.\r\nThe sunstone is a basic navigation aid. It lets you track time of day and wind position. \r\nHowever, it does not give you full cardinal directions.\r\nYou will need this to upgrade to a full compass later.\r\nThe idea is to pair this mod with ZenMap and experience the first portion of the game with no compass.\r\n[restart required for changes to take effect]"); PlayerDeath = Config.Define<DeathRule>(true, "Crafting", "Player Death", DeathRule.Tombstone, "What happens to the crafted item when the player dies?"); AutoRemoveDeathPin = Config.Define<bool>(true, "Death Pins", "Auto Remove Death Pin", true, "Death pins will be automatically removed from the map & compass after looting the tombstone"); ForceRemoveDeathPinKey = Config.Define<KeyCode>(false, "Death Pins", "Key - Force Remove Death Pin", (KeyCode)127, "Normally you don't need this key. However, if you were away and someone looted your tombstone\r\nwhile your character was not there then it is possible that your Death Pin would persist even\r\nthough the tombstone was gone. In that scenario you can stand near your pin and press this key\r\nto manually cleanup your map & compass.\r\nNOTE: The ZenMap mod automatically tracks and removes death pins reliably 100% of the time\r\neven if you are far away or offline and someone else loots your tombstone it will still work."); RepositionStatusEffects = Config.Define<bool>(true, "Compatibility", "Resposition Status Effects", true, "Reposition the Status Effect icons to make room for the compass.\r\nDisable this for compatibility with other mods which reposition the Status Effects."); RepositionShipPowerIndicator = Config.Define<bool>(true, "Compatibility", "Reposition Ship Power Indicator", true, "Reposition ship power indicator HUD element (sails / rudder power)\r\nThis mod will by default position it just to the right of the wheel for easy viewing\r\nDisable this for compatibility with other mods which reposition the ship power HUD element"); } } [HarmonyPatch] internal static class DeathPinPatch { [HarmonyPatch(typeof(Player), "OnDeath")] private static class PlayerOnDeath { private static bool _isInvEmpty; [UsedImplicitly] private static void Prefix(Player __instance) { _isInvEmpty = ((Humanoid)__instance).GetInventory().NrOfItems() == 0; } [UsedImplicitly] private static void Postfix(Player __instance) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (_isInvEmpty) { RemoveDeathPinAt(((Component)__instance).transform.position); } } } private static void RemoveDeathPin(TombStone tombstone) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) RemoveDeathPinAt(((Component)tombstone).transform.position); } private static void RemoveDeathPinAt(Vector3 worldPosition, float radius = 5f) { //IL_0025: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Invalid comparison between Unknown and I4 //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (!Configs.AutoRemoveDeathPin.Value) { return; } if (Plugin.IsZenMapLoaded) { Logging<Plugin>.Info((object)"ZenMap is handling death pin cleanup", 0); return; } Logging<Plugin>.Info((object)$"Looking death pins on map at {worldPosition}", 0); PinData closestPin = Minimap.instance.GetClosestPin(worldPosition, radius, false); if (closestPin != null && (int)closestPin.m_type == 4) { Minimap.instance.RemovePin(closestPin); Logging<Plugin>.Info((object)$"Pin found and removed at {worldPosition}", 0); } else { Logging<Plugin>.Info((object)"Pin not found.", 0); } } internal static void CheckForceRemoveButtonPress() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && ZInput.GetKeyDown(Configs.ForceRemoveDeathPinKey.Value, true)) { RemoveDeathPinAt(((Component)Player.m_localPlayer).transform.position); } } [HarmonyTranspiler] [HarmonyPatch(typeof(TombStone), "UpdateDespawn")] private static IEnumerable<CodeInstruction> TombStone_UpdateDespawn(IEnumerable<CodeInstruction> codes) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0046: Unknown result type (might be due to invalid IL or missing references) Action<TombStone> action = RemoveDeathPin; CodeInstruction[] array = (CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)action.Method) }; return new CodeMatcher(codes, (ILGenerator)null).End().Insert(array).InstructionEnumeration(); } } internal static class Extensions { internal static float Yaw(this Vector3 v) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Utils.YawFromDirection(v); } public static Vector3 SmoothScale(this Vector3 v, float scale) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: 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_000c: Unknown result type (might be due to invalid IL or missing references) return v.SmoothMove(Vector3.one * scale); } public static Vector3 SmoothMove(this Vector3 orig, Vector3 target) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0007: 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) Vector3 zero = Vector3.zero; return Vector3.SmoothDamp(orig, target, ref zero, 0.05f); } } [HarmonyPatch] internal class Patches { [HarmonyPatch(typeof(Minimap), "SetMapMode")] private static class Minimap_SetMapMode { [UsedImplicitly] private static void Prefix(Minimap __instance, ref MapMode mode) { if (Game.m_noMap && (int)mode == 0) { mode = (MapMode)1; } } [UsedImplicitly] private static void Postfix(Minimap __instance, MapMode mode) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (Game.m_noMap && (int)mode == 1) { __instance.m_mode = (MapMode)0; } } } [HarmonyPatch(typeof(Minimap), "CenterMap")] private static class Minimap_CenterMap { [UsedImplicitly] private static void Prefix(Minimap __instance) { //IL_0008: 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) if (Game.m_noMap && (int)__instance.m_mode == 0) { __instance.m_mode = (MapMode)1; } } [UsedImplicitly] private static void Postfix(Minimap __instance) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (Game.m_noMap && (int)__instance.m_mode == 1) { __instance.m_mode = (MapMode)0; } } } [HarmonyPostfix] [HarmonyPatch(typeof(Hud), "UpdateShipHud")] [HarmonyPriority(100)] private static void Hud_UpdateShipHud(Hud __instance) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_0082: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Invalid comparison between Unknown and I4 //IL_00be: Unknown result type (might be due to invalid IL or missing references) bool activeSelf = __instance.m_shipHudRoot.activeSelf; Compass compass = Plugin.Compass; if (compass != null) { ((Transform)__instance.m_shipWindIndicatorRoot).position = compass.transform.position; ((Transform)__instance.m_shipWindIndicatorRoot).localScale = compass.transform.localScale; Transform parent = __instance.m_rudder.transform.parent; ((Component)parent).gameObject.SetActive(activeSelf); if (Configs.RepositionShipPowerIndicator.Value) { Vector3 val = 74f * UI.ScaleFactor * Vector3.right; Transform transform = ((Component)__instance.m_shipRudderIndicator).transform; parent.position = transform.position + val; } if (activeSelf) { bool flag = (int)Minimap.instance.m_mode == 2; ((Transform)__instance.m_shipWindIndicatorRoot).eulerAngles = compass.Heading; __instance.m_shipControlsRoot.SetActive(!flag); ((Component)parent).gameObject.SetActive(!flag); } else { ((Transform)__instance.m_shipWindIndicatorRoot).eulerAngles = compass.North; ((Transform)__instance.m_shipWindIconRoot).localEulerAngles = Vector3.forward * (0f - EnvMan.instance.GetWindDir().Yaw()); ((Graphic)__instance.m_shipWindIcon).color = Color.white; __instance.m_shipHudRoot.gameObject.SetActive(true); } } } [HarmonyTranspiler] [HarmonyPatch(typeof(Hud), "UpdateStamina")] private static IEnumerable<CodeInstruction> Hud_UpdateStamina_Transpile(IEnumerable<CodeInstruction> instructions) { return IgnoreShipHudRoot(instructions); } [HarmonyTranspiler] [HarmonyPatch(typeof(Hud), "UpdateEitr")] private static IEnumerable<CodeInstruction> Hud_UpdateEitr_Transpile(IEnumerable<CodeInstruction> instructions) { return IgnoreShipHudRoot(instructions); } private static IEnumerable<CodeInstruction> IgnoreShipHudRoot(IEnumerable<CodeInstruction> instructions) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(typeof(Hud), "m_shipHudRoot"); MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(GameObject), "activeSelf"); CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null); val.MatchEndForward((CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)fieldInfo, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)methodInfo, (string)null) }).ThrowIfInvalid("Unable to find IL match").Advance(1) .Insert((CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Pop, (object)null), new CodeInstruction(OpCodes.Ldc_I4_0, (object)null) }); return val.InstructionEnumeration(); } [HarmonyPostfix] [HarmonyPatch(typeof(Inventory), "MoveInventoryToGrave")] private static void RestoreFromGraveInventory(Inventory __instance, Inventory original) { if (((Humanoid)Player.m_localPlayer).m_inventory != original || Configs.PlayerDeath.Value == Configs.DeathRule.Tombstone) { return; } bool flag = false; for (int num = __instance.m_inventory.Count; num > 0; num--) { ItemData item = __instance.GetItem(num - 1); if (!item.IsNavItem()) { flag = true; switch (Configs.PlayerDeath.Value) { case Configs.DeathRule.Keep: Logging<Plugin>.Info((object)"Player died, keeping compass", 0); __instance.m_inventory.Remove(item); original.m_inventory.Add(item); break; case Configs.DeathRule.Destroy: Logging<Plugin>.Info((object)"Player died, compass destroyed", 0); __instance.m_inventory.Remove(item); break; default: throw new ArgumentOutOfRangeException("DeathRule", "Invalid death rule"); } } } if (flag) { __instance.Changed(); original.Changed(); } } } [BepInPlugin("ZenDragon.ZenCompass", "ZenCompass", "1.4.10")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class Plugin : ZenMod<Plugin> { public const string PluginName = "ZenCompass"; public const string PluginVersion = "1.4.10"; public const string PluginID = "ZenDragon.ZenCompass"; private const string ZenMapPluginID = "ZenDragon.ZenMap"; internal static Compass? Compass; internal static bool IsZenMapLoaded => Chainloader.PluginInfos.ContainsKey("ZenDragon.ZenMap"); protected override void Setup() { if (IsZenMapLoaded) { Logging<Plugin>.Info((object)"ZenDragon.ZenMap is loaded", 0); } base.RegisterCraftingItems += CompassItem.AddCraftingItems; } protected override void TitleScene(bool isFirstBoot) { Compass = null; } protected override void WorldStart() { Compass = new Compass(); } protected override void Shutdown() { Compass?.Destroy(); } private void LateUpdate() { if (Compass != null) { Compass.Update(); DeathPinPatch.CheckForceRemoveButtonPress(); } } } } [CompilerGenerated] internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T> { object IEnumerator.Current => _item; T IEnumerator<T>.Current => _item; public Enumerator(T item) { _item = item; } bool IEnumerator.MoveNext() { if (!_moveNextCalled) { return _moveNextCalled = true; } return false; } void IEnumerator.Reset() { _moveNextCalled = false; } void IDisposable.Dispose() { } } int ICollection.Count => 1; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => 1; T IReadOnlyList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection<T>.Count => 1; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } public <>z__ReadOnlySingleElementList(T item) { _item = item; } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.CopyTo(Array array, int index) { array.SetValue(_item, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return EqualityComparer<T>.Default.Equals(_item, (T)value); } int IList.IndexOf(object value) { if (!EqualityComparer<T>.Default.Equals(_item, (T)value)) { return -1; } return 0; } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return new Enumerator(_item); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return EqualityComparer<T>.Default.Equals(_item, item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { if (!EqualityComparer<T>.Default.Equals(_item, item)) { return -1; } return 0; } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } }