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 MimirsWell v1.0.0
plugins/MimirsWell/MimirsWell.dll
Decompiled a month 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.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.0.0.0")] namespace MimirsWell; internal static class ChestUpgrade { private static readonly Dictionary<string, string> Steps = new Dictionary<string, string> { { "piece_chest_wood", "MW_RuneChest_Wood" }, { "piece_chest", "MW_RuneChest_Iron" }, { "piece_chest_blackmetal", "MW_RuneChest_Blackmetal" } }; internal const string ChiselPrefab = "MW_RuneChisel"; private static readonly FieldInfo RightItemField = AccessTools.Field(typeof(Humanoid), "m_rightItem"); internal static bool HasChisel() { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return false; } foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems()) { if (IsChisel(allItem)) { return true; } } return false; } internal static bool WieldsChisel() { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return false; } if (IsChisel(((Humanoid)localPlayer).GetCurrentWeapon())) { return true; } if (RightItemField != null && IsChisel((ItemData)/*isinst with value type is only supported in some contexts*/)) { return true; } foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems()) { if (allItem.m_equipped && IsChisel(allItem)) { return true; } } return false; } private static bool IsChisel(ItemData item) { if (item == null) { return false; } if (item.m_shared.m_name == "$mw_chisel") { return true; } if (Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return ((Object)item.m_dropPrefab).name == "MW_RuneChisel"; } return false; } internal static void LogState(Container chest) { Player localPlayer = Player.m_localPlayer; ItemData val = (Object.op_Implicit((Object)(object)localPlayer) ? ((Humanoid)localPlayer).GetCurrentWeapon() : null); object? obj = RightItemField?.GetValue(localPlayer); ItemData val2 = (ItemData)((obj is ItemData) ? obj : null); MimirsWellPlugin.Log.LogDebug((object)("Chest interact: " + CleanName(Object.op_Implicit((Object)(object)chest) ? ((Object)((Component)chest).gameObject).name : "none") + ", upgrade target " + (Find(chest) ?? "none") + ", current weapon '" + ((val != null) ? val.m_shared.m_name : "none") + "', right hand '" + ((val2 != null) ? val2.m_shared.m_name : "none") + "', " + $"carries chisel {HasChisel()}, wields chisel {WieldsChisel()}")); } internal static string Find(Container chest) { if (!Object.op_Implicit((Object)(object)chest)) { return null; } if (!Steps.TryGetValue(CleanName(((Object)((Component)chest).gameObject).name), out var value)) { return null; } return value; } internal static string HoverText(Container chest) { string text = Find(chest); if (text == null) { return string.Empty; } GameObject prefab = PrefabManager.Instance.GetPrefab(text); Piece val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<Piece>() : null); string text2 = (Object.op_Implicit((Object)(object)val) ? val.m_name : text); if (WieldsChisel()) { return Localization.instance.Localize("\n<color=#8fc7ff>[<b>$KEY_Use</b>] $mw_upgrade_to " + text2 + "</color>"); } if (!HasChisel()) { return Localization.instance.Localize("\n<color=#9a8f80>$mw_upgrade_to " + text2 + ": $mw_upgrade_needs_chisel</color>"); } return Localization.instance.Localize("\n<color=#9a8f80>$mw_upgrade_to " + text2 + ": $mw_upgrade_hold_chisel</color>"); } internal static bool Upgrade(Container chest) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_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_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) string text = Find(chest); Player localPlayer = Player.m_localPlayer; if (text == null || !Object.op_Implicit((Object)(object)localPlayer)) { return false; } if (!WieldsChisel()) { Message(HasChisel() ? "$mw_upgrade_hold_chisel" : "$mw_upgrade_needs_chisel"); return true; } ZNetView component = ((Component)chest).GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid()) { return false; } if (chest.IsInUse() || RuneChest.IsLockedByOther(chest, localPlayer.GetPlayerID())) { Message("$mw_chest_busy"); return true; } if (!PrivateArea.CheckAccess(((Component)chest).transform.position, 0f, true, false)) { return true; } GameObject prefab = PrefabManager.Instance.GetPrefab(text); if (!Object.op_Implicit((Object)(object)prefab)) { MimirsWellPlugin.Log.LogWarning((object)("Upgrade target " + text + " is not available")); return true; } component.ClaimOwnership(); if (!component.IsOwner()) { Message("$mw_upgrade_failed"); return true; } List<ItemData> list = new List<ItemData>(); foreach (ItemData allItem in chest.GetInventory().GetAllItems()) { list.Add(allItem.Clone()); } Vector3 position = ((Component)chest).transform.position; Quaternion rotation = ((Component)chest).transform.rotation; Piece component2 = ((Component)chest).GetComponent<Piece>(); GameObject val = Object.Instantiate<GameObject>(prefab, position, rotation); Container component3 = val.GetComponent<Container>(); Piece component4 = val.GetComponent<Piece>(); if (!Object.op_Implicit((Object)(object)component3)) { Object.Destroy((Object)(object)val); MimirsWellPlugin.Log.LogWarning((object)("Upgrade target " + text + " has no container")); return true; } Inventory inventory = component3.GetInventory(); foreach (ItemData item in list) { if (!inventory.AddItem(item, item.m_gridPos)) { inventory.AddItem(item); } } CopyCreator(component2, component4); component.Destroy(); if (Object.op_Implicit((Object)(object)component4) && component4.m_placeEffect != null) { component4.m_placeEffect.Create(position, rotation, (Transform)null, 1f, -1, ZDOID.None); } Message("$mw_upgrade_done"); return true; } private static void CopyCreator(Piece from, Piece to) { if (!Object.op_Implicit((Object)(object)from) || !Object.op_Implicit((Object)(object)to)) { return; } string[] array = new string[2] { "m_creator", "m_creatorPlatformUserIDIndex" }; foreach (string text in array) { FieldInfo fieldInfo = AccessTools.Field(typeof(Piece), text); if (fieldInfo != null) { fieldInfo.SetValue(to, fieldInfo.GetValue(from)); } } } private static string CleanName(string name) { int num = name.IndexOf("(Clone)", StringComparison.Ordinal); if (num < 0) { return name; } return name.Substring(0, num); } private static void Message(string token) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize(token), 0, (Sprite)null, false); } } } internal enum ItemFilter { All, Materials, Food, Weapons, Armor, Tools, Misc } internal enum SortMode { Name, Amount, Weight } public class HoardContainer : MonoBehaviour { private class SlotState { public string Key; public int Expected; } private static readonly List<HoardContainer> Open = new List<HoardContainer>(); private static readonly FieldInfo DragItemField = AccessTools.Field(typeof(InventoryGui), "m_dragItem"); private static readonly FieldInfo DragInventoryField = AccessTools.Field(typeof(InventoryGui), "m_dragInventory"); private static readonly FieldInfo DragAmountField = AccessTools.Field(typeof(InventoryGui), "m_dragAmount"); private static readonly FieldInfo CurrentContainerField = AccessTools.Field(typeof(InventoryGui), "m_currentContainer"); private static readonly MethodInfo SetupDragItemMethod = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", (Type[])null, (Type[])null); private static readonly FieldInfo ItemsField = AccessTools.Field(typeof(Inventory), "m_inventory"); private static readonly MethodInfo UpdateWeightMethod = AccessTools.Method(typeof(Inventory), "UpdateTotalWeight", (Type[])null, (Type[])null); private Dictionary<ItemData, SlotState> m_slots = new Dictionary<ItemData, SlotState>(); private readonly Dictionary<string, Vector2i> m_positions = new Dictionary<string, Vector2i>(); internal Container Container; internal MimirsWellStation Well; private bool m_open; private float m_nextPoll; private float m_lastChange; private bool m_needsRelayout; private string m_search = string.Empty; private ItemFilter m_filter; private SortMode m_sort; private int m_totalRows; private const int MaxRows = 64; private static float s_nextFullMessage; internal static bool AnyOpen => Open.Count > 0; internal bool IsOpen => m_open; internal int TotalRows => m_totalRows; private static int MinRows => Mathf.Max(1, MimirsWellPlugin.HoardRows.Value); internal SortMode Sort => m_sort; internal ItemFilter Filter => m_filter; private Inventory Mirror { get { if (!Object.op_Implicit((Object)(object)Container)) { return null; } return Container.GetInventory(); } } private static List<ItemData> SlotsOf(Inventory inventory) { return ItemsField?.GetValue(inventory) as List<ItemData>; } internal static bool IsMirror(Inventory inventory) { if (inventory == null) { return false; } foreach (HoardContainer item in Open) { if (Object.op_Implicit((Object)(object)item) && item.Mirror == inventory) { return true; } } return false; } private void Awake() { Container = ((Component)this).GetComponent<Container>(); Well = ((Component)this).GetComponent<MimirsWellStation>(); } private void OnDestroy() { Open.Remove(this); if (m_open) { EndSession(writeBack: false); } } internal static void CloseAll() { for (int num = Open.Count - 1; num >= 0; num--) { Open[num].EndSession(writeBack: true); } } internal void BeginSession() { if (!m_open && Object.op_Implicit((Object)(object)Container) && Object.op_Implicit((Object)(object)Well)) { m_open = true; m_search = string.Empty; Open.Add(this); StorageSession.Begin(Well); Sync(); HoardControls.Show(this); } } private void EndSession(bool writeBack) { if (m_open) { m_open = false; Open.Remove(this); if (writeBack) { Sync(); } Inventory mirror = Mirror; if (mirror != null) { mirror.RemoveAll(); } m_slots.Clear(); StorageSession.End(); HoardControls.Hide(); } } private void Update() { if (!m_open) { return; } StorageSession current = StorageSession.Current; InventoryGui instance = InventoryGui.instance; if (current == null || !Object.op_Implicit((Object)(object)instance) || (Object)(object)CurrentContainer(instance) != (Object)(object)Container || !InventoryGui.IsVisible()) { EndSession(writeBack: true); return; } current.Update(); ClampDrag(instance); if (Time.time < m_nextPoll) { return; } m_nextPoll = Time.time + 0.1f; if (IsDragging()) { return; } if (m_needsRelayout && !ModifierHeld() && Time.time > m_lastChange + 0.4f) { m_needsRelayout = false; Relayout(); } else if (HasChanged() || current.Dirty) { if (ModifierHeld()) { WriteThrough(current); } else { Sync(); } } } private bool HasChanged() { Inventory mirror = Mirror; if (mirror == null) { return false; } List<ItemData> allItems = mirror.GetAllItems(); if (allItems.Count != m_slots.Count) { return true; } foreach (ItemData item in allItems) { if (!m_slots.TryGetValue(item, out var value) || value.Expected != item.m_stack) { return true; } } return false; } internal void Sync() { StorageSession current = StorageSession.Current; if (current != null) { WriteBack(current); SplitOversizedStacks(current); Rebuild(current); current.Dirty = false; } } private void WriteThrough(StorageSession session) { WriteBack(session); SplitOversizedStacks(session); Inventory mirror = Mirror; if (mirror == null) { return; } Dictionary<ItemData, SlotState> dictionary = new Dictionary<ItemData, SlotState>(); foreach (ItemData allItem in mirror.GetAllItems()) { if (m_slots.TryGetValue(allItem, out var value)) { value.Expected = allItem.m_stack; } else { value = new SlotState { Key = MatchKey(allItem), Expected = allItem.m_stack }; } dictionary[allItem] = value; } int num = Mathf.Max(1, mirror.GetWidth()); int height = mirror.GetHeight(); if (mirror.GetAllItems().Count > (height - 1) * num && height < 64) { mirror.SetHeight(height + 1); m_totalRows = height + 1; } m_slots = dictionary; session.Dirty = false; m_lastChange = Time.time; m_needsRelayout = true; } private static bool ModifierHeld() { if (!ZInput.GetKey((KeyCode)306, false) && !ZInput.GetKey((KeyCode)305, false) && !ZInput.GetKey((KeyCode)304, false)) { return ZInput.GetKey((KeyCode)303, false); } return true; } private void WriteBack(StorageSession session) { Inventory mirror = Mirror; if (mirror == null) { return; } HashSet<ItemData> hashSet = new HashSet<ItemData>(); int num = 0; int num2 = 0; foreach (ItemData item in new List<ItemData>(mirror.GetAllItems())) { if (!m_slots.TryGetValue(item, out var value)) { StoreOrGiveBack(session, item, item.m_stack); num += item.m_stack; continue; } hashSet.Add(item); int num3 = item.m_stack - value.Expected; if (num3 > 0) { StoreOrGiveBack(session, item, num3); num += num3; } else if (num3 < 0) { num2 += RemoveByKey(session, value.Key, -num3); } } foreach (KeyValuePair<ItemData, SlotState> slot in m_slots) { if (!hashSet.Contains(slot.Key)) { num2 += RemoveByKey(session, slot.Value.Key, slot.Value.Expected); } } if (num > 0 || num2 > 0) { MimirsWellPlugin.Log.LogDebug((object)$"Well write-back: {num2} taken out, {num} put in"); } } private static int RemoveByKey(StorageSession session, string key, int amount) { int num = 0; foreach (RuneChest chest in session.Chests) { if (amount <= 0) { break; } if (!Object.op_Implicit((Object)(object)chest) || !chest.IsUsable) { continue; } Inventory inventory = chest.Inventory; if (inventory == null) { continue; } foreach (ItemData item in new List<ItemData>(inventory.GetAllItems())) { if (amount <= 0) { break; } if (!(MatchKey(item) != key)) { int num2 = Mathf.Min(amount, item.m_stack); inventory.RemoveItem(item, num2); amount -= num2; num += num2; } } } if (amount > 0) { MimirsWellPlugin.Log.LogWarning((object)$"Well write-back could not find {amount} of {key} in the bound chests"); } return num; } internal static bool AcceptDrop(Inventory mirror, Inventory from, ItemData item, int amount, int x, int y) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) if (from == null || item == null) { return false; } List<ItemData> list = SlotsOf(mirror); if (list == null) { return false; } amount = Mathf.Clamp(amount, 1, item.m_stack); StorageSession current = StorageSession.Current; if (current == null) { return false; } amount = current.CapacityFor(item, amount); if (amount <= 0) { return false; } ItemData val = null; foreach (ItemData item2 in list) { if (item2.m_gridPos.x == x && item2.m_gridPos.y == y) { val = item2; break; } } if (val != null && MatchKey(val) == MatchKey(item)) { ItemData obj = val; obj.m_stack += amount; } else { Vector2i val2 = (Vector2i)((val == null) ? new Vector2i(x, y) : TakeFreeSlot(mirror, list)); if (val2.x < 0) { int num = current.StoreIntoChests(item, amount); if (num <= 0) { return false; } from.RemoveItem(item, num); return true; } ItemData val3 = item.Clone(); val3.m_stack = amount; val3.m_equipped = false; val3.m_gridPos = val2; list.Add(val3); } from.RemoveItem(item, amount); return true; } private static Vector2i TakeFreeSlot(Inventory mirror, List<ItemData> slots) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) Vector2i val = FreeSlot(mirror, slots); if (val.x >= 0) { return val; } int height = mirror.GetHeight(); if (height >= 64) { return new Vector2i(-1, -1); } mirror.SetHeight(height + 1); return new Vector2i(0, height); } private static Vector2i FreeSlot(Inventory mirror, List<ItemData> slots) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < mirror.GetHeight(); i++) { for (int j = 0; j < mirror.GetWidth(); j++) { bool flag = false; foreach (ItemData slot in slots) { if (slot.m_gridPos.x == j && slot.m_gridPos.y == i) { flag = true; break; } } if (!flag) { return new Vector2i(j, i); } } } return new Vector2i(-1, -1); } private static string MatchKey(ItemData item) { string text = item.m_shared.m_name + "|" + item.m_quality + "|" + item.m_variant + "|" + item.m_worldLevel; if (item.m_shared.m_maxStackSize > 1) { return text; } return text + "|" + item.m_durability.ToString("F1") + "|" + item.m_crafterName; } private static void StoreOrGiveBack(StorageSession session, ItemData item, int amount) { if (amount > 0) { int num = session.StoreIntoChests(item, amount); int num2 = amount - num; if (num2 > 0) { GiveBack(session, item, num2, tryChestsFirst: false); } } } private static void GiveBack(StorageSession session, ItemData template, int amount, bool tryChestsFirst) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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) if (amount <= 0) { return; } if (tryChestsFirst) { amount -= session.StoreIntoChests(template, amount); if (amount <= 0) { return; } } Player localPlayer = Player.m_localPlayer; int num = Mathf.Max(1, template.m_shared.m_maxStackSize); while (amount > 0 && Object.op_Implicit((Object)(object)localPlayer)) { int num2 = Mathf.Min(amount, num); ItemData val = template.Clone(); val.m_stack = num2; val.m_equipped = false; if (!((Humanoid)localPlayer).GetInventory().CanAddItem(val, num2) || !((Humanoid)localPlayer).GetInventory().AddItem(val)) { break; } amount -= num2; } if (amount <= 0) { Message("$mw_msg_hoardfull"); } else if (Object.op_Implicit((Object)(object)localPlayer)) { ItemData obj = template.Clone(); obj.m_stack = amount; obj.m_equipped = false; ItemDrop.DropItem(obj, amount, ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward + Vector3.up, Quaternion.identity); Message("$mw_msg_dropped"); } } private static void SplitOversizedStacks(StorageSession session) { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); foreach (ItemData item in new List<ItemData>(inventory.GetAllItems())) { int maxStackSize = item.m_shared.m_maxStackSize; if (maxStackSize <= 1 || item.m_stack <= maxStackSize) { continue; } int num = item.m_stack - maxStackSize; item.m_stack = maxStackSize; ItemData val = item.Clone(); int i; int num2; for (i = 0; i < num; i += num2) { num2 = Mathf.Min(num - i, maxStackSize); ItemData val2 = val.Clone(); val2.m_stack = num2; val2.m_equipped = false; if (!inventory.CanAddItem(val2, num2) || !inventory.AddItem(val2)) { break; } } if (i < num) { GiveBack(session, val, num - i, tryChestsFirst: true); } } } private void Rebuild(StorageSession session) { //IL_0074: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_010a: 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_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) Inventory mirror = Mirror; if (mirror == null) { return; } List<HoardEntry> list = BuildGroups(session); list.Sort(CompareGroups); int num = Mathf.Max(1, mirror.GetWidth()); List<ItemData> list2 = SlotsOf(mirror); if (list2 == null) { return; } Dictionary<HoardEntry, Vector2i> dictionary = new Dictionary<HoardEntry, Vector2i>(); HashSet<int> hashSet = new HashSet<int>(); foreach (HoardEntry item2 in list) { if (m_positions.TryGetValue(item2.Key, out var value)) { int item = value.y * num + value.x; if (value.x < num && hashSet.Add(item)) { dictionary[item2] = value; } } } int i = 0; foreach (HoardEntry item3 in list) { if (!dictionary.ContainsKey(item3)) { for (; hashSet.Contains(i); i++) { } hashSet.Add(i); dictionary[item3] = new Vector2i(i % num, i / num); } } int num2 = 0; int num3 = -1; foreach (KeyValuePair<HoardEntry, Vector2i> item4 in dictionary) { num2 = Mathf.Max(num2, item4.Value.y); num3 = Mathf.Max(num3, item4.Value.y * num + item4.Value.x); } m_totalRows = Mathf.Max(MinRows, num2 + 2); int totalRows = m_totalRows; list2.Clear(); m_slots.Clear(); m_positions.Clear(); mirror.SetHeight(totalRows); foreach (KeyValuePair<HoardEntry, Vector2i> item5 in dictionary) { HoardEntry key = item5.Key; if (key.Total > 0) { ItemData val = key.Sample.Clone(); val.m_equipped = false; val.m_stack = key.Total; val.m_gridPos = item5.Value; list2.Add(val); m_slots[val] = new SlotState { Key = key.Key, Expected = key.Total }; m_positions[key.Key] = item5.Value; } } UpdateWeightMethod?.Invoke(mirror, null); m_needsRelayout = num3 + 1 > dictionary.Count; m_lastChange = Time.time; UpdateTitle(session, list.Count); HoardControls.Refresh(); } private List<HoardEntry> BuildGroups(StorageSession session) { List<HoardEntry> list = new List<HoardEntry>(); Dictionary<string, HoardEntry> dictionary = new Dictionary<string, HoardEntry>(); foreach (RuneChest chest in session.Chests) { Inventory inventory = chest.Inventory; if (inventory == null) { continue; } foreach (ItemData allItem in inventory.GetAllItems()) { if (Matches(allItem)) { string key = MatchKey(allItem); if (!dictionary.TryGetValue(key, out var value)) { value = new HoardEntry { Key = key, Sample = allItem }; list.Add(value); dictionary[key] = value; } if (allItem.m_shared.m_maxStackSize <= 1 && value.Total > 0) { value = new HoardEntry { Key = key, Sample = allItem }; list.Add(value); } value.Total += allItem.m_stack; } } } return list; } private bool Matches(ItemData item) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Invalid comparison between Unknown and I4 //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Invalid comparison between Unknown and I4 //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Invalid comparison between Unknown and I4 //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Invalid comparison between Unknown and I4 //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Invalid comparison between Unknown and I4 //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Invalid comparison between Unknown and I4 //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Invalid comparison between Unknown and I4 //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Invalid comparison between Unknown and I4 //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Invalid comparison between Unknown and I4 //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Invalid comparison between Unknown and I4 //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Invalid comparison between Unknown and I4 //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Invalid comparison between Unknown and I4 //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Invalid comparison between Unknown and I4 //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Invalid comparison between Unknown and I4 //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Invalid comparison between Unknown and I4 //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Invalid comparison between Unknown and I4 //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Invalid comparison between Unknown and I4 //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Invalid comparison between Unknown and I4 //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Invalid comparison between Unknown and I4 //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Invalid comparison between Unknown and I4 if (m_search.Length > 0 && Localization.instance.Localize(item.m_shared.m_name).IndexOf(m_search, StringComparison.CurrentCultureIgnoreCase) < 0) { return false; } ItemType itemType = item.m_shared.m_itemType; switch (m_filter) { case ItemFilter.Materials: if ((int)itemType != 1 && (int)itemType != 9) { return (int)itemType == 23; } return true; case ItemFilter.Food: if ((int)itemType != 2) { return (int)itemType == 21; } return true; case ItemFilter.Weapons: if ((int)itemType != 3 && (int)itemType != 14 && (int)itemType != 22 && (int)itemType != 4 && (int)itemType != 5) { return (int)itemType == 15; } return true; case ItemFilter.Armor: if ((int)itemType != 6 && (int)itemType != 7 && (int)itemType != 11 && (int)itemType != 17 && (int)itemType != 12 && (int)itemType != 18) { return (int)itemType == 24; } return true; case ItemFilter.Tools: return (int)itemType == 19; case ItemFilter.Misc: if ((int)itemType != 16 && (int)itemType != 13 && (int)itemType != 10) { return (int)itemType == 0; } return true; default: return true; } } private int CompareGroups(HoardEntry a, HoardEntry b) { switch (m_sort) { case SortMode.Amount: return b.Total.CompareTo(a.Total); case SortMode.Weight: return (b.Sample.m_shared.m_weight * (float)b.Total).CompareTo(a.Sample.m_shared.m_weight * (float)a.Total); default: { int num = string.Compare(Localization.instance.Localize(a.Sample.m_shared.m_name), Localization.instance.Localize(b.Sample.m_shared.m_name), StringComparison.CurrentCultureIgnoreCase); if (num == 0) { return b.Total.CompareTo(a.Total); } return num; } } } private void UpdateTitle(StorageSession session, int shown) { Container.m_name = ((session.Denied > 0) ? $"$mw_well_name <color=#d08a8a>({session.Denied} $mw_ui_busy)</color>" : "$mw_well_name"); } internal void SetSearch(string search) { search = search ?? string.Empty; if (!(m_search == search)) { m_search = search; Relayout(); } } private void Relayout() { m_positions.Clear(); Sync(); } internal void SetFilter(ItemFilter filter) { if (m_filter != filter) { m_filter = filter; Relayout(); } } internal void CycleFilter() { m_filter = (ItemFilter)((int)(m_filter + 1) % 7); Relayout(); } internal void CycleSort() { m_sort = (SortMode)((int)(m_sort + 1) % 3); Relayout(); } private void ClampDrag(InventoryGui gui) { if (DragItemField == null || DragInventoryField == null || DragAmountField == null) { return; } object? value = DragItemField.GetValue(gui); ItemData val = (ItemData)((value is ItemData) ? value : null); if (val == null) { return; } object? value2 = DragInventoryField.GetValue(gui); Inventory val2 = (Inventory)((value2 is Inventory) ? value2 : null); if (val2 != null && val2 == Mirror) { int num = Mathf.Max(1, val.m_shared.m_maxStackSize); if (DragAmountField.GetValue(gui) is int num2 && num2 > num) { DragAmountField.SetValue(gui, num); } } } private static bool IsDragging() { if (!Object.op_Implicit((Object)(object)InventoryGui.instance) || DragItemField == null) { return false; } return DragItemField.GetValue(InventoryGui.instance) != null; } internal static ItemData DragItem(InventoryGui gui) { object? obj = DragItemField?.GetValue(gui); return (ItemData)((obj is ItemData) ? obj : null); } internal static Inventory DragInventory(InventoryGui gui) { object? obj = DragInventoryField?.GetValue(gui); return (Inventory)((obj is Inventory) ? obj : null); } internal static int DragAmount(InventoryGui gui) { object obj = DragAmountField?.GetValue(gui); if (obj is int) { return (int)obj; } return 0; } internal static void ReportFull() { if (!(Time.time < s_nextFullMessage)) { s_nextFullMessage = Time.time + 1f; Message("$mw_msg_hoardfull"); } } internal static void ClearDrag(InventoryGui gui) { SetupDragItemMethod?.Invoke(gui, new object[3] { null, null, 0 }); } private static Container CurrentContainer(InventoryGui gui) { if (!(CurrentContainerField != null)) { return null; } object? value = CurrentContainerField.GetValue(gui); return (Container)((value is Container) ? value : null); } private static void Message(string token) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize(token), 0, (Sprite)null, false); } } } internal class HoardControls : MonoBehaviour { private const float ControlHeight = 28f; private const float Inset = 10f; private const float MinimumGap = 90f; private static readonly FieldInfo ContainerGridField = AccessTools.Field(typeof(InventoryGui), "m_containerGrid"); private static HoardControls s_instance; private HoardContainer m_hoard; private InputField m_search; private Button m_filterButton; private Button m_sortButton; private GameObject m_searchGo; private GameObject m_filterGo; private GameObject m_sortGo; private bool m_searchFocused; internal static void Show(HoardContainer hoard) { if (EnsureCreated()) { s_instance.m_hoard = hoard; ((Component)s_instance).gameObject.SetActive(true); s_instance.m_search.text = string.Empty; s_instance.Dock(); s_instance.UpdateLabels(); } } internal static void Hide() { if (Object.op_Implicit((Object)(object)s_instance)) { s_instance.m_hoard = null; s_instance.SetSearchFocus(focused: false); s_instance.Undock(); ((Component)s_instance).gameObject.SetActive(false); } } internal static void Refresh() { if (Object.op_Implicit((Object)(object)s_instance) && ((Component)s_instance).gameObject.activeSelf) { s_instance.UpdateLabels(); } } private static bool EnsureCreated() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)s_instance)) { return true; } if (GUIManager.Instance == null || !Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront)) { return false; } GameObject val = new GameObject("MW_HoardControls", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(GUIManager.CustomGUIFront.transform, false); s_instance = val.AddComponent<HoardControls>(); try { s_instance.Build(); } catch (Exception arg) { MimirsWellPlugin.Log.LogError((object)$"Building the well controls failed: {arg}"); Object.Destroy((Object)(object)val); s_instance = null; return false; } val.SetActive(false); return true; } private void Build() { //IL_0018: 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_002c: 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_00b2: Expected O, but got Unknown //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown Transform transform = ((Component)this).transform; m_searchGo = GUIManager.Instance.CreateInputField(transform, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, (ContentType)0, Localization.instance.Localize("$mw_ui_search"), 15, 160f, 28f); m_search = m_searchGo.GetComponent<InputField>(); ((UnityEvent<string>)(object)m_search.onValueChanged).AddListener((UnityAction<string>)delegate(string value) { m_hoard?.SetSearch(value); }); m_filterGo = CreateButton(transform, out m_filterButton); ((UnityEvent)m_filterButton.onClick).AddListener((UnityAction)delegate { m_hoard?.CycleFilter(); UpdateLabels(); }); m_sortGo = CreateButton(transform, out m_sortButton); ((UnityEvent)m_sortButton.onClick).AddListener((UnityAction)delegate { m_hoard?.CycleSort(); UpdateLabels(); }); } private static GameObject CreateButton(Transform parent, out Button button) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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) GameObject val = GUIManager.Instance.CreateButton(string.Empty, parent, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, 120f, 28f); button = val.GetComponent<Button>(); Text componentInChildren = ((Component)button).GetComponentInChildren<Text>(); if (Object.op_Implicit((Object)(object)componentInChildren)) { componentInChildren.resizeTextForBestFit = false; componentInChildren.fontSize = 14; componentInChildren.alignment = (TextAnchor)4; componentInChildren.horizontalOverflow = (HorizontalWrapMode)1; } return val; } private void Dock() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_018b: 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_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) InventoryGui instance = InventoryGui.instance; if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)instance.m_container)) { return; } RectTransform container = instance.m_container; RectTransform val = (RectTransform)((Component)this).transform; ((Transform)val).SetParent((Transform)(object)container, false); val.anchorMin = Vector2.zero; val.anchorMax = Vector2.one; val.offsetMin = Vector2.zero; val.offsetMax = Vector2.zero; ((Transform)val).SetAsLastSibling(); Rect val2 = LocalRect((!Object.op_Implicit((Object)(object)instance.m_takeAllButton)) ? ((RectTransform)null) : ((RectTransform)((Component)instance.m_takeAllButton).transform), container); Rect rect = container.rect; float xMin = ((Rect)(ref rect)).xMin; rect = container.rect; float xMax = ((Rect)(ref rect)).xMax; float num; if (!(((Rect)(ref val2)).height > 1f)) { rect = container.rect; num = ((Rect)(ref rect)).yMax - 34f; } else { num = ((Rect)(ref val2)).center.y; } float centreY = num; float num2 = xMax - xMin - 40f; MimirsWellPlugin.Log.LogDebug((object)$"Well window title row: {num2:0} px between the vanilla buttons"); if (num2 < 90f) { m_searchGo.SetActive(false); m_sortGo.SetActive(false); m_filterGo.SetActive(false); return; } float num3 = Mathf.Clamp(num2 * 0.27f, 90f, 140f); bool flag = num2 >= 90f + num3 * 2f + 20f; float num4 = num2 - (flag ? (num3 * 2f + 20f) : (num3 + 10f)); Rect rect2 = container.rect; float num5 = xMin + 20f; Place(m_searchGo, rect2, num5, centreY, num4); num5 += num4 + 10f; if (flag) { Place(m_sortGo, rect2, num5, centreY, num3); num5 += num3 + 10f; } else { m_sortGo.SetActive(false); } Place(m_filterGo, rect2, num5, centreY, num3); ScrollToTop(instance); } private static void ScrollToTop(InventoryGui gui) { object? obj = ContainerGridField?.GetValue(gui); InventoryGrid val = (InventoryGrid)((obj is InventoryGrid) ? obj : null); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.m_scrollbar)) { val.m_scrollbar.value = 1f; } } private static void Place(GameObject go, Rect space, float x, float centreY, float width) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) go.SetActive(true); RectTransform component = go.GetComponent<RectTransform>(); component.anchorMin = Vector2.zero; component.anchorMax = Vector2.zero; component.pivot = new Vector2(0f, 0.5f); component.sizeDelta = new Vector2(width, 28f); component.anchoredPosition = new Vector2(x - ((Rect)(ref space)).xMin, centreY - ((Rect)(ref space)).yMin); } private static Rect LocalRect(RectTransform target, RectTransform space) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)target) || !Object.op_Implicit((Object)(object)space)) { return default(Rect); } Vector3[] array = (Vector3[])(object)new Vector3[4]; target.GetWorldCorners(array); Vector3 val = ((Transform)space).InverseTransformPoint(array[0]); Vector3 val2 = ((Transform)space).InverseTransformPoint(array[2]); return new Rect(val.x, val.y, val2.x - val.x, val2.y - val.y); } private void Undock() { if (Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront)) { ((Component)this).transform.SetParent(GUIManager.CustomGUIFront.transform, false); } } private void Update() { if (!Object.op_Implicit((Object)(object)m_hoard) || !m_hoard.IsOpen) { Hide(); return; } bool flag = Object.op_Implicit((Object)(object)m_search) && m_search.isFocused; if (flag != m_searchFocused) { SetSearchFocus(flag); } } private void OnDisable() { SetSearchFocus(focused: false); } private void SetSearchFocus(bool focused) { m_searchFocused = focused; GUIManager.BlockInput(focused); } private void UpdateLabels() { if (!((Object)(object)m_hoard == (Object)null)) { Text val = (Object.op_Implicit((Object)(object)m_filterButton) ? ((Component)m_filterButton).GetComponentInChildren<Text>() : null); if (Object.op_Implicit((Object)(object)val)) { val.text = Localization.instance.Localize(FilterToken(m_hoard.Filter)); } Text val2 = (Object.op_Implicit((Object)(object)m_sortButton) ? ((Component)m_sortButton).GetComponentInChildren<Text>() : null); if (Object.op_Implicit((Object)(object)val2)) { val2.text = Localization.instance.Localize(SortToken(m_hoard.Sort)); } } } private static string FilterToken(ItemFilter filter) { return filter switch { ItemFilter.Materials => "$mw_ui_materials", ItemFilter.Food => "$mw_ui_food", ItemFilter.Weapons => "$mw_ui_weapons", ItemFilter.Armor => "$mw_ui_armor", ItemFilter.Tools => "$mw_ui_tools", ItemFilter.Misc => "$mw_ui_misc", _ => "$mw_ui_all", }; } private static string SortToken(SortMode sort) { return sort switch { SortMode.Amount => "$mw_ui_sort_amount", SortMode.Weight => "$mw_ui_sort_weight", _ => "$mw_ui_sort_name", }; } } [BepInPlugin("benka.MimirsWell", "Mimir's Well", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] internal class MimirsWellPlugin : BaseUnityPlugin { public const string PluginGUID = "benka.MimirsWell"; public const string PluginName = "Mimir's Well"; public const string PluginVersion = "1.0.0"; public const string PieceCategory = "Mimir"; public const string PieceTable = "Hammer"; internal static MimirsWellPlugin Instance; internal static ManualLogSource Log; internal static ConfigEntry<float> NetworkRadius; internal static ConfigEntry<bool> RuneGlow; internal static ConfigEntry<int> HoardWidth; internal static ConfigEntry<int> HoardRows; private void Awake() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; NetworkRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Network", "Radius", 20f, new ConfigDescription("Range in meters within which rune chests are bound to Mímir's Well. Chests further away than the loaded area cannot be reached anyway.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 40f), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); HoardWidth = ((BaseUnityPlugin)this).Config.Bind<int>("Window", "Columns", 8, new ConfigDescription("Slots per row in the well window.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(4, 12), Array.Empty<object>())); HoardRows = ((BaseUnityPlugin)this).Config.Bind<int>("Window", "MaxRows", 10, new ConfigDescription("Most rows the well window may grow to. Stacks beyond that stay in their chests and are counted in the title.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(3, 16), Array.Empty<object>())); RuneGlow = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "RuneGlow", true, "Rune chests glow softly while bound to a well."); Translations.Register(); PrefabManager.OnVanillaPrefabsAvailable += AddPieces; new Harmony("benka.MimirsWell").PatchAll(); Log.LogInfo((object)"Mimir's Well 1.0.0 loaded"); } private void AddPieces() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) try { PieceManager.Instance.AddPieceCategory("Mimir"); AddWell(); AddRuneChest("MW_RuneChest_Wood", "piece_chest_wood", "$mw_runechest_wood", "$mw_runechest_wood_desc", "piece_workbench", (RequirementConfig[])(object)new RequirementConfig[3] { Req("Wood", 10), Req("FineWood", 4), Req("GreydwarfEye", 2) }); AddRuneChest("MW_RuneChest_Iron", "piece_chest", "$mw_runechest_iron", "$mw_runechest_iron_desc", "piece_workbench", (RequirementConfig[])(object)new RequirementConfig[3] { Req("FineWood", 10), Req("Iron", 2), Req("ElderBark", 4) }); AddRuneChest("MW_RuneChest_Blackmetal", "piece_chest_blackmetal", "$mw_runechest_blackmetal", "$mw_runechest_blackmetal_desc", "forge", (RequirementConfig[])(object)new RequirementConfig[4] { Req("BlackMetal", 6), Req("FineWood", 10), Req("Tar", 2), Req("SurtlingCore", 1) }); AddChisel(); } finally { PrefabManager.OnVanillaPrefabsAvailable -= AddPieces; } } private void AddChisel() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) GameObject val = PrefabManager.Instance.CreateClonedPrefab("MW_RuneChisel", "Hammer"); if (!Object.op_Implicit((Object)(object)val)) { Log.LogError((object)"Could not clone Hammer, the rune chisel is not available"); return; } ItemDrop component = val.GetComponent<ItemDrop>(); if (Object.op_Implicit((Object)(object)component)) { SharedData shared = component.m_itemData.m_shared; shared.m_name = "$mw_chisel"; shared.m_description = "$mw_chisel_desc"; shared.m_itemType = (ItemType)19; shared.m_maxStackSize = 1; shared.m_useDurability = false; shared.m_buildPieces = null; } ItemManager instance = ItemManager.Instance; ItemConfig val2 = new ItemConfig(); val2.Name = "$mw_chisel"; val2.Description = "$mw_chisel_desc"; val2.Amount = 1; val2.CraftingStation = "piece_workbench"; val2.Icon = RenderIcon(val); val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[4] { Req("FineWood", 10), Req("Bronze", 3), Req("GreydwarfEye", 10), Req("SurtlingCore", 1) }; bool flag = instance.AddItem(new CustomItem(val, false, val2)); Log.LogDebug((object)$"Rune chisel registered: {flag}, prefab '{((Object)val).name}', item name '{component?.m_itemData.m_shared.m_name}'"); } private static Sprite RenderIcon(GameObject prefab) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown try { return RenderManager.Instance.Render(new RenderRequest(prefab) { Rotation = RenderManager.IsometricRotation, UseCache = true, TargetPlugin = ((BaseUnityPlugin)Instance).Info.Metadata }); } catch (Exception ex) { Log.LogWarning((object)("Could not render an icon for " + ((Object)prefab).name + ": " + ex.Message)); return null; } } private static Sprite ChestBackground() { GameObject prefab = PrefabManager.Instance.GetPrefab("piece_chest_wood"); Container val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<Container>() : null); if (!Object.op_Implicit((Object)(object)val)) { return null; } return val.m_bkg; } private static RequirementConfig Req(string item, int amount) { //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_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown return new RequirementConfig { Item = item, Amount = amount, Recover = true }; } private void AddWell() { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Expected O, but got Unknown GameObject val = PrefabManager.Instance.CreateClonedPrefab("MW_MimirsWell", "guard_stone"); if (!Object.op_Implicit((Object)(object)val)) { Log.LogError((object)"Could not clone guard_stone, Mímir's Well is not available"); return; } MimirsWellStation mimirsWellStation = val.AddComponent<MimirsWellStation>(); PrivateArea component = val.GetComponent<PrivateArea>(); float hoverOffset = 1f; MeshRenderer val2 = null; if (Object.op_Implicit((Object)(object)component)) { mimirsWellStation.m_areaMarker = component.m_areaMarker; val2 = component.m_model; hoverOffset = component.m_hoverOffset; if (Object.op_Implicit((Object)(object)component.m_enabledEffect)) { Object.DestroyImmediate((Object)(object)component.m_enabledEffect); } Object.DestroyImmediate((Object)(object)component); } WellModel.Apply(val, val2); mimirsWellStation.m_model = val2; Container obj = val.AddComponent<Container>(); obj.m_name = "$mw_well_name"; obj.m_width = HoardWidth.Value; obj.m_height = HoardRows.Value; obj.m_privacy = (PrivacySetting)2; obj.m_checkGuardStone = true; obj.m_autoDestroyEmpty = false; obj.m_defaultItems = new DropTable(); obj.m_hoverOffset = hoverOffset; obj.m_bkg = ChestBackground(); val.AddComponent<HoardContainer>(); PieceManager instance = PieceManager.Instance; PieceConfig val3 = new PieceConfig(); val3.Name = "$mw_well_name"; val3.Description = "$mw_well_desc"; val3.PieceTable = "Hammer"; val3.Category = "Mimir"; val3.Icon = RenderIcon(val); val3.CraftingStation = "piece_workbench"; val3.Requirements = (RequirementConfig[])(object)new RequirementConfig[4] { Req("Stone", 20), Req("FineWood", 10), Req("GreydwarfEye", 10), Req("SurtlingCore", 2) }; instance.AddPiece(new CustomPiece(val, false, val3)); } private void AddRuneChest(string name, string basePrefab, string displayName, string description, string station, RequirementConfig[] requirements) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_00a5: 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_00ba: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown GameObject val = PrefabManager.Instance.CreateClonedPrefab(name, basePrefab); if (!Object.op_Implicit((Object)(object)val)) { Log.LogError((object)("Could not clone " + basePrefab + ", " + name + " is not available")); return; } Container component = val.GetComponent<Container>(); if (Object.op_Implicit((Object)(object)component)) { component.m_name = displayName; } val.AddComponent<RuneChest>(); PieceManager.Instance.AddPiece(new CustomPiece(val, false, new PieceConfig { Name = displayName, Description = description, PieceTable = "Hammer", Category = "Mimir", Icon = RenderIcon(val), CraftingStation = station, Requirements = requirements })); } } public class MimirsWellStation : MonoBehaviour { internal static readonly List<MimirsWellStation> All = new List<MimirsWellStation>(); public GameObject m_glow; public CircleProjector m_areaMarker; public MeshRenderer m_model; private ZNetView m_nview; public static float Radius => MimirsWellPlugin.NetworkRadius.Value; private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)m_nview) && m_nview.GetZDO() != null) { All.Add(this); if (Object.op_Implicit((Object)(object)m_areaMarker)) { m_areaMarker.m_radius = Radius; ((Component)m_areaMarker).gameObject.SetActive(false); } ((MonoBehaviour)this).InvokeRepeating("UpdateAreaMarker", 0.2f, 0.2f); } } private void OnDestroy() { All.Remove(this); } private void UpdateAreaMarker() { if (Object.op_Implicit((Object)(object)m_areaMarker)) { bool flag = false; Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer)) { GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject(); flag = Object.op_Implicit((Object)(object)hoverObject) && (Object)(object)hoverObject.GetComponentInParent<MimirsWellStation>() == (Object)(object)this; } if (flag) { m_areaMarker.m_radius = Radius; } if (((Component)m_areaMarker).gameObject.activeSelf != flag) { ((Component)m_areaMarker).gameObject.SetActive(flag); } } } internal List<RuneChest> GetChestsInRange() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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) float num = Radius * Radius; Vector3 position = ((Component)this).transform.position; List<RuneChest> list = new List<RuneChest>(); foreach (RuneChest item in RuneChest.All) { if (Object.op_Implicit((Object)(object)item) && item.IsUsable) { Vector3 val = ((Component)item).transform.position - position; if (((Vector3)(ref val)).sqrMagnitude <= num) { list.Add(item); } } } return list; } internal static MimirsWellStation FindWellFor(Vector3 position) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0045: Unknown result type (might be due to invalid IL or missing references) MimirsWellStation result = null; float num = float.MaxValue; float num2 = Radius * Radius; foreach (MimirsWellStation item in All) { if (Object.op_Implicit((Object)(object)item)) { Vector3 val = ((Component)item).transform.position - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude <= num2 && sqrMagnitude < num) { result = item; num = sqrMagnitude; } } } return result; } } internal static class ObjLoader { private static readonly char[] Space = new char[2] { ' ', '\t' }; public static Mesh Load(string path, out List<string> groups) { //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0128: 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) groups = new List<string>(); List<Vector3> list = new List<Vector3>(); List<Vector3> list2 = new List<Vector3>(); List<Vector2> list3 = new List<Vector2>(); List<Vector3> list4 = new List<Vector3>(); List<Vector3> list5 = new List<Vector3>(); List<Vector2> list6 = new List<Vector2>(); Dictionary<string, int> lookup = new Dictionary<string, int>(); List<List<int>> list7 = new List<List<int>>(); List<int> list8 = null; foreach (string item in File.ReadLines(path)) { string text = item.Trim(); if (text.Length == 0 || text[0] == '#') { continue; } string[] array = text.Split(Space, StringSplitOptions.RemoveEmptyEntries); switch (array[0]) { case "v": list.Add(new Vector3(0f - Float(array[1]), Float(array[2]), Float(array[3]))); break; case "vn": list2.Add(new Vector3(0f - Float(array[1]), Float(array[2]), Float(array[3]))); break; case "vt": list3.Add(new Vector2(Float(array[1]), (array.Length > 2) ? Float(array[2]) : 0f)); break; case "usemtl": groups.Add((array.Length > 1) ? array[1] : "default"); list8 = new List<int>(); list7.Add(list8); break; case "f": if (list8 == null) { groups.Add("default"); list8 = new List<int>(); list7.Add(list8); } AddFace(array, list, list2, list3, list4, list5, list6, lookup, list8); break; } } Mesh val = new Mesh { name = Path.GetFileNameWithoutExtension(path) }; if (list4.Count > 65000) { val.indexFormat = (IndexFormat)1; } val.SetVertices(list4); if (list6.Count == list4.Count) { val.SetUVs(0, list6); } val.subMeshCount = list7.Count; for (int i = 0; i < list7.Count; i++) { val.SetTriangles(list7[i], i); } if (list5.Count == list4.Count) { val.SetNormals(list5); } else { val.RecalculateNormals(); } val.RecalculateTangents(); val.RecalculateBounds(); return val; } private static void AddFace(string[] parts, List<Vector3> positions, List<Vector3> normals, List<Vector2> uvs, List<Vector3> vertices, List<Vector3> vertexNormals, List<Vector2> vertexUvs, Dictionary<string, int> lookup, List<int> triangles) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) List<int> list = new List<int>(parts.Length - 1); for (int i = 1; i < parts.Length; i++) { string text = parts[i]; if (!lookup.TryGetValue(text, out var value)) { string[] array = text.Split(new char[1] { '/' }); value = vertices.Count; vertices.Add(positions[Index(array[0], positions.Count)]); if (array.Length > 1 && array[1].Length > 0 && uvs.Count > 0) { vertexUvs.Add(uvs[Index(array[1], uvs.Count)]); } if (array.Length > 2 && array[2].Length > 0 && normals.Count > 0) { vertexNormals.Add(normals[Index(array[2], normals.Count)]); } lookup[text] = value; } list.Add(value); } for (int j = 1; j < list.Count - 1; j++) { triangles.Add(list[0]); triangles.Add(list[j + 1]); triangles.Add(list[j]); } } private static int Index(string value, int count) { int num = int.Parse(value, CultureInfo.InvariantCulture); if (num <= 0) { return count + num; } return num - 1; } private static float Float(string value) { return float.Parse(value, CultureInfo.InvariantCulture); } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] internal static class InventoryGridAmountPatch { private static readonly FieldInfo ElementsField = AccessTools.Field(typeof(InventoryGrid), "m_elements"); private static void Postfix(InventoryGrid __instance) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = __instance.GetInventory(); if (!HoardContainer.IsMirror(inventory) || !(ElementsField?.GetValue(__instance) is IEnumerable enumerable)) { return; } foreach (object item in enumerable) { InventoryElement val = (InventoryElement)((item is InventoryElement) ? item : null); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.m_amount) && ((Behaviour)val.m_amount).enabled) { ItemData val2 = ItemAt(inventory, val.Position); if (val2 != null) { val.m_amount.text = val2.m_stack.ToString(); } } } } private static ItemData ItemAt(Inventory inventory, Vector2i position) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_gridPos == position) { return allItem; } } return null; } } [HarmonyPatch(typeof(Hud), "Awake")] internal static class HudAwakePatch { private static void Postfix(Hud __instance) { GameObject prefab = PrefabManager.Instance.GetPrefab("MW_MimirsWell"); Piece val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<Piece>() : null); int num = ((__instance.m_pieceCategoryTabs != null) ? __instance.m_pieceCategoryTabs.Length : (-1)); MimirsWellPlugin.Log.LogDebug((object)string.Format("Build menu has {0} category tabs, the well sits in category {1}", num, Object.op_Implicit((Object)(object)val) ? ((object)Unsafe.As<PieceCategory, PieceCategory>(ref val.m_category)/*cast due to .constrained prefix*/).ToString() : "unknown")); } } [HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[] { typeof(Inventory), typeof(ItemData), typeof(int), typeof(int), typeof(int) })] internal static class InventoryMoveItemToThisPatch { private static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item, int amount, int x, int y, ref bool __result) { if (!HoardContainer.IsMirror(__instance)) { return true; } __result = HoardContainer.AcceptDrop(__instance, fromInventory, item, amount, x, y); if (!__result) { HoardContainer.ReportFull(); } return false; } } [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")] internal static class InventoryGuiSelectedItemPatch { private static bool Prefix(InventoryGui __instance, InventoryGrid grid, Vector2i pos) { //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) if (!Object.op_Implicit((Object)(object)grid) || !HoardContainer.IsMirror(grid.GetInventory())) { return true; } ItemData val = HoardContainer.DragItem(__instance); Inventory val2 = HoardContainer.DragInventory(__instance); if (val == null || val2 == null || HoardContainer.IsMirror(val2)) { return true; } int amount = HoardContainer.DragAmount(__instance); if (HoardContainer.AcceptDrop(grid.GetInventory(), val2, val, amount, pos.x, pos.y)) { HoardContainer.ClearDrag(__instance); return false; } HoardContainer.ReportFull(); return false; } } [HarmonyPatch(typeof(InventoryGui), "SetupDragItem")] internal static class InventoryGuiSetupDragItemPatch { private static void Prefix(ItemData item, Inventory inventory, ref int amount) { if (item != null && HoardContainer.IsMirror(inventory)) { amount = Mathf.Min(amount, Mathf.Max(1, item.m_shared.m_maxStackSize)); } } } [HarmonyPatch(typeof(InventoryGui), "UpdateContainer")] internal static class InventoryGuiUpdateContainerPatch { private static bool s_hidden; private static void Postfix(InventoryGui __instance) { if (HoardContainer.AnyOpen) { if (Object.op_Implicit((Object)(object)__instance.m_containerName)) { ((Behaviour)__instance.m_containerName).enabled = false; } SetActive(__instance.m_takeAllButton, active: false); SetActive(__instance.m_stackAllButton, active: false); s_hidden = true; } } internal static void Restore(InventoryGui gui) { if (s_hidden && Object.op_Implicit((Object)(object)gui)) { s_hidden = false; if (Object.op_Implicit((Object)(object)gui.m_containerName)) { ((Behaviour)gui.m_containerName).enabled = true; } SetActive(gui.m_takeAllButton, active: true); SetActive(gui.m_stackAllButton, active: true); } } private static void SetActive(Button button, bool active) { if (Object.op_Implicit((Object)(object)button) && ((Component)button).gameObject.activeSelf != active) { ((Component)button).gameObject.SetActive(active); } } } [HarmonyPatch(typeof(InventoryGui), "UpdateContainerWeight")] internal static class InventoryGuiContainerWeightPatch { private static void Postfix(InventoryGui __instance) { if (!Object.op_Implicit((Object)(object)__instance.m_containerWeight)) { return; } Transform parent = __instance.m_containerWeight.transform.parent; if (Object.op_Implicit((Object)(object)parent)) { bool flag = !HoardContainer.AnyOpen; if (((Component)parent).gameObject.activeSelf != flag) { ((Component)parent).gameObject.SetActive(flag); } } } } [HarmonyPatch(typeof(InventoryGui), "Show")] internal static class InventoryGuiShowPatch { private static void Prefix(InventoryGui __instance, Container container) { HoardContainer hoardContainer = (Object.op_Implicit((Object)(object)container) ? ((Component)container).GetComponent<HoardContainer>() : null); if (Object.op_Implicit((Object)(object)hoardContainer)) { hoardContainer.BeginSession(); } else { InventoryGuiUpdateContainerPatch.Restore(__instance); } } } [HarmonyPatch(typeof(InventoryGui), "Hide")] internal static class InventoryGuiHidePatch { private static void Postfix() { HoardContainer.CloseAll(); } } [HarmonyPatch(typeof(Container), "Save")] internal static class ContainerSavePatch { private static bool Prefix(Container __instance) { return !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<HoardContainer>()); } } [HarmonyPatch(typeof(Container), "AddDefaultItems")] internal static class ContainerAddDefaultItemsPatch { private static bool Prefix(Container __instance) { return !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<HoardContainer>()); } } [HarmonyPatch(typeof(Container), "Load")] internal static class ContainerLoadPatch { private static bool Prefix(Container __instance, ref bool __result) { if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<HoardContainer>())) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class ContainerHoverTextPatch { private static void Postfix(Container __instance, ref string __result) { MimirsWellStation component = ((Component)__instance).GetComponent<MimirsWellStation>(); if (Object.op_Implicit((Object)(object)component)) { __result += Localization.instance.Localize($"\n<color=#8fc7ff>$mw_well_bound: {component.GetChestsInRange().Count}</color>"); return; } RuneChest component2 = ((Component)__instance).GetComponent<RuneChest>(); if (!Object.op_Implicit((Object)(object)component2)) { __result += ChestUpgrade.HoverText(__instance); return; } long playerID = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Player.m_localPlayer.GetPlayerID() : 0); if (RuneChest.IsLockedByOther(__instance, playerID)) { __result += Localization.instance.Localize("\n<color=#d08a8a>$mw_chest_busy</color>"); return; } __result += (component2.IsLinked ? Localization.instance.Localize("\n<color=#8fc7ff>$mw_chest_linked</color>") : Localization.instance.Localize("\n<color=#9a8f80>$mw_chest_unlinked</color>")); __result += ChestUpgrade.HoverText(__instance); } } [HarmonyPatch(typeof(Container), "Interact")] internal static class ContainerInteractPatch { private static bool Prefix(Container __instance, Humanoid character, bool hold, bool alt, ref bool __result) { if (!hold && (Object)(object)character == (Object)(object)Player.m_localPlayer && ChestUpgrade.Find(__instance) != null) { ChestUpgrade.LogState(__instance); if (ChestUpgrade.WieldsChisel()) { __result = ChestUpgrade.Upgrade(__instance); return false; } } if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<RuneChest>())) { return true; } long playerID = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Player.m_localPlayer.GetPlayerID() : 0); if (!RuneChest.IsLockedByOther(__instance, playerID)) { return true; } if ((Object)(object)character == (Object)(object)Player.m_localPlayer && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, Localization.instance.Localize("$mw_chest_busy"), 0, (Sprite)null, false); } __result = true; return false; } } [HarmonyPatch(typeof(Container), "RPC_RequestOpen")] internal static class ContainerRequestOpenPatch { private static bool Prefix(Container __instance, long playerID) { return !RuneChest.IsLockedByOther(__instance, playerID); } } [HarmonyPatch(typeof(Container), "RPC_RequestStack")] internal static class ContainerRequestStackPatch { private static bool Prefix(Container __instance, long playerID) { return !RuneChest.IsLockedByOther(__instance, playerID); } } [HarmonyPatch(typeof(Container), "RPC_RequestTakeAll")] internal static class ContainerRequestTakeAllPatch { private static bool Prefix(Container __instance, long playerID) { return !RuneChest.IsLockedByOther(__instance, playerID); } } public class RuneChest : MonoBehaviour { internal static readonly List<RuneChest> All = new List<RuneChest>(); private const string LockOwnerKey = "MW_lockBy"; private const string LockTimeKey = "MW_lockAt"; private const double LockTimeout = 15.0; private static readonly MethodInfo CheckAccessMethod = AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null); internal Container Container; private ZNetView m_nview; private Light m_glow; private bool m_linked; private bool m_awaitingOwnership; private float m_awaitingUntil; internal bool IsLocked { get; private set; } internal bool IsLinked => m_linked; internal Inventory Inventory { get { if (!Object.op_Implicit((Object)(object)Container)) { return null; } return Container.GetInventory(); } } internal bool IsUsable { get { if (Object.op_Implicit((Object)(object)this) && Object.op_Implicit((Object)(object)m_nview) && m_nview.IsValid() && Object.op_Implicit((Object)(object)Container)) { return Container.GetInventory() != null; } return false; } } private static double NetTime { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0.0; } return ZNet.instance.GetTimeSeconds(); } } private static long LocalPlayerID { get { if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return 0L; } return Player.m_localPlayer.GetPlayerID(); } } private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); Container = ((Component)this).GetComponent<Container>(); if (Object.op_Implicit((Object)(object)m_nview) && m_nview.GetZDO() != null && Object.op_Implicit((Object)(object)Container)) { m_nview.Register<long>("MW_RequestLock", (Action<long, long>)RPC_RequestLock); m_nview.Register<bool>("MW_LockResponse", (Action<long, bool>)RPC_LockResponse); All.Add(this); CreateGlow(); ((MonoBehaviour)this).InvokeRepeating("UpdateLink", Random.Range(0.4f, 1.4f), 1f); } } private void OnDestroy() { All.Remove(this); StorageSession.Current?.OnChestLost(this); } private void CreateGlow() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (MimirsWellPlugin.RuneGlow.Value) { GameObject val = new GameObject("MW_RuneGlow"); val.transform.SetParent(((Component)this).transform, false); val.transform.localPosition = new Vector3(0f, 0.6f, 0f); m_glow = val.AddComponent<Light>(); m_glow.type = (LightType)2; m_glow.color = new Color(0.45f, 0.72f, 1f); m_glow.range = 2.2f; m_glow.intensity = 0f; m_glow.shadows = (LightShadows)0; } } private void UpdateLink() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) m_linked = (Object)(object)MimirsWellStation.FindWellFor(((Component)this).transform.position) != (Object)null; UpdateGlow(); } private void UpdateGlow() { if (Object.op_Implicit((Object)(object)m_glow)) { m_glow.intensity = ((!m_linked) ? 0f : (IsLocked ? 1.3f : 0.45f)); } } internal bool IsAccessible() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Container) || !Container.m_checkGuardStone) { return true; } return PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false); } internal void RequestLock() { StorageSession current = StorageSession.Current; if (!IsUsable || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { current?.OnLockResult(this, granted: false); } else if (m_nview.IsOwner()) { if (Container.IsInUse() || IsLockedByOther(Container, LocalPlayerID)) { current?.OnLockResult(this, granted: false); return; } Lock(); current?.OnLockResult(this, granted: true); } else { m_awaitingOwnership = false; m_nview.InvokeRPC("MW_RequestLock", new object[1] { Player.m_localPlayer.GetPlayerID() }); } } private void RPC_RequestLock(long sender, long playerID) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (m_nview.IsOwner()) { bool flag = !Container.IsInUse() && !IsLockedByOther(Container, playerID) && HasAccess(playerID); if (flag) { ZDO zDO = m_nview.GetZDO(); ZDOMan.instance.ForceSendZDO(sender, zDO.m_uid); zDO.SetOwner(sender); } m_nview.InvokeRPC(sender, "MW_LockResponse", new object[1] { flag }); } } private void RPC_LockResponse(long sender, bool granted) { StorageSession current = StorageSession.Current; if (current != null && current.IsPending(this)) { if (!granted) { current.OnLockResult(this, granted: false); } else if (m_nview.IsOwner()) { Lock(); current.OnLockResult(this, granted: true); } else { m_awaitingOwnership = true; m_awaitingUntil = Time.time + 2f; } } } private void Update() { if (m_awaitingOwnership) { StorageSession current = StorageSession.Current; if (current == null || !current.IsPending(this)) { m_awaitingOwnership = false; } else if (IsUsable && m_nview.IsOwner()) { m_awaitingOwnership = false; Lock(); current.OnLockResult(this, granted: true); } else if (Time.time > m_awaitingUntil) { m_awaitingOwnership = false; current.OnLockResult(this, granted: false); } } } private void Lock() { IsLocked = true; WriteLock(LocalPlayerID); UpdateGlow(); } internal void Unlock() { IsLocked = false; if (IsUsable && m_nview.IsOwner()) { WriteLock(0L); } UpdateGlow(); } internal void RefreshLock() { if (IsLocked && IsUsable && m_nview.IsOwner()) { WriteLock(LocalPlayerID); } } private void WriteLock(long playerID) { ZDO zDO = m_nview.GetZDO(); if (zDO != null) { zDO.Set("MW_lockBy", playerID); zDO.Set("MW_lockAt", (playerID == 0L) ? 0 : ((long)NetTime)); } } internal static bool IsLockedByOther(Container container, long playerID) { if (!Object.op_Implicit((Object)(object)container)) { return false; } ZNetView component = ((Component)container).GetComponent<ZNetView>(); ZDO val = ((Object.op_Implicit((Object)(object)component) && component.IsValid()) ? component.GetZDO() : null); if (val == null) { return false; } long num = val.GetLong("MW_lockBy", 0L); if (num == 0L || num == playerID) { return false; } return NetTime - (double)val.GetLong("MW_lockAt", 0L) < 15.0; } private bool HasAccess(long playerID) { if (CheckAccessMethod == null) { return true; } try { return (bool)CheckAccessMethod.Invoke(Container, new object[1] { playerID }); } catch { return true; } } } internal class HoardEntry { public string Key; public ItemData Sample; public int Total; } internal class StorageSession { public readonly MimirsWellStation Well; private readonly List<RuneChest> m_locked = new List<RuneChest>(); private readonly Dictionary<RuneChest, float> m_pending = new Dictionary<RuneChest, float>(); private float m_nextHeartbeat; public static StorageSession Current { get; private set; } public int Denied { get; private set; } public bool Dirty { get; set; } = true; public int PendingCount => m_pending.Count; public List<RuneChest> Chests => m_locked; private StorageSession(MimirsWellStation well) { Well = well; } public static StorageSession Begin(MimirsWellStation well) { End(); StorageSession storageSession = (Current = new StorageSession(well)); foreach (RuneChest item in well.GetChestsInRange()) { if (!item.IsAccessible()) { storageSession.Denied++; continue; } storageSession.m_pending[item] = Time.time + 3f; item.RequestLock(); } MimirsWellPlugin.Log.LogDebug((object)($"Well opened: {well.GetChestsInRange().Count} rune chests in range, " + $"{storageSession.m_locked.Count} bound, {storageSession.m_pending.Count} pending, {storageSession.Denied} denied " + $"(radius {MimirsWellStation.Radius}m, {RuneChest.All.Count} rune chests loaded)")); return storageSession; } public static void End() { StorageSession current = Current; Current = null; if (current == null) { return; } foreach (RuneChest item in current.m_locked) { if (Object.op_Implicit((Object)(object)item)) { item.Unlock(); } } current.m_locked.Clear(); current.m_pending.Clear(); } public bool IsPending(RuneChest chest) { return m_pending.ContainsKey(chest); } public void OnLockResult(RuneChest chest, bool granted) { if (m_pending.Remove(chest)) { if (granted) { m_locked.Add(chest); } else { Denied++; } Dirty = true; } } public void OnChestLost(RuneChest chest) { m_pending.Remove(chest); if (m_locked.Remove(chest)) { Dirty = true; } } public void Update() { if (m_pending.Count > 0) { List<RuneChest> list = null; foreach (KeyValuePair<RuneChest, float> item in m_pending) { if (Time.time > item.Value) { (list ?? (list = new List<RuneChest>())).Add(item.Key); } } if (list != null) { foreach (RuneChest item2 in list) { OnLockResult(item2, granted: false); } } } for (int num = m_locked.Count - 1; num >= 0; num--) { if (!Object.op_Implicit((Object)(object)m_locked[num]) || !m_locked[num].IsUsable) { m_locked.RemoveAt(num); Dirty = true; } } if (!(Time.time >= m_nextHeartbeat)) { return; } m_nextHeartbeat = Time.time + 3f; foreach (RuneChest item3 in m_locked) { item3.RefreshLock(); } } public int StoreIntoChests(ItemData item, int amount) { if (item == null || amount <= 0) { return 0; } List<RuneChest> list = new List<RuneChest>(m_locked); list.Sort((RuneChest a, RuneChest b) => Holds(b, item).CompareTo(Holds(a, item))); int num = 0; foreach (RuneChest item2 in list) { if (amount <= 0) { break; } if (!Object.op_Implicit((Object)(object)item2) || !item2.IsUsable || !item2.IsLocked) { continue; } Inventory inventory = item2.Inventory; if (inventory == null) { continue; } int num2 = FitAmount(inventory, item, amount); if (num2 > 0) { ItemData val = item.Clone(); val.m_stack = num2; val.m_equipped = false; if (inventory.AddItem(val)) { amount -= num2; num += num2; } } } if (num > 0) { Dirty = true; } return num; } public int CapacityFor(ItemData item, int amount) { if (item == null || amount <= 0) { return 0; } int num = 0; foreach (RuneChest item2 in m_locked) { if (num >= amount) { break; } if (Object.op_Implicit((Object)(object)item2) && item2.IsUsable && item2.IsLocked) { Inventory inventory = item2.Inventory; if (inventory != null) { num += FitAmount(inventory, item, amount - num); } } } return Mathf.Min(num, amount); } private static int Holds(RuneChest chest, ItemData item) { if (!Object.op_Implicit((Object)(object)chest)) { return 0; } Inventory inventory = chest.Inventory; if (inventory == null) { return 0; } return (inventory.CountItems(item.m_shared.m_name, -1, false) > 0) ? 1 : 0; } private static int FitAmount(Inventory inventory, ItemData item, int want) { if (want <= 0) { return 0; } if (inventory.CanAddItem(item, want)) { return want; } int num = 0; int num2 = want; while (num < num2) { int num3 = (num + num2 + 1) / 2; if (inventory.CanAddItem(item, num3)) { num = num3; } else { num2 = num3 - 1; } } return num; } } internal static class Translations { public static void Register() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "jotunn_cat_mimir", "Mímir" }, { "mw_well_name", "Mímir's Well" }, { "mw_well_desc", "A rune stone bound to the well of wisdom. Look into it to see everything stored in the rune chests around it." }, { "mw_well_use", "Look into the well" }, { "mw_well_bound", "Bound rune chests" }, { "mw_runechest_wood", "Rune chest" }, { "mw_runechest_wood_desc", "A wooden chest carved with binding runes. Mímir's Well can see into it." }, { "mw_runechest_iron", "Bound rune chest" }, { "mw_runechest_iron_desc", "An iron-bound chest carved with binding runes. Mímir's Well can see into it." }, { "mw_runechest_blackmetal", "Blackmetal rune chest" }, { "mw_runechest_blackmetal_desc", "A blackmetal chest carved with binding runes. Mímir's Well can see into it." }, { "mw_chisel", "Rune chisel" }, { "mw_chisel_desc", "Carved from fine wood and bronze, its edge knows the binding runes. Carry it and marking a chest costs nothing." }, { "mw_upgrade_to", "Carve into a" }, { "mw_upgrade_needs_chisel", "needs the rune chisel" }, { "mw_upgrade_hold_chisel", "hold the rune chisel" }, { "mw_upgrade_done", "The runes take hold" }, { "mw_upgrade_failed", "The chest does not answer" }, { "mw_chest_linked", "Bound to Mímir's Well" }, { "mw_chest_unlinked", "No well in reach, the runes are silent" }, { "mw_chest_busy", "Someone is looking into this chest" }, { "mw_ui_title", "Mímir's Well" }, { "mw_ui_search", "Search..." }, { "mw_ui_network", "Hoard" }, { "mw_ui_chests", "chests" }, { "mw_ui_slots", "slots" }, { "mw_ui_busy", "in use" }, { "mw_ui_waiting", "binding..." }, { "mw_ui_inventory", "Your inventory" }, { "mw_ui_all", "All" }, { "mw_ui_materials", "Materials" }, { "mw_ui_food", "Food" }, { "mw_ui_weapons", "Weapons" }, { "mw_ui_armor", "Armor" }, { "mw_ui_tools", "Tools" }, { "mw_ui_misc", "Other" }, { "mw_ui_sort_name", "Sort: Name" }, { "mw_ui_sort_amount", "Sort: Amount" }, { "mw_ui_sort_weight", "Sort: Weight" }, { "mw_ui_quickstack", "Sort in" }, { "mw_ui_storeall", "Store all" }, { "mw_ui_close", "Close" }, { "mw_ui_hint", "Left click: stack · Shift: all · Right click: one" }, { "mw_ui_empty", "The well is quiet. Build rune chests nearby." }, { "mw_ui_hidden", "more stacks" }, { "mw_ui_stacks", "stacks" }, { "mw_msg_full", "Your inventory is full" }, { "mw_msg_hoardfull", "The rune chests are full" }, { "mw_msg_dropped", "The rune chests are full, dropped at your feet" }, { "mw_msg_stored", "Stored" } }); text = "German"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "jotunn_cat_mimir", "Mímir" }, { "mw_well_name", "Mímirs Brunnen" }, { "mw_well_desc", "Ein Runenstein, gebunden an den Brunnen der Weisheit. Blick hinein und sieh alles, was in den Runentruhen ringsum lagert." }, { "mw_well_use", "In den Brunnen blicken" }, { "mw_well_bound", "Gebundene Runentruhen" }, { "mw_runechest_wood", "Runentruhe" }, { "mw_runechest_wood_desc", "Eine Holztruhe mit eingeritzten Bindungsrunen. Mímirs Brunnen kann hineinsehen." }, { "mw_runechest_iron", "Beschlagene Runentruhe" }, { "mw_runechest_iron_desc", "Eine eisenbeschlagene Truhe mit Bindungsrunen. Mímirs Brunnen kann hineinsehen." }, { "mw_runechest_blackmetal", "Schwarzmetall-Runentruhe" }, { "mw_runechest_blackmetal_desc", "Eine Schwarzmetalltruhe mit Bindungsrunen. Mímirs Brunnen kann hineinsehen." }, { "mw_chisel", "Runenmeißel" }, { "mw_chisel_desc", "Aus Feinholz und Bronze gefertigt, seine Schneide kennt die Bindungsrunen. Wer ihn trägt, zeichnet Truhen ohne Kosten." }, { "mw_upgrade_to", "Verwandeln in" }, { "mw_upgrade_needs_chisel", "braucht den Runenmeißel" }, { "mw_upgrade_hold_chisel", "Runenmeißel in die Hand nehmen" }, { "mw_upgrade_done", "Die Runen greifen" }, { "mw_upgrade_failed", "Die Truhe antwortet nicht" }, { "mw_chest_linked", "Gebunden an Mímirs Brunnen" }, { "mw_chest_unlinked", "Kein Brunnen in Reichweite, die Runen schweigen" }, { "mw_chest_busy", "Jemand blickt gerade in diese Truhe" }, { "mw_ui_title", "Mímirs Brunnen" }, { "mw_ui_search", "Suchen..." }, { "mw_ui_network", "Hort" }, { "mw_ui_chests", "Truhen" }, { "mw_ui_slots", "Plätze" }, { "mw_ui_busy", "belegt" }, { "mw_ui_waiting", "binde..." }, { "mw_ui_inventory", "Dein Inventar" }, { "mw_ui_all", "Alle" }, { "mw_ui_materials", "Material" }, { "mw_ui_food", "Nahrung" }, { "mw_ui_weapons", "Waffen" }, { "mw_ui_armor", "Rüstung" }, { "mw_ui_tools", "Werkzeug" }, { "mw_ui_misc", "Sonst." }, { "mw_ui_sort_name", "Sort.: Name" }, { "mw_ui_sort_amount", "Sort.: Anzahl" }, { "mw_ui_sort_weight", "Sort.: Gewicht" }, { "mw_ui_quickstack", "Einsortieren" }, { "mw_ui_storeall", "Alles einlagern" }, { "mw_ui_close", "Schließen" }, { "mw_ui_hint", "Linksklick: Stapel · Shift: alles · Rechtsklick: eins" }, { "mw_ui_empty", "Der Brunnen ist still. Baue Runentruhen in der Nähe." }, { "mw_ui_hidden", "weitere Stapel" }, { "mw_ui_stacks", "Stapel" }, { "mw_msg_full", "Dein Inventar ist voll" }, { "mw_msg_hoardfull", "Die Runentruhen sind voll" }, { "mw_msg_dropped", "Runentruhen voll, vor deinen Füßen abgelegt" }, { "mw_msg_stored", "Eingelagert" } }); } } internal static class WellModel { private const string ModelFile = "MimirsWell.obj"; private static readonly string[] StoneDonors = new string[4] { "blackmarble_post01", "piece_blackmarble_wall_2x2", "guard_stone", "piece_stonecutter" }; private static readonly string[] MetalDonors = new string[4] { "piece_chest_blackmetal", "forge", "piece_artisanstation", "piece_cartographytable" }; public static void Apply(GameObject prefab, MeshRenderer renderer) { //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)renderer)) { MimirsWellPlugin.Log.LogWarning((object)"The well prefab has no renderer to put the model on, keeping the guard stone look"); return; } string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "MimirsWell.obj"); if (!File.Exists(text)) { MimirsWellPlugin.Log.LogWarning((object)("Model " + text + " not found, keeping the guard stone look")); return; } Mesh val; List<string> groups; try { val = ObjLoader.Load(text, out groups); } catch (Exception arg) { MimirsWellPlugin.Log.LogError((object)string.Format("Could not read {0}: {1}", "MimirsWell.obj", arg)); return; } MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>(); if (!Object.op_Implicit((Object)(object)component)) { MimirsWellPlugin.Log.LogWarning((object)"The well renderer has no mesh filter, keeping the guard stone look"); return; } Material val2 = FindMaterial(StoneDonors) ?? ((Renderer)renderer).sharedMaterial; Material val3 = CreateMetalMaterial(FindMaterial(MetalDonors) ?? val2); Material[] array = (Material[])(object)new Material[groups.Count]; for (int i = 0; i < groups.Count; i++) { string text2 = groups[i]; if (!(text2 == "metal")) { if (text2 == "glow") { array[i] = CreateGlowMaterial(val2); } else { array[i] = val2; } } else { array[i] = val3; } } component.sharedMesh = val; ((Renderer)renderer).sharedMaterials = array; ((Component)renderer).transform.localPosition = Vector3.zero; ((Component)renderer).transform.localRotation = Quaternion.identity; ((Component)renderer).transform.localScale = Vector3.one; ((Renderer)renderer).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)renderer).receiveShadows = true; ReplaceColliders(prefab); RemoveDonorEffects(prefab); AddPoolLight(prefab); LogLeftovers(prefab, (Renderer)(object)renderer); ManualLogSource log = MimirsWellPlugin.Log; string text3 = string.Format("Well model loaded: {0} vertices, {1} groups ({2}), ", val.vertexCount, val.subMeshCount, string.Join(", ", groups.ToArray())); string arg2 = ((val2 != null) ? ((Object)val2).name : null); string arg3 = ((val3 != null) ? ((Object)val3).name : null); Bounds bounds = val.bounds; log.LogDebug((object)(text3 + $"stone material '{arg2}', metal material '{arg3}', bounds {((Bounds)(ref bounds)).size}")); } private static void AddPoolLight(GameObject prefab) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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) GameObject val = new GameObject("MW_PoolLight"); val.transform.SetParent(prefab.transform, false); val.transform.localPosition = new Vector3(0f, 0.75f, 0f); Light obj = val.AddComponent<Light>(); obj.type = (LightType)2; obj.color = new Color(0.3f, 0.6f, 1f); obj.range = 4f; obj.intensity = 0.95f; obj.shadows = (LightShadows)0; } private static void RemoveDonorEffects(GameObject prefab) { ParticleSystem[] componentsInChildren = prefab.GetComponentsInChildren<ParticleSystem>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)((Component)componentsInChildren[i]).gameObject); } } private static void LogLeftovers(GameObject prefab, Renderer keep) { List<string> list = new List<string>(); Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)(object)keep)) { list.Add($"{((Object)val).name} ({((object)val).GetType().Name}, active {((Component)val).gameObject.activeSelf})"); } } ParticleSystem[] componentsInChildren2 = prefab.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val2 in componentsInChildren2) { list.Add(((Object)val2).name + " (ParticleSystem)"); } if (list.Count > 0) { MimirsWellPlugin.Log.LogDebug((object)("Well prefab also carries: " + string.Join(", ", list.ToArray()))); } } private static void ReplaceColliders(GameObject prefab) { //IL_003e: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if (!val.isTrigger) { Object.DestroyImmediate((Object)(object)val); } } BoxCollider obj = prefab.AddComponent<BoxCollider>(); obj.center = new Vector3(0f, 0.4f, 0f); obj.size = new Vector3(1.75f, 0.8f, 1.75f); BoxCollider obj2 = prefab.AddComponent<BoxCollider>(); obj2.center = new Vector3(0f, 1.2f, 0.5f); obj2.size = new Vector3(0.95f, 1.7f, 0.45f); } private static bool IsStaticShader(Material material) { if (!Object.op_Implicit((Object)(object)material) || !Object.op_Implicit((Object)(object)material.shader)) { return false; } string text = ((Object)material.shader).name.ToLowerInvariant(); if (text.Contains("veget") || text.Contains("grass") || text.Contains("cloth") || text.Contains("wind") || text.Contains("water") || text.Contains("particle") || text.Contains("tar") || text.Contains("yggdrasil")) { return false; } if (!text.Contains("piece") && !text.Contains("static") && !text.Contains("standard") && !text.Contains("creature")) { return text.Contains("rock"); } return true; } private static Material FindMaterial(string[] donors) { foreach (string text in donors) { GameObject prefab = PrefabManager.Instance.GetPrefab(text); if (!Object.op_Implicit((Object)(object)prefab)) { continue; } MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true); for (int j = 0; j < componentsInChildren.Length; j++) { Material sharedMaterial = ((Renderer)componentsInChildren[j]).sharedMaterial; if (Object.op_Implicit((Object)(object)sharedMaterial)) { if (IsStaticShader(sharedMaterial)) { MimirsWellPlugin.Log.LogDebug((object)("Using material '" + ((Object)sharedMaterial).name + "' from " + text + " (shader '" + ((Object)sharedMaterial.shader).name + "')")); return sharedMaterial; } MimirsWellPlugin.Log.LogDebug((object)("Skipping material '" + ((Object)sharedMaterial).name