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 Innangard v0.3.5
plugins/Innangard.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using Innangard.Blueprints; using Innangard.Jobs; using Innangard.Trade; using Innangard.UI; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Splatform; using UnityEngine; using UnityEngine.AI; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: AssemblyCompany("Innangard")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.5.0")] [assembly: AssemblyInformationalVersion("0.3.5")] [assembly: AssemblyProduct("Innangard")] [assembly: AssemblyTitle("Innangard")] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.5.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 Innangard { [HarmonyPatch(typeof(WearNTear), "Destroy")] internal static class BaseDestroyedPatch { [HarmonyPrefix] private static void Prefix(WearNTear __instance, HitData hitData) { if (hitData != null) { SettlementAlarm.StructureLost(__instance, hitData.GetAttacker()); } Frithstone frithstone = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponentInParent<Frithstone>() : null); if ((Object)(object)frithstone != (Object)null && (Object)(object)frithstone.Net != (Object)null && frithstone.Net.IsValid()) { SettlementCode.RememberVacated(frithstone.Net.GetZDO()); } } } [HarmonyPatch] internal static class BuildMenuCategory { internal const UsageTagFlags Ours = (UsageTagFlags)1073741824; private const string Label = "Innangard"; internal static void Claim(GameObject prefab) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) Piece val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>() : null); if ((Object)(object)val != (Object)null) { val.m_usage = (UsageTagFlags)1073741824; } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void PutOurRowFirst(ByUsagePieceList __instance) { UsageTagFlags[] usageTags = __instance.m_usageTags; string[] usageTagDisplayNames = __instance.m_usageTagDisplayNames; if (usageTags == null || usageTagDisplayNames == null || usageTags.Length != usageTagDisplayNames.Length) { Logger.LogWarning((object)"Innangard: the build menu's tag list is not the shape this was written for, so the mod's pieces stay under Misc."); } else if (usageTags.Length == 0 || (int)usageTags[0] != 1073741824) { UsageTagFlags[] array = (UsageTagFlags[])(object)new UsageTagFlags[usageTags.Length + 1]; string[] array2 = new string[usageTagDisplayNames.Length + 1]; array[0] = (UsageTagFlags)1073741824; array2[0] = "Innangard"; Array.Copy(usageTags, 0, array, 1, usageTags.Length); Array.Copy(usageTagDisplayNames, 0, array2, 1, usageTagDisplayNames.Length); Set("m_usageTags", __instance, array); Set("m_usageTagDisplayNames", __instance, array2); } } private static void Set(string field, ByUsagePieceList list, object value) { FieldInfo fieldInfo = AccessTools.Field(typeof(ByUsagePieceList), field); if (fieldInfo == null) { Logger.LogWarning((object)("Innangard: the build menu has no " + field + " to add a row to; the mod's pieces stay under Misc.")); } else { fieldInfo.SetValue(list, value); } } } [Flags] internal enum CaretakerDuties { None = 0, Mending = 1, Sorting = 2, Fires = 4, MachineFuel = 8, MachineInput = 0x10, Gathering = 0x20, All = 0x3F } internal sealed class CaretakerTestCommand : ConsoleCommand { private static bool _running; private static readonly string[] ItemPrefabs = new string[34] { "Flint", "Amber", "Ruby", "AmberPearl", "Chitin", "Obsidian", "Crystal", "Ectoplasm", "WitheredBone", "Bloodbag", "Ooze", "Thistle", "Guck", "FreezeGland", "Carapace", "Sap", "Needle", "Feathers", "GreydwarfEye", "Entrails", "Resin", "Bilebag", "Mandible", "RoyalJelly", "LinenThread", "Barley", "Flax", "SharpeningStone", "Tar", "BlackCore", "Eitr", "Softtissue", "Wisp", "DragonTear" }; private const string ChestPrefab = "piece_chest_wood"; private static bool _stop; private static readonly int Floors = LayerMask.GetMask(new string[3] { "static_solid", "terrain", "piece" }); private static readonly int Solids = LayerMask.GetMask(new string[6] { "Default", "static_solid", "piece", "piece_nonsolid", "character", "terrain" }); public override string Name => "inn.test.caretaker"; public override string Help => "[seconds] - (devcommands) puts three chests and something to sort beside you, watches the caretakers sort it, reports, then cleans up"; public override bool IsCheat => true; public override void Run(string[] args) { if (!DebugCommand.Allowed(((ConsoleCommand)this).Name)) { return; } if (args.Length != 0 && args[0] == "stop") { _stop = _running; Console.instance.Print(_running ? "Innangard: stopping the caretaker test and cleaning up." : "Innangard: the caretaker test is not running."); return; } if (_running) { Console.instance.Print("Innangard: the caretaker test is already running. \"inn.test.caretaker stop\" ends it."); return; } _stop = false; float seconds = 180f; if (args.Length != 0 && float.TryParse(args[0], out var result) && result >= 30f) { seconds = result; } InnangardPlugin instance = InnangardPlugin.Instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(Watch(seconds)); } } private static void Say(string text) { Console instance = Console.instance; if (instance != null) { instance.Print(text); } Logger.LogInfo((object)("Innangard[caretaker-test]: " + text)); } private static int CountIn(Container chest, string name) { Inventory val = (((Object)(object)chest != (Object)null) ? chest.GetInventory() : null); if (val != null) { return (from item in val.GetAllItems() where item?.m_shared?.m_name == name select item).Sum((ItemData item) => item.m_stack); } return 0; } private static IEnumerator Watch(float seconds) { _running = true; List<GameObject> made = new List<GameObject>(); List<ItemDrop> loose = new List<ItemDrop>(); Container home = null; Container strayA = null; Container strayB = null; string name = null; int spawned = 0; try { Player player = Player.m_localPlayer; SettlerController asking = (((Object)(object)player != (Object)null) ? ChestLabels.ResidentHere(((Component)player).transform.position) : null); if ((Object)(object)asking == (Object)null) { Say("Stand inside one of your settlements and run it again."); yield break; } List<SettlerController> caretakers = SettlerController.Instances.Where((SettlerController s) => (Object)(object)s != (Object)null && s.IsValidSettler && s.CurrentRole == SettlerRole.Caretaker && s.SettlementOwnerId == asking.SettlementOwnerId && s.InSettlementArea(((Component)player).transform.position)).ToList(); if (caretakers.Count == 0) { Say("There is no caretaker in this settlement. Give someone the trade and run it again."); yield break; } ZNetScene instance = ZNetScene.instance; GameObject chestPrefab = ((instance != null) ? instance.GetPrefab("piece_chest_wood") : null); List<Container> source = SettlementStorage.Managed(asking); GameObject itemPrefab = null; int fewest = int.MaxValue; string[] itemPrefabs = ItemPrefabs; foreach (string text in itemPrefabs) { ObjectDB instance2 = ObjectDB.instance; GameObject val = ((instance2 != null) ? instance2.GetItemPrefab(text) : null); ItemData val2 = ((val == null) ? null : val.GetComponent<ItemDrop>()?.m_itemData); if (val2 != null && ChestSortRules.IsSortable(val2)) { string held = val2.m_shared.m_name; int num2 = source.Sum((Container chest) => CountIn(chest, held)) + caretakers.Sum((SettlerController c) => c.InventoryItemCount(held)); if ((Object)(object)itemPrefab == (Object)null || num2 < fewest) { itemPrefab = val; fewest = num2; } if (num2 == 0) { break; } } } GameObject obj = itemPrefab; ItemData sample = ((obj == null) ? null : obj.GetComponent<ItemDrop>()?.m_itemData); if ((Object)(object)chestPrefab == (Object)null || sample == null) { Say(((Object)(object)chestPrefab == (Object)null) ? "Could not find piece_chest_wood in the game." : "None of the materials the test sorts could be found in the game."); yield break; } name = sample.m_shared.m_name; Vector3 at = ((Component)player).transform.position; Vector3 val3 = Vector3.ProjectOnPlane(((Component)player).transform.forward, Vector3.up); Vector3 ahead = ((Vector3)(ref val3)).normalized; home = Place(0f, "home"); strayA = Place(55f, "A"); strayB = Place(-55f, "B"); yield return null; yield return null; ChestSortRules.RequestLabel(home, "Test: " + ChestLabels.Pretty(name) + " goes here"); ChestSortRules.RequestLabel(strayA, "Test: strays A"); ChestSortRules.RequestLabel(strayB, "Test: strays B"); ChestSortRules.RequestSet(home, new string[1] { name }, configured: true); ChestSortRules.RequestSet(strayA, new string[0], configured: true); ChestSortRules.RequestSet(strayB, new string[0], configured: true); Fill(strayA, 20); Fill(strayA, 20); Fill(strayB, 20); spawned = CountIn(strayA, name) + CountIn(strayB, name); for (int num3 = 0; num3 < 3; num3++) { ItemData obj2 = sample.Clone(); obj2.m_stack = 5; obj2.m_dropPrefab = itemPrefab; Vector3 val4 = at - ahead * 3f + Quaternion.Euler(0f, 90f, 0f) * ahead * (float)(num3 - 1) * 1.5f; val4.y = FloorAt(val4, at.y) + 0.3f; ItemDrop val5 = ItemDrop.DropItem(obj2, 5, val4, Quaternion.identity); if ((Object)(object)val5 != (Object)null) { loose.Add(val5); spawned += 5; } } int homeAtStart = CountIn(home, name); int returnsAtStart = CaretakerJob.CargoReturns; int onTheWayAtStart = CaretakerJob.DroppedOnTheWay; CaretakerJob.MostStopsSeen = 0; Say($"Set up: {spawned} {ChestLabels.Pretty(name)} - {CountIn(strayA, name)} in strays A, {CountIn(strayB, name)} in strays B, {loose.Count} handful(s) on the floor; the settlement already had {fewest} of its own. " + $"Watching {caretakers.Count} caretaker(s) for up to {seconds:0} s. Stay near, but do not open the test chests."); float started = Time.time; float? strayAEmpty = null; float? strayBEmpty = null; float? floorClear = null; float? allHome = null; float nextNote = Time.time + 15f; while (Time.time - started < seconds) { yield return (object)new WaitForSeconds(1f); float num4 = Time.time - started; if ((Object)(object)((IEnumerable<GameObject>)made).FirstOrDefault((Func<GameObject, bool>)((GameObject chest) => (Object)(object)chest == (Object)null || (Object)(object)chest.GetComponent<ZNetView>() == (Object)null || !chest.GetComponent<ZNetView>().IsValid())) != (Object)null || made.Any((GameObject chest) => (Object)(object)chest == (Object)null)) { Say("STOPPED a test chest was removed, so the counts mean nothing from here. Cleaning up."); yield break; } if (_stop) { Say("STOPPED by inn.test.caretaker stop. Cleaning up."); yield break; } int num5 = CountIn(strayA, name); int num6 = CountIn(strayB, name); int num7 = loose.Count((ItemDrop drop) => (Object)(object)drop != (Object)null && (Object)(object)drop.m_nview != (Object)null && drop.m_nview.IsValid()); int num8 = CountIn(home, name) - homeAtStart; if (num5 == 0 && !strayAEmpty.HasValue) { strayAEmpty = num4; } if (num6 == 0 && !strayBEmpty.HasValue) { strayBEmpty = num4; } if (num7 == 0 && !floorClear.HasValue) { floorClear = num4; } if (num8 >= spawned && !allHome.HasValue) { allHome = num4; } if (Time.time >= nextNote) { nextNote = Time.time + 15f; string text2 = $"{num4:0} s: strays A {num5}, strays B {num6}, floor {num7}, home {Mathf.Max(0, num8)}/{spawned}"; Say(text2); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)1, "Caretaker test - " + text2, 0, (Sprite)null, false); } } if (num5 == 0 && num6 == 0 && num7 == 0 && num8 >= spawned && caretakers.All((SettlerController c) => c.InventoryItemCount(name) == 0)) { break; } } int num9 = CaretakerJob.CargoReturns - returnsAtStart; int num10 = CaretakerJob.DroppedOnTheWay - onTheWayAtStart; int num11 = Mathf.Max(0, CountIn(home, name) - homeAtStart); Say("---- caretaker test ----"); Say(Line(strayAEmpty.HasValue && strayBEmpty.HasValue, "the chests told to give everything away were emptied", "A at " + At(strayAEmpty) + ", B at " + At(strayBEmpty))); Say(Line(floorClear.HasValue, "what was on the floor was picked up", "at " + At(floorClear))); int num12 = CountIn(strayA, name) + CountIn(strayB, name) + loose.Count((ItemDrop drop) => (Object)(object)drop != (Object)null && (Object)(object)drop.m_nview != (Object)null && drop.m_nview.IsValid()) + caretakers.Sum((SettlerController c) => c.InventoryItemCount(name)); Say(Line(num11 >= spawned && num12 == 0, "all of it reached the chest it belongs in", $"{num11} arrived, {num12} still in the stray chests, on the floor or in a pack")); Say(Line(CaretakerJob.MostStopsSeen <= 6, "no collecting round stopped at more than six chests", $"the longest stopped at {CaretakerJob.MostStopsSeen}")); Say(Line(num9 == 0, "no sorting cargo had to be carried back", (num9 == 0) ? "none" : $"{num9} tick(s) carrying it back")); Say($"INFO deliveries made on the way round: {num10}"); if (num11 < spawned) { Where(caretakers, asking, name, home, strayA, strayB); } foreach (SettlerController item in caretakers) { Say("INFO " + item.PanelName + ": \"" + Localization.instance.Localize(item.CurrentStatusText ?? string.Empty) + "\", " + $"carrying {item.InventoryItemCount(name)} {ChestLabels.Pretty(name)}"); } void Fill(Container chest, int amount) { ItemData val6 = sample.Clone(); val6.m_stack = amount; val6.m_dropPrefab = itemPrefab; chest.GetInventory().AddItem(val6); } Container Place(float angle, string label) { //IL_0001: 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_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) //IL_0026: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_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_00c6: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) Vector3 val6 = at + Quaternion.Euler(0f, angle, 0f) * ahead * 3f; val6.y = FloorAt(val6, at.y); bool flag = false; float[] array = new float[4] { 3f, 4f, 2.5f, 5f }; foreach (float num13 in array) { float[] array2 = new float[5] { 0f, 20f, -20f, 40f, -40f }; foreach (float num14 in array2) { Vector3 tried = at + Quaternion.Euler(0f, angle + num14, 0f) * ahead * num13; tried.y = FloorAt(tried, at.y); if (Free(tried) && made.All((GameObject other) => Vector3.Distance(other.transform.position, tried) > 1.5f)) { val6 = tried; flag = true; break; } } if (flag) { break; } } GameObject val7 = Object.Instantiate<GameObject>(chestPrefab, val6, Quaternion.LookRotation(-ahead)); Piece component = val7.GetComponent<Piece>(); if (component != null) { component.SetCreator(player.GetPlayerID(), PlatformUserID.None); } made.Add(val7); return val7.GetComponent<Container>() ?? val7.GetComponentInChildren<Container>(); } } finally { CleanUp(made, loose, name, spawned, home, strayA, strayB); _running = false; } } private static float FloorAt(Vector3 spot, float playerY) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0018: 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) RaycastHit val = default(RaycastHit); if (!Physics.Raycast(new Vector3(spot.x, playerY + 1.2f, spot.z), Vector3.down, ref val, 3.5f, Floors, (QueryTriggerInteraction)1)) { return playerY; } return ((RaycastHit)(ref val)).point.y; } private static bool Free(Vector3 floor) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_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) return !Physics.CheckBox(floor + Vector3.up * 0.55f, new Vector3(0.6f, 0.45f, 0.45f), Quaternion.identity, Solids, (QueryTriggerInteraction)1); } private static string Line(bool ok, string what, string detail) { return (ok ? "PASS " : "FAIL ") + what + " - " + detail; } private static string At(float? at) { if (at.HasValue) { return $"{at.Value:0} s"; } return "never"; } private static void Where(List<SettlerController> caretakers, SettlerController asking, string name, Container home, Container strayA, Container strayB) { //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_00e4: Unknown result type (might be due to invalid IL or missing references) Say($"INFO still in strays A: {CountIn(strayA, name)}, strays B: {CountIn(strayB, name)}"); foreach (SettlerController caretaker in caretakers) { int num = caretaker.InventoryItemCount(name); if (num > 0) { Say($"INFO {caretaker.PanelName} is carrying {num}"); } } Vector3 position = ((Component)Player.m_localPlayer).transform.position; foreach (Container item in SettlementStorage.Managed(asking)) { if (!((Object)(object)item == (Object)(object)home) && !((Object)(object)item == (Object)(object)strayA) && !((Object)(object)item == (Object)(object)strayB)) { int num2 = CountIn(item, name); if (num2 > 0) { Say($"INFO {num2} in {ChestLabels.AsDestination(item)} ({ChestLabels.Where(position, item)})"); } } } } private static void CleanUp(List<GameObject> made, List<ItemDrop> loose, string name, int spawned, params Container[] chests) { if (made.Count == 0 && loose.Count == 0) { return; } int num = spawned; foreach (ItemDrop item in loose) { if ((Object)(object)item != (Object)null && (Object)(object)item.m_nview != (Object)null && item.m_nview.IsValid()) { num -= item.m_itemData.m_stack; ZNetScene.instance.Destroy(((Component)item).gameObject); } } int num2 = 0; foreach (Container val in chests) { Inventory val2 = (((Object)(object)val != (Object)null) ? val.GetInventory() : null); if (val2 == null || name == null) { continue; } foreach (ItemData item2 in (from item in val2.GetAllItems() where item.m_shared.m_name == name select item).ToList()) { if (num <= 0) { break; } int num3 = Mathf.Min(num, item2.m_stack); val2.RemoveItem(item2, num3); num -= num3; } num2 += val2.GetAllItems().Count; val.DropAllItems(); } foreach (GameObject item3 in made) { if ((Object)(object)item3 != (Object)null) { ZNetScene.instance.Destroy(item3); } } Say($"Cleaned up: the test chests are gone. {Mathf.Max(0, num)} of the test's {ChestLabels.Pretty(name ?? string.Empty)} is still out in the settlement" + ((num2 > 0) ? $"; {num2} stack(s) of yours that had gone into the test chests are set down where they stood." : ".")); } } internal sealed class ChestCensusCommand : ConsoleCommand { public override string Name => "inn.chests"; public override string Help => "- every chest this settlement can use: what it holds, what it is for, how full"; public override bool IsCheat => false; public override void Run(string[] args) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) Player player = Player.m_localPlayer; if ((Object)(object)player == (Object)null) { Console.instance.Print("Innangard: nobody is standing anywhere."); return; } SettlerController settlerController = Nearest(((Component)player).transform.position); if ((Object)(object)settlerController == (Object)null) { Console.instance.Print("Innangard: no resident nearby to ask. Stand in a settlement."); return; } List<Container> list = SettlementStorage.Managed(settlerController); if (list.Count == 0) { Console.instance.Print("Innangard: " + settlerController.PanelName + " can use no chest here at all. A chest must stand inside the settlement, be placed by a player, and be open to it."); return; } List<Container> intake = settlerController.ResolveIntakeStorages(); list.Sort((Container left, Container right) => Vector3.Distance(((Component)player).transform.position, ((Component)left).transform.position).CompareTo(Vector3.Distance(((Component)player).transform.position, ((Component)right).transform.position))); int told = 0; int inferred = 0; int num = 0; int num2 = 0; int num3 = 0; Console.instance.Print($"Innangard: {list.Count} chest(s) {settlerController.PanelName} can use."); foreach (Container item in list) { Inventory inventory = item.GetInventory(); if (inventory != null) { int num4 = inventory.GetWidth() * inventory.GetHeight(); int emptySlots = inventory.GetEmptySlots(); num3 += num4 - emptySlots; num2 += emptySlots; if (emptySlots == 0) { num++; } string text = Rule(item, intake, ref told, ref inferred); Console.instance.Print($" {Where(player, item)} {num4 - emptySlots}/{num4} slots" + ((emptySlots == 0) ? " FULL" : string.Empty) + " {" + text + "}"); string text2 = Holding(inventory); if (text2.Length > 0) { Console.instance.Print(" " + text2); } } } Console.instance.Print($" -- {told} told what to hold, {inferred} going by what is in them, " + $"{list.Count - told - inferred} saying nothing; {num} full; " + $"{num3} slot(s) used and {num2} free."); Console.instance.Print(" A chest that says nothing takes anything it already has more than one of, and an empty one takes anything at all. That is the rule a settlement runs on when nobody marks anything."); Console.instance.Print(" Set a chest to a kind and that kind is gathered into it from the chests that merely hold it. A chest set to take everything away is emptied."); Console.instance.Print(" A hand-picked list beats a kind: where two chests claim the same thing, the hand-picked one takes it all and the other stays empty. Clear the list to put them back on equal terms."); LeftAlone(player, settlerController); } private static void LeftAlone(Player player, SettlerController asking) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) List<Container> list = new List<Container>(); Container[] array = SceneObjectCache.Get<Container>(1f); foreach (Container val in array) { if ((Object)(object)val != (Object)null && !(val is SettlerInventory) && ((Component)val).gameObject.activeInHierarchy && ChestSortRules.LeftAlone(val) && asking.InSettlementArea(((Component)val).transform.position)) { list.Add(val); } } if (list.Count == 0) { return; } list.Sort((Container left, Container right) => Vector3.Distance(((Component)player).transform.position, ((Component)left).transform.position).CompareTo(Vector3.Distance(((Component)player).transform.position, ((Component)right).transform.position))); Console.instance.Print($" {list.Count} chest(s) left alone - yours, inside the " + "settlement, and nobody here touches them:"); foreach (Container item in list) { Inventory inventory = item.GetInventory(); int num = ((inventory != null) ? (inventory.GetWidth() * inventory.GetHeight()) : 0); int num2 = ((inventory != null) ? inventory.GetEmptySlots() : 0); Console.instance.Print($" {Where(player, item)} {num - num2}/{num} slots" + " {LEFT ALONE}"); } } private static string Where(Player player, Container chest) { //IL_0006: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_009a: 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_005f: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)chest).transform.position - ((Component)player).transform.position; Vector2 val2 = new Vector2(val.x, val.z); float magnitude = ((Vector2)(ref val2)).magnitude; string arg = ((Mathf.Abs(val.y) < 1.5f) ? string.Empty : ((val.y > 0f) ? $" {val.y:0}m up" : $" {0f - val.y:0}m down")); return $"{magnitude,4:0}m {Compass(val)}{arg}".PadRight(14); } private static string Compass(Vector3 there) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Atan2(there.x, there.z) * 57.29578f; return (new string[8] { "N", "NE", "E", "SE", "S", "SW", "W", "NW" })[Mathf.RoundToInt(Mathf.Repeat(num, 360f) / 45f) % 8].PadRight(2); } private static string Rule(Container chest, List<Container> intake, ref int told, ref int inferred) { string text = (intake.Contains(chest) ? ", ticked for the settlement" : string.Empty); int num = ChestSortRules.KindsOf(chest); if (num != 0) { told++; return "for " + Kinds(num) + text; } if (ChestSortRules.IsConfigured(chest)) { told++; HashSet<string> hashSet = ChestSortRules.ReadItems(chest); return ((hashSet.Count == 0) ? "OUTBOX - nothing belongs here, so everything in it is taken away" : ($"by hand: {hashSet.Count} item(s) - " + string.Join(", ", hashSet.Select(Pretty).Take(4)) + ((hashSet.Count > 4) ? ", ..." : string.Empty))) + text; } string text2 = Inferred(chest); if (text2.Length > 0) { inferred++; return "unmarked, reads as " + text2 + text; } return "unmarked and empty - a home for anything" + text; } private static string Kinds(int kinds) { List<string> list = new List<string>(4); StockCategories.Kind[] order = StockCategories.Order; for (int i = 0; i < order.Length; i++) { StockCategories.Kind kind = order[i]; if ((kinds & (1 << (int)kind)) != 0) { list.Add(kind.ToString()); } } if (list.Count <= 0) { return "nothing"; } return string.Join("+", list); } private static string Inferred(Container chest) { Inventory inventory = chest.GetInventory(); if (inventory == null) { return string.Empty; } List<string> list = new List<string>(4); HashSet<string> hashSet = new HashSet<string>(); foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem?.m_shared != null && ChestSortRules.IsSortable(allItem) && hashSet.Add(allItem.m_shared.m_name) && ChestSortRules.Accepts(chest, allItem.m_shared.m_name)) { list.Add(Pretty(allItem.m_shared.m_name)); } } if (list.Count == 0) { return string.Empty; } return string.Join(", ", list.Take(4)) + ((list.Count > 4) ? ", ..." : string.Empty); } private static string Holding(Inventory inside) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (ItemData allItem in inside.GetAllItems()) { if (allItem?.m_shared != null && allItem.m_stack > 0) { dictionary.TryGetValue(allItem.m_shared.m_name, out var value); dictionary[allItem.m_shared.m_name] = value + allItem.m_stack; } } if (dictionary.Count == 0) { return string.Empty; } return string.Join(", ", from entry in dictionary.OrderByDescending((KeyValuePair<string, int> entry) => entry.Value).Take(6) select $"{entry.Value} {Pretty(entry.Key)}") + ((dictionary.Count > 6) ? $", and {dictionary.Count - 6} more" : string.Empty); } private static string Pretty(string sharedName) { Localization instance = Localization.instance; string text = ((instance != null) ? instance.Localize(sharedName) : null); if (!string.IsNullOrEmpty(text)) { return text; } return sharedName; } private static SettlerController Nearest(Vector3 to) { //IL_002e: 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) SettlerController result = null; float num = float.MaxValue; foreach (SettlerController instance in SettlerController.Instances) { if (!((Object)(object)instance == (Object)null) && instance.IsValidSettler) { float num2 = Vector3.Distance(to, instance.Position); if (num2 < num) { num = num2; result = instance; } } } return result; } } internal static class ChestContents { internal sealed class Summary { internal uint Revision; internal int Slots; internal readonly Dictionary<string, int> SortableSlots = new Dictionary<string, int>(StringComparer.Ordinal); internal readonly Dictionary<string, int> Counts = new Dictionary<string, int>(StringComparer.Ordinal); internal int UsedSortable; internal int MostSlotsOfOne; internal int Count(string sharedName) { if (!Counts.TryGetValue(sharedName, out var value)) { return 0; } return value; } internal bool Dominates(string sharedName) { if (UsedSortable == 0) { return true; } SortableSlots.TryGetValue(sharedName, out var value); if (value == 0) { return false; } if (value <= 1) { return MostSlotsOfOne <= value; } return true; } } private static readonly Dictionary<Container, Summary> Known = new Dictionary<Container, Summary>(); private static readonly List<Container> Gone = new List<Container>(); private static float _nextPrune; internal static Summary Of(Container container) { Inventory val = ((container != null) ? container.GetInventory() : null); if (val == null) { return null; } PruneNow(); uint lastRevision = container.m_lastRevision; int count = val.m_inventory.Count; if (Known.TryGetValue(container, out var value) && value.Revision == lastRevision && value.Slots == count) { return value; } if (value == null) { value = new Summary(); Known[container] = value; } Count(val, value); value.Revision = lastRevision; value.Slots = count; return value; } private static void Count(Inventory inventory, Summary summary) { summary.SortableSlots.Clear(); summary.Counts.Clear(); summary.UsedSortable = 0; summary.MostSlotsOfOne = 0; foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem?.m_shared == null) { continue; } string name = allItem.m_shared.m_name; if (allItem.m_stack > 0) { summary.Counts.TryGetValue(name, out var value); summary.Counts[name] = value + allItem.m_stack; } if (ChestSortRules.IsSortable(allItem)) { summary.UsedSortable++; summary.SortableSlots.TryGetValue(name, out var value2); value2++; summary.SortableSlots[name] = value2; if (value2 > summary.MostSlotsOfOne) { summary.MostSlotsOfOne = value2; } } } } private static void PruneNow() { if (Time.unscaledTime < _nextPrune) { return; } _nextPrune = Time.unscaledTime + 30f; Gone.Clear(); foreach (Container key in Known.Keys) { if ((Object)(object)key == (Object)null) { Gone.Add(key); } } foreach (Container item in Gone) { Known.Remove(item); } Gone.Clear(); } } internal static class ChestLabels { internal enum Mode { Named, Mine, Kinds, List, Outbox, CatchAll, Guess, Empty } private struct Answer { internal float Until; internal string Line; } private const int Shown = 3; private static readonly Dictionary<string, Answer> Answers = new Dictionary<string, Answer>(); private const float AnswerLasts = 1f; internal static string Core(Container chest, out Mode mode) { string text = ChestSortRules.LabelOf(chest); if (text.Length > 0) { mode = Mode.Named; return text; } if (ChestSortRules.LeftAlone(chest)) { mode = Mode.Mine; return string.Empty; } if (ChestSortRules.IsCatchAll(chest)) { mode = Mode.CatchAll; return string.Empty; } int kinds = ChestSortRules.KindsOf(chest); if (kinds != 0) { mode = Mode.Kinds; return Cut(from kind in StockCategories.Order where (kinds & (1 << (int)kind)) != 0 select Localization.instance.Localize(StockCategories.TitleKey(kind))); } if (ChestSortRules.IsConfigured(chest)) { HashSet<string> hashSet = ChestSortRules.ReadItems(chest); if (hashSet.Count == 0) { mode = Mode.Outbox; return string.Empty; } mode = Mode.List; return Cut(from name in hashSet.Select(Pretty) orderby name select name); } ChestContents.Summary summary = ChestContents.Of(chest); if (summary == null || summary.UsedSortable == 0) { mode = Mode.Empty; return string.Empty; } mode = Mode.Guess; return Cut(from entry in summary.SortableSlots where summary.Dominates(entry.Key) orderby entry.Value descending select Pretty(entry.Key)); } internal static string HoverLine(Container chest) { Mode mode; string text = Core(chest, out mode); string text2; switch (mode) { case Mode.Named: text2 = "<color=#FFD27F>" + text + "</color>"; break; case Mode.Mine: text2 = Localization.instance.Localize("$inn_chest_hover_mine"); break; case Mode.Kinds: case Mode.List: text2 = string.Format(Localization.instance.Localize("$inn_chest_hover_for"), text); break; case Mode.Outbox: text2 = Localization.instance.Localize("$inn_chest_hover_outbox"); break; case Mode.CatchAll: text2 = Localization.instance.Localize("$inn_chest_hover_catch_all"); break; case Mode.Guess: text2 = string.Format(Localization.instance.Localize("$inn_chest_hover_guess"), text); break; default: text2 = Localization.instance.Localize("$inn_chest_hover_empty"); break; } string text3 = text2; Inventory inventory = chest.GetInventory(); if (inventory != null && inventory.GetEmptySlots() == 0) { text3 += Localization.instance.Localize("$inn_chest_hover_full"); } return text3; } internal static string AsDestination(Container chest) { Mode mode; string text = Core(chest, out mode); switch (mode) { case Mode.Named: return text; case Mode.Kinds: case Mode.List: return string.Format(Localization.instance.Localize("$inn_chest_tip_chest_for"), text); case Mode.Guess: return string.Format(Localization.instance.Localize("$inn_chest_tip_chest_with"), text); case Mode.CatchAll: return Localization.instance.Localize("$inn_chest_tip_catch_all"); default: return Localization.instance.Localize("$inn_chest_tip_an_empty_chest"); } } internal static string Cut(IEnumerable<string> names) { List<string> list = names.Where((string name) => !string.IsNullOrEmpty(name)).ToList(); if (list.Count <= 3) { return string.Join(", ", list); } return string.Join(", ", list.Take(3)) + $" … (+{list.Count - 3})"; } internal static string Pretty(string sharedName) { Localization instance = Localization.instance; string text = ((instance != null) ? instance.Localize(sharedName) : null); if (!string.IsNullOrEmpty(text)) { return text; } return sharedName; } internal static string Where(Vector3 from, Container chest) { //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_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)chest).transform.position - from; Vector2 val2 = new Vector2(val.x, val.z); float magnitude = ((Vector2)(ref val2)).magnitude; if (magnitude < 2f) { return Localization.instance.Localize("$inn_chest_tip_here"); } float num = Mathf.Atan2(val.x, val.z) * 57.29578f; string[] array = new string[8] { "N", "NE", "E", "SE", "S", "SW", "W", "NW" }; return $"{magnitude:0} m {array[Mathf.RoundToInt(Mathf.Repeat(num, 360f) / 45f) % 8]}"; } internal static string BelongsLine(ItemData item) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || item?.m_shared == null || !ChestSortRules.IsSortable(item) || (Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.IsVisible()) { return string.Empty; } Container currentContainer = InventoryGui.instance.m_currentContainer; bool flag = (Object)(object)currentContainer != (Object)null && !(currentContainer is SettlerInventory) && currentContainer.GetInventory() != null && currentContainer.GetInventory().ContainsItem(item); string key = item.m_shared.m_name + "|" + (flag ? ((Object)currentContainer).GetInstanceID().ToString() : "-"); if (Answers.TryGetValue(key, out var value) && Time.unscaledTime < value.Until) { return value.Line; } if (Answers.Count > 256) { Answers.Clear(); } string text = WorkOut(localPlayer, item, flag ? currentContainer : null); Answers[key] = new Answer { Until = Time.unscaledTime + 1f, Line = text }; return text; } private static string WorkOut(Player player, ItemData item, Container heldIn) { //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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)player).transform.position; SettlerController settlerController = ResidentHere(position); if ((Object)(object)settlerController == (Object)null) { return string.Empty; } bool stays; bool fullAtRule; Container val = Destination(settlerController, item, heldIn, position, out stays, out fullAtRule); string text = (stays ? Localization.instance.Localize("$inn_chest_tip_stays") : ((!((Object)(object)val != (Object)null)) ? Localization.instance.Localize(fullAtRule ? "$inn_chest_tip_full" : "$inn_chest_tip_nowhere") : string.Format(Localization.instance.Localize("$inn_chest_tip_belongs"), AsDestination(val), Where(position, val)))); return "\n<color=#C8B896>" + text + "</color>"; } internal static Container Destination(SettlerController asking, ItemData item, Container heldIn, Vector3 here, out bool stays, out bool fullAtRule) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) string name = item.m_shared.m_name; List<Container> list = SettlementStorage.Managed(asking); Container val = (((Object)(object)InventoryGui.instance != (Object)null) ? InventoryGui.instance.m_currentContainer : null); bool flag = (Object)(object)val != (Object)null && !(val is SettlerInventory) && !list.Contains(val) && ChestSortRules.IsStationaryPlayerChest(val) && !ChestSortRules.LeftAlone(val) && !TradeChest.Is(val) && asking.InSettlementArea(((Component)val).transform.position) && val.CheckAccess(asking.SettlementOwnerId); if (flag) { list.Add(val); } int num = (((Object)(object)heldIn != (Object)null && (flag || list.Contains(heldIn))) ? ChestSortRules.Precision(heldIn, name) : int.MaxValue); Container val2 = null; int num2 = int.MaxValue; float num3 = float.MaxValue; fullAtRule = false; foreach (Container item2 in list) { if ((Object)(object)item2 == (Object)(object)heldIn) { continue; } int num4 = ChestSortRules.Precision(item2, name); if (num4 == int.MaxValue || num4 > num2) { continue; } Inventory inventory = item2.GetInventory(); if (inventory == null) { continue; } int num5 = inventory.FindFreeStackSpace(name, (float)item.m_worldLevel); if (num5 + inventory.GetEmptySlots() * item.m_shared.m_maxStackSize <= 0) { fullAtRule |= num4 < 6; continue; } float num6 = ((num5 > 0) ? 0f : 1f) + Vector3.Distance(here, ((Component)item2).transform.position) * 0.001f; if (num4 < num2 || num6 < num3) { num2 = num4; num3 = num6; val2 = item2; } } stays = num != int.MaxValue && ((Object)(object)val2 == (Object)null || num2 >= num); if (!stays) { return val2; } return null; } internal static SettlerController ResidentHere(Vector3 here) { //IL_002f: 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_0039: Unknown result type (might be due to invalid IL or missing references) SettlerController result = null; float num = float.MaxValue; foreach (SettlerController instance in SettlerController.Instances) { if (!((Object)(object)instance == (Object)null) && instance.IsValidSettler && instance.InSettlementArea(here)) { float num2 = Vector3.Distance(here, instance.Position); if (num2 < num) { num = num2; result = instance; } } } return result; } } internal sealed class ChestSortPanel : MonoBehaviour { private sealed class ItemChoice { internal string SharedName; internal string DisplayName; internal Sprite Icon; internal Button Button; } private sealed class Copied { internal int Kinds; internal bool Configured; internal bool CatchAll; internal HashSet<string> Items; internal string Said; } [HarmonyPatch(typeof(Container), "Interact")] private static class OpenPatch { [HarmonyPrefix] private static bool Prefix(Container __instance, Humanoid character, bool hold, ref bool __result) { if (!hold) { Player val = (Player)(object)((character is Player) ? character : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { if (!ModifierHeld() || !ChestSortRules.CanConfigure(__instance, val.GetPlayerID())) { return true; } Toggle(__instance); __result = true; return false; } } return true; } private static bool ModifierHeld() { return InnInput.ModifierHeld(); } } private const float PanelWidth = 780f; private const float PanelHeight = 880f; private const float LeastHeight = 260f; private const float TitleHeight = 40f; private const float Edge = 14f; private const float Gap = 8f; private const float MaxUseDistance = 10f; private const float BetweenRefreshes = 0.25f; private const float ItemButtonHeight = 34f; private const float ListLeastHeight = 160f; private const float IconSize = 28f; private static readonly (IntakeRoles Role, string LabelKey)[] IntakeChoices = new(IntakeRoles, string)[11] { (IntakeRoles.Lumberjack, "$inn_trade_lumberjack"), (IntakeRoles.Miner, "$inn_trade_miner"), (IntakeRoles.Farmer, "$inn_trade_farmer"), (IntakeRoles.Forager, "$inn_trade_forager"), (IntakeRoles.Hunter, "$inn_trade_hunter"), (IntakeRoles.Fisherman, "$inn_role_fisherman"), (IntakeRoles.Cook, "$inn_trade_cook"), (IntakeRoles.Builder, "$inn_role_builder"), (IntakeRoles.Guard, "$inn_trade_guard"), (IntakeRoles.Follower, "$inn_trade_follower"), (IntakeRoles.Smith, "$inn_trade_smith") }; private static ChestSortPanel _instance; private Container _container; private GameObject _panel; private bool _blocking; private float _heightNow = -1f; private float _scaledAt = -1f; private float _nextRefresh; private bool _wasConfigured; private HashSet<string> _selected = new HashSet<string>(StringComparer.Ordinal); private readonly List<ItemChoice> _choices = new List<ItemChoice>(); private Text _intakeState; private Text _intakeNoFrithstone; private RectTransform _intakeControls; private Button _intakeRemove; private Button _intakeAll; private readonly List<Button> _roleButtons = new List<Button>(); private Text _origin; private InputField _search; private RectTransform _grid; private Text _noMatch; private Text _chosenCount; private readonly List<Button> _kindButtons = new List<Button>(); private Button _anything; private Button _byHand; private Button _outbox; private Button _catchAll; private Button _mine; private Text _mineHelp; private RectTransform _picking; private RectTransform _intakeGrid; private Button _intakeChoose; private bool _showingCrafts; private int _kinds; private InputField _label; private static Copied _copied; private Button _paste; private GameObject _footer; private RectTransform _list; private ScrollRect _scroll; private RectTransform _column; private bool _remeasure; private LayoutElement _slack; private static SettlerRole TradeOf(IntakeRoles role) { return role switch { IntakeRoles.Lumberjack => SettlerRole.Lumberjack, IntakeRoles.Miner => SettlerRole.Miner, IntakeRoles.Farmer => SettlerRole.Farmer, IntakeRoles.Forager => SettlerRole.Forager, IntakeRoles.Hunter => SettlerRole.Hunter, IntakeRoles.Fisherman => SettlerRole.Fisherman, IntakeRoles.Cook => SettlerRole.Cook, IntakeRoles.Builder => SettlerRole.Builder, IntakeRoles.Guard => SettlerRole.Guard, IntakeRoles.Follower => SettlerRole.Follower, IntakeRoles.Smith => SettlerRole.Smith, _ => SettlerRole.Idle, }; } internal static void Toggle(Container container) { if ((Object)(object)_instance == (Object)null) { GameObject val = (((Object)(object)InnangardPlugin.Instance != (Object)null) ? ((Component)InnangardPlugin.Instance).gameObject : null); if ((Object)(object)val == (Object)null) { return; } _instance = val.AddComponent<ChestSortPanel>(); } if ((Object)(object)_instance._container == (Object)(object)container) { _instance.Close(); } else { _instance.Open(container); } } private void Awake() { GUIManager.OnCustomGUIAvailable += Forget; } private void OnDestroy() { GUIManager.OnCustomGUIAvailable -= Forget; Release(); if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } private void Forget() { _panel = null; _heightNow = -1f; _container = null; _choices.Clear(); _roleButtons.Clear(); _kindButtons.Clear(); _scaledAt = -1f; Release(); } private void Open(Container container) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !ChestSortRules.CanConfigure(container, localPlayer.GetPlayerID())) { return; } try { if (Build()) { _container = container; FrithLore.Tell("inn_lore_chest"); _wasConfigured = ChestSortRules.IsConfigured(container); _kinds = ChestSortRules.KindsOf(container); _selected = ChestSortRules.ReadItems(container); Populate(BuildChoices(container, _selected)); _search.text = string.Empty; _label.text = ChestSortRules.LabelOf(container); ((Component)_picking).gameObject.SetActive(_wasConfigured); _showingCrafts = false; _remeasure = true; _panel.SetActive(true); Block(); Refresh(); } } catch (Exception ex) { Logger.LogError((object)("Innangard[stores]: the sorting window failed to open: " + ex)); Close(); } } private void Close() { SaveLabel(); _container = null; if ((Object)(object)_panel != (Object)null) { _panel.SetActive(false); } Release(); } private void Block() { if (!_blocking) { _blocking = true; GUIManager.BlockInput(true); } } private void Release() { if (_blocking) { _blocking = false; GUIManager.BlockInput(false); } } private void Update() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_container == (Object)null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !((Component)_container).gameObject.activeInHierarchy || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)_container).transform.position) > 10f || Input.GetKeyDown((KeyCode)27)) { Close(); return; } Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; if (Time.unscaledTime >= _nextRefresh) { _nextRefresh = Time.unscaledTime + 0.25f; Refresh(); } } private bool Build() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_panel != (Object)null) { return true; } Transform val = (((Object)(object)GUIManager.CustomGUIFront != (Object)null) ? GUIManager.CustomGUIFront.transform : null); if ((Object)(object)val == (Object)null || GUIManager.Instance == null) { return false; } _panel = GUIManager.Instance.CreateWoodpanel(val, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 780f, 880f, true); if ((Object)(object)_panel == (Object)null) { return false; } ((Object)_panel).name = "inn_chest_panel"; RectTransform obj = Child("inn_chest_title", _panel.transform); obj.anchorMin = new Vector2(0f, 1f); obj.anchorMax = new Vector2(1f, 1f); obj.pivot = new Vector2(0.5f, 1f); obj.anchoredPosition = new Vector2(0f, -14f); obj.sizeDelta = new Vector2(-28f, 40f); InnangardGui.Fill(((Graphic)InnangardGui.Write((Transform)(object)obj, Localization.instance.Localize("$inn_stores_filter_title"), 22, GUIManager.Instance.ValheimOrange, (TextAnchor)4)).rectTransform); ((UnityEvent)GUIManager.Instance.CreateButton("x", _panel.transform, new Vector2(1f, 1f), new Vector2(1f, 1f), new Vector2(-30f, -30f), 32f, 32f).GetComponent<Button>().onClick).AddListener(new UnityAction(Close)); RectTransform obj2 = Child("inn_chest_body", _panel.transform); obj2.offsetMin = new Vector2(14f, 14f); obj2.offsetMax = new Vector2(-14f, -62f); RectTransform column = (_column = InnangardGui.Stack(obj2, 8f, fits: false, (TextAnchor)0)); BuildNaming(column); BuildIntake(column); BuildFilter(column); Flexible(column, ((Component)_picking).gameObject); Flexible(_picking, ((Component)_list).gameObject); ((Component)_list).GetComponent<LayoutElement>().minHeight = 160f; return true; } private void Remeasure() { if (_remeasure && !((Object)(object)_column == (Object)null)) { _remeasure = false; Canvas.ForceUpdateCanvases(); LayoutRebuilder.ForceRebuildLayoutImmediate(_column); Canvas.ForceUpdateCanvases(); LayoutRebuilder.ForceRebuildLayoutImmediate(_column); } } private static void Flexible(RectTransform column, GameObject grows) { for (int i = 0; i < ((Transform)column).childCount; i++) { GameObject gameObject = ((Component)((Transform)column).GetChild(i)).gameObject; LayoutElement val = gameObject.GetComponent<LayoutElement>() ?? gameObject.AddComponent<LayoutElement>(); val.flexibleHeight = (((Object)(object)gameObject == (Object)(object)grows) ? 1f : 0f); val.minHeight = (((Object)(object)gameObject == (Object)(object)grows) ? 0f : val.minHeight); } } private void BuildIntake(RectTransform column) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) RectTransform val = InnangardGui.Card(InnangardGui.Section(column, "$inn_stores_intake_section"), 4f); InnangardGui.Note(val, Localization.instance.Localize("$inn_stores_intake_help")); _intakeNoFrithstone = InnangardGui.Note(val, Localization.instance.Localize("$inn_stores_intake_no_frithstone")); ((Graphic)_intakeNoFrithstone).color = InnangardGui.Warning; _intakeControls = InnangardGui.Stack(val, 4f, fits: false, (TextAnchor)0); RowWidget rowWidget = InnangardGui.Row(_intakeControls, string.Empty); _intakeState = rowWidget.Label; _intakeAll = rowWidget.Button("$inn_stores_intake_all", 130f, delegate { _showingCrafts = false; RequestIntake(IntakeRoles.All, said: true); }); _intakeRemove = rowWidget.Button("$inn_stores_intake_remove", 190f, delegate { _showingCrafts = false; RequestIntake(IntakeRoles.None, said: false); }); _intakeChoose = rowWidget.Button("$inn_stores_intake_choose", 170f, delegate { _showingCrafts = !_showingCrafts; _remeasure = true; Refresh(); }); _intakeGrid = InnangardGui.Grid(_intakeControls, 3, 190f, 30f); RectTransform intakeGrid = _intakeGrid; (IntakeRoles, string)[] intakeChoices = IntakeChoices; for (int num = 0; num < intakeChoices.Length; num++) { (IntakeRoles, string) tuple = intakeChoices[num]; IntakeRoles item = tuple.Item1; string item2 = tuple.Item2; IntakeRoles which = item; Button item3 = InnangardGui.Press(intakeGrid, Localization.instance.Localize(item2), 190f, 30f, delegate { SettlementIntake settlementIntake = CurrentIntake(); if (settlementIntake != null && (Object)(object)_container != (Object)null) { IntakeRoles intakeRoles = settlementIntake.RolesOf(_container); settlementIntake.Request(_container, ((intakeRoles & which) != IntakeRoles.None) ? (intakeRoles & ~which) : (intakeRoles | which)); } }); _roleButtons.Add(item3); } } private void BuildNaming(RectTransform column) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) RowWidget rowWidget = InnangardGui.Row(column, "$inn_stores_label", 34f); GameObject val = GUIManager.Instance.CreateInputField((Transform)(object)rowWidget.Controls, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), Vector2.zero, (ContentType)0, Localization.instance.Localize("$inn_stores_label_placeholder"), 16, 320f, 28f); LayoutElement obj = val.AddComponent<LayoutElement>(); obj.preferredWidth = 320f; obj.minWidth = 320f; obj.flexibleWidth = 0f; obj.preferredHeight = 28f; _label = val.GetComponent<InputField>(); _label.characterLimit = 32; ((UnityEvent<string>)(object)_label.onEndEdit).AddListener((UnityAction<string>)delegate { SaveLabel(); }); rowWidget.Button("×", 32f, delegate { _label.text = string.Empty; _label.DeactivateInputField(); SaveLabel(); }); } private void BuildFilter(RectTransform column) { //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) RowWidget rowWidget = InnangardGui.Row(column, string.Empty); rowWidget.Button("$inn_stores_copy", 200f, CopyRule); _paste = rowWidget.Button("$inn_stores_paste_nothing", 360f, PasteRule); _origin = InnangardGui.Title(column, string.Empty); InnangardGui.Note(column, Localization.instance.Localize("$inn_stores_filter_help")); RectTransform parent = InnangardGui.Grid(column, 3, 190f, 30f); StockCategories.Kind[] order = StockCategories.Order; foreach (StockCategories.Kind kind in order) { StockCategories.Kind mine = kind; _kindButtons.Add(InnangardGui.Press(parent, Localization.instance.Localize(StockCategories.TitleKey(mine)), 190f, 30f, delegate { Flip(mine); })); } InnangardGui.Note(column, Localization.instance.Localize("$inn_stores_filter_several_kinds")); RowWidget rowWidget2 = InnangardGui.Row(column, string.Empty); _anything = rowWidget2.Button("$inn_stores_filter_use_contents", 240f, delegate { if ((Object)(object)_container != (Object)null) { ChestSortRules.RequestSet(_container, Array.Empty<string>(), configured: false); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "$inn_stores_filter_back_to_auto", 0, (Sprite)null, false); } } Close(); }); _byHand = rowWidget2.Button("$inn_stores_filter_by_name", 240f, delegate { bool flag = !((Component)_picking).gameObject.activeSelf; if (flag && (Object)(object)_container != (Object)null && _selected.Count == 0 && !ChestSortRules.IsConfigured(_container) && !ChestSortRules.IsForKinds(_container)) { SelectPresentMaterials(); Paint(); } ((Component)_picking).gameObject.SetActive(flag); _remeasure = true; Refresh(); }); RowWidget rowWidget3 = InnangardGui.Row(column, string.Empty); _outbox = rowWidget3.Button("$inn_stores_filter_outbox", 300f, delegate { if ((Object)(object)_container != (Object)null) { ChestSortRules.RequestSet(_container, Array.Empty<string>(), configured: true); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "$inn_stores_filter_outbox_set", 0, (Sprite)null, false); } } Close(); }); InnangardGui.Note(column, Localization.instance.Localize("$inn_stores_filter_outbox_help")); RowWidget rowWidget4 = InnangardGui.Row(column, string.Empty); _catchAll = rowWidget4.Button("$inn_stores_filter_catch_all", 300f, delegate { if ((Object)(object)_container != (Object)null) { ChestSortRules.RequestCatchAll(_container); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "$inn_stores_filter_catch_all_set", 0, (Sprite)null, false); } } Close(); }); InnangardGui.Note(column, Localization.instance.Localize("$inn_stores_filter_catch_all_help")); RectTransform val = InnangardGui.Section(column, "$inn_stores_private_section"); RowWidget rowWidget5 = InnangardGui.Row(val, string.Empty); _mine = rowWidget5.Button("$inn_stores_filter_leave_alone", 300f, delegate { if ((Object)(object)_container != (Object)null) { bool flag = !ChestSortRules.LeftAlone(_container); ChestSortRules.RequestLeaveAlone(_container, flag); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, flag ? "$inn_stores_filter_left_alone" : "$inn_stores_filter_shared_again", 0, (Sprite)null, false); } } Close(); }); _mineHelp = InnangardGui.Note(val, Localization.instance.Localize("$inn_stores_filter_leave_alone_help")); _picking = InnangardGui.Stack(column, 8f, fits: false, (TextAnchor)0); RowWidget rowWidget6 = InnangardGui.Row(_picking, "$inn_stores_sort_search", 34f); GameObject val2 = GUIManager.Instance.CreateInputField((Transform)(object)rowWidget6.Controls, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), Vector2.zero, (ContentType)0, string.Empty, 16, 320f, 28f); LayoutElement obj = val2.AddComponent<LayoutElement>(); obj.preferredWidth = 320f; obj.minWidth = 320f; obj.flexibleWidth = 0f; obj.preferredHeight = 28f; _search = val2.GetComponent<InputField>(); _search.characterLimit = 24; ((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)delegate { Sort(); }); rowWidget6.Button("×", 32f, delegate { _search.text = string.Empty; _search.DeactivateInputField(); Sort(); }); RowWidget rowWidget7 = InnangardGui.Row(_picking, string.Empty, 34f); rowWidget7.Button("$inn_stores_filter_from_inside", 280f, delegate { int count = _selected.Count; SelectPresentMaterials(); Paint(); Diagnostics.Log($"Innangard[stores]: took the list from the chest - {_selected.Count - count} " + $"new name(s), {_selected.Count} chosen, {_choices.Count} row(s) on offer"); }); rowWidget7.Button("$inn_stores_filter_start_over", 150f, delegate { _selected.Clear(); Paint(); }); RectTransform val3 = InnangardGui.Scroller(_picking, 4f); _scroll = ((Component)val3).GetComponentInParent<ScrollRect>(); _list = (((Object)(object)_scroll != (Object)null) ? ((Component)_scroll).GetComponent<RectTransform>() : val3); Transform val4 = (Transform)(object)val3; while ((Object)(object)val4.parent != (Object)null && (Object)(object)val4.parent != (Object)(object)_picking) { val4 = val4.parent; } _list = (RectTransform)(object)((val4 is RectTransform) ? val4 : null); _grid = InnangardGui.Grid(val3, 3, 240f, 34f); _noMatch = InnangardGui.Note(val3, Localization.instance.Localize("$inn_stores_filter_no_match")); RowWidget rowWidget8 = InnangardGui.Row(_picking, string.Empty, 36f); _chosenCount = rowWidget8.Label; rowWidget8.Button("$inn_stores_filter_keep", 160f, delegate { if ((Object)(object)_container != (Object)null) { ChestSortRules.RequestSet(_container, _selected, configured: true); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "$inn_stores_filter_kept", 0, (Sprite)null, false); } } Close(); }); rowWidget8.Button("$inn_tend_close", 90f, Close); RectTransform val5 = Child("inn_chest_slack", (Transform)(object)column); _slack = ((Component)val5).gameObject.AddComponent<LayoutElement>(); _slack.minHeight = 0f; _slack.preferredHeight = 0f; RowWidget rowWidget9 = InnangardGui.Row(column, string.Empty, 36f); rowWidget9.Button("$inn_tend_close", 90f, Close); _footer = ((Component)rowWidget9.Root).gameObject; } private void Populate(List<ItemChoice> choices) { for (int num = ((Transform)_grid).childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)((Transform)_grid).GetChild(num)).gameObject); } _choices.Clear(); foreach (ItemChoice choice in choices) { ItemChoice mine = choice; mine.Button = InnangardGui.Press(_grid, choice.DisplayName, 240f, 34f, delegate { if (!_selected.Remove(mine.SharedName)) { _selected.Add(mine.SharedName); } Paint(); }); IconOn(mine.Button, choice.Icon); _choices.Add(mine); } Sort(); Paint(); ((MonoBehaviour)this).StartCoroutine(ScrollToTop()); } private IEnumerator ScrollToTop() { yield return null; if ((Object)(object)_scroll != (Object)null) { Canvas.ForceUpdateCanvases(); _scroll.verticalNormalizedPosition = 1f; } } private static void IconOn(Button button, Sprite icon) { //IL_0028: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_008b: 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_00b5: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) Text componentInChildren = ((Component)button).GetComponentInChildren<Text>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.alignment = (TextAnchor)3; ((Graphic)componentInChildren).rectTransform.offsetMin = new Vector2(44f, ((Graphic)componentInChildren).rectTransform.offsetMin.y); } if (!((Object)(object)icon == (Object)null)) { GameObject val = new GameObject("inn_icon", new Type[2] { typeof(RectTransform), typeof(Image) }) { layer = 5 }; RectTransform component = val.GetComponent<RectTransform>(); ((Transform)component).SetParent(((Component)button).transform, false); ((Transform)component).localScale = Vector3.one; component.anchorMin = new Vector2(0f, 0.5f); component.anchorMax = new Vector2(0f, 0.5f); component.pivot = new Vector2(0f, 0.5f); component.anchoredPosition = new Vector2(8f, 0f); component.sizeDelta = new Vector2(28f, 28f); Image component2 = val.GetComponent<Image>(); component2.sprite = icon; component2.preserveAspect = true; ((Graphic)component2).raycastTarget = false; } } private void Refresh() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_container == (Object)null || (Object)(object)_panel == (Object)null) { return; } float scale = InnGuiSkin.Scale; if (!Mathf.Approximately(scale, _scaledAt)) { _scaledAt = scale; _panel.transform.localScale = Vector3.one * scale; } SettlementIntake settlementIntake = CurrentIntake(); bool flag = settlementIntake != null; ((Component)_intakeNoFrithstone).gameObject.SetActive(!flag); ((Component)_intakeControls).gameObject.SetActive(flag); if (flag) { IntakeRoles intakeRoles = settlementIntake.RolesOf(_container); bool flag2 = intakeRoles != IntakeRoles.None; _intakeState.text = Localization.instance.Localize(flag2 ? "$inn_stores_intake_current" : "$inn_stores_intake_available"); ((Component)_intakeRemove).gameObject.SetActive(flag2); InnangardGui.Chosen(_intakeAll, intakeRoles == IntakeRoles.All); bool flag3 = flag2 && intakeRoles != IntakeRoles.All; bool flag4 = _showingCrafts || flag3; if (((Component)_intakeGrid).gameObject.activeSelf != flag4) { ((Component)_intakeGrid).gameObject.SetActive(flag4); _remeasure = true; } ((Component)_intakeChoose).gameObject.SetActive(!flag3); for (int i = 0; i < _roleButtons.Count && i < IntakeChoices.Length; i++) { InnangardGui.Chosen(_roleButtons[i], (intakeRoles & IntakeChoices[i].Role) != 0); InnangardGui.Usable(_roleButtons[i], SettlerRoles.Offered(TradeOf(IntakeChoices[i].Role))); } } _kinds = ChestSortRules.KindsOf(_container); _wasConfigured = ChestSortRules.IsConfigured(_container); bool flag5 = ChestSortRules.IsCatchAll(_container); _origin.text = (flag5 ? Localization.instance.Localize("$inn_stores_filter_is_catch_all") : ((_kinds != 0) ? string.Format(Localization.instance.Localize("$inn_stores_filter_of_a_kind"), KindsNamed()) : Localization.instance.Localize((!_wasConfigured) ? "$inn_stores_filter_from_contents" : ((ChestSortRules.ReadItems(_container).Count == 0) ? "$inn_stores_filter_is_outbox" : "$inn_stores_filter_by_hand")))); for (int j = 0; j < _kindButtons.Count && j < StockCategories.Order.Length; j++) { InnangardGui.Chosen(_kindButtons[j], (_kinds & (1 << (int)StockCategories.Order[j])) != 0); } InnangardGui.Say(_paste, (_copied == null) ? "$inn_stores_paste_nothing" : string.Format(Localization.instance.Localize("$inn_stores_paste"), _copied.Said)); InnangardGui.Usable(_paste, _copied != null); bool flag6 = ChestSortRules.LeftAlone(_container); InnangardGui.Chosen(_mine, flag6); InnangardGui.Say(_mine, flag6 ? "$inn_stores_filter_share_again" : "$inn_stores_filter_leave_alone"); if ((Object)(object)_mineHelp != (Object)null) { _mineHelp.text = Localization.instance.Localize(flag6 ? "$inn_stores_filter_leave_alone_on" : "$inn_stores_filter_leave_alone_help"); } if (flag6) { _origin.text = Localization.instance.Localize("$inn_stores_filter_is_left_alone"); } bool flag7 = _wasConfigured && ChestSortRules.ReadItems(_container).Count == 0; InnangardGui.Chosen(_outbox, flag7); InnangardGui.Chosen(_catchAll, flag5); InnangardGui.Chosen(_anything, _kinds == 0 && !_wasConfigured && !flag5); InnangardGui.Chosen(_byHand, (_wasConfigured && !flag7) || ((Component)_picking).gameObject.activeSelf); _slack.flexibleHeight = (((Component)_picking).gameObject.activeSelf ? 0f : 1f); if ((Object)(object)_footer != (Object)null && _footer.activeSelf == ((Component)_picking).gameObject.activeSelf) { _footer.SetActive(!((Component)_picking).gameObject.activeSelf); _remeasure = true; } Remeasure(); Resize(); } private void Resize() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_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) RectTransform val = (((Object)(object)_panel != (Object)null) ? _panel.GetComponent<RectTransform>() : null); if ((Object)(object)val == (Object)null || (Object)(object)_column == (Object)null) { return; } float num = 76f; float num2 = LayoutUtility.GetPreferredHeight(_column) + num; float num3 = (((Component)_picking).gameObject.activeSelf ? Mathf.Max(880f, num2) : Mathf.Max(num2, 260f)); Transform parent = ((Transform)val).parent; RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (val2 != null) { Rect rect = val2.rect; if (((Rect)(ref rect)).height > 0f) { float num4 = Mathf.Max(_panel.transform.localScale.y, 0.01f); float num5 = num3; rect = val2.rect; num3 = Mathf.Max(260f, Mathf.Min(num5, ((Rect)(ref rect)).height * 0.95f / num4)); } } if (!(Mathf.Abs(num3 - _heightNow) < 2f)) { _heightNow = num3; val.sizeDelta = new Vector2(780f, num3); if (((Component)_picking).gameObject.activeSelf) { ((MonoBehaviour)this).StartCoroutine(ReportListHeight(num3)); } } } private IEnumerator ReportListHeight(float frameHeight) { yield return null; if ((Object)(object)_list != (Object)null && (Object)(object)_picking != (Object)null && ((Component)_picking).gameObject.activeSelf) { string text = $"Innangard[stores]: sorting window {frameHeight:0} tall, hand-picked list "; Rect rect = _list.rect; Diagnostics.Log(text + $"{((Rect)(ref rect)).height:0} tall with {_choices.Count} name(s) on offer"); } } private void Flip(StockCategories.Kind kind) { if (!((Object)(object)_container == (Object)null)) { int num = 1 << (int)kind; _kinds = (((_kinds & num) != 0) ? (_kinds & ~num) : (_kinds | num)); ChestSortRules.RequestKinds(_container, _kinds); Paint(); Refresh(); } } private string KindsNamed() { StringBuilder stringBuilder = new StringBuilder(); StockCategories.Kind[] order = StockCategories.Order; foreach (StockCategories.Kind kind in order) { if ((_kinds & (1 << (int)kind)) != 0) { if (stringBuilder.Length > 0) { stringBuilder.Append(", "); } stringBuilder.Append(Localization.instance.Localize(StockCategories.TitleKey(kind))); } } return stringBuilder.ToString(); } private SettlementIntake CurrentIntake() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)_container == (Object)null) { return null; } return SettlementIntake.CandidateFor(_container, localPlayer.GetPlayerID()); } private void SaveLabel() { if ((Object)(object)_container == (Object)null || (Object)(object)_label == (Object)null) { return; } string text = ChestSortRules.CleanLabel(_label.text); if (!(text == ChestSortRules.LabelOf(_container))) { ChestSortRules.RequestLabel(_container, text); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, (text.Length > 0) ? string.Format(Localization.instance.Localize("$inn_stores_label_set"), text) : Localization.instance.Localize("$inn_stores_label_cleared"), 0, (Sprite)null, false); } } } private void CopyRule() { if (!((Object)(object)_container == (Object)null)) { int kinds = ChestSortRules.KindsOf(_container); bool configured = ChestSortRules.IsConfigured(_container); HashSet<string> items = ChestSortRules.ReadItems(_container); bool flag = ChestSortRules.IsCatchAll(_container); _copied = new Copied { Kinds = kinds, Configured = configured, CatchAll = flag, Items = items, Said = (flag ? Localization.instance.Localize("$inn_stores_filter_catch_all") : RuleWords(kinds, configured, items)) }; Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, string.Format(Localization.instance.Localize("$inn_stores_copied"), _copied.Said), 0, (Sprite)null, false); } Refresh(); } } private void PasteRule() { if (!((Object)(object)_container == (Object)null) && _copied != null) { ApplyRule(_container, _copied.Kinds, _copied.Configured, _copied.Items, _copied.CatchAll); _selected = new HashSet<string>(_copied.Items, StringComparer.Ordinal); Populate(BuildChoices(_container, _selected)); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, string.Format(Localization.instance.Localize("$inn_stores_pasted"), _copied.Said), 0, (Sprite)null, false); } Refresh(); } } internal static void ApplyRule(Container container, int kinds, bool configured, IEnumerable<string> items, bool catchAll = false) { if (catchAll) { ChestSortRules.RequestCatchAll(container); } else if (kinds != 0) { ChestSortRules.RequestKinds(container, kinds); } else { ChestSortRules.RequestSet(container, items, configured); } } private static string RuleWords(int kinds, bool configured, HashSet<string> items) { if (kinds != 0) { return ChestLabels.Cut(from kind in StockCategories.Order where (kinds & (1 << (int)kind)) != 0 select Localization.instance.Localize(StockCategories.TitleKey(kind))); } if (!configured) { return Localization.instance.Localize("$inn_stores_filter_use_contents"); } if (items.Count == 0) { return Localization.instance.Localize("$inn_stores_filter_outbox"); } return ChestLabels.Cut(from name in items.Select(ChestLabels.Pretty) orderby name select name); } private void RequestIntake(IntakeRoles roles, bool said) { SettlementIntake settlementIntake = CurrentIntake(); if (settlementIntake == null || (Object)(object)_container == (Object)null) { return; } settlementIntake.Request(_container, roles); if (said) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "$inn_stores_intake_saved", 0, (Sprite)null, false); } } } private void Paint() { int num = 0; foreach (ItemChoice choice in _choices) { if (_selected.Contains(choice.SharedName)) { ((Component)choice.Button).transform.SetSiblingIndex(num++); } } foreach (ItemChoice choice2 in _choices) { bool flag = _selected.Contains(choice2.SharedName); InnangardGui.Chosen(choice2.Button, flag); if (!flag) { ((Component)choice2.Button).transform.SetSiblingIndex(num++); } } _chosenCount.text = string.Format(Localization.instance.Localize("$inn_stores_filter_chosen"), _selected.Count); ((MonoBehaviour)this).StartCoroutine(ScrollToTop()); } private void Sort() { string looking = (((Object)(object)_search != (Object)null) ? _search.text : string.Empty).Trim(); int num = 0; foreach (ItemChoice choice in _choices) { bool flag = Matches(choice, looking); if (((Component)choice.Button).gameObject.activeSelf != flag) { ((Component)choice.Button).gameObject.SetActive(flag); } if (flag) { num++; } } ((Component)_noMatch).gameObject.SetActive(num == 0); } private static bool Matches(ItemChoice choice, string looking) { if (string.IsNullOrWhiteSpace(looking)) { return true; } if (choice.DisplayName.IndexOf(looking, StringComparison.OrdinalIgnoreCase) < 0) { return choice.SharedName.IndexOf(looking, StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private void SelectPresentMaterials() { Container container = _container; Inventory val = ((container != null) ? container.GetInventory() : null); if (val == null) { return; } foreach (ItemData allItem in val.GetAllItems()) { if (ChestSortRules.IsSortable(allItem)) { _selected.Add(allItem.m_shared.m_name); } } } private static List<ItemChoice> BuildChoices(Container container, HashSet<string> selected) { HashSet<string> hashSet = new HashSet<string>(selected, StringComparer.Ordinal); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { hashSet.UnionWith(localPlayer.m_knownMaterial); } Inventory inventory = container.GetInventory(); if (inventory != null) { hashSet.UnionWith(from item in inventory.GetAllItems() where item != null select item.m_shared.m_name); } List<ItemChoice> list = new List<ItemChoice>(); if ((Object)(object)ObjectDB.instance == (Object)null) { return list; } foreach (GameObject item in ObjectDB.instance.m_items) { ItemData val = ((item == null) ? null : item.GetComponent<ItemDrop>()?.m_itemData); if (ChestSortRules.IsSortable(val) && hashSet.Contains(val.m_shared.m_name)) { list.Add(new ItemChoice { SharedName = val.m_shared.m_name, DisplayName = Localization.instance.Localize(val.m_shared.m_name), Icon = val.GetIcon() }); } } HashSet<string> hashSet2 = new HashSet<string>(list.Select((ItemChoice choice) => choice.SharedName), StringComparer.Ordinal); if (inventory != null) { foreach (ItemData allItem in inventory.GetAllItems()) { if (ChestSortRules.IsSortable(allItem) && hashSet2.Add(allItem.m_shared.m_name)) { list.Add(new ItemChoice { SharedName = allItem.m_shared.m_name, DisplayName = Localization.instance.Localize(allItem.m_shared.m_name), Icon = allItem.GetIcon() }); Diagnostics.Log("Innangard[stores]: " + allItem.m_shared.m_name + " is in the chest but not in the item database; offered from the chest itself"); } } } return (from choice in list group choice by choice.SharedName into @group select @group.First() into choice orderby choice.DisplayName select choice).ToList(); } private static RectTransform Child(string name, Transform parent) { //IL_0014: 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) RectTransform component = new GameObject(name, new Type[1] { typeof(RectTransform) }) { layer = 5 }.GetComponent<RectTransform>(); ((Transform)component).SetParent(parent, false); ((Transform)component).localScale = Vector3.one; InnangardGui.Fill(component); return component; } } internal static class ChestSortRules { [HarmonyPatch(typeof(Container), "Awake")] private static class RegisterPatch { [HarmonyPostfix] private static void Postfix(Container __instance) { Register(__instance); } } [HarmonyPatch(typeof(Container), "GetHoverText")] private static class HoverPatch { [HarmonyPostfix] private static void Postfix(Container __instance, ref string __result) { if ((Object)(object)Player.m_localPlayer != (Object)null && IsStationaryPlayerChest(__instance)) { string text = ChestLabels.HoverLine(__instance); if (text.Length > 0) { __result = __result + "\n" + text; } __result = __result + "\n" + Localization.instance.Localize(InnInput.Relabel(Localization.instance.Localize("$inn_stores_filter_hover"))); } } } private const char Separator = '|'; private const string RpcSetSort = "inn_SetChestSort"; private const string ZdoConfigured = "inn_sort_configured"; private const string ZdoItems = "inn_sort_items"; private const string ZdoKind = "inn_chest_sort_kind"; private const string ZdoKinds = "inn_sort_kinds"; private const string ZdoLeaveAlone = "inn_sort_leave_alone"; private const string ZdoLabel = "inn_chest_label"; private const string ZdoCatchAll = "inn_sort_catch_all"; internal const int LabelLength = 32; internal const int ByHand = 0; internal const int ByKind = 2; internal const int ByLeftovers = 3; internal const int ByHabit = 4; internal const int ByCatchAll = 5; internal const int ByRoom = 6; internal const int NotAtAll = int.MaxValue; internal static void Register(Container container) { ZNetView val = container?.m_nview; if (!((Object)(object)val == (Object)null) && val.IsValid() && !(container is SettlerInventory)) { val.Register<long, string>("inn_SetChestSort", (Action<long, long, string>)delegate(long sender, long requesterId, string payload) { Receive(container, sender, requesterId, payload); }); } } internal static bool LeftAlone(Container container) { if (TryGetZdo(container, out var zdo)) { return zdo.GetBool("inn_sort_leave_alone", false); } return false; } internal static void RequestLeaveAlone(Container container, bool leaveAlone) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && CanConfigure(container, localPlayer.GetPlayerID())) { container.m_nview.InvokeRPC("inn_SetChestSort", new object[2] { localPlayer.GetPlayerID(), "4|" + (leaveAlone ? "1" : "0") }); } } internal static string LabelOf(Container container) { if (!TryGetZdo(container, out var zdo)) { return string.Empty; } return zdo.GetString("inn_chest_label", string.Empty); } internal static string CleanLabel(string label) { if (string.IsNullOrEmpty(label)) { return string.Empty; } string text = new string(label.Where((char c) => c != '<' && c != '>' && c != '|' && !char.IsControl(c)).ToArray()).Trim(); if (text.Length <= 32) { return text; } return text.Substring(0, 32).TrimEnd(Array.Empty<char>()); } internal static void RequestLabel(Container container, string label) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && CanConfigure(container, localPlayer.GetPlayerID())) { container.m_nview.InvokeRPC("inn_SetChestSort", new object[2] { localPlayer.GetPlayerID(), "5|" + CleanLabel(label) }); } } internal static bool TogglePin(Container container, string sharedName, out bool pinned) { pinned = false; if ((Object)(object)container == (Object)null || string.IsNullOrEmpty(sharedName) || IsForKinds(container) || IsCatchAll(container)) { return false; } HashSet<string> hashSet = (IsConfigured(container) ? ReadItems(container) : new HashSet<string>(StringComparer.Ordinal)); pinned = !hashSet.Remove(sharedName); if (pinned) { hashSet.Add(sharedName); } RequestSet(container, hashSet, hashSet.Count > 0, openHere: true); return true; } internal static bool PinContents(Container container, out int added) { added = 0; Inventory val = ((container != null) ? container.GetInventory() : null); if (val == null || IsForKinds(container) || IsCatchAll(container)) { return false; } HashSet<string> hashSet = (IsConfigured(container) ? ReadItems(container) : new HashSet<string>(StringComparer.Ordinal)); foreach (ItemData allItem in val.GetAllItems()) { if (IsSortable(allItem) && hashSet.Add(allItem.m_shared.m_name)) { added++; } } if (hashSet.Count == 0) { return false; } RequestSet(container, hashSet, configured: true, openHere: true); return true; } internal static bool WasToldWhatItHolds(Container container) { if (KindsOf(container) == 0 && !IsConfigured(container)) { return IsCatchAll(container); } return true; } internal static bool IsCatchAll(Container container) { if (TryGetZdo(container, out var zdo)) { return zdo.GetBool("inn_sort_catch_all", false); } return false; } internal static void RequestCatchAll(Container container) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && CanConfigure(container, localPlayer.GetPlayerID())) { container.m_nview.InvokeRPC("inn_SetChestSort", new object[2] { localPlayer.GetPlayerID(), "6|1" }); } } internal static bool Refuses(Container container, string sharedName) { if (WasToldWhatItHolds(container)) { return Precision(container, sharedName) == int.MaxValue; } return false; } internal static bool IsConfigured(Container container) { if (TryGetZdo(container, out var zdo)) { return zdo.GetBool("inn_sort_configured", false); } return false; } internal static int KindsOf(Container container) { if (!TryGetZdo(container, out var zdo)) { return 0; } int num = zdo.GetInt("inn_sort_kinds", 0); if (num != 0) { return num & ((1 << StockCategories.Order.Length) - 1); } int num2 = zdo.GetInt("inn_chest_sort_kind", 0); if (num2 <= 0 || num2 > StockCategories.Order.Length) { return 0; } return 1 << num2 - 1; } internal static bool IsForKinds(Container container) { return KindsOf(container) != 0; } internal static bool HasKind(Container container, StockCategories.Kind kind) { return (KindsOf(container) & (1 << (int)kind)) != 0; } internal static HashSet<string> ReadItems(Container container) { HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); if (!TryGetZdo(container, out var zdo)) { return hashSet; } string[] array = zdo.GetString("inn_sort_items", string.Empty).Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries); foreach (string item in array) { hashSet.Add(item); } return hashSet; } internal static bool Accepts(Container container, string sharedName) { if ((Object)(object)container == (Object)null || string.IsNullOrEmpty(sharedName)) { return false; } if (IsCatchAll(container)) { return true; } int num = KindsOf(container); if (num != 0) { return (num & (1 << (int)StockCategories.Of(sharedName))) != 0; } if (IsConfigured(container)) { return ReadItems(container).Contains(sharedName); } return Dominates(container, sharedName); } internal static int Precision(Container container, string sharedName) { if ((Object)(object)container == (Object)null || string.IsNullOrEmpty(sharedName)) { return int.MaxValue; } if (IsCatchAll(container)) { return 5; } int num = KindsOf(container); if (num != 0) { StockCategories.Kind kind = StockCategories.Of(sharedName); if ((num & (1 << (int)kind)) == 0) { return int.MaxValue; } if (kind != StockCategories.Kind.Other) { return 2; } return 3; } if (IsConfigured(container)) { if (!ReadItems(container).Contains(sharedName)) { return int.MaxValue; } return 0; } if (!Dominates(container, sharedName)) { return int.MaxValue; } if (!Empty(container)) { return 4; } return 6; } private static bool Empty(Container container) { ChestContents.Summary summary = ChestContents.Of(container); if (summary != null) { return summary.UsedSortable == 0; } return true; } internal static bool Dominates(Container container, string sharedName) { return ChestContents.Of(container)?.Dominates(sharedName) ?? false; } internal static bool IsSortable(ItemData item) { //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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Invalid comparison between Unknown and I4 //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Invalid comparison between Unknown and I4 //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (item?.m_shared == null || item.m_shared.m_questItem || item.m_equipped) { return false; } ItemType itemType = item.m_shared.m_itemType; if ((int)itemType <= 13) { if (itemType - 1 <= 1 || (int)itemType == 9 || (int)itemType == 13) { goto IL_0057; } } else if ((int)itemType == 16 || (int)itemType == 21 || (int)itemType == 23) { goto IL_0057; } return StockCategories.IsEquipment(item.m_shared.m_itemType); IL_0057: return true; } internal static void RequestSet(Container container, IEnumerable<string> items, bool configured, bool openHere = false) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !CanConfigure(container, localPlayer.GetPlayerID(), openHere)) { return; } string text = "0"; if (configured) { IOrderedEnumerable<string> values = from name in items.Where((string name) => !string.IsNullOrEmpty(name) && name.IndexOf('|') < 0).Distinct() orderby name select name; text = "1|" + string.Join('|'.ToString(), values); } container.m_nview.InvokeRPC("inn_SetChestSort", new object[2] { localPlayer.GetPlayerID(), text }); } internal static void RequestKinds(Container container, int mask) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && CanConfigure(container, localPlayer.GetPlayerID())) { container.m_nview.InvokeRPC("inn_SetChestSort", new object[2] { localPlayer.GetPlayerID(), "3|" + mask }); } } internal static bool IsStationaryPlayerChest(Container container) { if ((Object)(object)container == (Object)null || container is SettlerInventory || !((Component)container).gameObject.activeInHierarchy) { return false; } if ((Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid()) { return false; } if ((Object)(object)container.m_wagon != (Object)null || (Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null || (Object)(object)((Component)container).GetComponentInParent<Vagon>() != (Object)null) { return false; } if (Devours(container)) { return false; } Piece val = ((Component)container).GetComponent<Piece>() ?? ((Component)container).GetComponentInParent<Piece>(); if ((Object)(object)val != (Object)null) { return val.IsPlacedByPlayer(); } return false; } internal static bool Devours(Container container) { if ((Object)(object)container != (Object)null) { if (!((Object)(object)((Component)container).GetComponent<Incinerator>() != (Object)null)) { return (Object)(object)((Component)container).GetComponentInParent<Incinerator>() != (Object)null; } return true; } return false; } internal static bool CanConfigure(Container container, long playerId, bool openHere = false) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) bool flag = openHere && (Object)(object)container != (Object)null && (Object)(object)InventoryGui.instance != (Object)null && (Object)(object)InventoryGui.instance.m_currentContainer == (Object)(object)container; if (playerId == 0L || !IsStationaryPlayerChest(container) || (!flag && InUse(container)) || !container.CheckAccess(playerId)) { return false; } return PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false); } private static void Receive(Container container, long sender, long requesterId, string payload) { //IL_00a1: 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_0198: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)container == (Object)null || (Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid() || reques