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 AllfathersChest v0.7.2
plugins/AllfathersChest.dll
Decompiled 12 hours agousing System; 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 System.Security; using System.Security.Permissions; using System.Text; using AllfathersChest.Chest; using AllfathersChest.Sorting; using AllfathersChest.Ui; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("AllfathersChest")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("One chest you throw everything into; it sorts the contents into the chests around it.")] [assembly: AssemblyFileVersion("0.7.2.0")] [assembly: AssemblyInformationalVersion("0.7.2+63df982a1b7fe64ac160fa92fbfdbdb1920794c1")] [assembly: AssemblyProduct("Allfather's Chest")] [assembly: AssemblyTitle("AllfathersChest")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.7.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace AllfathersChest { public static class ModConfig { public static ConfigEntry<bool> Enabled; public static ConfigEntry<ModLanguage> Language; public static ConfigEntry<string> BasePrefab; public static ConfigEntry<int> Width; public static ConfigEntry<int> Height; public static ConfigEntry<int> Cost; public static ConfigEntry<bool> AutoSort; public static ConfigEntry<float> UpkeepSeconds; public static ConfigEntry<float> Radius; public static ConfigEntry<bool> ShowCounter; public static ConfigEntry<bool> ShowRange; public static ConfigEntry<bool> GroundPickup; public static ConfigEntry<float> GroundGraceSeconds; public static ConfigEntry<bool> Verbose; public static void Bind(ConfigFile cfg) { Enabled = cfg.Bind<bool>("1 - General", "Enabled", true, "Master switch. Off, the chest is still there and still opens - the button simply does nothing. / Hauptschalter. Aus heisst: die Truhe steht und oeffnet weiterhin, der Knopf tut nur nichts mehr."); Language = cfg.Bind<ModLanguage>("1 - General", "Language", ModLanguage.Game, "Which language the chest speaks. Game follows Valheim. / Welche Sprache die Truhe spricht. Game folgt Valheim."); BasePrefab = cfg.Bind<string>("2 - Chest", "BasePrefab", "piece_chest", "The game piece the chest is copied from - its looks, nothing else. piece_chest is the reinforced one. Change it if you would rather have a different chest standing there. / Das Spielbauteil, von dem die Truhe kopiert wird - nur das Aussehen. piece_chest ist die verstaerkte Truhe. Aendern, wenn dort lieber eine andere stehen soll."); Width = cfg.Bind<int>("2 - Chest", "Width", 8, "Slots across. Eight by four is twice a reinforced chest, which is about one trip home. / Plaetze in der Breite. Acht mal vier ist doppelt so viel wie eine verstaerkte Truhe, also ungefaehr ein Heimweg."); Height = cfg.Bind<int>("2 - Chest", "Height", 4, "Slots down. / Plaetze in der Hoehe."); Cost = cfg.Bind<int>("2 - Chest", "Cost", 20, "Wood to build one. / Holz zum Bauen."); AutoSort = cfg.Bind<bool>("3 - Sorting", "AutoSort", true, "Look after the chest without being asked: sweep the ground if that is on, and hand everything out. Off, nothing moves until somebody presses the button. / Sich ungefragt um die Truhe kuemmern: den Boden einsammeln, falls eingeschaltet, und alles verteilen. Aus heisst: es bewegt sich nichts, bis jemand den Knopf drueckt."); UpkeepSeconds = cfg.Bind<float>("3 - Sorting", "UpkeepSeconds", 5f, "Seconds between two unattended passes, for both halves. / Sekunden zwischen zwei unbeaufsichtigten Durchgaengen, fuer beide Haelften."); Radius = cfg.Bind<float>("3 - Sorting", "Radius", 20f, "How far the chest reaches, in metres, as a sphere - so a cellar two floors down counts. / Wie weit die Truhe reicht, in Metern, als Kugel - ein Keller zwei Etagen tiefer zaehlt also dazu."); ShowCounter = cfg.Bind<bool>("3 - Sorting", "ShowCounter", true, "Show on the chest how much it has sorted and how much found no home. / Auf der Truhe anzeigen, wie viel sie sortiert hat und wie viel keine Kiste fand."); ShowRange = cfg.Bind<bool>("3 - Sorting", "ShowRange", false, "Draw the chest's reach as a wireframe sphere while you stand near it. Three circles, not one: the reach is a sphere, so a cellar below counts and the shape has to say so. For setting up; off the rest of the time. / Die Reichweite als Drahtkugel zeichnen, solange du in der Naehe stehst. Drei Kreise, nicht einer: die Reichweite ist eine Kugel, ein Keller darunter zaehlt also dazu, und die Form soll das sagen. Zum Einrichten; sonst aus."); GroundPickup = cfg.Bind<bool>("4 - Ground", "PickUpFromGround", false, "When the button is pressed, also pick up what is lying on the ground within reach, whoever dropped it. Off by default: a chest that empties the floor is a surprise the first time it happens. / Beim Druecken des Knopfes auch aufheben, was in Reichweite auf dem Boden liegt, egal wer es fallen liess. Standardmaessig aus: eine Truhe, die den Boden leerraeumt, ueberrascht beim ersten Mal."); GroundGraceSeconds = cfg.Bind<float>("4 - Ground", "GraceSeconds", 8f, "How long a thing must have lain there before the chest will take it. Somebody putting something down for somebody else should have a moment to do it. / Wie lange etwas gelegen haben muss, bevor die Truhe es nimmt. Wer etwas fuer jemanden hinlegt, soll einen Moment dafuer haben."); Verbose = cfg.Bind<bool>("5 - Debug", "Verbose", false, "Write every move to the log. Loud, and the first thing to turn on when something goes somewhere unexpected. / Jeden Zug ins Log schreiben. Laut, und das Erste, was man einschaltet, wenn etwas irgendwo landet, wo es nicht hingehoert."); Language.SettingChanged += delegate { Texts.Setting = Language.Value; }; Texts.Setting = Language.Value; } } [BepInPlugin("sohneg.AllfathersChest", "Allfather's Chest", "0.7.2")] [BepInProcess("valheim.exe")] public class AllfathersChestPlugin : BaseUnityPlugin { public const string ModGuid = "sohneg.AllfathersChest"; public const string ModName = "Allfather's Chest"; public const string ModVersion = "0.7.2"; private const float PieceCheckSeconds = 2f; public static ManualLogSource Log; public static AllfathersChestPlugin Instance; private Harmony _harmony; private float _nextPieceCheck; private float _nextUpkeep; private void Awake() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Texts.Log = delegate(string message) { Log.LogWarning((object)message); }; Texts.GameLanguage = () => (Localization.instance == null) ? "" : Localization.instance.GetSelectedLanguage(); Texts.Load(); ModConfig.Bind(((BaseUnityPlugin)this).Config); _harmony = new Harmony("sohneg.AllfathersChest"); _harmony.PatchAll(); Log.LogInfo((object)"Allfather's Chest 0.7.2 is awake."); } private void Update() { if ((Object)(object)ZNetScene.instance == (Object)null) { SortingChestPiece.Reset(); ContainerRegistry.Clear(); SortButton.Reset(); Upkeep.Reset(); return; } SortButton.Tick(); float unscaledTime = Time.unscaledTime; if (unscaledTime >= _nextUpkeep) { _nextUpkeep = unscaledTime + Mathf.Max(1f, ModConfig.UpkeepSeconds.Value); try { Upkeep.Tick(); } catch (Exception ex) { Log.LogError((object)("The chest stumbled while looking after itself: " + ex)); } } if (!(unscaledTime >= _nextPieceCheck)) { return; } _nextPieceCheck = unscaledTime + 2f; try { SortingChestPiece.Tick(); } catch (Exception ex2) { Log.LogError((object)("Could not keep the chest in the build menu: " + ex2)); } } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } Instance = null; } } public enum ModLanguage { Game, English, Deutsch } public static class Texts { public const string Fallback = "en"; private static readonly Dictionary<string, Dictionary<string, string[]>> Tables = new Dictionary<string, Dictionary<string, string[]>>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> Reported = new HashSet<string>(StringComparer.Ordinal); public static Func<string> GameLanguage; public static Action<string> Log; public static ModLanguage Setting = ModLanguage.Game; public static readonly string[] Available = new string[2] { "en", "de" }; public static void Load() { Tables.Clear(); Reported.Clear(); for (int i = 0; i < Available.Length; i++) { string text = Available[i]; Dictionary<string, string[]> dictionary = ReadEmbedded(text); if (dictionary != null) { Tables[text] = dictionary; } } } public static string Get(string key, params string[] values) { return GetIn(ActiveCode(), key, values); } public static string GetIn(string code, string key, params string[] values) { return Fill(Pick(code, key), values); } public static string ActiveCode() { return Setting switch { ModLanguage.English => "en", ModLanguage.Deutsch => "de", _ => FromGame(), }; } public static bool Has(string code) { if (code != null) { return Tables.ContainsKey(code); } return false; } public static ICollection<string> KeysOf(string code) { if (!Tables.TryGetValue(code ?? "", out var value)) { return new string[0]; } return value.Keys; } public static int VariantCount(string code, string key) { return VariantsOf(code, key).Length; } public static string[] VariantsOf(string code, string key) { if (!Tables.TryGetValue(code ?? "", out var value)) { return new string[0]; } if (!value.TryGetValue(key ?? "", out var value2)) { return new string[0]; } return value2; } private static string FromGame() { string a = ""; try { if (GameLanguage != null) { a = GameLanguage() ?? ""; } } catch { } if (!string.Equals(a, "German", StringComparison.OrdinalIgnoreCase)) { return "en"; } return "de"; } private static string Pick(string code, string key) { string[] array = Lookup(code, key); if (array == null || array.Length == 0) { return key ?? ""; } return array[0]; } private static string[] Lookup(string code, string key) { if (string.IsNullOrEmpty(key)) { return null; } if (Tables.TryGetValue(code ?? "", out var value) && value.TryGetValue(key, out var value2)) { return value2; } if (!string.Equals(code, "en", StringComparison.OrdinalIgnoreCase) && Tables.TryGetValue("en", out value) && value.TryGetValue(key, out value2)) { Report("Text '" + key + "' is missing from " + code + ".json, using en."); return value2; } Report("Text '" + key + "' is missing from every language file."); return null; } private static string Fill(string template, string[] values) { if (string.IsNullOrEmpty(template) || values == null || values.Length == 0) { return template ?? ""; } StringBuilder stringBuilder = new StringBuilder(template); for (int i = 0; i + 1 < values.Length; i += 2) { stringBuilder.Replace("{" + values[i] + "}", values[i + 1] ?? ""); } return stringBuilder.ToString(); } private static Dictionary<string, string[]> ReadEmbedded(string code) { string text = "AllfathersChest.Localization." + code + ".json"; try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { Report("Language file " + text + " is not embedded in this build."); return null; } using StreamReader streamReader = new StreamReader(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), detectEncodingFromByteOrderMarks: true); Dictionary<string, string[]> dictionary = Parse(streamReader.ReadToEnd()); if (dictionary == null || dictionary.Count == 0) { Report("Language file " + text + " could not be read."); return null; } return dictionary; } catch (Exception ex) { Report("Language file " + text + " could not be read: " + ex.GetType().Name + ": " + ex.Message); return null; } } public static Dictionary<string, string[]> Parse(string json) { if (string.IsNullOrEmpty(json)) { return null; } Dictionary<string, string[]> dictionary = new Dictionary<string, string[]>(StringComparer.Ordinal); List<string> list = new List<string>(); int i = 0; SkipSpace(json, ref i); if (i >= json.Length || json[i] != '{') { return null; } i++; while (i < json.Length) { SkipSpace(json, ref i); if (i >= json.Length || json[i] == '}') { break; } if (json[i] == ',') { i++; continue; } string text = ReadString(json, ref i); if (text == null) { break; } SkipSpace(json, ref i); if (i >= json.Length || json[i] != ':') { break; } i++; SkipSpace(json, ref i); if (i >= json.Length) { break; } list.Clear(); if (json[i] == '[') { i++; while (i < json.Length) { SkipSpace(json, ref i); if (i >= json.Length) { break; } if (json[i] == ']') { i++; break; } if (json[i] == ',') { i++; continue; } string text2 = ReadString(json, ref i); if (text2 == null) { break; } list.Add(text2); } } else { if (json[i] != '"') { for (; i < json.Length && json[i] != ',' && json[i] != '}'; i++) { } continue; } string text3 = ReadString(json, ref i); if (text3 != null) { list.Add(text3); } } if (list.Count > 0) { dictionary[text] = list.ToArray(); } } return dictionary; } private static void SkipSpace(string s, ref int i) { while (i < s.Length && char.IsWhiteSpace(s[i])) { i++; } } private static string ReadString(string s, ref int i) { SkipSpace(s, ref i); if (i >= s.Length || s[i] != '"') { return null; } i++; StringBuilder stringBuilder = new StringBuilder(); while (i < s.Length) { char c = s[i++]; switch (c) { case '"': return stringBuilder.ToString(); default: stringBuilder.Append(c); continue; case '\\': break; } if (i >= s.Length) { break; } char c2 = s[i++]; switch (c2) { case 'n': stringBuilder.Append('\n'); break; case 'r': stringBuilder.Append('\r'); break; case 't': stringBuilder.Append('\t'); break; case 'b': stringBuilder.Append('\b'); break; case 'f': stringBuilder.Append('\f'); break; case 'u': if (i + 4 <= s.Length) { if (int.TryParse(s.Substring(i, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result)) { stringBuilder.Append((char)result); } i += 4; } break; default: stringBuilder.Append(c2); break; } } return null; } private static void Report(string message) { if (Reported.Add(message) && Log != null) { Log(message); } } } } namespace AllfathersChest.Ui { internal static class SortButton { [CompilerGenerated] private static class <>O { public static UnityAction <0>__OnClick; } private const float Width = 180f; private static GameObject _go; private static TMP_Text[] _labels; private static UITooltip _tooltip; private static bool _shown; public static void Build(InventoryGui gui) { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Expected O, but got Unknown //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gui == (Object)null || (Object)(object)gui.m_takeAllButton == (Object)null || (Object)(object)gui.m_container == (Object)null || ((Object)(object)_go != (Object)null && (Object)(object)_go.transform.parent == (Object)(object)gui.m_container)) { return; } _go = Object.Instantiate<GameObject>(((Component)gui.m_takeAllButton).gameObject, (Transform)(object)gui.m_container, false); ((Object)_go).name = "AllfathersChest_SortButton"; Localize[] componentsInChildren = _go.GetComponentsInChildren<Localize>(true); foreach (Localize val in componentsInChildren) { Object.Destroy((Object)(object)val); } Button component = _go.GetComponent<Button>(); if ((Object)(object)component != (Object)null) { ((UnityEventBase)component.onClick).RemoveAllListeners(); ButtonClickedEvent onClick = component.onClick; object obj = <>O.<0>__OnClick; if (obj == null) { UnityAction val2 = OnClick; <>O.<0>__OnClick = val2; obj = (object)val2; } ((UnityEvent)onClick).AddListener((UnityAction)obj); } _labels = _go.GetComponentsInChildren<TMP_Text>(true); _tooltip = _go.GetComponent<UITooltip>(); string text = Texts.Get("button.sort"); for (int j = 0; j < _labels.Length; j++) { if (!((Object)(object)_labels[j] == (Object)null)) { _labels[j].enableAutoSizing = true; _labels[j].fontSizeMin = 10f; _labels[j].overflowMode = (TextOverflowModes)1; _labels[j].text = text; } } if ((Object)(object)_tooltip != (Object)null) { _tooltip.m_topic = text; _tooltip.m_text = Texts.Get("button.tip"); } RectTransform val3 = (RectTransform)_go.transform; val3.anchorMin = new Vector2(1f, 0f); val3.anchorMax = new Vector2(1f, 0f); val3.pivot = new Vector2(1f, 1f); val3.anchoredPosition = new Vector2(0f, -6f); val3.sizeDelta = new Vector2(180f, val3.sizeDelta.y); _shown = true; Show(visible: false); } public static void Tick() { if (!((Object)(object)_go == (Object)null)) { InventoryGui instance = InventoryGui.instance; Container val = (((Object)(object)instance != (Object)null) ? instance.m_currentContainer : null); Show((Object)(object)val != (Object)null && SortingChestPiece.IsOurs(val)); } } public static void Reset() { _go = null; _labels = null; _tooltip = null; _shown = false; } private static void Show(bool visible) { if (visible != _shown) { _shown = visible; _go.SetActive(visible); } } private static void OnClick() { InventoryGui instance = InventoryGui.instance; Container val = (((Object)(object)instance != (Object)null) ? instance.m_currentContainer : null); if (!((Object)(object)val == (Object)null) && SortingChestPiece.IsOurs(val)) { Distributor.Result result = Distributor.SortNow(val); Say(result); } } private static void Say(Distributor.Result result) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } int num = result.Moved + result.Gleaned; string text; if (num == 0 && result.Stuck == 0) { text = Texts.Get("message.none"); } else { text = Texts.Get("message.sorted", "count", num.ToString()); if (result.Stuck > 0) { text = text + ", " + Texts.Get("message.stuck", "count", result.Stuck.ToString()); } } ((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false); } } } namespace AllfathersChest.Sorting { internal static class Distributor { public struct Result { public int Gleaned; public int Moved; public int Stuck; } private const int MovesPerPress = 128; private static readonly List<Container> Candidates = new List<Container>(); private static readonly List<ChestFacts> Facts = new List<ChestFacts>(); private static readonly List<List<ItemData>> RealStacks = new List<List<ItemData>>(); private static readonly List<ItemData> Pending = new List<ItemData>(); public static Result SortNow(Container hub) { Result result = default(Result); if (!ModConfig.Enabled.Value) { return result; } if ((Object)(object)hub == (Object)null || (Object)(object)hub.m_nview == (Object)null || !hub.m_nview.IsValid()) { return result; } if (!hub.m_nview.IsOwner()) { return result; } Inventory inventory = hub.GetInventory(); if (inventory == null) { return result; } InUse.Forget(hub); if (inventory.NrOfItems() == 0) { Counter.Reset(hub); return result; } return Run(hub, inventory, 128, ModConfig.GroundPickup.Value); } public static Result Distribute(Container hub, int budget) { Result result = default(Result); if ((Object)(object)hub == (Object)null || (Object)(object)hub.m_nview == (Object)null || !hub.m_nview.IsValid()) { return result; } if (!hub.m_nview.IsOwner()) { return result; } Inventory inventory = hub.GetInventory(); if (inventory == null) { return result; } if (inventory.NrOfItems() == 0) { Counter.Reset(hub); return result; } return Run(hub, inventory, budget, ModConfig.GroundPickup.Value); } private static Result Run(Container hub, Inventory from, int budget, bool glean) { Result result = default(Result); ContainerRegistry.Candidates(hub, ModConfig.Radius.Value, Candidates); if (Candidates.Count == 0) { return result; } Describe(hub); if (glean) { result.Gleaned = Gleaner.Glean(hub, ModConfig.Radius.Value, budget, Facts); } int num = 0; int num2 = 0; int num3 = 0; Pending.Clear(); Pending.AddRange(from.GetAllItems()); for (int i = 0; i < Pending.Count; i++) { if (budget <= 0) { break; } ItemData val = Pending[i]; if (val == null || val.m_stack <= 0 || !from.ContainsItem(val)) { continue; } while (budget > 0 && val.m_stack > 0) { Describe(hub); List<Move> list = StorePlanner.Plan(Facts_Of(val), Facts); if (list.Count == 0) { num2 += val.m_stack; break; } budget--; int num4 = Carry(hub, from, val, list[0]); if (num4 <= 0) { break; } num += num4; num3++; } } Counter.Note(hub, num, num2); result.Moved = num; result.Stuck = num2; if ((num > 0 || result.Gleaned > 0) && ModConfig.Verbose.Value) { AllfathersChestPlugin.Log.LogInfo((object)("Gleaned " + result.Gleaned + "; sorted " + num + " thing(s) in " + num3 + " move(s); " + num2 + " found no chest; " + Candidates.Count + " chest(s) in range.")); } return result; } private static int Carry(Container hub, Inventory from, ItemData item, Move move) { //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) if (move.ChestId < 0 || move.ChestId >= Candidates.Count) { return 0; } Container val = Candidates[move.ChestId]; if ((Object)(object)val == (Object)null || (Object)(object)val.m_nview == (Object)null || !val.m_nview.IsValid()) { return 0; } if (InUse.Anywhere(val)) { if (ModConfig.Verbose.Value) { AllfathersChestPlugin.Log.LogInfo((object)(" skipping " + Readable(val.m_name) + " - in use by " + InUse.Holder(val))); } return 0; } if (!val.m_nview.IsOwner()) { Take(val.m_nview); return 0; } Inventory inventory = val.GetInventory(); if (inventory == null) { return 0; } Vector2i val3; if (move.StackIndex >= 0) { List<ItemData> list = RealStacks[move.ChestId]; if (move.StackIndex >= list.Count) { return 0; } ItemData val2 = list[move.StackIndex]; if (val2 == null || !inventory.ContainsItem(val2)) { return 0; } val3 = val2.m_gridPos; } else { val3 = inventory.FindEmptySlot(true); if (val3.x < 0 || val3.y < 0) { return 0; } } int stack = item.m_stack; int num = Mathf.Min(move.Amount, stack); if (num <= 0) { return 0; } inventory.MoveItemToThis(from, item, num, val3.x, val3.y); int num2 = stack - item.m_stack; if (num2 <= 0) { return 0; } val.Save(); hub.Save(); if (ModConfig.Verbose.Value) { AllfathersChestPlugin.Log.LogInfo((object)(" " + num2 + "x " + Readable(Name(item)) + " -> " + Readable(val.m_name) + " at " + val3.x + "," + val3.y)); } return num2; } private static bool Take(ZNetView view) { view.ClaimOwnership(); return view.IsOwner(); } private static void Describe(Container hub) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) Facts.Clear(); RealStacks.Clear(); Vector3 position = ((Component)hub).transform.position; for (int i = 0; i < Candidates.Count; i++) { Container val = Candidates[i]; Inventory inventory = val.GetInventory(); ChestFacts chestFacts = new ChestFacts { Id = i, Distance = Vector3.Distance(position, ((Component)val).transform.position), EmptySlots = inventory.GetEmptySlots() }; List<ItemData> allItems = inventory.GetAllItems(); List<ItemData> list = new List<ItemData>(allItems.Count); for (int j = 0; j < allItems.Count; j++) { ItemData val2 = allItems[j]; if (val2 != null && val2.m_shared != null) { chestFacts.Stacks.Add(Facts_Of(val2)); list.Add(val2); } } Facts.Add(chestFacts); RealStacks.Add(list); } } internal static StackFacts Facts_Of(ItemData item) { return new StackFacts { Name = Name(item), Quality = item.m_quality, WorldLevel = item.m_worldLevel, Stack = item.m_stack, MaxStack = ((item.m_shared != null) ? item.m_shared.m_maxStackSize : 0) }; } private static string Name(ItemData item) { if (item == null || item.m_shared == null) { return ""; } return item.m_shared.m_name; } private static string Readable(string token) { if (string.IsNullOrEmpty(token)) { return "?"; } if (Localization.instance == null) { return token; } return Localization.instance.Localize(token); } } internal static class Gleaner { public static int Glean(Container hub, float radius, int budget, IList<ChestFacts> homes) { //IL_0032: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) if (homes == null || homes.Count == 0) { return 0; } List<ItemDrop> s_instances = ItemDrop.s_instances; if (s_instances == null || s_instances.Count == 0) { return 0; } Inventory inventory = hub.GetInventory(); if (inventory == null) { return 0; } Vector3 position = ((Component)hub).transform.position; float num = radius * radius; float num2 = Mathf.Max(0f, ModConfig.GroundGraceSeconds.Value); int num3 = 0; int num4 = 0; for (int i = 0; i < s_instances.Count; i++) { if (budget <= 0) { break; } ItemDrop val = s_instances[i]; if ((Object)(object)val == (Object)null || val.IsPiece() || (Object)(object)val.m_nview == (Object)null || !val.m_nview.IsValid()) { continue; } Vector3 val2 = ((Component)val).transform.position - position; if (((Vector3)(ref val2)).sqrMagnitude > num || val.GetTimeSinceSpawned() < (double)num2) { continue; } ItemData itemData = val.m_itemData; if (itemData == null || itemData.m_shared == null || itemData.m_stack <= 0 || itemData.m_shared.m_questItem || !inventory.CanAddItem(itemData, itemData.m_stack)) { continue; } if (StorePlanner.Plan(Distributor.Facts_Of(itemData), homes).Count == 0) { num4++; continue; } if (!val.CanPickup(false)) { val.RequestOwn(); continue; } val.Load(); itemData = val.m_itemData; if (itemData == null || itemData.m_stack <= 0) { continue; } int stack = itemData.m_stack; if (inventory.AddItem(itemData)) { ZNetScene.instance.Destroy(((Component)val).gameObject); hub.Save(); num3 += stack; budget--; if (ModConfig.Verbose.Value) { AllfathersChestPlugin.Log.LogInfo((object)(" picked up " + stack + "x " + Readable(itemData.m_shared.m_name))); } } } if (num4 > 0 && ModConfig.Verbose.Value) { AllfathersChestPlugin.Log.LogInfo((object)(" " + num4 + " thing(s) left on the ground - no chest free for them right now.")); } return num3; } private static string Readable(string token) { if (string.IsNullOrEmpty(token)) { return "?"; } if (Localization.instance == null) { return token; } return Localization.instance.Localize(token); } } public struct StackFacts { public string Name; public int Quality; public int WorldLevel; public int Stack; public int MaxStack; } public sealed class ChestFacts { public int Id; public float Distance; public int EmptySlots; public readonly List<StackFacts> Stacks = new List<StackFacts>(); } public struct Move { public int ChestId; public int Amount; public int StackIndex; } public static class StorePlanner { public static List<Move> Plan(StackFacts item, IList<ChestFacts> chests) { List<Move> list = new List<Move>(); if (item.Stack <= 0 || item.MaxStack <= 0 || chests == null || chests.Count == 0) { return list; } List<ChestFacts> list2 = Ordered(chests); int num = item.Stack; for (int i = 0; i < list2.Count; i++) { if (num <= 0) { break; } ChestFacts chestFacts = list2[i]; for (int j = 0; j < chestFacts.Stacks.Count; j++) { if (num <= 0) { break; } StackFacts there = chestFacts.Stacks[j]; if (Mergeable(item, there)) { int num2 = there.MaxStack - there.Stack; if (num2 > 0) { int num3 = ((num2 < num) ? num2 : num); list.Add(new Move { ChestId = chestFacts.Id, Amount = num3, StackIndex = j }); num -= num3; } } } } for (int k = 0; k < list2.Count; k++) { if (num <= 0) { break; } ChestFacts chestFacts2 = list2[k]; if (Keeps(chestFacts2, item.Name)) { int num4 = chestFacts2.EmptySlots; while (num4 > 0 && num > 0) { int num5 = ((item.MaxStack < num) ? item.MaxStack : num); list.Add(new Move { ChestId = chestFacts2.Id, Amount = num5, StackIndex = -1 }); num -= num5; num4--; } } } return list; } private static List<ChestFacts> Ordered(IList<ChestFacts> chests) { List<ChestFacts> list = new List<ChestFacts>(chests); for (int i = 1; i < list.Count; i++) { ChestFacts chestFacts = list[i]; int num = i - 1; while (num >= 0 && list[num].Distance > chestFacts.Distance) { list[num + 1] = list[num]; num--; } list[num + 1] = chestFacts; } return list; } private static bool Mergeable(StackFacts item, StackFacts there) { if (string.Equals(item.Name, there.Name, StringComparison.Ordinal) && item.Quality == there.Quality) { return item.WorldLevel == there.WorldLevel; } return false; } private static bool Keeps(ChestFacts chest, string name) { for (int i = 0; i < chest.Stacks.Count; i++) { if (string.Equals(chest.Stacks[i].Name, name, StringComparison.Ordinal)) { return true; } } return false; } } internal static class Upkeep { private const int Budget = 16; private static readonly List<Container> Hubs = new List<Container>(); private static readonly List<Container> Everything = new List<Container>(); private static readonly HashSet<ZDOID> Settled = new HashSet<ZDOID>(); private static readonly HashSet<ZDOID> Current = new HashSet<ZDOID>(); private static long _toldAbout; public static void Tick() { //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.Enabled.Value || (Object)(object)ZNetScene.instance == (Object)null) { return; } Speak(); if (!ModConfig.AutoSort.Value) { return; } ContainerRegistry.Hubs(Hubs); Current.Clear(); for (int i = 0; i < Hubs.Count; i++) { Container val = Hubs[i]; if ((Object)(object)val == (Object)null || (Object)(object)val.m_nview == (Object)null || !val.m_nview.IsValid()) { continue; } ZDO zDO = val.m_nview.GetZDO(); if (zDO == null) { continue; } if (!val.m_nview.IsOwner()) { Announce(val, zDO); continue; } ZDOID uid = zDO.m_uid; Current.Add(uid); if (Settled.Contains(uid) && !InUse.Anywhere(val)) { InUse.Forget(val); Report(Distributor.Distribute(val, 16)); } } Settled.Clear(); foreach (ZDOID item in Current) { Settled.Add(item); } } private static void Speak() { ContainerRegistry.All(Everything); for (int i = 0; i < Everything.Count; i++) { InUse.Publish(Everything[i]); } } public static void Reset() { Hubs.Clear(); Everything.Clear(); Settled.Clear(); Current.Clear(); _toldAbout = 0L; } private static void Announce(Container hub, ZDO zdo) { if (!ModConfig.Verbose.Value) { return; } long owner = zdo.GetOwner(); if (owner != _toldAbout) { _toldAbout = owner; string text = "nobody"; if (owner != 0L && (Object)(object)ZNet.instance != (Object)null) { ZNetPeer peer = ZNet.instance.GetPeer(owner); text = ((peer == null || string.IsNullOrEmpty(peer.m_playerName)) ? owner.ToString() : peer.m_playerName); } AllfathersChestPlugin.Log.LogInfo((object)("The chest belongs to " + text + " right now, so their machine looks after it - not this one.")); } } private static void Report(Distributor.Result result) { if (ModConfig.Verbose.Value && (result.Gleaned != 0 || result.Moved != 0)) { AllfathersChestPlugin.Log.LogInfo((object)("Upkeep: swept " + result.Gleaned + ", handed out " + result.Moved + ", " + result.Stuck + " still with nowhere to go.")); } } } } namespace AllfathersChest.Patches { [HarmonyPatch(typeof(Container), "Awake")] internal static class ContainerAwakePatch { private static void Postfix(Container __instance) { ContainerRegistry.Note(__instance); } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class ContainerHoverPatch { private static void Postfix(Container __instance, ref string __result) { if (ModConfig.ShowCounter.Value && SortingChestPiece.IsOurs(__instance)) { string text = Counter.Line(__instance); if (text.Length != 0) { __result = text + "\n" + __result; } } } } [HarmonyPatch(typeof(Container), "SetInUse")] internal static class ContainerInUsePatch { private static void Postfix(Container __instance, bool inUse) { InUse.Mark(__instance, inUse); } } [HarmonyPatch(typeof(InventoryGui), "Awake")] internal static class InventoryGuiAwakePatch { [HarmonyPostfix] private static void Postfix(InventoryGui __instance) { SortButton.Build(__instance); } } } namespace AllfathersChest.Chest { internal static class ContainerRegistry { private static readonly List<Container> Known = new List<Container>(); public static int Count => Known.Count; public static void Note(Container container) { if (!((Object)(object)container == (Object)null)) { Known.Add(container); } } public static void All(List<Container> into) { into.Clear(); Sweep(); into.AddRange(Known); } public static void Hubs(List<Container> into) { into.Clear(); Sweep(); for (int i = 0; i < Known.Count; i++) { if (SortingChestPiece.IsOurs(Known[i])) { into.Add(Known[i]); } } } public static void Candidates(Container hub, float radius, List<Container> into) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Invalid comparison between Unknown and I4 //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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) into.Clear(); if ((Object)(object)hub == (Object)null) { return; } Sweep(); Vector3 position = ((Component)hub).transform.position; float num = radius * radius; for (int i = 0; i < Known.Count; i++) { Container val = Known[i]; if (val != hub && !SortingChestPiece.IsOurs(val) && (int)val.m_privacy == 2 && !((Object)(object)val.m_wagon != (Object)null) && !((Object)(object)val.m_nview == (Object)null) && val.m_nview.IsValid() && val.GetInventory() != null) { Vector3 val2 = ((Component)val).transform.position - position; if (!(((Vector3)(ref val2)).sqrMagnitude > num) && !InUse.Anywhere(val)) { into.Add(val); } } } } public static void Clear() { Known.Clear(); } private static void Sweep() { for (int num = Known.Count - 1; num >= 0; num--) { if ((Object)(object)Known[num] == (Object)null) { Known.RemoveAt(num); } } } } internal static class Counter { private const string MovedKey = "sohneg_ac_moved"; private const string StuckKey = "sohneg_ac_stuck"; public static void Note(Container hub, int moved, int stuck) { ZDO val = Writable(hub); if (val != null) { if (moved > 0) { val.Set("sohneg_ac_moved", val.GetInt("sohneg_ac_moved", 0) + moved); } val.Set("sohneg_ac_stuck", stuck); } } public static void Reset(Container hub) { ZDO val = Writable(hub); if (val != null && (val.GetInt("sohneg_ac_moved", 0) != 0 || val.GetInt("sohneg_ac_stuck", 0) != 0)) { val.Set("sohneg_ac_moved", 0); val.Set("sohneg_ac_stuck", 0); } } public static string Line(Container hub) { if ((Object)(object)hub == (Object)null || (Object)(object)hub.m_nview == (Object)null || !hub.m_nview.IsValid()) { return ""; } ZDO zDO = hub.m_nview.GetZDO(); if (zDO == null) { return ""; } int num = zDO.GetInt("sohneg_ac_moved", 0); int num2 = zDO.GetInt("sohneg_ac_stuck", 0); if (num == 0 && num2 == 0) { return Texts.Get("chest.idle"); } string text = ""; if (num > 0) { text = Texts.Get("chest.moved", "count", num.ToString()); } if (num2 > 0) { string text2 = Texts.Get("chest.stuck", "count", num2.ToString()); text = ((text.Length > 0) ? (text + ", " + text2) : text2); } return text; } private static ZDO Writable(Container hub) { if ((Object)(object)hub == (Object)null || (Object)(object)hub.m_nview == (Object)null || !hub.m_nview.IsValid()) { return null; } if (!hub.m_nview.IsOwner()) { return null; } return hub.m_nview.GetZDO(); } } internal static class InUse { private const string Key = "sohneg_ac_state"; private const int Unknown = 0; private const int Closed = 1; private const int Open = 2; private const float Margin = 2f; private const float FallbackReach = 6f; public static void Mark(Container container, bool open) { if (!((Object)(object)container == (Object)null) && !((Object)(object)container.m_nview == (Object)null) && container.m_nview.IsValid() && container.m_nview.IsOwner()) { ZDO zDO = container.m_nview.GetZDO(); if (zDO != null) { zDO.Set("sohneg_ac_state", (!open) ? 1 : 2); } } } public static void Publish(Container container) { if ((Object)(object)container == (Object)null || (Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid() || !container.m_nview.IsOwner()) { return; } ZDO zDO = container.m_nview.GetZDO(); if (zDO != null) { int num = ((!container.IsInUse()) ? 1 : 2); if (zDO.GetInt("sohneg_ac_state", 0) != num) { zDO.Set("sohneg_ac_state", num); } } } public static bool Anywhere(Container container) { if ((Object)(object)container == (Object)null || (Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid()) { return false; } if (container.IsInUse()) { return true; } ZDO zDO = container.m_nview.GetZDO(); if (zDO == null) { return false; } return zDO.GetInt("sohneg_ac_state", 0) switch { 2 => true, 1 => false, _ => OwnerIsStandingAtIt(container, zDO), }; } private static bool OwnerIsStandingAtIt(Container container, ZDO zdo) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_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) if ((Object)(object)ZNet.instance == (Object)null) { return false; } long owner = zdo.GetOwner(); if (owner == 0L) { return false; } if (owner == ZDOMan.GetSessionID()) { return false; } ZNetPeer peer = ZNet.instance.GetPeer(owner); if (peer == null) { return false; } float num = Reach(); Vector3 val = peer.m_refPos - ((Component)container).transform.position; return ((Vector3)(ref val)).sqrMagnitude <= num * num; } private static float Reach() { InventoryGui instance = InventoryGui.instance; float num = (((Object)(object)instance != (Object)null) ? instance.m_autoCloseDistance : 0f); if (num <= 0f) { num = 6f; } return num + 2f; } public static void Forget(Container container) { if (!((Object)(object)container == (Object)null) && !((Object)(object)container.m_nview == (Object)null) && container.m_nview.IsValid() && container.m_nview.IsOwner() && !container.IsInUse()) { ZDO zDO = container.m_nview.GetZDO(); if (zDO != null && zDO.GetInt("sohneg_ac_state", 0) != 1) { zDO.Set("sohneg_ac_state", 1); } } } public static string Holder(Container container) { if ((Object)(object)container == (Object)null || (Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid()) { return ""; } if (container.IsInUse()) { return "us"; } ZDO zDO = container.m_nview.GetZDO(); if (zDO == null) { return ""; } long owner = zDO.GetOwner(); if (owner == 0L || owner == ZDOMan.GetSessionID()) { return ""; } ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetPeer(owner) : null); if (val == null) { return ""; } string text = (string.IsNullOrEmpty(val.m_playerName) ? owner.ToString() : val.m_playerName); if (zDO.GetInt("sohneg_ac_state", 0) != 2) { return text + " (standing by it)"; } return text + " (says so)"; } } internal sealed class RangeRing : MonoBehaviour { private const int Segments = 96; private const float ViewingMargin = 20f; private const float CheckSeconds = 0.25f; private static readonly string[] Shaders = new string[3] { "Hidden/Internal-Colored", "Sprites/Default", "Unlit/Color" }; private static Material _material; private static bool _complained; private LineRenderer[] _rings; private float _drawnRadius = -1f; private float _nextCheck; private void Update() { if (Time.unscaledTime < _nextCheck) { return; } _nextCheck = Time.unscaledTime + 0.25f; float value = ModConfig.Radius.Value; if (!ModConfig.ShowRange.Value || !PlayerIsNear(value)) { Show(visible: false); return; } if (_rings == null || !Mathf.Approximately(value, _drawnRadius)) { Build(value); } Show(_rings != null); } private void OnDestroy() { _rings = null; } private bool PlayerIsNear(float radius) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } float num = radius + 20f; Vector3 val = ((Component)localPlayer).transform.position - ((Component)this).transform.position; return ((Vector3)(ref val)).sqrMagnitude <= num * num; } private void Build(float radius) { //IL_0022: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) Material val = Paint(); if (!((Object)(object)val == (Object)null)) { Clear(); _rings = (LineRenderer[])(object)new LineRenderer[3] { Circle(val, radius, Vector3.right, Vector3.forward), Circle(val, radius, Vector3.right, Vector3.up), Circle(val, radius, Vector3.forward, Vector3.up) }; _drawnRadius = radius; } } private LineRenderer Circle(Material material, float radius, Vector3 a, Vector3 b) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_00c8: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("AllfathersChest_Range"); val.transform.SetParent(((Component)this).transform, false); val.transform.rotation = Quaternion.identity; LineRenderer val2 = val.AddComponent<LineRenderer>(); val2.useWorldSpace = false; val2.loop = true; val2.positionCount = 96; val2.widthMultiplier = 0.08f; ((Renderer)val2).sharedMaterial = material; val2.startColor = new Color(1f, 0.79f, 0.32f, 0.55f); val2.endColor = val2.startColor; ((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)val2).receiveShadows = false; ((Renderer)val2).lightProbeUsage = (LightProbeUsage)0; Vector3[] array = (Vector3[])(object)new Vector3[96]; for (int i = 0; i < 96; i++) { float num = (float)i * 2f * (float)Math.PI / 96f; array[i] = (a * Mathf.Cos(num) + b * Mathf.Sin(num)) * radius; } val2.SetPositions(array); return val2; } private void Show(bool visible) { if (_rings == null) { return; } for (int i = 0; i < _rings.Length; i++) { if (!((Object)(object)_rings[i] == (Object)null) && ((Renderer)_rings[i]).enabled != visible) { ((Renderer)_rings[i]).enabled = visible; } } } private void Clear() { if (_rings == null) { return; } for (int i = 0; i < _rings.Length; i++) { if ((Object)(object)_rings[i] != (Object)null) { Object.Destroy((Object)(object)((Component)_rings[i]).gameObject); } } _rings = null; } private static Material Paint() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown if ((Object)(object)_material != (Object)null) { return _material; } if (_complained) { return null; } Shader val = null; for (int i = 0; i < Shaders.Length; i++) { if (!((Object)(object)val == (Object)null)) { break; } val = Shader.Find(Shaders[i]); } if ((Object)(object)val == (Object)null) { _complained = true; AllfathersChestPlugin.Log.LogWarning((object)"No shader for the range rings - 3 - Sorting / ShowRange will do nothing. Everything else is unaffected."); return null; } _material = new Material(val); ((Object)_material).hideFlags = (HideFlags)61; _material.SetInt("_SrcBlend", 5); _material.SetInt("_DstBlend", 10); _material.SetInt("_Cull", 0); _material.SetInt("_ZWrite", 0); return _material; } } internal static class SortingChestPiece { public const string PrefabName = "AllfathersChest_Hub"; private static readonly string[] Fallbacks = new string[3] { "piece_chest", "piece_chest_wood", "piece_chest_blackmetal" }; private static GameObject _prefab; private static GameObject _holder; private static bool _complained; private static Player _knownTo; private static int _sizedFor; private static int _costedFor; public static bool Exists => (Object)(object)_prefab != (Object)null; public static bool IsOurs(Container container) { if ((Object)(object)container == (Object)null) { return false; } return string.Equals(Utils.GetPrefabName(((Component)container).gameObject), "AllfathersChest_Hub", StringComparison.Ordinal); } public static void Tick() { try { EnsurePrefab(); EnsureSize(); EnsureCost(); EnsureInScene(); EnsureInBuildMenu(); EnsureKnown(); } catch (Exception ex) { if (!_complained) { _complained = true; AllfathersChestPlugin.Log.LogError((object)("Could not set up the chest: " + ex)); } } } public static void Reset() { _complained = false; _knownTo = null; } private static void EnsurePrefab() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_prefab != (Object)null) { return; } ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { return; } GameObject val = FindBase(instance); if ((Object)(object)val == (Object)null) { return; } if ((Object)(object)_holder == (Object)null) { _holder = new GameObject("AllfathersChest_PrefabHolder"); _holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_holder); } GameObject val2 = Object.Instantiate<GameObject>(val, _holder.transform); ((Object)val2).name = "AllfathersChest_Hub"; ZNetView val3 = val2.GetComponent<ZNetView>(); if ((Object)(object)val3 == (Object)null) { val3 = val2.AddComponent<ZNetView>(); } val3.m_persistent = true; Container component = val2.GetComponent<Container>(); if ((Object)(object)component == (Object)null) { AllfathersChestPlugin.Log.LogError((object)("The base piece '" + ((Object)val).name + "' has no Container. Set 2 - Chest / BasePrefab to an actual chest.")); return; } component.m_name = Texts.Get("chest.name"); component.m_privacy = (PrivacySetting)2; component.m_defaultItems = null; if ((Object)(object)val2.GetComponent<RangeRing>() == (Object)null) { val2.AddComponent<RangeRing>(); } Piece val4 = val2.GetComponent<Piece>(); if ((Object)(object)val4 == (Object)null) { val4 = val2.AddComponent<Piece>(); } val4.m_name = Texts.Get("chest.name"); val4.m_description = Texts.Get("chest.description"); val4.m_category = (PieceCategory)0; val4.m_enabled = true; val4.m_groundPiece = false; val4.m_allowedInDungeons = true; val4.m_craftingStation = null; if ((Object)(object)val4.m_icon == (Object)null) { Piece component2 = val.GetComponent<Piece>(); if ((Object)(object)component2 != (Object)null) { val4.m_icon = component2.m_icon; } } _prefab = val2; _sizedFor = 0; _costedFor = 0; AllfathersChestPlugin.Log.LogInfo((object)("Chest built from " + ((Object)val).name + ".")); } private static GameObject FindBase(ZNetScene scene) { string text = (ModConfig.BasePrefab.Value ?? "").Trim(); if (text.Length > 0) { GameObject prefab = scene.GetPrefab(text); if ((Object)(object)prefab != (Object)null) { return prefab; } AllfathersChestPlugin.Log.LogWarning((object)("No prefab named '" + text + "' - falling back. Set 2 - Chest / BasePrefab to one that exists.")); } for (int i = 0; i < Fallbacks.Length; i++) { GameObject prefab2 = scene.GetPrefab(Fallbacks[i]); if ((Object)(object)prefab2 != (Object)null) { return prefab2; } } return null; } private static void EnsureSize() { if ((Object)(object)_prefab == (Object)null) { return; } int num = Mathf.Clamp(ModConfig.Width.Value, 1, 8); int num2 = Mathf.Clamp(ModConfig.Height.Value, 1, 8); int num3 = num * 100 + num2; if (num3 != _sizedFor) { Container component = _prefab.GetComponent<Container>(); if (!((Object)(object)component == (Object)null)) { component.m_width = num; component.m_height = num2; _sizedFor = num3; } } } private static void EnsureCost() { if ((Object)(object)_prefab == (Object)null) { return; } int num = Mathf.Clamp(ModConfig.Cost.Value, 1, 999); if (num == _costedFor) { return; } Piece component = _prefab.GetComponent<Piece>(); if (!((Object)(object)component == (Object)null)) { Requirement[] array = Cost(num); if (array != null) { component.m_resources = array; _costedFor = num; } } } private static Requirement[] Cost(int amount) { //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_003c: 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_004b: Expected O, but got Unknown GameObject val = Resolve("Wood"); if ((Object)(object)val == (Object)null) { return null; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { return null; } return (Requirement[])(object)new Requirement[1] { new Requirement { m_resItem = component, m_amount = amount, m_recover = true } }; } private static GameObject Resolve(string name) { ObjectDB instance = ObjectDB.instance; GameObject val = (((Object)(object)instance != (Object)null) ? instance.GetItemPrefab(name) : null); if ((Object)(object)val != (Object)null) { return val; } ZNetScene instance2 = ZNetScene.instance; if (!((Object)(object)instance2 != (Object)null)) { return null; } return instance2.GetPrefab(name); } private static void EnsureInScene() { if ((Object)(object)_prefab == (Object)null) { return; } ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || instance.m_namedPrefabs == null) { return; } int stableHashCode = StringExtensionMethods.GetStableHashCode("AllfathersChest_Hub"); if (!instance.m_namedPrefabs.ContainsKey(stableHashCode)) { instance.m_namedPrefabs[stableHashCode] = _prefab; if (instance.m_prefabs != null && !instance.m_prefabs.Contains(_prefab)) { instance.m_prefabs.Add(_prefab); } } } private static void EnsureInBuildMenu() { if (!((Object)(object)_prefab == (Object)null)) { PieceTable val = HammerPieces(); if (!((Object)(object)val == (Object)null) && val.m_pieces != null && !val.m_pieces.Contains(_prefab)) { val.m_pieces.Add(_prefab); AllfathersChestPlugin.Log.LogInfo((object)"Chest added to the hammer's build menu."); } } } private static void EnsureKnown() { if ((Object)(object)_prefab == (Object)null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { _knownTo = null; } else if (_knownTo != localPlayer) { Piece component = _prefab.GetComponent<Piece>(); if (!((Object)(object)component == (Object)null)) { localPlayer.AddKnownPiece(component); localPlayer.UpdateAvailablePiecesList(); _knownTo = localPlayer; AllfathersChestPlugin.Log.LogInfo((object)("The chest is known to " + localPlayer.GetPlayerName() + " and the build menu was refreshed.")); } } } public static string Describe() { if ((Object)(object)_prefab == (Object)null) { return "No prefab yet - the base chest was not found. Check BasePrefab."; } Piece component = _prefab.GetComponent<Piece>(); Container component2 = _prefab.GetComponent<Container>(); PieceTable val = HammerPieces(); bool value = (Object)(object)ZNetScene.instance != (Object)null && ZNetScene.instance.m_namedPrefabs != null && ZNetScene.instance.m_namedPrefabs.ContainsKey(StringExtensionMethods.GetStableHashCode("AllfathersChest_Hub")); bool value2 = (Object)(object)val != (Object)null && val.m_pieces != null && val.m_pieces.Contains(_prefab); bool value3 = (Object)(object)val != (Object)null && val.m_availablePieces != null && (Object)(object)component != (Object)null && Contains(val, component); return "prefab: yes | in scene: " + Yes(value) + " | in hammer list: " + Yes(value2) + " | shown in menu: " + Yes(value3) + " | known: " + Yes((Object)(object)_knownTo != (Object)null) + " | grid: " + (((Object)(object)component2 != (Object)null) ? (component2.m_width + "x" + component2.m_height) : "-") + " | icon: " + Yes((Object)(object)component != (Object)null && (Object)(object)component.m_icon != (Object)null) + " | cost: " + (((Object)(object)component != (Object)null && component.m_resources != null) ? component.m_resources.Length.ToString() : "0") + " requirement(s)"; } private static bool Contains(PieceTable table, Piece piece) { foreach (Piece availablePiece in table.m_availablePieces) { if (availablePiece == piece) { return true; } } return false; } private static string Yes(bool value) { if (!value) { return "NO"; } return "yes"; } private static PieceTable HammerPieces() { GameObject val = Resolve("Hammer"); if ((Object)(object)val == (Object)null) { return null; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { return null; } return component.m_itemData.m_shared.m_buildPieces; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }