Decompiled source of AllfathersChest v0.7.2

plugins/AllfathersChest.dll

Decompiled 12 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using AllfathersChest.Chest;
using AllfathersChest.Sorting;
using AllfathersChest.Ui;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("AllfathersChest")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("One chest you throw everything into; it sorts the contents into the chests around it.")]
[assembly: AssemblyFileVersion("0.7.2.0")]
[assembly: AssemblyInformationalVersion("0.7.2+63df982a1b7fe64ac160fa92fbfdbdb1920794c1")]
[assembly: AssemblyProduct("Allfather's Chest")]
[assembly: AssemblyTitle("AllfathersChest")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.7.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AllfathersChest
{
	public static class ModConfig
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<ModLanguage> Language;

		public static ConfigEntry<string> BasePrefab;

		public static ConfigEntry<int> Width;

		public static ConfigEntry<int> Height;

		public static ConfigEntry<int> Cost;

		public static ConfigEntry<bool> AutoSort;

		public static ConfigEntry<float> UpkeepSeconds;

		public static ConfigEntry<float> Radius;

		public static ConfigEntry<bool> ShowCounter;

		public static ConfigEntry<bool> ShowRange;

		public static ConfigEntry<bool> GroundPickup;

		public static ConfigEntry<float> GroundGraceSeconds;

		public static ConfigEntry<bool> Verbose;

		public static void Bind(ConfigFile cfg)
		{
			Enabled = cfg.Bind<bool>("1 - General", "Enabled", true, "Master switch. Off, the chest is still there and still opens - the button simply does nothing. / Hauptschalter. Aus heisst: die Truhe steht und oeffnet weiterhin, der Knopf tut nur nichts mehr.");
			Language = cfg.Bind<ModLanguage>("1 - General", "Language", ModLanguage.Game, "Which language the chest speaks. Game follows Valheim. / Welche Sprache die Truhe spricht. Game folgt Valheim.");
			BasePrefab = cfg.Bind<string>("2 - Chest", "BasePrefab", "piece_chest", "The game piece the chest is copied from - its looks, nothing else. piece_chest is the reinforced one. Change it if you would rather have a different chest standing there. / Das Spielbauteil, von dem die Truhe kopiert wird - nur das Aussehen. piece_chest ist die verstaerkte Truhe. Aendern, wenn dort lieber eine andere stehen soll.");
			Width = cfg.Bind<int>("2 - Chest", "Width", 8, "Slots across. Eight by four is twice a reinforced chest, which is about one trip home. / Plaetze in der Breite. Acht mal vier ist doppelt so viel wie eine verstaerkte Truhe, also ungefaehr ein Heimweg.");
			Height = cfg.Bind<int>("2 - Chest", "Height", 4, "Slots down. / Plaetze in der Hoehe.");
			Cost = cfg.Bind<int>("2 - Chest", "Cost", 20, "Wood to build one. / Holz zum Bauen.");
			AutoSort = cfg.Bind<bool>("3 - Sorting", "AutoSort", true, "Look after the chest without being asked: sweep the ground if that is on, and hand everything out. Off, nothing moves until somebody presses the button. / Sich ungefragt um die Truhe kuemmern: den Boden einsammeln, falls eingeschaltet, und alles verteilen. Aus heisst: es bewegt sich nichts, bis jemand den Knopf drueckt.");
			UpkeepSeconds = cfg.Bind<float>("3 - Sorting", "UpkeepSeconds", 5f, "Seconds between two unattended passes, for both halves. / Sekunden zwischen zwei unbeaufsichtigten Durchgaengen, fuer beide Haelften.");
			Radius = cfg.Bind<float>("3 - Sorting", "Radius", 20f, "How far the chest reaches, in metres, as a sphere - so a cellar two floors down counts. / Wie weit die Truhe reicht, in Metern, als Kugel - ein Keller zwei Etagen tiefer zaehlt also dazu.");
			ShowCounter = cfg.Bind<bool>("3 - Sorting", "ShowCounter", true, "Show on the chest how much it has sorted and how much found no home. / Auf der Truhe anzeigen, wie viel sie sortiert hat und wie viel keine Kiste fand.");
			ShowRange = cfg.Bind<bool>("3 - Sorting", "ShowRange", false, "Draw the chest's reach as a wireframe sphere while you stand near it. Three circles, not one: the reach is a sphere, so a cellar below counts and the shape has to say so. For setting up; off the rest of the time. / Die Reichweite als Drahtkugel zeichnen, solange du in der Naehe stehst. Drei Kreise, nicht einer: die Reichweite ist eine Kugel, ein Keller darunter zaehlt also dazu, und die Form soll das sagen. Zum Einrichten; sonst aus.");
			GroundPickup = cfg.Bind<bool>("4 - Ground", "PickUpFromGround", false, "When the button is pressed, also pick up what is lying on the ground within reach, whoever dropped it. Off by default: a chest that empties the floor is a surprise the first time it happens. / Beim Druecken des Knopfes auch aufheben, was in Reichweite auf dem Boden liegt, egal wer es fallen liess. Standardmaessig aus: eine Truhe, die den Boden leerraeumt, ueberrascht beim ersten Mal.");
			GroundGraceSeconds = cfg.Bind<float>("4 - Ground", "GraceSeconds", 8f, "How long a thing must have lain there before the chest will take it. Somebody putting something down for somebody else should have a moment to do it. / Wie lange etwas gelegen haben muss, bevor die Truhe es nimmt. Wer etwas fuer jemanden hinlegt, soll einen Moment dafuer haben.");
			Verbose = cfg.Bind<bool>("5 - Debug", "Verbose", false, "Write every move to the log. Loud, and the first thing to turn on when something goes somewhere unexpected. / Jeden Zug ins Log schreiben. Laut, und das Erste, was man einschaltet, wenn etwas irgendwo landet, wo es nicht hingehoert.");
			Language.SettingChanged += delegate
			{
				Texts.Setting = Language.Value;
			};
			Texts.Setting = Language.Value;
		}
	}
	[BepInPlugin("sohneg.AllfathersChest", "Allfather's Chest", "0.7.2")]
	[BepInProcess("valheim.exe")]
	public class AllfathersChestPlugin : BaseUnityPlugin
	{
		public const string ModGuid = "sohneg.AllfathersChest";

		public const string ModName = "Allfather's Chest";

		public const string ModVersion = "0.7.2";

		private const float PieceCheckSeconds = 2f;

		public static ManualLogSource Log;

		public static AllfathersChestPlugin Instance;

		private Harmony _harmony;

		private float _nextPieceCheck;

		private float _nextUpkeep;

		private void Awake()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Texts.Log = delegate(string message)
			{
				Log.LogWarning((object)message);
			};
			Texts.GameLanguage = () => (Localization.instance == null) ? "" : Localization.instance.GetSelectedLanguage();
			Texts.Load();
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("sohneg.AllfathersChest");
			_harmony.PatchAll();
			Log.LogInfo((object)"Allfather's Chest 0.7.2 is awake.");
		}

		private void Update()
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				SortingChestPiece.Reset();
				ContainerRegistry.Clear();
				SortButton.Reset();
				Upkeep.Reset();
				return;
			}
			SortButton.Tick();
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime >= _nextUpkeep)
			{
				_nextUpkeep = unscaledTime + Mathf.Max(1f, ModConfig.UpkeepSeconds.Value);
				try
				{
					Upkeep.Tick();
				}
				catch (Exception ex)
				{
					Log.LogError((object)("The chest stumbled while looking after itself: " + ex));
				}
			}
			if (!(unscaledTime >= _nextPieceCheck))
			{
				return;
			}
			_nextPieceCheck = unscaledTime + 2f;
			try
			{
				SortingChestPiece.Tick();
			}
			catch (Exception ex2)
			{
				Log.LogError((object)("Could not keep the chest in the build menu: " + ex2));
			}
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
			Instance = null;
		}
	}
	public enum ModLanguage
	{
		Game,
		English,
		Deutsch
	}
	public static class Texts
	{
		public const string Fallback = "en";

		private static readonly Dictionary<string, Dictionary<string, string[]>> Tables = new Dictionary<string, Dictionary<string, string[]>>(StringComparer.OrdinalIgnoreCase);

		private static readonly HashSet<string> Reported = new HashSet<string>(StringComparer.Ordinal);

		public static Func<string> GameLanguage;

		public static Action<string> Log;

		public static ModLanguage Setting = ModLanguage.Game;

		public static readonly string[] Available = new string[2] { "en", "de" };

		public static void Load()
		{
			Tables.Clear();
			Reported.Clear();
			for (int i = 0; i < Available.Length; i++)
			{
				string text = Available[i];
				Dictionary<string, string[]> dictionary = ReadEmbedded(text);
				if (dictionary != null)
				{
					Tables[text] = dictionary;
				}
			}
		}

		public static string Get(string key, params string[] values)
		{
			return GetIn(ActiveCode(), key, values);
		}

		public static string GetIn(string code, string key, params string[] values)
		{
			return Fill(Pick(code, key), values);
		}

		public static string ActiveCode()
		{
			return Setting switch
			{
				ModLanguage.English => "en", 
				ModLanguage.Deutsch => "de", 
				_ => FromGame(), 
			};
		}

		public static bool Has(string code)
		{
			if (code != null)
			{
				return Tables.ContainsKey(code);
			}
			return false;
		}

		public static ICollection<string> KeysOf(string code)
		{
			if (!Tables.TryGetValue(code ?? "", out var value))
			{
				return new string[0];
			}
			return value.Keys;
		}

		public static int VariantCount(string code, string key)
		{
			return VariantsOf(code, key).Length;
		}

		public static string[] VariantsOf(string code, string key)
		{
			if (!Tables.TryGetValue(code ?? "", out var value))
			{
				return new string[0];
			}
			if (!value.TryGetValue(key ?? "", out var value2))
			{
				return new string[0];
			}
			return value2;
		}

		private static string FromGame()
		{
			string a = "";
			try
			{
				if (GameLanguage != null)
				{
					a = GameLanguage() ?? "";
				}
			}
			catch
			{
			}
			if (!string.Equals(a, "German", StringComparison.OrdinalIgnoreCase))
			{
				return "en";
			}
			return "de";
		}

		private static string Pick(string code, string key)
		{
			string[] array = Lookup(code, key);
			if (array == null || array.Length == 0)
			{
				return key ?? "";
			}
			return array[0];
		}

		private static string[] Lookup(string code, string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return null;
			}
			if (Tables.TryGetValue(code ?? "", out var value) && value.TryGetValue(key, out var value2))
			{
				return value2;
			}
			if (!string.Equals(code, "en", StringComparison.OrdinalIgnoreCase) && Tables.TryGetValue("en", out value) && value.TryGetValue(key, out value2))
			{
				Report("Text '" + key + "' is missing from " + code + ".json, using en.");
				return value2;
			}
			Report("Text '" + key + "' is missing from every language file.");
			return null;
		}

		private static string Fill(string template, string[] values)
		{
			if (string.IsNullOrEmpty(template) || values == null || values.Length == 0)
			{
				return template ?? "";
			}
			StringBuilder stringBuilder = new StringBuilder(template);
			for (int i = 0; i + 1 < values.Length; i += 2)
			{
				stringBuilder.Replace("{" + values[i] + "}", values[i + 1] ?? "");
			}
			return stringBuilder.ToString();
		}

		private static Dictionary<string, string[]> ReadEmbedded(string code)
		{
			string text = "AllfathersChest.Localization." + code + ".json";
			try
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				using Stream stream = executingAssembly.GetManifestResourceStream(text);
				if (stream == null)
				{
					Report("Language file " + text + " is not embedded in this build.");
					return null;
				}
				using StreamReader streamReader = new StreamReader(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), detectEncodingFromByteOrderMarks: true);
				Dictionary<string, string[]> dictionary = Parse(streamReader.ReadToEnd());
				if (dictionary == null || dictionary.Count == 0)
				{
					Report("Language file " + text + " could not be read.");
					return null;
				}
				return dictionary;
			}
			catch (Exception ex)
			{
				Report("Language file " + text + " could not be read: " + ex.GetType().Name + ": " + ex.Message);
				return null;
			}
		}

		public static Dictionary<string, string[]> Parse(string json)
		{
			if (string.IsNullOrEmpty(json))
			{
				return null;
			}
			Dictionary<string, string[]> dictionary = new Dictionary<string, string[]>(StringComparer.Ordinal);
			List<string> list = new List<string>();
			int i = 0;
			SkipSpace(json, ref i);
			if (i >= json.Length || json[i] != '{')
			{
				return null;
			}
			i++;
			while (i < json.Length)
			{
				SkipSpace(json, ref i);
				if (i >= json.Length || json[i] == '}')
				{
					break;
				}
				if (json[i] == ',')
				{
					i++;
					continue;
				}
				string text = ReadString(json, ref i);
				if (text == null)
				{
					break;
				}
				SkipSpace(json, ref i);
				if (i >= json.Length || json[i] != ':')
				{
					break;
				}
				i++;
				SkipSpace(json, ref i);
				if (i >= json.Length)
				{
					break;
				}
				list.Clear();
				if (json[i] == '[')
				{
					i++;
					while (i < json.Length)
					{
						SkipSpace(json, ref i);
						if (i >= json.Length)
						{
							break;
						}
						if (json[i] == ']')
						{
							i++;
							break;
						}
						if (json[i] == ',')
						{
							i++;
							continue;
						}
						string text2 = ReadString(json, ref i);
						if (text2 == null)
						{
							break;
						}
						list.Add(text2);
					}
				}
				else
				{
					if (json[i] != '"')
					{
						for (; i < json.Length && json[i] != ',' && json[i] != '}'; i++)
						{
						}
						continue;
					}
					string text3 = ReadString(json, ref i);
					if (text3 != null)
					{
						list.Add(text3);
					}
				}
				if (list.Count > 0)
				{
					dictionary[text] = list.ToArray();
				}
			}
			return dictionary;
		}

		private static void SkipSpace(string s, ref int i)
		{
			while (i < s.Length && char.IsWhiteSpace(s[i]))
			{
				i++;
			}
		}

		private static string ReadString(string s, ref int i)
		{
			SkipSpace(s, ref i);
			if (i >= s.Length || s[i] != '"')
			{
				return null;
			}
			i++;
			StringBuilder stringBuilder = new StringBuilder();
			while (i < s.Length)
			{
				char c = s[i++];
				switch (c)
				{
				case '"':
					return stringBuilder.ToString();
				default:
					stringBuilder.Append(c);
					continue;
				case '\\':
					break;
				}
				if (i >= s.Length)
				{
					break;
				}
				char c2 = s[i++];
				switch (c2)
				{
				case 'n':
					stringBuilder.Append('\n');
					break;
				case 'r':
					stringBuilder.Append('\r');
					break;
				case 't':
					stringBuilder.Append('\t');
					break;
				case 'b':
					stringBuilder.Append('\b');
					break;
				case 'f':
					stringBuilder.Append('\f');
					break;
				case 'u':
					if (i + 4 <= s.Length)
					{
						if (int.TryParse(s.Substring(i, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
						{
							stringBuilder.Append((char)result);
						}
						i += 4;
					}
					break;
				default:
					stringBuilder.Append(c2);
					break;
				}
			}
			return null;
		}

		private static void Report(string message)
		{
			if (Reported.Add(message) && Log != null)
			{
				Log(message);
			}
		}
	}
}
namespace AllfathersChest.Ui
{
	internal static class SortButton
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__OnClick;
		}

		private const float Width = 180f;

		private static GameObject _go;

		private static TMP_Text[] _labels;

		private static UITooltip _tooltip;

		private static bool _shown;

		public static void Build(InventoryGui gui)
		{
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Expected O, but got Unknown
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Expected O, but got Unknown
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)gui == (Object)null || (Object)(object)gui.m_takeAllButton == (Object)null || (Object)(object)gui.m_container == (Object)null || ((Object)(object)_go != (Object)null && (Object)(object)_go.transform.parent == (Object)(object)gui.m_container))
			{
				return;
			}
			_go = Object.Instantiate<GameObject>(((Component)gui.m_takeAllButton).gameObject, (Transform)(object)gui.m_container, false);
			((Object)_go).name = "AllfathersChest_SortButton";
			Localize[] componentsInChildren = _go.GetComponentsInChildren<Localize>(true);
			foreach (Localize val in componentsInChildren)
			{
				Object.Destroy((Object)(object)val);
			}
			Button component = _go.GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				((UnityEventBase)component.onClick).RemoveAllListeners();
				ButtonClickedEvent onClick = component.onClick;
				object obj = <>O.<0>__OnClick;
				if (obj == null)
				{
					UnityAction val2 = OnClick;
					<>O.<0>__OnClick = val2;
					obj = (object)val2;
				}
				((UnityEvent)onClick).AddListener((UnityAction)obj);
			}
			_labels = _go.GetComponentsInChildren<TMP_Text>(true);
			_tooltip = _go.GetComponent<UITooltip>();
			string text = Texts.Get("button.sort");
			for (int j = 0; j < _labels.Length; j++)
			{
				if (!((Object)(object)_labels[j] == (Object)null))
				{
					_labels[j].enableAutoSizing = true;
					_labels[j].fontSizeMin = 10f;
					_labels[j].overflowMode = (TextOverflowModes)1;
					_labels[j].text = text;
				}
			}
			if ((Object)(object)_tooltip != (Object)null)
			{
				_tooltip.m_topic = text;
				_tooltip.m_text = Texts.Get("button.tip");
			}
			RectTransform val3 = (RectTransform)_go.transform;
			val3.anchorMin = new Vector2(1f, 0f);
			val3.anchorMax = new Vector2(1f, 0f);
			val3.pivot = new Vector2(1f, 1f);
			val3.anchoredPosition = new Vector2(0f, -6f);
			val3.sizeDelta = new Vector2(180f, val3.sizeDelta.y);
			_shown = true;
			Show(visible: false);
		}

		public static void Tick()
		{
			if (!((Object)(object)_go == (Object)null))
			{
				InventoryGui instance = InventoryGui.instance;
				Container val = (((Object)(object)instance != (Object)null) ? instance.m_currentContainer : null);
				Show((Object)(object)val != (Object)null && SortingChestPiece.IsOurs(val));
			}
		}

		public static void Reset()
		{
			_go = null;
			_labels = null;
			_tooltip = null;
			_shown = false;
		}

		private static void Show(bool visible)
		{
			if (visible != _shown)
			{
				_shown = visible;
				_go.SetActive(visible);
			}
		}

		private static void OnClick()
		{
			InventoryGui instance = InventoryGui.instance;
			Container val = (((Object)(object)instance != (Object)null) ? instance.m_currentContainer : null);
			if (!((Object)(object)val == (Object)null) && SortingChestPiece.IsOurs(val))
			{
				Distributor.Result result = Distributor.SortNow(val);
				Say(result);
			}
		}

		private static void Say(Distributor.Result result)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			int num = result.Moved + result.Gleaned;
			string text;
			if (num == 0 && result.Stuck == 0)
			{
				text = Texts.Get("message.none");
			}
			else
			{
				text = Texts.Get("message.sorted", "count", num.ToString());
				if (result.Stuck > 0)
				{
					text = text + ", " + Texts.Get("message.stuck", "count", result.Stuck.ToString());
				}
			}
			((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
		}
	}
}
namespace AllfathersChest.Sorting
{
	internal static class Distributor
	{
		public struct Result
		{
			public int Gleaned;

			public int Moved;

			public int Stuck;
		}

		private const int MovesPerPress = 128;

		private static readonly List<Container> Candidates = new List<Container>();

		private static readonly List<ChestFacts> Facts = new List<ChestFacts>();

		private static readonly List<List<ItemData>> RealStacks = new List<List<ItemData>>();

		private static readonly List<ItemData> Pending = new List<ItemData>();

		public static Result SortNow(Container hub)
		{
			Result result = default(Result);
			if (!ModConfig.Enabled.Value)
			{
				return result;
			}
			if ((Object)(object)hub == (Object)null || (Object)(object)hub.m_nview == (Object)null || !hub.m_nview.IsValid())
			{
				return result;
			}
			if (!hub.m_nview.IsOwner())
			{
				return result;
			}
			Inventory inventory = hub.GetInventory();
			if (inventory == null)
			{
				return result;
			}
			InUse.Forget(hub);
			if (inventory.NrOfItems() == 0)
			{
				Counter.Reset(hub);
				return result;
			}
			return Run(hub, inventory, 128, ModConfig.GroundPickup.Value);
		}

		public static Result Distribute(Container hub, int budget)
		{
			Result result = default(Result);
			if ((Object)(object)hub == (Object)null || (Object)(object)hub.m_nview == (Object)null || !hub.m_nview.IsValid())
			{
				return result;
			}
			if (!hub.m_nview.IsOwner())
			{
				return result;
			}
			Inventory inventory = hub.GetInventory();
			if (inventory == null)
			{
				return result;
			}
			if (inventory.NrOfItems() == 0)
			{
				Counter.Reset(hub);
				return result;
			}
			return Run(hub, inventory, budget, ModConfig.GroundPickup.Value);
		}

		private static Result Run(Container hub, Inventory from, int budget, bool glean)
		{
			Result result = default(Result);
			ContainerRegistry.Candidates(hub, ModConfig.Radius.Value, Candidates);
			if (Candidates.Count == 0)
			{
				return result;
			}
			Describe(hub);
			if (glean)
			{
				result.Gleaned = Gleaner.Glean(hub, ModConfig.Radius.Value, budget, Facts);
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			Pending.Clear();
			Pending.AddRange(from.GetAllItems());
			for (int i = 0; i < Pending.Count; i++)
			{
				if (budget <= 0)
				{
					break;
				}
				ItemData val = Pending[i];
				if (val == null || val.m_stack <= 0 || !from.ContainsItem(val))
				{
					continue;
				}
				while (budget > 0 && val.m_stack > 0)
				{
					Describe(hub);
					List<Move> list = StorePlanner.Plan(Facts_Of(val), Facts);
					if (list.Count == 0)
					{
						num2 += val.m_stack;
						break;
					}
					budget--;
					int num4 = Carry(hub, from, val, list[0]);
					if (num4 <= 0)
					{
						break;
					}
					num += num4;
					num3++;
				}
			}
			Counter.Note(hub, num, num2);
			result.Moved = num;
			result.Stuck = num2;
			if ((num > 0 || result.Gleaned > 0) && ModConfig.Verbose.Value)
			{
				AllfathersChestPlugin.Log.LogInfo((object)("Gleaned " + result.Gleaned + "; sorted " + num + " thing(s) in " + num3 + " move(s); " + num2 + " found no chest; " + Candidates.Count + " chest(s) in range."));
			}
			return result;
		}

		private static int Carry(Container hub, Inventory from, ItemData item, Move move)
		{
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			if (move.ChestId < 0 || move.ChestId >= Candidates.Count)
			{
				return 0;
			}
			Container val = Candidates[move.ChestId];
			if ((Object)(object)val == (Object)null || (Object)(object)val.m_nview == (Object)null || !val.m_nview.IsValid())
			{
				return 0;
			}
			if (InUse.Anywhere(val))
			{
				if (ModConfig.Verbose.Value)
				{
					AllfathersChestPlugin.Log.LogInfo((object)("  skipping " + Readable(val.m_name) + " - in use by " + InUse.Holder(val)));
				}
				return 0;
			}
			if (!val.m_nview.IsOwner())
			{
				Take(val.m_nview);
				return 0;
			}
			Inventory inventory = val.GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			Vector2i val3;
			if (move.StackIndex >= 0)
			{
				List<ItemData> list = RealStacks[move.ChestId];
				if (move.StackIndex >= list.Count)
				{
					return 0;
				}
				ItemData val2 = list[move.StackIndex];
				if (val2 == null || !inventory.ContainsItem(val2))
				{
					return 0;
				}
				val3 = val2.m_gridPos;
			}
			else
			{
				val3 = inventory.FindEmptySlot(true);
				if (val3.x < 0 || val3.y < 0)
				{
					return 0;
				}
			}
			int stack = item.m_stack;
			int num = Mathf.Min(move.Amount, stack);
			if (num <= 0)
			{
				return 0;
			}
			inventory.MoveItemToThis(from, item, num, val3.x, val3.y);
			int num2 = stack - item.m_stack;
			if (num2 <= 0)
			{
				return 0;
			}
			val.Save();
			hub.Save();
			if (ModConfig.Verbose.Value)
			{
				AllfathersChestPlugin.Log.LogInfo((object)("  " + num2 + "x " + Readable(Name(item)) + " -> " + Readable(val.m_name) + " at " + val3.x + "," + val3.y));
			}
			return num2;
		}

		private static bool Take(ZNetView view)
		{
			view.ClaimOwnership();
			return view.IsOwner();
		}

		private static void Describe(Container hub)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			Facts.Clear();
			RealStacks.Clear();
			Vector3 position = ((Component)hub).transform.position;
			for (int i = 0; i < Candidates.Count; i++)
			{
				Container val = Candidates[i];
				Inventory inventory = val.GetInventory();
				ChestFacts chestFacts = new ChestFacts
				{
					Id = i,
					Distance = Vector3.Distance(position, ((Component)val).transform.position),
					EmptySlots = inventory.GetEmptySlots()
				};
				List<ItemData> allItems = inventory.GetAllItems();
				List<ItemData> list = new List<ItemData>(allItems.Count);
				for (int j = 0; j < allItems.Count; j++)
				{
					ItemData val2 = allItems[j];
					if (val2 != null && val2.m_shared != null)
					{
						chestFacts.Stacks.Add(Facts_Of(val2));
						list.Add(val2);
					}
				}
				Facts.Add(chestFacts);
				RealStacks.Add(list);
			}
		}

		internal static StackFacts Facts_Of(ItemData item)
		{
			return new StackFacts
			{
				Name = Name(item),
				Quality = item.m_quality,
				WorldLevel = item.m_worldLevel,
				Stack = item.m_stack,
				MaxStack = ((item.m_shared != null) ? item.m_shared.m_maxStackSize : 0)
			};
		}

		private static string Name(ItemData item)
		{
			if (item == null || item.m_shared == null)
			{
				return "";
			}
			return item.m_shared.m_name;
		}

		private static string Readable(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return "?";
			}
			if (Localization.instance == null)
			{
				return token;
			}
			return Localization.instance.Localize(token);
		}
	}
	internal static class Gleaner
	{
		public static int Glean(Container hub, float radius, int budget, IList<ChestFacts> homes)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			if (homes == null || homes.Count == 0)
			{
				return 0;
			}
			List<ItemDrop> s_instances = ItemDrop.s_instances;
			if (s_instances == null || s_instances.Count == 0)
			{
				return 0;
			}
			Inventory inventory = hub.GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			Vector3 position = ((Component)hub).transform.position;
			float num = radius * radius;
			float num2 = Mathf.Max(0f, ModConfig.GroundGraceSeconds.Value);
			int num3 = 0;
			int num4 = 0;
			for (int i = 0; i < s_instances.Count; i++)
			{
				if (budget <= 0)
				{
					break;
				}
				ItemDrop val = s_instances[i];
				if ((Object)(object)val == (Object)null || val.IsPiece() || (Object)(object)val.m_nview == (Object)null || !val.m_nview.IsValid())
				{
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - position;
				if (((Vector3)(ref val2)).sqrMagnitude > num || val.GetTimeSinceSpawned() < (double)num2)
				{
					continue;
				}
				ItemData itemData = val.m_itemData;
				if (itemData == null || itemData.m_shared == null || itemData.m_stack <= 0 || itemData.m_shared.m_questItem || !inventory.CanAddItem(itemData, itemData.m_stack))
				{
					continue;
				}
				if (StorePlanner.Plan(Distributor.Facts_Of(itemData), homes).Count == 0)
				{
					num4++;
					continue;
				}
				if (!val.CanPickup(false))
				{
					val.RequestOwn();
					continue;
				}
				val.Load();
				itemData = val.m_itemData;
				if (itemData == null || itemData.m_stack <= 0)
				{
					continue;
				}
				int stack = itemData.m_stack;
				if (inventory.AddItem(itemData))
				{
					ZNetScene.instance.Destroy(((Component)val).gameObject);
					hub.Save();
					num3 += stack;
					budget--;
					if (ModConfig.Verbose.Value)
					{
						AllfathersChestPlugin.Log.LogInfo((object)("  picked up " + stack + "x " + Readable(itemData.m_shared.m_name)));
					}
				}
			}
			if (num4 > 0 && ModConfig.Verbose.Value)
			{
				AllfathersChestPlugin.Log.LogInfo((object)("  " + num4 + " thing(s) left on the ground - no chest free for them right now."));
			}
			return num3;
		}

		private static string Readable(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return "?";
			}
			if (Localization.instance == null)
			{
				return token;
			}
			return Localization.instance.Localize(token);
		}
	}
	public struct StackFacts
	{
		public string Name;

		public int Quality;

		public int WorldLevel;

		public int Stack;

		public int MaxStack;
	}
	public sealed class ChestFacts
	{
		public int Id;

		public float Distance;

		public int EmptySlots;

		public readonly List<StackFacts> Stacks = new List<StackFacts>();
	}
	public struct Move
	{
		public int ChestId;

		public int Amount;

		public int StackIndex;
	}
	public static class StorePlanner
	{
		public static List<Move> Plan(StackFacts item, IList<ChestFacts> chests)
		{
			List<Move> list = new List<Move>();
			if (item.Stack <= 0 || item.MaxStack <= 0 || chests == null || chests.Count == 0)
			{
				return list;
			}
			List<ChestFacts> list2 = Ordered(chests);
			int num = item.Stack;
			for (int i = 0; i < list2.Count; i++)
			{
				if (num <= 0)
				{
					break;
				}
				ChestFacts chestFacts = list2[i];
				for (int j = 0; j < chestFacts.Stacks.Count; j++)
				{
					if (num <= 0)
					{
						break;
					}
					StackFacts there = chestFacts.Stacks[j];
					if (Mergeable(item, there))
					{
						int num2 = there.MaxStack - there.Stack;
						if (num2 > 0)
						{
							int num3 = ((num2 < num) ? num2 : num);
							list.Add(new Move
							{
								ChestId = chestFacts.Id,
								Amount = num3,
								StackIndex = j
							});
							num -= num3;
						}
					}
				}
			}
			for (int k = 0; k < list2.Count; k++)
			{
				if (num <= 0)
				{
					break;
				}
				ChestFacts chestFacts2 = list2[k];
				if (Keeps(chestFacts2, item.Name))
				{
					int num4 = chestFacts2.EmptySlots;
					while (num4 > 0 && num > 0)
					{
						int num5 = ((item.MaxStack < num) ? item.MaxStack : num);
						list.Add(new Move
						{
							ChestId = chestFacts2.Id,
							Amount = num5,
							StackIndex = -1
						});
						num -= num5;
						num4--;
					}
				}
			}
			return list;
		}

		private static List<ChestFacts> Ordered(IList<ChestFacts> chests)
		{
			List<ChestFacts> list = new List<ChestFacts>(chests);
			for (int i = 1; i < list.Count; i++)
			{
				ChestFacts chestFacts = list[i];
				int num = i - 1;
				while (num >= 0 && list[num].Distance > chestFacts.Distance)
				{
					list[num + 1] = list[num];
					num--;
				}
				list[num + 1] = chestFacts;
			}
			return list;
		}

		private static bool Mergeable(StackFacts item, StackFacts there)
		{
			if (string.Equals(item.Name, there.Name, StringComparison.Ordinal) && item.Quality == there.Quality)
			{
				return item.WorldLevel == there.WorldLevel;
			}
			return false;
		}

		private static bool Keeps(ChestFacts chest, string name)
		{
			for (int i = 0; i < chest.Stacks.Count; i++)
			{
				if (string.Equals(chest.Stacks[i].Name, name, StringComparison.Ordinal))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class Upkeep
	{
		private const int Budget = 16;

		private static readonly List<Container> Hubs = new List<Container>();

		private static readonly List<Container> Everything = new List<Container>();

		private static readonly HashSet<ZDOID> Settled = new HashSet<ZDOID>();

		private static readonly HashSet<ZDOID> Current = new HashSet<ZDOID>();

		private static long _toldAbout;

		public static void Tick()
		{
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			Speak();
			if (!ModConfig.AutoSort.Value)
			{
				return;
			}
			ContainerRegistry.Hubs(Hubs);
			Current.Clear();
			for (int i = 0; i < Hubs.Count; i++)
			{
				Container val = Hubs[i];
				if ((Object)(object)val == (Object)null || (Object)(object)val.m_nview == (Object)null || !val.m_nview.IsValid())
				{
					continue;
				}
				ZDO zDO = val.m_nview.GetZDO();
				if (zDO == null)
				{
					continue;
				}
				if (!val.m_nview.IsOwner())
				{
					Announce(val, zDO);
					continue;
				}
				ZDOID uid = zDO.m_uid;
				Current.Add(uid);
				if (Settled.Contains(uid) && !InUse.Anywhere(val))
				{
					InUse.Forget(val);
					Report(Distributor.Distribute(val, 16));
				}
			}
			Settled.Clear();
			foreach (ZDOID item in Current)
			{
				Settled.Add(item);
			}
		}

		private static void Speak()
		{
			ContainerRegistry.All(Everything);
			for (int i = 0; i < Everything.Count; i++)
			{
				InUse.Publish(Everything[i]);
			}
		}

		public static void Reset()
		{
			Hubs.Clear();
			Everything.Clear();
			Settled.Clear();
			Current.Clear();
			_toldAbout = 0L;
		}

		private static void Announce(Container hub, ZDO zdo)
		{
			if (!ModConfig.Verbose.Value)
			{
				return;
			}
			long owner = zdo.GetOwner();
			if (owner != _toldAbout)
			{
				_toldAbout = owner;
				string text = "nobody";
				if (owner != 0L && (Object)(object)ZNet.instance != (Object)null)
				{
					ZNetPeer peer = ZNet.instance.GetPeer(owner);
					text = ((peer == null || string.IsNullOrEmpty(peer.m_playerName)) ? owner.ToString() : peer.m_playerName);
				}
				AllfathersChestPlugin.Log.LogInfo((object)("The chest belongs to " + text + " right now, so their machine looks after it - not this one."));
			}
		}

		private static void Report(Distributor.Result result)
		{
			if (ModConfig.Verbose.Value && (result.Gleaned != 0 || result.Moved != 0))
			{
				AllfathersChestPlugin.Log.LogInfo((object)("Upkeep: swept " + result.Gleaned + ", handed out " + result.Moved + ", " + result.Stuck + " still with nowhere to go."));
			}
		}
	}
}
namespace AllfathersChest.Patches
{
	[HarmonyPatch(typeof(Container), "Awake")]
	internal static class ContainerAwakePatch
	{
		private static void Postfix(Container __instance)
		{
			ContainerRegistry.Note(__instance);
		}
	}
	[HarmonyPatch(typeof(Container), "GetHoverText")]
	internal static class ContainerHoverPatch
	{
		private static void Postfix(Container __instance, ref string __result)
		{
			if (ModConfig.ShowCounter.Value && SortingChestPiece.IsOurs(__instance))
			{
				string text = Counter.Line(__instance);
				if (text.Length != 0)
				{
					__result = text + "\n" + __result;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Container), "SetInUse")]
	internal static class ContainerInUsePatch
	{
		private static void Postfix(Container __instance, bool inUse)
		{
			InUse.Mark(__instance, inUse);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Awake")]
	internal static class InventoryGuiAwakePatch
	{
		[HarmonyPostfix]
		private static void Postfix(InventoryGui __instance)
		{
			SortButton.Build(__instance);
		}
	}
}
namespace AllfathersChest.Chest
{
	internal static class ContainerRegistry
	{
		private static readonly List<Container> Known = new List<Container>();

		public static int Count => Known.Count;

		public static void Note(Container container)
		{
			if (!((Object)(object)container == (Object)null))
			{
				Known.Add(container);
			}
		}

		public static void All(List<Container> into)
		{
			into.Clear();
			Sweep();
			into.AddRange(Known);
		}

		public static void Hubs(List<Container> into)
		{
			into.Clear();
			Sweep();
			for (int i = 0; i < Known.Count; i++)
			{
				if (SortingChestPiece.IsOurs(Known[i]))
				{
					into.Add(Known[i]);
				}
			}
		}

		public static void Candidates(Container hub, float radius, List<Container> into)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			into.Clear();
			if ((Object)(object)hub == (Object)null)
			{
				return;
			}
			Sweep();
			Vector3 position = ((Component)hub).transform.position;
			float num = radius * radius;
			for (int i = 0; i < Known.Count; i++)
			{
				Container val = Known[i];
				if (val != hub && !SortingChestPiece.IsOurs(val) && (int)val.m_privacy == 2 && !((Object)(object)val.m_wagon != (Object)null) && !((Object)(object)val.m_nview == (Object)null) && val.m_nview.IsValid() && val.GetInventory() != null)
				{
					Vector3 val2 = ((Component)val).transform.position - position;
					if (!(((Vector3)(ref val2)).sqrMagnitude > num) && !InUse.Anywhere(val))
					{
						into.Add(val);
					}
				}
			}
		}

		public static void Clear()
		{
			Known.Clear();
		}

		private static void Sweep()
		{
			for (int num = Known.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)Known[num] == (Object)null)
				{
					Known.RemoveAt(num);
				}
			}
		}
	}
	internal static class Counter
	{
		private const string MovedKey = "sohneg_ac_moved";

		private const string StuckKey = "sohneg_ac_stuck";

		public static void Note(Container hub, int moved, int stuck)
		{
			ZDO val = Writable(hub);
			if (val != null)
			{
				if (moved > 0)
				{
					val.Set("sohneg_ac_moved", val.GetInt("sohneg_ac_moved", 0) + moved);
				}
				val.Set("sohneg_ac_stuck", stuck);
			}
		}

		public static void Reset(Container hub)
		{
			ZDO val = Writable(hub);
			if (val != null && (val.GetInt("sohneg_ac_moved", 0) != 0 || val.GetInt("sohneg_ac_stuck", 0) != 0))
			{
				val.Set("sohneg_ac_moved", 0);
				val.Set("sohneg_ac_stuck", 0);
			}
		}

		public static string Line(Container hub)
		{
			if ((Object)(object)hub == (Object)null || (Object)(object)hub.m_nview == (Object)null || !hub.m_nview.IsValid())
			{
				return "";
			}
			ZDO zDO = hub.m_nview.GetZDO();
			if (zDO == null)
			{
				return "";
			}
			int num = zDO.GetInt("sohneg_ac_moved", 0);
			int num2 = zDO.GetInt("sohneg_ac_stuck", 0);
			if (num == 0 && num2 == 0)
			{
				return Texts.Get("chest.idle");
			}
			string text = "";
			if (num > 0)
			{
				text = Texts.Get("chest.moved", "count", num.ToString());
			}
			if (num2 > 0)
			{
				string text2 = Texts.Get("chest.stuck", "count", num2.ToString());
				text = ((text.Length > 0) ? (text + ", " + text2) : text2);
			}
			return text;
		}

		private static ZDO Writable(Container hub)
		{
			if ((Object)(object)hub == (Object)null || (Object)(object)hub.m_nview == (Object)null || !hub.m_nview.IsValid())
			{
				return null;
			}
			if (!hub.m_nview.IsOwner())
			{
				return null;
			}
			return hub.m_nview.GetZDO();
		}
	}
	internal static class InUse
	{
		private const string Key = "sohneg_ac_state";

		private const int Unknown = 0;

		private const int Closed = 1;

		private const int Open = 2;

		private const float Margin = 2f;

		private const float FallbackReach = 6f;

		public static void Mark(Container container, bool open)
		{
			if (!((Object)(object)container == (Object)null) && !((Object)(object)container.m_nview == (Object)null) && container.m_nview.IsValid() && container.m_nview.IsOwner())
			{
				ZDO zDO = container.m_nview.GetZDO();
				if (zDO != null)
				{
					zDO.Set("sohneg_ac_state", (!open) ? 1 : 2);
				}
			}
		}

		public static void Publish(Container container)
		{
			if ((Object)(object)container == (Object)null || (Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid() || !container.m_nview.IsOwner())
			{
				return;
			}
			ZDO zDO = container.m_nview.GetZDO();
			if (zDO != null)
			{
				int num = ((!container.IsInUse()) ? 1 : 2);
				if (zDO.GetInt("sohneg_ac_state", 0) != num)
				{
					zDO.Set("sohneg_ac_state", num);
				}
			}
		}

		public static bool Anywhere(Container container)
		{
			if ((Object)(object)container == (Object)null || (Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid())
			{
				return false;
			}
			if (container.IsInUse())
			{
				return true;
			}
			ZDO zDO = container.m_nview.GetZDO();
			if (zDO == null)
			{
				return false;
			}
			return zDO.GetInt("sohneg_ac_state", 0) switch
			{
				2 => true, 
				1 => false, 
				_ => OwnerIsStandingAtIt(container, zDO), 
			};
		}

		private static bool OwnerIsStandingAtIt(Container container, ZDO zdo)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return false;
			}
			long owner = zdo.GetOwner();
			if (owner == 0L)
			{
				return false;
			}
			if (owner == ZDOMan.GetSessionID())
			{
				return false;
			}
			ZNetPeer peer = ZNet.instance.GetPeer(owner);
			if (peer == null)
			{
				return false;
			}
			float num = Reach();
			Vector3 val = peer.m_refPos - ((Component)container).transform.position;
			return ((Vector3)(ref val)).sqrMagnitude <= num * num;
		}

		private static float Reach()
		{
			InventoryGui instance = InventoryGui.instance;
			float num = (((Object)(object)instance != (Object)null) ? instance.m_autoCloseDistance : 0f);
			if (num <= 0f)
			{
				num = 6f;
			}
			return num + 2f;
		}

		public static void Forget(Container container)
		{
			if (!((Object)(object)container == (Object)null) && !((Object)(object)container.m_nview == (Object)null) && container.m_nview.IsValid() && container.m_nview.IsOwner() && !container.IsInUse())
			{
				ZDO zDO = container.m_nview.GetZDO();
				if (zDO != null && zDO.GetInt("sohneg_ac_state", 0) != 1)
				{
					zDO.Set("sohneg_ac_state", 1);
				}
			}
		}

		public static string Holder(Container container)
		{
			if ((Object)(object)container == (Object)null || (Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid())
			{
				return "";
			}
			if (container.IsInUse())
			{
				return "us";
			}
			ZDO zDO = container.m_nview.GetZDO();
			if (zDO == null)
			{
				return "";
			}
			long owner = zDO.GetOwner();
			if (owner == 0L || owner == ZDOMan.GetSessionID())
			{
				return "";
			}
			ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetPeer(owner) : null);
			if (val == null)
			{
				return "";
			}
			string text = (string.IsNullOrEmpty(val.m_playerName) ? owner.ToString() : val.m_playerName);
			if (zDO.GetInt("sohneg_ac_state", 0) != 2)
			{
				return text + " (standing by it)";
			}
			return text + " (says so)";
		}
	}
	internal sealed class RangeRing : MonoBehaviour
	{
		private const int Segments = 96;

		private const float ViewingMargin = 20f;

		private const float CheckSeconds = 0.25f;

		private static readonly string[] Shaders = new string[3] { "Hidden/Internal-Colored", "Sprites/Default", "Unlit/Color" };

		private static Material _material;

		private static bool _complained;

		private LineRenderer[] _rings;

		private float _drawnRadius = -1f;

		private float _nextCheck;

		private void Update()
		{
			if (Time.unscaledTime < _nextCheck)
			{
				return;
			}
			_nextCheck = Time.unscaledTime + 0.25f;
			float value = ModConfig.Radius.Value;
			if (!ModConfig.ShowRange.Value || !PlayerIsNear(value))
			{
				Show(visible: false);
				return;
			}
			if (_rings == null || !Mathf.Approximately(value, _drawnRadius))
			{
				Build(value);
			}
			Show(_rings != null);
		}

		private void OnDestroy()
		{
			_rings = null;
		}

		private bool PlayerIsNear(float radius)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			float num = radius + 20f;
			Vector3 val = ((Component)localPlayer).transform.position - ((Component)this).transform.position;
			return ((Vector3)(ref val)).sqrMagnitude <= num * num;
		}

		private void Build(float radius)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			Material val = Paint();
			if (!((Object)(object)val == (Object)null))
			{
				Clear();
				_rings = (LineRenderer[])(object)new LineRenderer[3]
				{
					Circle(val, radius, Vector3.right, Vector3.forward),
					Circle(val, radius, Vector3.right, Vector3.up),
					Circle(val, radius, Vector3.forward, Vector3.up)
				};
				_drawnRadius = radius;
			}
		}

		private LineRenderer Circle(Material material, float radius, Vector3 a, Vector3 b)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("AllfathersChest_Range");
			val.transform.SetParent(((Component)this).transform, false);
			val.transform.rotation = Quaternion.identity;
			LineRenderer val2 = val.AddComponent<LineRenderer>();
			val2.useWorldSpace = false;
			val2.loop = true;
			val2.positionCount = 96;
			val2.widthMultiplier = 0.08f;
			((Renderer)val2).sharedMaterial = material;
			val2.startColor = new Color(1f, 0.79f, 0.32f, 0.55f);
			val2.endColor = val2.startColor;
			((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)val2).receiveShadows = false;
			((Renderer)val2).lightProbeUsage = (LightProbeUsage)0;
			Vector3[] array = (Vector3[])(object)new Vector3[96];
			for (int i = 0; i < 96; i++)
			{
				float num = (float)i * 2f * (float)Math.PI / 96f;
				array[i] = (a * Mathf.Cos(num) + b * Mathf.Sin(num)) * radius;
			}
			val2.SetPositions(array);
			return val2;
		}

		private void Show(bool visible)
		{
			if (_rings == null)
			{
				return;
			}
			for (int i = 0; i < _rings.Length; i++)
			{
				if (!((Object)(object)_rings[i] == (Object)null) && ((Renderer)_rings[i]).enabled != visible)
				{
					((Renderer)_rings[i]).enabled = visible;
				}
			}
		}

		private void Clear()
		{
			if (_rings == null)
			{
				return;
			}
			for (int i = 0; i < _rings.Length; i++)
			{
				if ((Object)(object)_rings[i] != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)_rings[i]).gameObject);
				}
			}
			_rings = null;
		}

		private static Material Paint()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			if ((Object)(object)_material != (Object)null)
			{
				return _material;
			}
			if (_complained)
			{
				return null;
			}
			Shader val = null;
			for (int i = 0; i < Shaders.Length; i++)
			{
				if (!((Object)(object)val == (Object)null))
				{
					break;
				}
				val = Shader.Find(Shaders[i]);
			}
			if ((Object)(object)val == (Object)null)
			{
				_complained = true;
				AllfathersChestPlugin.Log.LogWarning((object)"No shader for the range rings - 3 - Sorting / ShowRange will do nothing. Everything else is unaffected.");
				return null;
			}
			_material = new Material(val);
			((Object)_material).hideFlags = (HideFlags)61;
			_material.SetInt("_SrcBlend", 5);
			_material.SetInt("_DstBlend", 10);
			_material.SetInt("_Cull", 0);
			_material.SetInt("_ZWrite", 0);
			return _material;
		}
	}
	internal static class SortingChestPiece
	{
		public const string PrefabName = "AllfathersChest_Hub";

		private static readonly string[] Fallbacks = new string[3] { "piece_chest", "piece_chest_wood", "piece_chest_blackmetal" };

		private static GameObject _prefab;

		private static GameObject _holder;

		private static bool _complained;

		private static Player _knownTo;

		private static int _sizedFor;

		private static int _costedFor;

		public static bool Exists => (Object)(object)_prefab != (Object)null;

		public static bool IsOurs(Container container)
		{
			if ((Object)(object)container == (Object)null)
			{
				return false;
			}
			return string.Equals(Utils.GetPrefabName(((Component)container).gameObject), "AllfathersChest_Hub", StringComparison.Ordinal);
		}

		public static void Tick()
		{
			try
			{
				EnsurePrefab();
				EnsureSize();
				EnsureCost();
				EnsureInScene();
				EnsureInBuildMenu();
				EnsureKnown();
			}
			catch (Exception ex)
			{
				if (!_complained)
				{
					_complained = true;
					AllfathersChestPlugin.Log.LogError((object)("Could not set up the chest: " + ex));
				}
			}
		}

		public static void Reset()
		{
			_complained = false;
			_knownTo = null;
		}

		private static void EnsurePrefab()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_prefab != (Object)null)
			{
				return;
			}
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			GameObject val = FindBase(instance);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if ((Object)(object)_holder == (Object)null)
			{
				_holder = new GameObject("AllfathersChest_PrefabHolder");
				_holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_holder);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, _holder.transform);
			((Object)val2).name = "AllfathersChest_Hub";
			ZNetView val3 = val2.GetComponent<ZNetView>();
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = val2.AddComponent<ZNetView>();
			}
			val3.m_persistent = true;
			Container component = val2.GetComponent<Container>();
			if ((Object)(object)component == (Object)null)
			{
				AllfathersChestPlugin.Log.LogError((object)("The base piece '" + ((Object)val).name + "' has no Container. Set 2 - Chest / BasePrefab to an actual chest."));
				return;
			}
			component.m_name = Texts.Get("chest.name");
			component.m_privacy = (PrivacySetting)2;
			component.m_defaultItems = null;
			if ((Object)(object)val2.GetComponent<RangeRing>() == (Object)null)
			{
				val2.AddComponent<RangeRing>();
			}
			Piece val4 = val2.GetComponent<Piece>();
			if ((Object)(object)val4 == (Object)null)
			{
				val4 = val2.AddComponent<Piece>();
			}
			val4.m_name = Texts.Get("chest.name");
			val4.m_description = Texts.Get("chest.description");
			val4.m_category = (PieceCategory)0;
			val4.m_enabled = true;
			val4.m_groundPiece = false;
			val4.m_allowedInDungeons = true;
			val4.m_craftingStation = null;
			if ((Object)(object)val4.m_icon == (Object)null)
			{
				Piece component2 = val.GetComponent<Piece>();
				if ((Object)(object)component2 != (Object)null)
				{
					val4.m_icon = component2.m_icon;
				}
			}
			_prefab = val2;
			_sizedFor = 0;
			_costedFor = 0;
			AllfathersChestPlugin.Log.LogInfo((object)("Chest built from " + ((Object)val).name + "."));
		}

		private static GameObject FindBase(ZNetScene scene)
		{
			string text = (ModConfig.BasePrefab.Value ?? "").Trim();
			if (text.Length > 0)
			{
				GameObject prefab = scene.GetPrefab(text);
				if ((Object)(object)prefab != (Object)null)
				{
					return prefab;
				}
				AllfathersChestPlugin.Log.LogWarning((object)("No prefab named '" + text + "' - falling back. Set 2 - Chest / BasePrefab to one that exists."));
			}
			for (int i = 0; i < Fallbacks.Length; i++)
			{
				GameObject prefab2 = scene.GetPrefab(Fallbacks[i]);
				if ((Object)(object)prefab2 != (Object)null)
				{
					return prefab2;
				}
			}
			return null;
		}

		private static void EnsureSize()
		{
			if ((Object)(object)_prefab == (Object)null)
			{
				return;
			}
			int num = Mathf.Clamp(ModConfig.Width.Value, 1, 8);
			int num2 = Mathf.Clamp(ModConfig.Height.Value, 1, 8);
			int num3 = num * 100 + num2;
			if (num3 != _sizedFor)
			{
				Container component = _prefab.GetComponent<Container>();
				if (!((Object)(object)component == (Object)null))
				{
					component.m_width = num;
					component.m_height = num2;
					_sizedFor = num3;
				}
			}
		}

		private static void EnsureCost()
		{
			if ((Object)(object)_prefab == (Object)null)
			{
				return;
			}
			int num = Mathf.Clamp(ModConfig.Cost.Value, 1, 999);
			if (num == _costedFor)
			{
				return;
			}
			Piece component = _prefab.GetComponent<Piece>();
			if (!((Object)(object)component == (Object)null))
			{
				Requirement[] array = Cost(num);
				if (array != null)
				{
					component.m_resources = array;
					_costedFor = num;
				}
			}
		}

		private static Requirement[] Cost(int amount)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			GameObject val = Resolve("Wood");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			ItemDrop component = val.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			return (Requirement[])(object)new Requirement[1]
			{
				new Requirement
				{
					m_resItem = component,
					m_amount = amount,
					m_recover = true
				}
			};
		}

		private static GameObject Resolve(string name)
		{
			ObjectDB instance = ObjectDB.instance;
			GameObject val = (((Object)(object)instance != (Object)null) ? instance.GetItemPrefab(name) : null);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			ZNetScene instance2 = ZNetScene.instance;
			if (!((Object)(object)instance2 != (Object)null))
			{
				return null;
			}
			return instance2.GetPrefab(name);
		}

		private static void EnsureInScene()
		{
			if ((Object)(object)_prefab == (Object)null)
			{
				return;
			}
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null || instance.m_namedPrefabs == null)
			{
				return;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode("AllfathersChest_Hub");
			if (!instance.m_namedPrefabs.ContainsKey(stableHashCode))
			{
				instance.m_namedPrefabs[stableHashCode] = _prefab;
				if (instance.m_prefabs != null && !instance.m_prefabs.Contains(_prefab))
				{
					instance.m_prefabs.Add(_prefab);
				}
			}
		}

		private static void EnsureInBuildMenu()
		{
			if (!((Object)(object)_prefab == (Object)null))
			{
				PieceTable val = HammerPieces();
				if (!((Object)(object)val == (Object)null) && val.m_pieces != null && !val.m_pieces.Contains(_prefab))
				{
					val.m_pieces.Add(_prefab);
					AllfathersChestPlugin.Log.LogInfo((object)"Chest added to the hammer's build menu.");
				}
			}
		}

		private static void EnsureKnown()
		{
			if ((Object)(object)_prefab == (Object)null)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				_knownTo = null;
			}
			else if (_knownTo != localPlayer)
			{
				Piece component = _prefab.GetComponent<Piece>();
				if (!((Object)(object)component == (Object)null))
				{
					localPlayer.AddKnownPiece(component);
					localPlayer.UpdateAvailablePiecesList();
					_knownTo = localPlayer;
					AllfathersChestPlugin.Log.LogInfo((object)("The chest is known to " + localPlayer.GetPlayerName() + " and the build menu was refreshed."));
				}
			}
		}

		public static string Describe()
		{
			if ((Object)(object)_prefab == (Object)null)
			{
				return "No prefab yet - the base chest was not found. Check BasePrefab.";
			}
			Piece component = _prefab.GetComponent<Piece>();
			Container component2 = _prefab.GetComponent<Container>();
			PieceTable val = HammerPieces();
			bool value = (Object)(object)ZNetScene.instance != (Object)null && ZNetScene.instance.m_namedPrefabs != null && ZNetScene.instance.m_namedPrefabs.ContainsKey(StringExtensionMethods.GetStableHashCode("AllfathersChest_Hub"));
			bool value2 = (Object)(object)val != (Object)null && val.m_pieces != null && val.m_pieces.Contains(_prefab);
			bool value3 = (Object)(object)val != (Object)null && val.m_availablePieces != null && (Object)(object)component != (Object)null && Contains(val, component);
			return "prefab: yes | in scene: " + Yes(value) + " | in hammer list: " + Yes(value2) + " | shown in menu: " + Yes(value3) + " | known: " + Yes((Object)(object)_knownTo != (Object)null) + " | grid: " + (((Object)(object)component2 != (Object)null) ? (component2.m_width + "x" + component2.m_height) : "-") + " | icon: " + Yes((Object)(object)component != (Object)null && (Object)(object)component.m_icon != (Object)null) + " | cost: " + (((Object)(object)component != (Object)null && component.m_resources != null) ? component.m_resources.Length.ToString() : "0") + " requirement(s)";
		}

		private static bool Contains(PieceTable table, Piece piece)
		{
			foreach (Piece availablePiece in table.m_availablePieces)
			{
				if (availablePiece == piece)
				{
					return true;
				}
			}
			return false;
		}

		private static string Yes(bool value)
		{
			if (!value)
			{
				return "NO";
			}
			return "yes";
		}

		private static PieceTable HammerPieces()
		{
			GameObject val = Resolve("Hammer");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			ItemDrop component = val.GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null)
			{
				return null;
			}
			return component.m_itemData.m_shared.m_buildPieces;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}